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