80 lines
2.2 KiB
GDScript
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)
|