SchildDerStaerke/scripts/player.gd

132 lines
4.0 KiB
GDScript

class_name Player
extends Unit
const CAMERA_PITCH_MIN_DEG := -90.0
const CAMERA_PITCH_MAX_DEG := 30.0
const JOYPAD_DEADZONE := 0.10
@export var mouse_sensitivity: float = 0.006
@export var rotation_speed: float = 24.0
@export var joypad_sensitivity: float = 2.0
@export var spring_arm: SpringArm3D
signal gold_changed(current_gold: int)
signal player_loaded()
var _gold: int = 0
var was_on_floor: bool = true
var gold: int:
get:
return _gold
set(value):
if _gold == value:
return
_gold = value
gold_changed.emit(_gold)
func _ready() -> void:
health = maximum_health
stamina = maximum_stamina
player_loaded.emit()
func _physics_process(delta: float) -> void:
# Physik: Schwerkraft, Bewegung, Ausrichtung, Kamera per Joypad
apply_gravity(delta)
update_movement(delta)
move_and_slide()
update_facing(delta)
handle_joypad_camera(delta)
func rotate_camera(pitch_delta: float, yaw_delta: float) -> void:
# Deltas anwenden; Pitch clampen, Yaw ungebunden
spring_arm.rotation.x += pitch_delta
spring_arm.rotation_degrees.x = clampf(spring_arm.rotation_degrees.x, CAMERA_PITCH_MIN_DEG, CAMERA_PITCH_MAX_DEG)
spring_arm.rotation.y += yaw_delta
func move_camera_joypad(x: float, y: float, delta: float) -> void:
# Skalierung nach Sensitivität und Framezeit; invertiert für Maus-ähnliches Gefühl
var pitch_delta := -y * joypad_sensitivity * delta
var yaw_delta := -x * joypad_sensitivity * delta
rotate_camera(pitch_delta, yaw_delta)
func player_game_over():
GameManager.game_over()
queue_free()
func _input(event: InputEvent) -> void:
# Kamera per Maus
handle_mouse_camera(event)
# Boden-/Luft-Logik
var on_floor := is_on_floor()
handle_jump(on_floor)
update_ground_state(on_floor)
# Menü
if event.is_action_pressed("Menue"):
get_tree().quit()
func apply_gravity(delta: float) -> void:
velocity.y += -gravity * delta
func update_movement(delta: float) -> void:
# Bewegungsinput lesen und anwenden
var vy := velocity.y
velocity.y = 0.0
var input_vector := Input.get_vector("left", "right", "forward", "back")
var direction := Vector3(input_vector.x, 0.0, input_vector.y).rotated(Vector3.UP, spring_arm.rotation.y)
if state == States.blocking:
direction = Vector3.ZERO # TODO: Gehen während Blocken erlauben
velocity = velocity.lerp(direction * speed, acceleration * delta)
var v_local := velocity * model.transform.basis
anim_tree.set("parameters/IWR/blend_position", Vector2(v_local.x, -v_local.z) / speed)
velocity.y = vy
func update_facing(delta: float) -> void:
# Sanft in Blickrichtung der Kamera drehen, wenn wir uns merklich bewegen
if velocity.length() > 1.0:
model.rotation.y = lerp_angle(model.rotation.y, spring_arm.rotation.y, rotation_speed * delta)
func handle_joypad_camera(delta: float) -> void:
var right_stick_x := Input.get_joy_axis(0, JOY_AXIS_RIGHT_X)
var right_stick_y := Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y)
if absf(right_stick_x) > JOYPAD_DEADZONE or absf(right_stick_y) > JOYPAD_DEADZONE:
move_camera_joypad(right_stick_x, right_stick_y, delta)
func handle_mouse_camera(event: InputEvent) -> void:
if event is InputEventMouseMotion:
var motion := event as InputEventMouseMotion
var pitch_delta := -motion.relative.y * mouse_sensitivity
var yaw_delta := -motion.relative.x * mouse_sensitivity
rotate_camera(pitch_delta, yaw_delta)
func handle_jump(on_floor: bool) -> void:
if on_floor and Input.is_action_just_pressed("jump"):
if can_spend_stamina(jump_cost):
spend_stamina(jump_cost)
velocity.y = jump_speed
state = States.jumping
anim_tree.set("parameters/conditions/grounded", false)
func update_ground_state(on_floor: bool) -> void:
# Gerade gelandet
if on_floor and not was_on_floor:
if state != States.idle:
state = States.idle
anim_tree.set("parameters/conditions/grounded", true)
# In der Luft ohne aktiven Sprung
if not on_floor and state != States.jumping:
anim_state.travel("Jump_Idle")
anim_tree.set("parameters/conditions/grounded", false)
anim_tree.set("parameters/conditions/jumping", state == States.jumping)
was_on_floor = on_floor