130 lines
3.9 KiB
GDScript
130 lines
3.9 KiB
GDScript
class_name Rogue
|
|
extends Player
|
|
|
|
# Animation-/Audio-Listen als Konstanten
|
|
const ATTACK_ANIMS: Array[String] = ["2H_Ranged_Shoot"]
|
|
const RELOAD_ANIMS: Array[String] = ["2H_Ranged_Reload"]
|
|
const AIM_ANIMS: Array[String] = ["2H_Ranged_Aiming"]
|
|
const FOOTSTEP_SOUNDS: Array[String] = ["res://resources/audio/footstep_grass_000.ogg", "res://resources/audio/footstep_grass_001.ogg", "res://resources/audio/footstep_grass_002.ogg", "res://resources/audio/footstep_grass_003.ogg", "res://resources/audio/footstep_grass_004.ogg"]
|
|
# Tuning-Konstanten
|
|
const FOV_AIM: float = 40.0
|
|
const FOV_DEFAULT: float = 70.0
|
|
const CROSSHAIR_RAY_DISTANCE: float = 100.0
|
|
const SHOOT_RAY_LENGTH: float = 1000.0
|
|
const SPRING_ARM_AIM_OFFSET_X: float = 0.5
|
|
const SPRING_ARM_AIM_LENGTH: float = 3.0
|
|
@export var arrow_scene: PackedScene
|
|
|
|
@onready var shoot_point: Node3D = $"Rig/Skeleton3D/handslot_r/2H_Crossbow/ShootPoint"
|
|
@onready var crossbow: MeshInstance3D = $"Rig/Skeleton3D/handslot_r/2H_Crossbow"
|
|
@onready var ik_target: Node3D = $Rig/Skeleton3D/ik_target
|
|
@onready var hand_ik: SkeletonIK3D = $Rig/Skeleton3D/ik_hand_r
|
|
|
|
@export var is_loaded: bool
|
|
|
|
var current_arrow: Projectile
|
|
|
|
|
|
func _ready() -> void:
|
|
# Falls im Editor als geladen markiert, Pfeil instantiieren
|
|
if is_loaded:
|
|
load_arrow()
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
var camera := get_viewport().get_camera_3d()
|
|
if camera:
|
|
camera.fov = FOV_AIM if state == States.aiming else FOV_DEFAULT
|
|
|
|
# IK-Ziel und Waffe Richtung Fadenkreuz ausrichten
|
|
hand_ik.target = ik_target.global_transform
|
|
hand_ik.start()
|
|
var screen_center: Vector2 = get_viewport().get_visible_rect().size * 0.5
|
|
var target_pos: Vector3 = camera.project_ray_origin(screen_center) + camera.project_ray_normal(screen_center) * CROSSHAIR_RAY_DISTANCE
|
|
ik_target.global_position = target_pos
|
|
crossbow.look_at(target_pos, Vector3.UP)
|
|
crossbow.rotate_object_local(Vector3.UP, PI) # Falls -Z nach vorne zeigt
|
|
|
|
if state == States.aiming:
|
|
spring_arm.transform.origin.x = SPRING_ARM_AIM_OFFSET_X
|
|
spring_arm.spring_length = SPRING_ARM_AIM_LENGTH
|
|
|
|
super._process(delta)
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
# Schießen
|
|
if event.is_action_pressed("attack"):
|
|
handle_attack()
|
|
|
|
# Nachladen
|
|
if event.is_action_pressed("reload"):
|
|
handle_reload()
|
|
|
|
# Zielen (gedrückt/losgelassen)
|
|
if event.is_action_pressed("block"):
|
|
state = States.aiming
|
|
if event.is_action_released("block"):
|
|
state = States.idle
|
|
|
|
anim_tree.set("parameters/conditions/aiming", state == States.aiming)
|
|
anim_tree.set("parameters/conditions/not_aiming", state != States.aiming)
|
|
|
|
super._input(event)
|
|
|
|
|
|
func handle_attack() -> void:
|
|
if not is_loaded:
|
|
print("No arrow loaded!")
|
|
return
|
|
if not can_spend_stamina(attack_cost):
|
|
return
|
|
|
|
spend_stamina(attack_cost)
|
|
anim_state.travel(ATTACK_ANIMS.pick_random())
|
|
is_loaded = false
|
|
|
|
|
|
func handle_reload() -> void:
|
|
if is_loaded:
|
|
print("Already loaded!")
|
|
return
|
|
|
|
anim_state.travel(RELOAD_ANIMS.pick_random())
|
|
is_loaded = true
|
|
|
|
|
|
func shoot_arrow() -> void:
|
|
if current_arrow == null:
|
|
return
|
|
|
|
var camera := get_viewport().get_camera_3d()
|
|
if camera:
|
|
var screen_center: Vector2 = get_viewport().get_visible_rect().size * 0.5
|
|
var from: Vector3 = camera.project_ray_origin(screen_center)
|
|
var to: Vector3 = from + camera.project_ray_normal(screen_center) * SHOOT_RAY_LENGTH
|
|
var direction: Vector3 = (to - shoot_point.global_position).normalized()
|
|
current_arrow.shoot(direction)
|
|
else:
|
|
current_arrow.shoot() # Fallback
|
|
|
|
|
|
# Beibehaltung für evtl. Animation-CallMethod; delegiert auf die neue Implementierung
|
|
func arrow_loaded() -> void:
|
|
load_arrow()
|
|
|
|
|
|
func load_arrow() -> void:
|
|
print("Arrow loaded...")
|
|
if arrow_scene == null:
|
|
push_warning("arrow_scene is null; cannot instantiate arrow.")
|
|
return
|
|
|
|
var arrow := arrow_scene.instantiate() as Projectile
|
|
if arrow == null:
|
|
push_warning("arrow_scene is not a Projectile.")
|
|
return
|
|
|
|
current_arrow = arrow
|
|
shoot_point.add_child(current_arrow)
|