TowerGameProto/scripts/Unit.gd

161 lines
4.9 KiB
GDScript3
Raw Normal View History

2025-04-16 22:56:14 +01:00
extends RigidBody2D
class_name Unit
enum TaskStatus {
INTERRUPTED,
DESTINATION_REACHED,
ITEM_PICKED_UP,
ITEM_DROPPED,
}
signal task_updated(task_status: TaskStatus)
@export var movement_force: float = 100
@export var max_speed: float = 10
@export var path_give_up_theshold: float = 96.0
@export var stuck_speed: float = 5.0
@export var stuck_time: float = 1.0
@export var target_distance: float = 64.0
static var splat_scene: PackedScene = preload("res://objects/splat.tscn")
var moving: bool = false
var target: Vector2 = Vector2(1628, 1565):
set(value):
moving = true
target = value
find_path()
var path: PackedVector2Array
var path_ptr: int = 0
var stuck_timer: float = 0.0
var stuck: bool = false
var facing: float = 0.1
func _process(delta: float) -> void:
#$PathDebugLine.global_position = Vector2()
if moving:
if global_position.distance_squared_to(target) > target_distance**2:
move(delta)
else:
moving = false
send_task_update(TaskStatus.DESTINATION_REACHED)
func move(delta: float) -> void:
var direction: Vector2
if !stuck:
var last_path_point: Vector2 = get_last_path_point()
var path_point: Vector2 = get_next_path_point()
# find out how far we are from the path
var prev_dist_sqr: float = position.distance_squared_to(last_path_point) if !last_path_point.is_zero_approx() else 999999
var next_dist_sqr: float = position.distance_squared_to(path_point)
# if we're too far from the path, give up on it and find a new one
if next_dist_sqr > (path_give_up_theshold ** 2):
find_path()
path_point = get_next_path_point()
# if we've reached the path point, move to the next one
if next_dist_sqr < prev_dist_sqr:
path_ptr += 1
path_point = get_next_path_point()
#var direction: Vector2 = (Vector2(randf() - 0.5, randf() - 0.5) * 2) * 10000
direction = (path_point - position).normalized()
else:
direction = (Vector2(randf() - 0.5, randf() - 0.5) * 2)
facing = direction.angle()
var target_velocity: Vector2 = direction * max_speed
var force: Vector2 = ((target_velocity - linear_velocity) / max_speed) * movement_force
apply_force(force)
#$ForceDebugLine.points[1] = force
if linear_velocity.length() < stuck_speed:
stuck_timer += delta
if stuck_timer >= stuck_time:
global_position = get_next_path_point()
stuck_timer = 0
#set_stuck_mode(true)
else:
#if stuck:
#set_stuck_mode(false)
stuck_timer = 0
func get_last_path_point() -> Vector2:
if path == null or path.is_empty():
find_path()
if path_ptr >= path.size() and path.size() >= 2:
return path[-2]
if path.size() <= 1:
return Vector2()
if path != null and !path.is_empty():
return $"..".map_to_local(path[path_ptr - 1])
else:
return Vector2()
func get_next_path_point() -> Vector2:
if path == null or path.is_empty():
find_path()
if path_ptr >= path.size() and !path.is_empty():
return path[-1]
if path != null and !path.is_empty():
return $"..".map_to_local(path[path_ptr])
else:
return position
func find_path() -> void:
path_ptr = 0
var astar_grid: AStarGrid2D = $"..".astar_grid
if astar_grid == null:
return
var source_coords: Vector2i = $"..".local_to_map(position)
var target_coords: Vector2i = $"..".local_to_map(target)
path = astar_grid.get_point_path(source_coords, target_coords, true)
var debug_points: PackedVector2Array
#debug_points.resize(path.size())
for point in path:
#var point: Vector2 = path[idx]
var global_point: Vector2 = $"..".map_to_local(point)
debug_points.append(global_point)
#$PathDebugLine.points = debug_points
func set_stuck_mode(stk: bool) -> void:
stuck = stk
$Sprite2D.modulate = Color(0.75, 0.25, 1.0) if stuck else Color(1,1,1,1)
var astar_grid: AStarGrid2D = $"..".astar_grid
if astar_grid == null:
return
var source_coords: Vector2i = $"..".local_to_map(position)
if stuck:
astar_grid.set_point_weight_scale(source_coords, astar_grid.get_point_weight_scale(source_coords) * 50)
else:
astar_grid.set_point_weight_scale(source_coords, astar_grid.get_point_weight_scale(source_coords) / 50)
func send_task_update(task_status: TaskStatus) -> void:
task_updated.emit(task_status)
func wait_for_task_status(task_status: TaskStatus) -> bool:
while true:
var status_received: TaskStatus = await task_updated;
if status_received == task_status:
return true
elif status_received == TaskStatus.INTERRUPTED:
return false
return false
func go_to_destination(destination: Vector2) -> bool:
target = destination
return await wait_for_task_status(TaskStatus.DESTINATION_REACHED)
func kill() -> void:
#var astar_grid: AStarGrid2D = $"..".astar_grid
#var source_coords: Vector2i = $"..".local_to_map(position)
#var scale: float = astar_grid.get_point_weight_scale(source_coords)
#print("Tile %s weight scale read: %f" % [source_coords, scale])
#astar_grid.set_point_weight_scale(source_coords, scale + 0.1)
var splat: Node2D = splat_scene.instantiate()
splat.global_position = global_position
add_sibling(splat)
queue_free()