feat: shared creature root, enemy definitions, defend duty, and player downing
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
class_name CreatureVisual
|
||||
extends Node3D
|
||||
|
||||
signal position_changed(creature_id: StringName, active_position: Vector3)
|
||||
signal arrived_at_sim_position(creature_id: StringName)
|
||||
|
||||
const ARRIVAL_DISTANCE := 0.5
|
||||
const PATH_RETARGET_DISTANCE := 0.8
|
||||
|
||||
@export_range(0.5, 12.0, 0.1) var move_speed := 3.5
|
||||
@export_range(0.05, 1.0, 0.05) var waypoint_reached_distance := 0.3
|
||||
@export_range(1.0, 20.0, 0.5) var rotation_speed := 8.0
|
||||
|
||||
var creature_id: StringName
|
||||
var sim_position := Vector3.INF
|
||||
var is_dead_visual := false
|
||||
|
||||
var current_path := PackedVector3Array()
|
||||
var path_index := 0
|
||||
var path_target := Vector3.INF
|
||||
var path_request_id := 0
|
||||
var path_pending := false
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if is_dead_visual:
|
||||
return
|
||||
if not sim_position.is_finite():
|
||||
return
|
||||
if _horizontal_distance_to(sim_position) <= ARRIVAL_DISTANCE:
|
||||
_stop_moving()
|
||||
return
|
||||
_ensure_path()
|
||||
if path_pending:
|
||||
return
|
||||
if current_path.is_empty() or path_index >= current_path.size():
|
||||
_request_path()
|
||||
return
|
||||
var next_position := current_path[path_index]
|
||||
var offset := next_position - global_position
|
||||
if offset.length() <= waypoint_reached_distance:
|
||||
path_index += 1
|
||||
return
|
||||
var direction := offset.normalized()
|
||||
global_position = global_position.move_toward(next_position, move_speed * delta)
|
||||
position_changed.emit(creature_id, global_position)
|
||||
var target_angle := atan2(direction.x, direction.z)
|
||||
rotation.y = lerp_angle(rotation.y, target_angle, rotation_speed * delta)
|
||||
|
||||
|
||||
func set_sim_position(position: Vector3) -> void:
|
||||
if not position.is_finite():
|
||||
return
|
||||
var moved := (
|
||||
not path_target.is_finite()
|
||||
or _horizontal_distance_to_position(sim_position, position) > PATH_RETARGET_DISTANCE
|
||||
)
|
||||
sim_position = position
|
||||
if moved and not is_dead_visual:
|
||||
_request_path()
|
||||
|
||||
|
||||
func play_death() -> void:
|
||||
is_dead_visual = true
|
||||
_stop_moving()
|
||||
var tween := create_tween()
|
||||
tween.set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
|
||||
tween.tween_property(self, "scale", Vector3(0.001, 0.001, 0.001), 0.45)
|
||||
tween.tween_callback(queue_free)
|
||||
|
||||
|
||||
func build_visual() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _ensure_path() -> void:
|
||||
if (
|
||||
path_pending
|
||||
or (
|
||||
path_target.is_finite()
|
||||
and (
|
||||
_horizontal_distance_to_position(path_target, sim_position)
|
||||
<= PATH_RETARGET_DISTANCE
|
||||
)
|
||||
)
|
||||
):
|
||||
return
|
||||
_request_path()
|
||||
|
||||
|
||||
func _request_path() -> void:
|
||||
path_request_id += 1
|
||||
var request_id := path_request_id
|
||||
path_target = sim_position
|
||||
current_path = PackedVector3Array()
|
||||
path_index = 0
|
||||
path_pending = true
|
||||
await get_tree().physics_frame
|
||||
if request_id != path_request_id or is_dead_visual:
|
||||
return
|
||||
if _horizontal_distance_to(sim_position) <= ARRIVAL_DISTANCE:
|
||||
path_pending = false
|
||||
return
|
||||
current_path = NavigationServer3D.map_get_path(
|
||||
get_world_3d().navigation_map, global_position, sim_position, true
|
||||
)
|
||||
path_pending = false
|
||||
if current_path.is_empty():
|
||||
_stop_moving()
|
||||
|
||||
|
||||
func _stop_moving() -> void:
|
||||
path_request_id += 1
|
||||
current_path = PackedVector3Array()
|
||||
path_index = 0
|
||||
path_pending = false
|
||||
path_target = Vector3.INF
|
||||
|
||||
|
||||
func _horizontal_distance_to(target_position: Vector3) -> float:
|
||||
return _horizontal_distance_to_position(global_position, target_position)
|
||||
|
||||
|
||||
static func _horizontal_distance_to_position(from_position: Vector3, to_position: Vector3) -> float:
|
||||
return Vector2(from_position.x, from_position.z).distance_to(
|
||||
Vector2(to_position.x, to_position.z)
|
||||
)
|
||||
Reference in New Issue
Block a user