X-Git-Url: http://git.purplebirdman.com/baabarian.git/blobdiff_plain/87f90ed1d61c12766366f39de1ee2c0213ffbe1f..ca42b9d6edede7042ef846887d04497bf80a9595:/player/player.gd diff --git a/player/player.gd b/player/player.gd index d538d8b..7cd2a81 100644 --- a/player/player.gd +++ b/player/player.gd @@ -10,17 +10,15 @@ class_name Player @export var air_speed := 3.0 @export var acceleration := 20.0 -@export var jump_speed := 6.0 @export var rotation_speed := 10.0 -@export var fall_speed := 1.2 @export var idle_timeout := 5.0 @export var hard_landing_limit := 10.0 @export_group("Physics") -@export var push_force := 1.5 +@export var push_force := 5.0 @export_group("Camera") -@export_range(1.0, 10.0) var camera_distance := 2.5 +@export_range(1.0, 10.0) var camera_distance := 2.0 @export_range(0.0, 1.0) var mouse_sensitivity := 0.15 @export_range(0.0, 1.0) var mouse_sensitivity_x := 1.0 @export_range(0.0, 1.0) var mouse_sensitivity_y := 0.5 @@ -31,24 +29,33 @@ class_name Player @onready var _debug: CanvasLayer = %debug @onready var _camera_pivot: Node3D = %camera_pivot @onready var _camera: Camera3D = %camera +@onready var _camera_spring: SpringArm3D = %spring @onready var _skin: AnimatedSkin = %skin +@onready var _dust: GPUParticles3D = %dust var _last_movement_direction := rotation +var _floor_normal := Vector3.ONE +var _ground_slope_input := 0.0 var _camera_input_direction := Vector2.ZERO enum {CAMERA_MOUSE_INPUT, CAMERA_JOYSTICK_INPUT} var _camera_input_method := CAMERA_MOUSE_INPUT var _idle_time: float = 0.0 -var _player_speed: float = walk_speed +var _player_speed: float = 0 func _ready() -> void: - $camera_pivot/SpringArm3D.spring_length = camera_distance _debug.draw.add_vector(self, "velocity", 1, 1, Color(0,1,0,1)) + _debug.draw.add_vector(self, "_floor_normal", 1, 1, Color(0, 0, 1, 1)) _debug.draw.add_vector(self, "_last_movement_direction", 1, 1, Color(1,0,0,1)) _debug.stats.add_property(self, "velocity", "length") _debug.stats.add_property(self, "_idle_time", "round") + _debug.stats.add_property(self, "_ground_slope_input", "round") + + _camera_spring.spring_length = camera_distance + _player_speed = jog_speed + _skin.set_grounded() func _physics_process(delta: float) -> void: @@ -73,12 +80,14 @@ func _unhandled_input(event: InputEvent) -> void: func _input(event: InputEvent): if event.is_action_pressed("player_run"): - _player_speed = jog_speed - elif event.is_action_released("player_run"): _player_speed = walk_speed + elif event.is_action_released("player_run"): + _player_speed = jog_speed if event.is_action_pressed("player_attack") and velocity.length() > jog_speed * .75: _player_speed = charge_speed + elif event.is_action_released("player_attack"): + _player_speed = jog_speed # Get the XZ input direction based on player's input relative to the camera @@ -102,13 +111,23 @@ func _process_camera(delta: float) -> void: # reset mouse movement vector if mouse input if _camera_input_method == CAMERA_MOUSE_INPUT: _camera_input_direction = Vector2.ZERO + + # change spring length depending on player speed + _camera_spring.spring_length = lerp( + _camera_spring.spring_length, camera_distance + velocity.length() / 4, delta + ) func _process_player_on_floor(delta: float): var move_direction := _get_player_move_direction() # if we're not stuck, then it's okay to set the velocity - velocity = velocity.move_toward(move_direction * _player_speed, acceleration * delta) + _floor_normal = get_floor_normal() + _ground_slope_input = (PI / 2) - velocity.angle_to(_floor_normal) + velocity = velocity.move_toward( + move_direction * (_player_speed + _ground_slope_input * _player_speed), + acceleration * delta + ) var movement_speed := Vector3(velocity.x, 0, velocity.z).length() # also, if we're moving, we're not idle @@ -120,18 +139,27 @@ func _process_player_on_floor(delta: float): _idle_time = 0.0 # if camera is unlocked, rotate whole skin to face movement direction - # else, rotate to face camera pivot global Y direction var skin_target_angle := Vector3.BACK.signed_angle_to(_last_movement_direction, Vector3.UP) _skin.global_rotation.y = lerp_angle( _skin.global_rotation.y, skin_target_angle, rotation_speed * delta ) - _skin.set_movement_speed(movement_speed) + + # lean into player momentum just a little bit + _skin.rotation.z = lerp_angle( + _skin.rotation.z, + clamp(_last_movement_direction.signed_angle_to(velocity, Vector3.UP) * movement_speed * 0.08, -PI/4, PI/ 4), + rotation_speed * delta * 0.25 + ) + + # let skin know how fast player is moving along the ground + _skin.set_grounded_speed(movement_speed) # timescale tweaking for fun effect! - if movement_speed >= charge_speed * 0.75: + if _player_speed == charge_speed: _skin.set_timescale(2.0) + else: _skin.set_timescale(1.0) @@ -139,11 +167,19 @@ func _process_player_on_floor(delta: float): func _process_player(delta: float) -> void: if is_on_floor(): _process_player_on_floor(delta) + + if _idle_time > idle_timeout: + _skin.set_idle() + else: + _skin.set_grounded() + + _dust.emitting = velocity.length() > (0.75 * charge_speed) and is_on_floor() + _dust.amount_ratio = velocity.length() else: + _skin.set_falling() velocity += get_gravity() * air_speed * delta - # now actually move! - var movement_speed := velocity.length() + var prev_velocity := velocity move_and_slide() # handle collisions @@ -151,4 +187,4 @@ func _process_player(delta: float) -> void: var c := get_slide_collision(i) if c.get_collider() is RigidBody3D: var col: RigidBody3D = c.get_collider() - col.apply_central_impulse(-c.get_normal() * push_force * movement_speed / col.mass) + col.apply_central_impulse(-c.get_normal() * prev_velocity.length() * push_force)