extends CharacterBody3D # Acceleration and deceleration are m/s². # max_speed is m/s. @export var accel := 6.7 @export var deccel := 8.5 @export var max_speed := 6.2 @export var has_suit := true @export var has_hvms2 := true @export var gravity := 9.8 @export var jump_velocity := 4.5 # Mouse sensitivity @export var mouse_sensitivity := 0.003 # Maximum camera pitch in degrees @export var max_pitch := 89.0 var movement_vec := Vector3.ZERO var input_vec := Vector4.ZERO var jump := false var air_jumps := 0 func _ready() -> void: if not has_suit: $yaw/pitch/Camera/Hud.visible = false if has_hvms2: max_speed = 30.0 accel = 10 deccel = 20 jump_velocity = 10 # Capture the mouse when the game starts Input.mouse_mode = Input.MOUSE_MODE_CAPTURED func _input(event: InputEvent) -> void: # Mouse-look if event is InputEventMouseMotion: if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: # Horizontal rotation: rotate the player $yaw.rotate_y(-event.relative.x * mouse_sensitivity) # Vertical rotation: rotate the camera $yaw/pitch.rotate_x(-event.relative.y * mouse_sensitivity) # Clamp pitch so the camera cannot flip upside down $yaw/pitch.rotation.x = clamp( $yaw/pitch.rotation.x, deg_to_rad(-max_pitch), deg_to_rad(max_pitch) ) return # Mouse click captures the mouse again if event is InputEventMouseButton: if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED return # Keyboard input if event is InputEventKey: var pressed: bool = event.pressed match event.keycode: KEY_W: input_vec.w = 1.0 if pressed else 0.0 KEY_S: input_vec.x = 1.0 if pressed else 0.0 KEY_A: input_vec.y = 1.0 if pressed else 0.0 KEY_D: input_vec.z = 1.0 if pressed else 0.0 KEY_SPACE: if pressed and is_on_floor(): jump=true KEY_ESCAPE: if pressed: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE KEY_SHIFT: if has_hvms2: velocity.y = max(velocity.y, -3) if pressed else velocity.y gravity = 3 if pressed else 9.8 if is_on_floor(): velocity=$yaw/pitch/Camera.basis*Vector3(0,0,50) func _physics_process(delta: float) -> void: # W/S/A/D input var input_direction := Vector2( input_vec.z - input_vec.y, input_vec.w - input_vec.x ) if input_direction.length() > 1.0: input_direction = input_direction.normalized() # Camera yaw only var yaw_basis: Basis = $yaw.global_transform.basis var forward := -yaw_basis.z var right := yaw_basis.x forward.y = 0.0 right.y = 0.0 forward = forward.normalized() right = right.normalized() var target_direction := ( right * input_direction.x + forward * input_direction.y ) # Target horizontal velocity in m/s var target_velocity := target_direction * max_speed # Current horizontal velocity in m/s var current_velocity := Vector3( velocity.x, 0.0, velocity.z ) # Acceleration/deceleration in m/s² var acceleration := accel if target_direction != Vector3.ZERO else deccel current_velocity = current_velocity.move_toward( target_velocity, acceleration * delta ) velocity.x = current_velocity.x velocity.z = current_velocity.z # Gravity if not is_on_floor(): velocity.y -= gravity * delta else: if jump: velocity.y=jump_velocity jump=false else: velocity.y=0.0 if global_position.y<=-1000: get_tree().reload_current_scene() move_and_slide()