SchildDerStaerke/scripts/projectile.gd

80 lines
2.2 KiB
GDScript

# GDScript
class_name Projectile
extends Node3D
signal hit(collider: Object)
@export var initial_speed: float = 50.0
@export var damage: float = 3.0
@export var lifetime_after_hit: float = 3.0
@export var uses_x_forward: bool = true # Mesh zeigt mit +X nach vorne
var speed: float = 0.0
var direction: Vector3 = Vector3.ZERO
@onready var ray_cast: RayCast3D = $RayCast3D
func _physics_process(delta: float) -> void:
if speed > 0.0:
var move_dir := direction if direction != Vector3.ZERO else -global_transform.basis.z
global_translate(move_dir * speed * delta)
if ray_cast and ray_cast.is_colliding():
var collider: Object = ray_cast.get_collider()
_on_hit(collider)
func shoot(new_direction: Vector3 = Vector3.ZERO) -> void:
direction = new_direction.normalized() if new_direction != Vector3.ZERO else -global_transform.basis.z
speed = initial_speed
# Beim Abfeuern aus der Waffen-Hierarchie lösen, damit Maus-/Kamerabewegung den Pfeil nicht beeinflusst
_detach_to_world()
# Visuelle Ausrichtung konsistent zur Flugrichtung setzen
_align_visual_to_direction()
if ray_cast:
ray_cast.enabled = true
func _align_visual_to_direction() -> void:
look_at(global_transform.origin + direction, Vector3.UP)
# Godot richtet -Z nach vorne aus; wenn das Mesh +X als "vorne" hat, um -90° um Y korrigieren
if uses_x_forward:
rotate_z(deg_to_rad(90.0))
func _detach_to_world() -> void:
var target_parent: Node = get_tree().current_scene if get_tree().current_scene != null else get_tree().root
if target_parent == null:
return
var gt := global_transform
var p := get_parent()
if p and p != target_parent:
p.remove_child(self)
target_parent.add_child(self)
global_transform = gt
func _on_hit(collider: Object) -> void:
if speed == 0.0:
return
speed = 0.0
if ray_cast:
ray_cast.enabled = false
emit_signal("hit", collider)
_apply_damage_if_supported(collider)
if lifetime_after_hit > 0.0:
var timer := get_tree().create_timer(lifetime_after_hit)
timer.timeout.connect(queue_free)
else:
queue_free()
func _apply_damage_if_supported(collider: Object) -> void:
if collider and collider.has_method("take_damage"):
collider.call("take_damage", damage)