user: How can you write a first person controller script in GDscript and apply it to a KinematicBody-node when using Godot Engine 3.x and what is the equivalent to the KinematicBody-node in Godot Engine 4.x and how does the first person controller script need to be changed to work in Godot Engine 4.x?

assistant: In Godot Engine 3.x, you can write a first person controller script in GDscript by creating a new script and attaching it to a KinematicBody node. Here is an example of a basic first person controller script:
```csharp
extends KinematicBody

var speed = 5
var mouse_sensitivity = 0.1
var jumping = false
var jump_speed = 10
var gravity = -20
var jump_height = 1.5
var jump_sustain = 0.1

func _input(event):
    if event is InputEventMouseMotion:
        rotation_degrees.y -= event.relative.x * mouse_sensitivity
        rotation_degrees.x = clamp(rotation_degrees.x + event.relative.y * mouse_sensitivity, -90, 90)
    
    if event is InputEventKey and event.pressed and event.scancode == KEY_W:
        var velocity = speed * Vector3(0, 0, 1)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move_and_slide(velocity)
        
    if event is InputEventKey and event.pressed and event.scancode == KEY_S:
        var velocity = speed * Vector3(0, 0, -1)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move_and_slide(velocity)
        
    if event is InputEventKey and event.pressed and event.scancode == KEY_A:
        var velocity = speed * Vector3(-1, 0, 0)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move_and_slide(velocity)
        
    if event is InputEventKey and event.pressed and event.scancode == KEY_D:
        var velocity = speed * Vector3(1, 0, 0)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move_and_slide(velocity)
        
    if event is InputEventKey and event.pressed and event.scancode == KEY_SPACE and not jumping:
        jumping = true
        var velocity = Vector3(0, jump_speed, 0)
        move_and_slide(velocity)
        
func _physics_process(delta):
    if jumping:
        var velocity = move_and_slide(Vector3(0, gravity * delta, 0))
        if velocity.y < 0:
            jumping = false
```

In Godot Engine 4.x, the equivalent to the KinematicBody node is the CharacterController node. To use this node, you will need to change your script to inherit from the CharacterController class. Additionally, the input handling and movement control will be different, as the CharacterController node uses a different API. Here is an example of how the first person controller script would look in Godot Engine 4.x:
```
extends CharacterController

var speed = 5
var mouse_sensitivity = 0.1
var jumping = false
var jump_speed = 10
var gravity = -20
var jump_height = 1.5
var jump_sustain = 0.1

func _input(event):
    if event is InputEventMouseMotion:
        rotation_degrees.y -= event.relative.x * mouse_sensitivity
        rotation_degrees.x = clamp(rotation_degrees.x + event.relative.y * mouse_sensitivity, -90, 90)

    if event is InputEventKey and event.pressed and event.scancode == KEY_W:
        var velocity = speed * Vector3(0, 0, 1)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move(velocity)
    
    if event is InputEventKey and event.pressed and event.scancode == KEY_S:
        var velocity = speed * Vector3(0, 0, -1)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move(velocity)
    
    if event is InputEventKey and event.pressed and event.scancode == KEY_A:
        var velocity = speed * Vector3(-1, 0, 0)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move(velocity)
    
    if event is InputEventKey and event.pressed and event.scancode == KEY_D:
        var velocity = speed * Vector3(1, 0, 0)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move(velocity)
    
    if event is InputEventKey and event.pressed and event.scancode == KEY_SPACE and not jumping:
        jumping = true
        var velocity = Vector3(0, jump_speed, 0)
        velocity = velocity.rotated(Vector3(0, 1, 0), -rotation.y)
        move(velocity)
    
func _physics_process(delta):
    if jumping:
        var velocity = move(Vector3(0, gravity * delta, 0))
    if velocity.y < 0:
        jumping = false
```

Note: The `move` method replaces the `move_and_slide` method from Godot Engine 3.x, and it uses the CharacterController API to handle movement.

user: Could you explain the _physics_process function?

assistant: The _physics_process function is a special function in the Godot engine that is called once per frame, with a delta value indicating the time passed since the last call. It's purpose is to handle the physics calculations for an object in the scene.

In this specific code block, it first checks if the jumping variable is true. If so, it calculates the new velocity of the object based on the gravity value multiplied by the delta value. This is to simulate the effect of gravity on the object.

Then, it checks if the new y component of the velocity is less than 0. If so, it sets jumping to false, which could indicate that the object has landed on the ground after jumping.