Last active
January 24, 2024 10:08
-
-
Save it-ankka/205844e549e37063df1729d504a5bb06 to your computer and use it in GitHub Desktop.
Simple Godot first-person character controller which also handles climbing stairs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class_name Player extends CharacterBody3D | |
@onready var head: Node3D = $Head | |
@onready var arms: Node3D = $Head/Camera3D/Arms | |
@onready var head_default_pos: Vector3 = head.position | |
@onready var arms_default_pos: Vector3 = arms.position | |
@export var SPEED: float = 10 | |
@export var JUMP_VELOCITY: float = 4.5 | |
@export var HEAD_LERP_SPEED: float = 10 | |
@export var MAX_STEP_HEIGHT: float = 0.3 | |
@export var MIN_STEP_WIDTH: float = 0.1 | |
@export var STEP_UP_MARGIN: float = 0.001 | |
@export var STEP_DOWN_MARGIN: float = 0.01 | |
@export_range(-90, 90, 0.001, "radians_as_degrees") var HEAD_ANGLE_MAX: float = PI/2 | |
@export_range(-90, 90, 0.001, "radians_as_degrees") var HEAD_ANGLE_MIN: float = -PI/2 | |
var look_sensitivity = ProjectSettings.get_setting("player/look_sensitivity") | |
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") | |
var input_dir: Vector2 = Vector2.ZERO | |
var mouse_dir: Vector2 = Vector2.ZERO | |
var is_falling = false | |
func _ready(): | |
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED | |
func _input(event): | |
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED and event is InputEventMouseMotion: | |
mouse_dir = event.relative | |
rotate_y(deg_to_rad(-event.relative.x * look_sensitivity)) | |
head.rotate_x(deg_to_rad(-event.relative.y * look_sensitivity)) | |
head.rotation.x = clamp(head.rotation.x, HEAD_ANGLE_MIN, HEAD_ANGLE_MAX) | |
func _physics_process(delta: float): | |
head.position = lerp(head.position, head_default_pos, HEAD_LERP_SPEED * delta) | |
input_dir = Input.get_vector("move_left","move_right","move_forward","move_backward").normalized() | |
var direction: Vector3 = global_transform.basis * Vector3(input_dir.x, 0, input_dir.y).normalized() | |
var just_jumped = is_on_floor() and Input.is_action_just_pressed("jump") | |
var vel_y = JUMP_VELOCITY if just_jumped else (velocity.y - gravity * delta) | |
if just_jumped: | |
is_falling = true | |
elif is_on_floor(): | |
is_falling = false | |
var horizontal_velocity = direction * SPEED | |
var horizontal_movement = horizontal_velocity * delta | |
var step_up = false | |
var coll: KinematicCollision3D = KinematicCollision3D.new() | |
var collides = test_move(global_transform, horizontal_movement, coll) | |
if collides and coll.get_position().y - global_position.y <= MAX_STEP_HEIGHT: | |
var step_delta = coll.get_position() - global_position | |
var stair_width_check_move = (direction * MIN_STEP_WIDTH) | |
var step_up_transform = global_transform.translated(Vector3.UP * (step_delta.y + STEP_UP_MARGIN)) | |
step_up = MIN_STEP_WIDTH <= 0 or !test_move(step_up_transform, stair_width_check_move, coll) | |
if step_up: | |
global_position.y += step_delta.y | |
head.position.y -= step_delta.y | |
global_position += horizontal_movement | |
if !collides and !is_on_floor() and !is_falling: | |
var can_step_down = test_move(global_transform, Vector3.DOWN * (MAX_STEP_HEIGHT + STEP_DOWN_MARGIN), coll) | |
if(can_step_down): | |
var step_delta = coll.get_position() - global_position | |
global_position.y += step_delta.y | |
head.position.y -= step_delta.y | |
else: | |
is_falling = true | |
velocity = horizontal_velocity + Vector3.UP * vel_y | |
if not step_up: | |
move_and_slide() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment