Pathfinding works now
parent
2ca824a2e3
commit
d6bf267bdc
|
@ -4,13 +4,24 @@ const MAX_SPEED: float = 300.0
|
||||||
const ACCELERATION: int = 2400
|
const ACCELERATION: int = 2400
|
||||||
@onready var graph: NavigationGraph = $"../NavGraph"
|
@onready var graph: NavigationGraph = $"../NavGraph"
|
||||||
|
|
||||||
|
var frozen: bool = false
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
var movement: Vector2 = Vector2()
|
# check if space is pressed
|
||||||
|
if Input.is_action_just_pressed("ui_select"):
|
||||||
|
frozen = !frozen
|
||||||
|
|
||||||
var next_pos: Vector2 = graph.determine_next_position(position, get_global_mouse_position())
|
var movement: Vector2 = Vector2()
|
||||||
movement = next_pos - global_position
|
if frozen:
|
||||||
if movement.length() < 20:
|
return
|
||||||
|
|
||||||
|
var pathfinding_result: PathfindingResult = graph.determine_next_position(position, get_global_mouse_position())
|
||||||
|
graph.draw_pathfinding_result(pathfinding_result)
|
||||||
|
|
||||||
|
movement = pathfinding_result.next_position - global_position
|
||||||
|
|
||||||
|
if pathfinding_result.is_next_target and movement.length() < 20:
|
||||||
movement = -velocity * 0.2
|
movement = -velocity * 0.2
|
||||||
else:
|
else:
|
||||||
movement = movement.normalized() * ACCELERATION * delta
|
movement = movement.normalized() * ACCELERATION * delta
|
||||||
|
|
|
@ -4,7 +4,8 @@ extends Node2D
|
||||||
# godot does not support types on dictionaries, actual type is Dictionary[NavigationNode, Array[NavigationNode]]
|
# godot does not support types on dictionaries, actual type is Dictionary[NavigationNode, Array[NavigationNode]]
|
||||||
var navigation_nodes: Dictionary = {}
|
var navigation_nodes: Dictionary = {}
|
||||||
# type is Dictionary[CNavigationPolygon, Array[NavigationNode]]
|
# type is Dictionary[CNavigationPolygon, Array[NavigationNode]]
|
||||||
var polygon_nodes: Dictionary = {}
|
var polygon_nodes: Dictionary = {}
|
||||||
|
var latest_navigation_result: PathfindingResult = null
|
||||||
|
|
||||||
|
|
||||||
func all_nodes() -> Array[NavigationNode]:
|
func all_nodes() -> Array[NavigationNode]:
|
||||||
|
@ -137,10 +138,14 @@ func erase_and_create_nodes_from_polygons(new_polys: Array[PackedVector2Array])
|
||||||
# connect all within a polygon
|
# connect all within a polygon
|
||||||
for poly in all_polygons():
|
for poly in all_polygons():
|
||||||
var nodes_in_polygon: Array[NavigationNode] = get_nodes_in_polygon(poly)
|
var nodes_in_polygon: Array[NavigationNode] = get_nodes_in_polygon(poly)
|
||||||
for i in range(len(nodes_in_polygon)):
|
connect_all_nodes(nodes_in_polygon)
|
||||||
for j in range(len(nodes_in_polygon)):
|
|
||||||
if i != j:
|
|
||||||
add_connection(nodes_in_polygon[i], nodes_in_polygon[j])
|
func connect_all_nodes(nodes: Array[NavigationNode]) -> void:
|
||||||
|
for i in range(len(nodes)):
|
||||||
|
for j in range(len(nodes)):
|
||||||
|
if i != j:
|
||||||
|
add_connection(nodes[i], nodes[j])
|
||||||
|
|
||||||
|
|
||||||
func _draw() -> void:
|
func _draw() -> void:
|
||||||
|
@ -153,9 +158,24 @@ func _draw() -> void:
|
||||||
draw_colored_polygon(poly.polygon, Color(0.5, 0.4, 0.9, 0.3))
|
draw_colored_polygon(poly.polygon, Color(0.5, 0.4, 0.9, 0.3))
|
||||||
draw_polyline(poly.polygon, Color.WHITE, 1, true)
|
draw_polyline(poly.polygon, Color.WHITE, 1, true)
|
||||||
|
|
||||||
|
if latest_navigation_result != null:
|
||||||
|
if latest_navigation_result.path.size() > 1:
|
||||||
|
for i in range(latest_navigation_result.path.size() - 1):
|
||||||
|
draw_line(latest_navigation_result.path[i].position, latest_navigation_result.path[i + 1].position, Color.GREEN, 1, false)
|
||||||
|
draw_circle(latest_navigation_result.next_position, 5, Color.GREEN)
|
||||||
|
|
||||||
func determine_next_position(current_position: Vector2, target_position: Vector2) -> Vector2:
|
|
||||||
# find both polygons
|
func draw_pathfinding_result(result: PathfindingResult) -> void:
|
||||||
|
if latest_navigation_result and latest_navigation_result.is_identical_to(result):
|
||||||
|
return
|
||||||
|
latest_navigation_result = result
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func determine_next_position(current_position: Vector2, target_position: Vector2) -> PathfindingResult:
|
||||||
|
var result: PathfindingResult = PathfindingResult.new()
|
||||||
|
|
||||||
|
# find both polygons containing the current and target positions
|
||||||
var current_polygon: CNavigationPolygon = null
|
var current_polygon: CNavigationPolygon = null
|
||||||
var target_polygon: CNavigationPolygon = null
|
var target_polygon: CNavigationPolygon = null
|
||||||
|
|
||||||
|
@ -165,32 +185,56 @@ func determine_next_position(current_position: Vector2, target_position: Vector2
|
||||||
if Geometry2D.is_point_in_polygon(target_position, poly.polygon):
|
if Geometry2D.is_point_in_polygon(target_position, poly.polygon):
|
||||||
target_polygon = poly
|
target_polygon = poly
|
||||||
|
|
||||||
# if the current position is not in any polygon, find the closest node and navigate to it
|
# if the current position is not in any polygon, navigate to the closest node
|
||||||
if not current_polygon:
|
if not current_polygon:
|
||||||
var closest_node: NavigationNode = find_closest_node_with_threshold(current_position, 100000)
|
var closest_node: NavigationNode = find_closest_node_with_threshold(current_position, 100000)
|
||||||
return closest_node.position
|
result.next_position = closest_node.position
|
||||||
|
return result
|
||||||
|
|
||||||
if not current_polygon or not target_polygon:
|
# if the target position is not in any polygon, return current position (cannot navigate)
|
||||||
return current_position
|
if not target_polygon:
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = current_position
|
||||||
|
return result
|
||||||
|
|
||||||
# check if the polygons are the same, if so, just return the target position
|
# if the current and target positions are in the same polygon, return the target position
|
||||||
if current_polygon == target_polygon:
|
if current_polygon == target_polygon:
|
||||||
return target_position
|
result.is_next_target = true
|
||||||
|
result.next_position = target_position
|
||||||
|
return result
|
||||||
|
|
||||||
|
# we will have to insert the start node into the graph and connect it to the nodes within the polygon,
|
||||||
|
# and remove it later on again
|
||||||
|
var start_node: NavigationNode = add_node(current_position.x, current_position.y, -1)
|
||||||
|
var nodes_in_polygon: Array[NavigationNode] = get_nodes_in_polygon(current_polygon)
|
||||||
|
polygon_nodes[current_polygon].append(start_node)
|
||||||
|
for node in nodes_in_polygon:
|
||||||
|
add_connection(start_node, node)
|
||||||
|
|
||||||
# the target position is simple, just take the center of the target polygon since we just need any point
|
# the target position is simple, just take the center of the target polygon since we just need any point
|
||||||
# in the polygon to roughly navigate to it, the alternate algorithm above will take care of the rest
|
# in the polygon to roughly navigate to it, the alternate algorithm above will take care of the rest
|
||||||
var end_node: NavigationNode = target_polygon.center_node
|
var end_node: NavigationNode = target_polygon.center_node
|
||||||
|
|
||||||
var path: Array[NavigationNode] = dijkstra(start_node, end_node)
|
var path: Array[NavigationNode] = dijkstra(start_node, end_node)
|
||||||
|
result.path = path
|
||||||
|
|
||||||
# If a path is found, return the position of the next node in the path
|
# remove the start node again
|
||||||
|
remove_node(start_node)
|
||||||
|
|
||||||
|
# if a path is found, return the position of the next node in the path
|
||||||
if path.size() > 1:
|
if path.size() > 1:
|
||||||
return path[1].position # Next node in the path
|
# next node in the path
|
||||||
|
result.next_position = path[1].position
|
||||||
|
return result
|
||||||
elif path.size() == 1:
|
elif path.size() == 1:
|
||||||
return target_position # Directly reachable
|
# directly reachable
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = target_position
|
||||||
else:
|
else:
|
||||||
# No path found; return current position
|
# no path found; return current position
|
||||||
return current_position
|
result.is_next_target = true
|
||||||
|
result.next_position = current_position
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
func array_contains_node(arr: Array, node: NavigationNode) -> bool:
|
func array_contains_node(arr: Array, node: NavigationNode) -> bool:
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
class_name PathfindingResult
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var path: Array[NavigationNode] = []
|
||||||
|
var next_position: Vector2 = Vector2.ZERO
|
||||||
|
var is_next_target: bool = false
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
path = []
|
||||||
|
next_position = Vector2.ZERO
|
||||||
|
is_next_target = false
|
||||||
|
|
||||||
|
func is_identical_to(other: PathfindingResult) -> bool:
|
||||||
|
if path.size() != other.path.size():
|
||||||
|
return false
|
||||||
|
for i in range(path.size()):
|
||||||
|
if path[i] != other.path[i]:
|
||||||
|
return false
|
||||||
|
if next_position != other.next_position:
|
||||||
|
return false
|
||||||
|
return true
|
|
@ -12,14 +12,14 @@ height = 49.9999
|
||||||
[node name="custom-graph-solver" type="Node2D"]
|
[node name="custom-graph-solver" type="Node2D"]
|
||||||
script = ExtResource("1_tis1c")
|
script = ExtResource("1_tis1c")
|
||||||
|
|
||||||
[node name="NavPolygon2D" type="Polygon2D" parent="."]
|
[node name="NavPolygon2D_1" type="Polygon2D" parent="."]
|
||||||
polygon = PackedVector2Array(164, 56, 379, 23, 603, 53, 684, 152, 759, 255, 572, 293, 598, 166, 422, 106, 344, 158, 509, 312, 438, 454, 489, 504, 610, 342, 734, 323, 834, 199, 786, 85, 958, 43, 1117, 48, 1109, 194, 1137, 565, 916, 550, 887, 386, 965, 359, 962, 473, 1000, 494, 1002, 204, 928, 184, 916, 304, 837, 382, 835, 541, 752, 563, 732, 421, 627, 450, 592, 618, 335, 540, 295, 412, 361, 311, 190, 169, 194, 329, 278, 510, 132, 589, 133, 459, 77, 311, 48, 130)
|
polygon = PackedVector2Array(164, 56, 379, 23, 603, 53, 684, 152, 759, 255, 572, 293, 598, 166, 422, 106, 344, 158, 509, 312, 438, 454, 489, 504, 610, 342, 734, 323, 834, 199, 786, 85, 958, 43, 1117, 48, 1109, 194, 1137, 565, 916, 550, 887, 386, 965, 359, 962, 473, 1000, 494, 1002, 204, 928, 184, 916, 304, 837, 382, 835, 541, 752, 563, 732, 421, 627, 450, 592, 618, 335, 540, 295, 412, 361, 311, 190, 169, 194, 329, 278, 510, 132, 589, 133, 459, 77, 311, 48, 130)
|
||||||
|
|
||||||
[node name="NavGraph" type="Node2D" parent="."]
|
[node name="NavGraph" type="Node2D" parent="."]
|
||||||
script = ExtResource("1_5s4ud")
|
script = ExtResource("1_5s4ud")
|
||||||
|
|
||||||
[node name="CharacterBody2D" type="CharacterBody2D" parent="."]
|
[node name="CharacterBody2D" type="CharacterBody2D" parent="."]
|
||||||
position = Vector2(448, 182)
|
position = Vector2(310, 140)
|
||||||
scale = Vector2(0.640001, 0.640001)
|
scale = Vector2(0.640001, 0.640001)
|
||||||
collision_mask = 3
|
collision_mask = 3
|
||||||
script = ExtResource("3_4rjft")
|
script = ExtResource("3_4rjft")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
# @onready var navigation_polygon: Polygon2D = $TestPolygon2D
|
@onready var navigation_polygon: Polygon2D = $NavPolygon2D_1
|
||||||
@onready var navigation_polygon: Polygon2D = $NavPolygon2D
|
|
||||||
@onready var graph: NavigationGraph = $NavGraph
|
@onready var graph: NavigationGraph = $NavGraph
|
||||||
@onready var character: CharacterBody2D = $CharacterBody2D
|
@onready var character: CharacterBody2D = $CharacterBody2D
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue