Files
2026-07-10 17:26:23 +02:00

69 lines
2.2 KiB
GDScript

class_name Weapon
extends Node3D
@export var def: WeaponDef
var shooter: PhysicsBody3D # Resolved in _ready(): nearest ancestor body
var _cooldown := 0.0
@onready var _muzzle: Marker3D = %Muzzle
@onready var _yaw: Node3D = get_node_or_null("%Yaw")
@onready var _pitch: Node3D = get_node_or_null("%Pitch")
@onready var hitbox: PhysicsBody3D = get_node_or_null("%Hitbox")
func _ready() -> void:
# Fallback: nearest ancestor body is the shooter (hand-placed weapons).
var n := get_parent()
while shooter == null and n != null:
shooter = n as PhysicsBody3D
n = n.get_parent()
func _physics_process(delta: float) -> void:
_cooldown = maxf(_cooldown - delta, 0.0)
func try_fire() -> bool:
if _cooldown > 0.0 or def == null or def.ammo == null:
return false
_cooldown = def.fire_interval
var p: Projectile = def.ammo.projectile_scene.instantiate()
get_tree().current_scene.add_child(p)
if shooter != null:
p.add_collision_exception_with(shooter)
if hitbox != null:
p.add_collision_exception_with(hitbox)
p.launch(def.ammo, _muzzle.global_transform, def.muzzle_speed_scale)
return true
func aim_at(point, delta: float) -> void:
if _yaw == null or def == null:
return
var yaw_step := deg_to_rad(def.traverse_speed_deg) * delta
var pitch_step := deg_to_rad(def.elevation_speed_deg) * delta
if point == null:
# Nobody aiming: slew back to the stowed position.
_yaw.rotation.y = rotate_toward(_yaw.rotation.y, 0.0, yaw_step)
if _pitch != null:
_pitch.rotation.x = rotate_toward(_pitch.rotation.x, 0.0, pitch_step)
return
# Yaw: desired angle lives in the space of the node we rotate *within*,
# i.e. the Yaw node's parent.
var local: Vector3 = _yaw.get_parent_node_3d().to_local(point)
var desired_yaw := atan2(-local.x, -local.z)
_yaw.rotation.y = rotate_toward(_yaw.rotation.y, desired_yaw, yaw_step)
if _pitch == null:
return
# Pitch: same idea, in the Pitch node's parent space (the freshly-yawed Yaw node).
var lp: Vector3 = _pitch.get_parent_node_3d().to_local(point)
var desired_pitch := clampf(
atan2(lp.y, Vector2(lp.x, lp.z).length()),
deg_to_rad(def.elevation_min_deg),
deg_to_rad(def.elevation_max_deg)
)
_pitch.rotation.x = rotate_toward(_pitch.rotation.x, desired_pitch, pitch_step)