extends RefCounted class_name UnitAction var unit: Unit = null var time_limit: float = 300.0 func process(delta: float) -> Unit.TaskStatus: time_limit -= delta if time_limit <= 0: return Unit.TaskStatus.TIMED_OUT return Unit.TaskStatus.DONE class MoveAction extends UnitAction: var last_distance_to_target: float = 99999999.9 var stuck_timer: float = 0.0 var move_target: Vector3 = Vector3(16, 1, 13): set(target): move_target = target unit.nav_agent_3d.target_position = move_target func process(delta: float) -> Unit.TaskStatus: if unit.nav_agent_3d.is_navigation_finished(): #task_updated.emit(TaskStatus.DONE) unit.target_velocity = Vector3() #nav_agent_3d.target_position = move_target + Vector3(randfn(0, move_radius), 0, randfn(0, move_radius)) #nav_agent_3d.target_position = NavigationServer3D.map_get_random_point(NavigationServer3D.get_maps()[0], 1, true) #last_distance_to_target = nav_agent_3d.distance_to_target() if unit.nav_agent_3d.is_target_reachable(): return Unit.TaskStatus.DONE else: return Unit.TaskStatus.IMPOSSIBLE else: var next_point: Vector3 = unit.nav_agent_3d.get_next_path_position() if unit.shapecast_3d.is_colliding(): var distance_to_target: float = unit.global_position.distance_to(next_point) var progress_rate: float = (last_distance_to_target - distance_to_target) / delta last_distance_to_target = distance_to_target if progress_rate < unit.minimum_progress_rate: stuck_timer += delta if stuck_timer >= unit.stuck_time: unit.unstuck() else: unit.label_3d.modulate = Color.WHITE stuck_timer = 0 DebugDraw3D.draw_sphere(unit.nav_agent_3d.target_position, 0.5, Color.RED) #DebugDraw3D.draw_sphere(next_point, 0.1, Color.YELLOW) var direction: Vector3 = (next_point - unit.global_position).normalized() #basis = Basis.looking_at(direction) #DebugDraw3D.draw_line(global_position, global_position + linear_velocity, Color.BLUE) unit.target_velocity = direction * unit.max_speed unit.nav_agent_3d.velocity = unit.target_velocity #DebugDraw3D.draw_line(global_position, global_positiaon + target_velocity, Color.MAGENTA) #DebugDraw3D.draw_text(global_position + Vector3(0,1,0), "%f" % nav_agent_3d.distance_to_target()) return Unit.TaskStatus.IN_PROGRESS class ChaseAction extends UnitAction: var target: Unit var target_position: Vector3 var last_distance_to_target: float = 99999999.9 var stuck_timer: float = 0.0 func process(delta: float) -> Unit.TaskStatus: if target == null or target.is_queued_for_deletion(): return Unit.TaskStatus.IMPOSSIBLE if target.global_position.distance_squared_to(target_position) >= 4.0: # TODO: we could try to intercept the target by: # - calculating our approximate time to reach the target # - forcasting the target's position that time in the future based on it's velocity # - do a raycast in that direction to prevent the future position from going through a wall target_position = target.global_position unit.nav_agent_3d.target_position = target_position if unit.nav_agent_3d.is_navigation_finished(): if unit.nav_agent_3d.is_target_reachable(): return Unit.TaskStatus.DONE else: return Unit.TaskStatus.IMPOSSIBLE else: var next_point: Vector3 = unit.nav_agent_3d.get_next_path_position() if unit.shapecast_3d.is_colliding(): var distance_to_target: float = unit.global_position.distance_to(next_point) var progress_rate: float = (last_distance_to_target - distance_to_target) / delta last_distance_to_target = distance_to_target if progress_rate < unit.minimum_progress_rate: stuck_timer += delta if stuck_timer >= unit.stuck_time: unit.unstuck() else: unit.label_3d.modulate = Color.WHITE stuck_timer = 0 DebugDraw3D.draw_sphere(unit.nav_agent_3d.target_position, 0.5, Color.RED) var direction: Vector3 = (next_point - unit.global_position).normalized() unit.target_velocity = direction * unit.max_speed unit.nav_agent_3d.velocity = unit.target_velocity return Unit.TaskStatus.IN_PROGRESS class BuildAction extends UnitAction: var building: Building func process(delta: float) -> Unit.TaskStatus: if building == null or building.is_queued_for_deletion(): return Unit.TaskStatus.IMPOSSIBLE building.build_progress += delta if building.build_state == Building.BuildState.READY: return Unit.TaskStatus.DONE elif building.build_state != Building.BuildState.BUILDING: return Unit.TaskStatus.IMPOSSIBLE # can't build if the building's not there else: return Unit.TaskStatus.IN_PROGRESS class RepairAction extends UnitAction: var building: Building func process(delta: float) -> Unit.TaskStatus: if building == null or building.is_queued_for_deletion() or building.build_state != Building.BuildState.READY: return Unit.TaskStatus.IMPOSSIBLE building.hp += delta * 10.0 if building.hp >= building.max_hp: building.hp = building.max_hp return Unit.TaskStatus.DONE return Unit.TaskStatus.IN_PROGRESS