SchildDerStaerke/scripts/rogue.gd

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 enough_stamina_available(attack_cost):
return
use_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)