main
Yan Wittmann 2024-11-21 18:32:27 +01:00
parent 2a22d3865c
commit 63aa1c0cb5
20 changed files with 584 additions and 437 deletions

View File

@ -6,6 +6,7 @@ const ACCELERATION: int = 2400
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
await get_tree().physics_frame
var movement: Vector2 = Vector2() var movement: Vector2 = Vector2()
nav.target_position = get_global_mouse_position() nav.target_position = get_global_mouse_position()

View File

@ -15,6 +15,10 @@ run/main_scene="res://scenes/mario-party/MarioParty.tscn"
config/features=PackedStringArray("4.3", "Forward Plus") config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[display]
window/stretch/mode="viewport"
[input] [input]
draw_toggle_polygon={ draw_toggle_polygon={

View File

@ -5,17 +5,17 @@ var polygon: PackedVector2Array
var center_node: NavigationNode var center_node: NavigationNode
func _init() -> void: func _init() -> void:
polygon = PackedVector2Array() polygon = PackedVector2Array()
func set_polygon(new_polygon: PackedVector2Array) -> PackedVector2Array: func set_polygon(new_polygon: PackedVector2Array) -> PackedVector2Array:
var new_polygon_clone: PackedVector2Array = new_polygon.duplicate() var new_polygon_clone: PackedVector2Array = new_polygon.duplicate()
new_polygon_clone.append(new_polygon_clone[0]) new_polygon_clone.append(new_polygon_clone[0])
polygon = new_polygon_clone polygon = new_polygon_clone
return polygon return polygon
func center() -> Vector2: func center() -> Vector2:
var center: Vector2 = Vector2() var center: Vector2 = Vector2()
for point in polygon: for point in polygon:
center += Vector2(point.x, point.y) center += Vector2(point.x, point.y)
center /= polygon.size() center /= polygon.size()
return center return center

View File

@ -8,26 +8,26 @@ var frozen: bool = false
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
# check if space is pressed # check if space is pressed
if Input.is_action_just_pressed("ui_select"): if Input.is_action_just_pressed("ui_select"):
frozen = !frozen frozen = !frozen
var movement: Vector2 = Vector2() var movement: Vector2 = Vector2()
if frozen: if frozen:
return return
var pathfinding_result: PathfindingResult = graph.determine_next_position(position, get_global_mouse_position()) var pathfinding_result: PathfindingResult = graph.determine_next_position(position, get_global_mouse_position())
graph.draw_pathfinding_result(pathfinding_result) graph.draw_pathfinding_result(pathfinding_result)
movement = pathfinding_result.next_position - global_position movement = pathfinding_result.next_position - global_position
if pathfinding_result.is_next_target and movement.length() < 20: 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
velocity += movement velocity += movement
if velocity.length() > MAX_SPEED: if velocity.length() > MAX_SPEED:
velocity = velocity.normalized() * MAX_SPEED velocity = velocity.normalized() * MAX_SPEED
move_and_slide() move_and_slide()

View File

@ -5,6 +5,7 @@ extends Node2D
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 var latest_navigation_result: PathfindingResult = null
var draw_polygons: bool = true var draw_polygons: bool = true
var draw_nodes: bool = false var draw_nodes: bool = false
@ -12,297 +13,294 @@ var draw_edges: bool = false
func all_nodes() -> Array[NavigationNode]: func all_nodes() -> Array[NavigationNode]:
# i've had a problem where godot would not allow me to directly return navigation_nodes.keys() # i've had a problem where godot would not allow me to directly return navigation_nodes.keys()
# because it wasn't able to cast the keys to Array[NavigationNode] directly because the type is not explicit # because it wasn't able to cast the keys to Array[NavigationNode] directly because the type is not explicit
# on the dictionary, so i had to do this workaround. # on the dictionary, so i had to do this workaround.
var keys: Array = navigation_nodes.keys() var keys: Array = navigation_nodes.keys()
var nodes: Array[NavigationNode] = [] var nodes: Array[NavigationNode] = []
for key in keys: for key in keys:
if key is NavigationNode: if key is NavigationNode:
nodes.append(key) nodes.append(key)
else: else:
push_error("Key is not a NavigationNode: %s" % key) push_error("Key is not a NavigationNode: %s" % key)
return nodes return nodes
func get_connections(from: NavigationNode) -> Array[NavigationNode]: func get_connections(from: NavigationNode) -> Array[NavigationNode]:
# the same problem as the all_nodes() function # the same problem as the all_nodes() function
var connections: Array = navigation_nodes[from] var connections: Array = navigation_nodes[from]
var nodes: Array[NavigationNode] = [] var nodes: Array[NavigationNode] = []
for connection in connections: for connection in connections:
if connection is NavigationNode: if connection is NavigationNode:
nodes.append(connection) nodes.append(connection)
else: else:
push_error("Connection is not a NavigationNode: %s" % connection) push_error("Connection is not a NavigationNode: %s" % connection)
return nodes return nodes
func add_connection(from: NavigationNode, to: NavigationNode) -> void: func add_connection(from: NavigationNode, to: NavigationNode) -> void:
if all_nodes().has(from): if all_nodes().has(from):
navigation_nodes[from].append(to) navigation_nodes[from].append(to)
else: else:
navigation_nodes[from] = [to] navigation_nodes[from] = [to]
func add_node(x: float, y: float, merge_threshold: float = -1.0) -> NavigationNode: func add_node(x: float, y: float, merge_threshold: float = -1.0) -> NavigationNode:
if merge_threshold > 0: if merge_threshold > 0:
var closest_node: NavigationNode = find_closest_node_with_threshold(Vector2(x, y), merge_threshold) var closest_node: NavigationNode = find_closest_node_with_threshold(Vector2(x, y), merge_threshold)
if closest_node: if closest_node:
closest_node.was_merged = true closest_node.was_merged = true
return closest_node return closest_node
var node: NavigationNode = NavigationNode.new() var node: NavigationNode = NavigationNode.new()
node.set_position(Vector2(x, y)) node.set_position(Vector2(x, y))
navigation_nodes[node] = [] navigation_nodes[node] = []
return node return node
func find_closest_node_with_threshold(position: Vector2, threshold: float) -> NavigationNode: func find_closest_node_with_threshold(position: Vector2, threshold: float) -> NavigationNode:
var closest_node: NavigationNode = null var closest_node: NavigationNode = null
var closest_distance: float = threshold var closest_distance: float = threshold
for node in all_nodes(): for node in all_nodes():
var distance: float = position.distance_to(node.position) var distance: float = position.distance_to(node.position)
if distance < closest_distance: if distance < closest_distance:
closest_node = node closest_node = node
closest_distance = distance closest_distance = distance
return closest_node return closest_node
func remove_connection(from: NavigationNode, to: NavigationNode) -> void: func remove_connection(from: NavigationNode, to: NavigationNode) -> void:
if all_nodes().has(from): if all_nodes().has(from):
navigation_nodes[from].erase(to) navigation_nodes[from].erase(to)
func remove_node(node: NavigationNode) -> void: func remove_node(node: NavigationNode) -> void:
navigation_nodes.erase(node) navigation_nodes.erase(node)
for other_node in all_nodes(): for other_node in all_nodes():
if other_node != node: if other_node != node:
remove_connection(other_node, node) remove_connection(other_node, node)
for poly in all_polygons(): for poly in all_polygons():
if node in polygon_nodes[poly]: if node in polygon_nodes[poly]:
polygon_nodes[poly].erase(node) polygon_nodes[poly].erase(node)
func all_polygons() -> Array[CNavigationPolygon]: func all_polygons() -> Array[CNavigationPolygon]:
var keys: Array = polygon_nodes.keys() var keys: Array = polygon_nodes.keys()
var polygons: Array[CNavigationPolygon] = [] var polygons: Array[CNavigationPolygon] = []
for key in keys: for key in keys:
if key is CNavigationPolygon: if key is CNavigationPolygon:
polygons.append(key) polygons.append(key)
else: else:
push_error("Key is not a NavigationPolygon: %s" % key) push_error("Key is not a NavigationPolygon: %s" % key)
return polygons return polygons
func get_nodes_in_polygon(poly: CNavigationPolygon) -> Array[NavigationNode]: func get_nodes_in_polygon(poly: CNavigationPolygon) -> Array[NavigationNode]:
var relevant_nodes: Array = polygon_nodes[poly] var relevant_nodes: Array = polygon_nodes[poly]
var nodes: Array[NavigationNode] = [] var nodes: Array[NavigationNode] = []
for node in relevant_nodes: for node in relevant_nodes:
if node is NavigationNode: if node is NavigationNode:
nodes.append(node) nodes.append(node)
else: else:
push_error("Node is not a NavigationNode: %s" % node) push_error("Node is not a NavigationNode: %s" % node)
return nodes return nodes
func erase_and_create_nodes_from_polygons(new_polys: Array[PackedVector2Array]) -> void: func erase_and_create_nodes_from_polygons(new_polys: Array[PackedVector2Array]) -> void:
navigation_nodes.clear() navigation_nodes.clear()
polygon_nodes.clear() polygon_nodes.clear()
for poly in new_polys: for poly in new_polys:
if poly.size() == 0: if poly.size() == 0:
continue continue
var navpoly: CNavigationPolygon = CNavigationPolygon.new() var navpoly: CNavigationPolygon = CNavigationPolygon.new()
poly = navpoly.set_polygon(poly) poly = navpoly.set_polygon(poly)
polygon_nodes[navpoly] = [] polygon_nodes[navpoly] = []
polygon_nodes[navpoly] = [] # create one in the center of each polygon that is kept no matter what
# var poly_center: Vector2 = navpoly.center()
# var center_node: NavigationNode = add_node(poly_center.x, poly_center.y, -1)
# center_node.was_merged = true
# polygon_nodes[navpoly].append(center_node)
# navpoly.center_node = center_node
# create one in the center of each polygon that is kept no matter what for i in range(len(poly) - 1):
# var poly_center: Vector2 = navpoly.center() var center: Vector2 = (poly[i] + poly[i + 1]) / 2
# var center_node: NavigationNode = add_node(poly_center.x, poly_center.y, -1) polygon_nodes[navpoly].append(add_node(center.x, center.y, 10))
# center_node.was_merged = true var quater: Vector2 = (poly[i] + center) / 2
# polygon_nodes[navpoly].append(center_node) polygon_nodes[navpoly].append(add_node(quater.x, quater.y, 10))
# navpoly.center_node = center_node var three_quater: Vector2 = (center + poly[i + 1]) / 2
polygon_nodes[navpoly].append(add_node(three_quater.x, three_quater.y, 10))
for i in range(len(poly) - 1): # clear any that were not merged
var center: Vector2 = (poly[i] + poly[i + 1]) / 2 for node in all_nodes():
polygon_nodes[navpoly].append(add_node(center.x, center.y, 10)) if not node.was_merged:
var quater: Vector2 = (poly[i] + center) / 2 remove_node(node)
polygon_nodes[navpoly].append(add_node(quater.x, quater.y, 10))
var three_quater: Vector2 = (center + poly[i + 1]) / 2
polygon_nodes[navpoly].append(add_node(three_quater.x, three_quater.y, 10))
# clear any that were not merged # connect all within a polygon
for node in all_nodes(): for poly in all_polygons():
if not node.was_merged: var nodes_in_polygon: Array[NavigationNode] = get_nodes_in_polygon(poly)
remove_node(node) connect_all_nodes(nodes_in_polygon)
# connect all within a polygon
for poly in all_polygons():
var nodes_in_polygon: Array[NavigationNode] = get_nodes_in_polygon(poly)
connect_all_nodes(nodes_in_polygon)
func connect_all_nodes(nodes: Array[NavigationNode]) -> void: func connect_all_nodes(nodes: Array[NavigationNode]) -> void:
for i in range(len(nodes)): for i in range(len(nodes)):
for j in range(len(nodes)): for j in range(len(nodes)):
if i != j: if i != j:
add_connection(nodes[i], nodes[j]) add_connection(nodes[i], nodes[j])
func _draw() -> void: func _draw() -> void:
if draw_nodes or draw_edges: if draw_nodes or draw_edges:
for from in all_nodes(): for from in all_nodes():
if draw_edges: if draw_edges:
for to in get_connections(from): for to in get_connections(from):
draw_line(from.position, to.position, Color.RED, 1, false) draw_line(from.position, to.position, Color.RED, 1, false)
if draw_nodes: if draw_nodes:
draw_circle(from.position, 5, Color.RED) draw_circle(from.position, 5, Color.RED)
if draw_polygons: if draw_polygons:
for poly in all_polygons(): for poly in all_polygons():
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 != null:
if latest_navigation_result.path.size() > 1: if latest_navigation_result.path.size() > 1:
for i in range(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_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) draw_circle(latest_navigation_result.next_position, 5, Color.GREEN)
func draw_pathfinding_result(result: PathfindingResult) -> void: func draw_pathfinding_result(result: PathfindingResult) -> void:
if latest_navigation_result and latest_navigation_result.is_identical_to(result): if latest_navigation_result and latest_navigation_result.is_identical_to(result):
return return
latest_navigation_result = result latest_navigation_result = result
queue_redraw() queue_redraw()
func determine_next_position(current_position: Vector2, target_position: Vector2) -> PathfindingResult: func determine_next_position(current_position: Vector2, target_position: Vector2) -> PathfindingResult:
var result: PathfindingResult = PathfindingResult.new() var result: PathfindingResult = PathfindingResult.new()
# find both polygons containing the current and target positions # 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
for poly in all_polygons(): for poly in all_polygons():
if Geometry2D.is_point_in_polygon(current_position, poly.polygon): if Geometry2D.is_point_in_polygon(current_position, poly.polygon):
current_polygon = poly current_polygon = poly
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, navigate to the closest node # 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)
result.next_position = closest_node.position result.next_position = closest_node.position
return result return result
# if the target position is not in any polygon, return current position (cannot navigate) # if the target position is not in any polygon, return current position (cannot navigate)
if not target_polygon: if not target_polygon:
result.is_next_target = true result.is_next_target = true
result.next_position = current_position result.next_position = current_position
return result return result
# if the current and target positions are in the same polygon, 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:
result.is_next_target = true result.is_next_target = true
result.next_position = target_position result.next_position = target_position
return result return result
# we will have to insert the start node into the graph and connect it to the nodes within the polygon, # 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 # and remove it later on again
var start_node: NavigationNode = add_node(current_position.x, current_position.y, -1) var start_node: NavigationNode = add_node(current_position.x, current_position.y, -1)
var nodes_in_current_polygon: Array[NavigationNode] = get_nodes_in_polygon(current_polygon) var nodes_in_current_polygon: Array[NavigationNode] = get_nodes_in_polygon(current_polygon)
polygon_nodes[current_polygon].append(start_node) polygon_nodes[current_polygon].append(start_node)
for node in nodes_in_current_polygon: for node in nodes_in_current_polygon:
add_connection(start_node, node) add_connection(start_node, node)
# the target position is simple, just find the closest node in the polygon to the target position, # the target position is simple, just find the closest node in the polygon to the target position,
# the alternate algorithm for within a polygon above will take care of the rest # the alternate algorithm for within a polygon above will take care of the rest
var end_node: NavigationNode = null var end_node: NavigationNode = null
var min_distance: float = INF var min_distance: float = INF
var nodes_in_target_polygon: Array[NavigationNode] = get_nodes_in_polygon(target_polygon) var nodes_in_target_polygon: Array[NavigationNode] = get_nodes_in_polygon(target_polygon)
for node in nodes_in_target_polygon: for node in nodes_in_target_polygon:
var distance: float = target_position.distance_to(node.position) var distance: float = target_position.distance_to(node.position)
if distance < min_distance: if distance < min_distance:
min_distance = distance min_distance = distance
end_node = node end_node = node
var path: Array[NavigationNode] = dijkstra(start_node, end_node) var path: Array[NavigationNode] = dijkstra(start_node, end_node)
result.path = path result.path = path
# remove the start node again # remove the start node again
remove_node(start_node) remove_node(start_node)
# if a path is found, return the position of the next node in the path # if a path is found, return the position of the next node in the path
if path.size() > 1: if path.size() > 1:
# next node in the path # next node in the path
result.next_position = path[1].position result.next_position = path[1].position
return result return result
elif path.size() == 1: elif path.size() == 1:
# directly reachable # directly reachable
result.is_next_target = true result.is_next_target = true
result.next_position = target_position result.next_position = target_position
else: else:
# no path found; return current position # no path found; return current position
result.is_next_target = true result.is_next_target = true
result.next_position = current_position result.next_position = current_position
return result return result
func array_contains_node(arr: Array, node: NavigationNode) -> bool: func array_contains_node(arr: Array, node: NavigationNode) -> bool:
for item in arr: for item in arr:
if item == node: if item == node:
return true return true
return false return false
func dijkstra(start_node: NavigationNode, end_node: NavigationNode) -> Array[NavigationNode]: func dijkstra(start_node: NavigationNode, end_node: NavigationNode) -> Array[NavigationNode]:
var open_set: Array[NavigationNode] = [] var open_set: Array[NavigationNode] = []
var closed_set: Array[NavigationNode] = [] var closed_set: Array[NavigationNode] = []
var distances: Dictionary = {} var distances: Dictionary = {}
var previous_nodes: Dictionary = {} var previous_nodes: Dictionary = {}
distances[start_node] = 0 distances[start_node] = 0
open_set.append(start_node) open_set.append(start_node)
while open_set.size() > 0: while open_set.size() > 0:
# Find the node with the smallest tentative distance var current_node: NavigationNode = open_set[0]
var current_node: NavigationNode = open_set[0] var current_distance: float = distances[current_node]
var current_distance: float = distances[current_node] for node in open_set:
for node in open_set: if distances[node] < current_distance:
if distances[node] < current_distance: current_node = node
current_node = node current_distance = distances[node]
current_distance = distances[node]
# If the end node is reached, reconstruct the path # if the end node is reached, reconstruct path
if current_node == end_node: if current_node == end_node:
var path: Array[NavigationNode] = [] var path: Array[NavigationNode] = []
var node: NavigationNode = end_node var node: NavigationNode = end_node
while node != null: while node != null:
path.insert(0, node) path.insert(0, node)
node = previous_nodes.get(node, null) node = previous_nodes.get(node, null)
return path return path
open_set.erase(current_node) open_set.erase(current_node)
closed_set.append(current_node) closed_set.append(current_node)
# Examine neighbors of the current node # neighbors of the current node
var neighbors = get_connections(current_node) var neighbors = get_connections(current_node)
for neighbor in neighbors: for neighbor in neighbors:
if array_contains_node(closed_set, neighbor): if array_contains_node(closed_set, neighbor):
continue continue
var tentative_distance: float = distances[current_node] + current_node.position.distance_to(neighbor.position) var tentative_distance: float = distances[current_node] + current_node.position.distance_to(neighbor.position)
if not array_contains_node(open_set, neighbor) or tentative_distance < distances.get(neighbor, INF): if not array_contains_node(open_set, neighbor) or tentative_distance < distances.get(neighbor, INF):
distances[neighbor] = tentative_distance distances[neighbor] = tentative_distance
previous_nodes[neighbor] = current_node previous_nodes[neighbor] = current_node
if not array_contains_node(open_set, neighbor): if not array_contains_node(open_set, neighbor):
open_set.append(neighbor) open_set.append(neighbor)
# No path found; return an empty array # no path found
return [] return []

View File

@ -14,10 +14,10 @@ script = ExtResource("1_tis1c")
navigation_polygon = [NodePath("NavPolygon2D_1"), NodePath("SmallPolygon2D"), NodePath("NavPolygon2D_2")] navigation_polygon = [NodePath("NavPolygon2D_1"), NodePath("SmallPolygon2D"), NodePath("NavPolygon2D_2")]
[node name="NavPolygon2D_2" type="Polygon2D" parent="."] [node name="NavPolygon2D_2" type="Polygon2D" parent="."]
polygon = PackedVector2Array(474, 298, 379, 295, 381, 261, 479, 98, 422, 71, 336, 203, 334, 47, 255, 43, 49, 42, 48, 119, 55, 247, 109, 244, 112, 126, 253, 119, 249, 176, 153, 177, 153, 240, 253, 236, 289, 322, 69, 300, 74, 390, 475, 400, 484, 463, 104, 458, 108, 630, 222, 633, 222, 542, 476, 569, 748, 642, 984, 642, 979, 580, 911, 563, 910, 495, 831, 495, 847, 563, 701, 493, 656, 402, 926, 414, 995, 516, 1110, 517, 985, 319, 774, 292, 765, 244, 884, 266, 896, 206, 764, 167, 675, 226, 703, 295, 652, 295, 554, 179, 805, 106, 935, 128, 998, 249, 1105, 257, 934, 19, 616, 61, 476, 167) visible = false
polygon = PackedVector2Array(474, 298, 379, 295, 381, 261, 479, 98, 422, 71, 336, 203, 334, 47, 255, 43, 49, 42, 48, 119, 55, 247, 109, 244, 134, 127, 253, 119, 249, 176, 153, 177, 153, 240, 253, 236, 289, 322, 69, 300, 74, 390, 475, 400, 619, 511, 222, 449, 108, 630, 222, 633, 297, 544, 476, 569, 748, 642, 984, 642, 979, 580, 911, 563, 910, 495, 831, 495, 847, 563, 701, 493, 656, 402, 926, 414, 995, 516, 1110, 517, 985, 319, 774, 292, 765, 244, 884, 266, 896, 206, 764, 167, 675, 226, 703, 295, 652, 295, 600, 200, 805, 106, 935, 128, 998, 249, 1105, 257, 934, 19, 616, 61, 476, 167)
[node name="NavPolygon2D_1" type="Polygon2D" parent="."] [node name="NavPolygon2D_1" type="Polygon2D" parent="."]
visible = false
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="SmallPolygon2D" type="Polygon2D" parent="."] [node name="SmallPolygon2D" type="Polygon2D" parent="."]

View File

@ -9,33 +9,33 @@ var seleted_polygon: int = 0
func _ready() -> void: func _ready() -> void:
for polygon in navigation_polygon: for polygon in navigation_polygon:
polygon.hide() polygon.hide()
update_polygon() update_polygon()
func update_polygon(): func update_polygon():
var polygons: Array[PackedVector2Array] = Geometry2D.decompose_polygon_in_convex(navigation_polygon[seleted_polygon].polygon) var polygons: Array[PackedVector2Array] = Geometry2D.decompose_polygon_in_convex(navigation_polygon[seleted_polygon].polygon)
graph.erase_and_create_nodes_from_polygons(polygons) graph.erase_and_create_nodes_from_polygons(polygons)
func _process(delta: float) -> void: func _process(delta: float) -> void:
# check for left and right arrow keys to change the selected polygon (0, len(navigation_polygon)-1) # check for left and right arrow keys to change the selected polygon (0, len(navigation_polygon)-1)
if Input.is_action_just_pressed("ui_right"): if Input.is_action_just_pressed("ui_right"):
seleted_polygon += 1 seleted_polygon += 1
if seleted_polygon >= len(navigation_polygon): if seleted_polygon >= len(navigation_polygon):
seleted_polygon = 0 seleted_polygon = 0
update_polygon() update_polygon()
if Input.is_action_just_pressed("ui_left"): if Input.is_action_just_pressed("ui_left"):
seleted_polygon -= 1 seleted_polygon -= 1
if seleted_polygon < 0: if seleted_polygon < 0:
seleted_polygon = len(navigation_polygon) - 1 seleted_polygon = len(navigation_polygon) - 1
update_polygon() update_polygon()
if Input.is_action_just_pressed("draw_toggle_polygon"): if Input.is_action_just_pressed("draw_toggle_polygon"):
graph.draw_polygons = !graph.draw_polygons graph.draw_polygons = !graph.draw_polygons
if Input.is_action_just_pressed("draw_toggle_nodes") or Input.is_action_just_pressed("draw_toggle_edges"): if Input.is_action_just_pressed("draw_toggle_nodes") or Input.is_action_just_pressed("draw_toggle_edges"):
graph.draw_nodes = !graph.draw_nodes graph.draw_nodes = !graph.draw_nodes
graph.draw_edges = !graph.draw_edges graph.draw_edges = !graph.draw_edges

File diff suppressed because one or more lines are too long

View File

@ -12,187 +12,191 @@ var last_dice_result: int = 0
var global_transform_size: Vector2 = Vector2(0, 0) var global_transform_size: Vector2 = Vector2(0, 0)
# #
const DIRECTIONS: Dictionary = { const DIRECTIONS: Dictionary = {
"up": Vector2(0, -1), "up": Vector2(0, -1),
"down": Vector2(0, 1), "down": Vector2(0, 1),
"left": Vector2(-1, 0), "left": Vector2(-1, 0),
"right": Vector2(1, 0) "right": Vector2(1, 0)
} }
var node_positions: Dictionary = {} var node_positions: Dictionary = {}
func _ready() -> void: func _ready() -> void:
global_transform_size = Vector2(16, 16) * data_layer.transform.get_scale() global_transform_size = Vector2(16, 16) * data_layer.transform.get_scale()
build_graph() build_graph()
# place the player at the first node # place the player at the first node
var current_player_position: Vector2 = node_positions.keys()[0] var current_player_position: Vector2 = node_positions.keys()[0]
player.global_position = local_to_world(current_player_position) player.global_position = local_to_world(current_player_position)
# bring player to top # bring player to top
player.z_index = 1 player.z_index = 1
roll_dice() roll_dice()
player.finished_movement.connect(roll_dice) player.finished_movement.connect(roll_dice)
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if Input.is_action_just_pressed("draw_toggle_nodes") or Input.is_action_just_pressed("draw_toggle_edges"): if Input.is_action_just_pressed("draw_toggle_nodes") or Input.is_action_just_pressed("draw_toggle_edges"):
navigation_graph.draw_nodes = !navigation_graph.draw_nodes navigation_graph.draw_nodes = !navigation_graph.draw_nodes
navigation_graph.draw_edges = !navigation_graph.draw_edges navigation_graph.draw_edges = !navigation_graph.draw_edges
navigation_graph.queue_redraw() navigation_graph.queue_redraw()
var dice_controls_min: int = 2 var dice_controls_min: int = 2
var dice_controls_max: int = 8 var dice_controls_max: int = 8
func roll_dice() -> void: func roll_dice() -> void:
last_dice_result = randi() % (dice_controls_max - dice_controls_min + 1) + dice_controls_min last_dice_result = randi() % (dice_controls_max - dice_controls_min + 1) + dice_controls_min
print("Dice result: ", last_dice_result) print("Dice result: ", last_dice_result)
$ResultLabel.text = "Rolled a " + str(last_dice_result) $ResultLabel.text = "Rolled a " + str(last_dice_result)
# Find possible movement options # Find possible movement options
var movement_options: Array[MPNavigationNode] = find_nodes_with_distance(world_to_local(player.global_position), last_dice_result) var movement_options: Array[MPNavigationNode] = find_nodes_with_distance(world_to_local(player.global_position), last_dice_result)
# visualize by spawning an indicator at each possible node, with a click event to move the player # visualize by spawning an indicator at each possible node, with a click event to move the player
for node in movement_options: for node in movement_options:
# res://scenes/mario-party/TileIndicator.tscn # res://scenes/mario-party/TileIndicator.tscn
var indicator_scene: Node2D = preload("res://scenes/mario-party/TileIndicator.tscn").instantiate() var indicator_scene: Node2D = preload("res://scenes/mario-party/TileIndicator.tscn").instantiate()
indicator_scene.scale = Vector2(2, 2) indicator_scene.scale = Vector2(2, 2)
var area_node: Area2D = indicator_scene.get_node("area") var area_node: Area2D = indicator_scene.get_node("area")
area_node.set_data(node.position, "player_movement") area_node.set_data(node.position, "player_movement")
area_node.indicator_clicked.connect(_on_indicator_clicked) area_node.indicator_clicked.connect(_on_indicator_clicked)
indicator_scene.global_position = local_to_world(node.get_position()) indicator_scene.global_position = local_to_world(node.get_position())
add_child(indicator_scene) add_child(indicator_scene)
# await get_tree().create_timer(1.0).timeout
# var picked = movement_options[randi() % (len(movement_options))]
# _on_indicator_clicked(picked.position, "player_movement")
func _on_indicator_clicked(pos: Vector2, type: String) -> void: func _on_indicator_clicked(pos: Vector2, type: String) -> void:
print("Indicator clicked: ", type, " ", pos) print("Indicator clicked: ", type, " ", pos)
if type == "player_movement": if type == "player_movement":
player.move_to(pos) player.move_to(pos)
# delete all indicators # delete all indicators
for child in get_children(): for child in get_children():
if child is Node2D: if child is Node2D:
var area_node: Area2D = child.get_node("area") var area_node: Area2D = child.get_node("area")
if area_node != null: if area_node != null:
if area_node.get_type() == "player_movement": if area_node.get_type() == "player_movement":
child.queue_free() child.queue_free()
func local_to_world(location: Vector2) -> Vector2: func local_to_world(location: Vector2) -> Vector2:
return location * global_transform_size + global_transform_size / 2 return location * global_transform_size + global_transform_size / 2
func world_to_local(location: Vector2) -> Vector2: func world_to_local(location: Vector2) -> Vector2:
return (location - global_transform_size / 2) / global_transform_size return (location - global_transform_size / 2) / global_transform_size
func build_graph() -> void: func build_graph() -> void:
print("Identifying nodes") print("Identifying nodes")
# Step 1: Place nodes at positions where is_tile is true # Step 1: Place nodes at positions where is_tile is true
for position in data_layer.get_used_cells(): for position in data_layer.get_used_cells():
var tile_data: TileData = data_layer.get_cell_tile_data(position) var tile_data: TileData = data_layer.get_cell_tile_data(position)
var is_tile: bool = tile_data.get_custom_data("is_tile") var is_tile: bool = tile_data.get_custom_data("is_tile")
if is_tile: if is_tile:
var node: MPNavigationNode = navigation_graph.add_node(position.x, position.y) var node: MPNavigationNode = navigation_graph.add_node(position.x, position.y)
node_positions[position] = node node_positions[position] = node
var indicator_scene: Node2D = preload("res://scenes/mario-party/TileIndicator.tscn").instantiate() var indicator_scene: Node2D = preload("res://scenes/mario-party/TileIndicator.tscn").instantiate()
var area_node: Area2D = indicator_scene.get_node("area") var area_node: Area2D = indicator_scene.get_node("area")
area_node.set_display_type("node") area_node.set_display_type("node")
indicator_scene.global_position = local_to_world(position) indicator_scene.global_position = local_to_world(position)
add_child(indicator_scene) add_child(indicator_scene)
# Step 2: Connect nodes using flood-fill based on walkable tiles # Step 2: Connect nodes using flood-fill based on walkable tiles
print("Connecting nodes") print("Connecting nodes")
for position in node_positions.keys(): for position in node_positions.keys():
connect_node(position) connect_node(position)
func connect_node(start_position: Vector2) -> void: func connect_node(start_position: Vector2) -> void:
var start_node = node_positions.get(Vector2i(start_position)) var start_node = node_positions.get(Vector2i(start_position))
var visited: Dictionary = {} var visited: Dictionary = {}
visited[start_position] = true visited[start_position] = true
# print("Connecting node at ", start_position) # print("Connecting node at ", start_position)
# For each direction, perform flood-fill # For each direction, perform flood-fill
for dir_name in DIRECTIONS.keys(): for dir_name in DIRECTIONS.keys():
var direction = DIRECTIONS[dir_name] var direction = DIRECTIONS[dir_name]
var next_position = start_position + direction var next_position = start_position + direction
# print("Checking direction ", dir_name, " from ", start_position, " to ", next_position) # print("Checking direction ", dir_name, " from ", start_position, " to ", next_position)
# Ensure the first tile respects the direction # Ensure the first tile respects the direction
if not is_valid_direction(next_position, dir_name): if not is_valid_direction(next_position, dir_name):
continue continue
# print("Flood-fill in direction ", dir_name, " from ", next_position) # print("Flood-fill in direction ", dir_name, " from ", next_position)
# Perform flood-fill from the valid tile # Perform flood-fill from the valid tile
var connected_nodes: Array = flood_fill(next_position, visited) var connected_nodes: Array = flood_fill(next_position, visited)
# Add connections between the start node and found nodes # Add connections between the start node and found nodes
for target_position in connected_nodes: for target_position in connected_nodes:
if target_position != start_position: if target_position != start_position:
if node_positions.has(Vector2i(target_position)): if node_positions.has(Vector2i(target_position)):
var target_node = node_positions.get(Vector2i(target_position)) var target_node = node_positions.get(Vector2i(target_position))
navigation_graph.add_connection(start_node, target_node) navigation_graph.add_connection(start_node, target_node)
print(start_position, " --> ", target_position) print(start_position, " --> ", target_position)
func flood_fill(start_position: Vector2, visited: Dictionary) -> Array: func flood_fill(start_position: Vector2, visited: Dictionary) -> Array:
var stack: Array[Vector2] = [start_position] var stack: Array[Vector2] = [start_position]
var connected_nodes: Array[Vector2] = [] var connected_nodes: Array[Vector2] = []
while stack.size() > 0: while stack.size() > 0:
var current_position = stack.pop_back() var current_position = stack.pop_back()
# print(" - Visiting ", current_position) # print(" - Visiting ", current_position)
# Skip if already visited # Skip if already visited
if visited.has(current_position): if visited.has(current_position):
continue continue
visited[current_position] = true visited[current_position] = true
# Skip if not walkable # Skip if not walkable
var tile_data: TileData = data_layer.get_cell_tile_data(current_position) var tile_data: TileData = data_layer.get_cell_tile_data(current_position)
if tile_data == null: if tile_data == null:
continue continue
var is_walkable: bool = tile_data.get_custom_data("is_walkable") var is_walkable: bool = tile_data.get_custom_data("is_walkable")
var is_tile: bool = tile_data.get_custom_data("is_tile") var is_tile: bool = tile_data.get_custom_data("is_tile")
if (not is_walkable) and (not is_tile): if (not is_walkable) and (not is_tile):
continue continue
# If this position is a node, add it to the result # If this position is a node, add it to the result
if is_tile: if is_tile:
# print(" - Found node tile at ", current_position) # print(" - Found node tile at ", current_position)
connected_nodes.append(current_position) connected_nodes.append(current_position)
# Add neighboring tiles to the stack if they respect the direction # Add neighboring tiles to the stack if they respect the direction
for dir_name in DIRECTIONS.keys(): for dir_name in DIRECTIONS.keys():
var direction = DIRECTIONS[dir_name] var direction = DIRECTIONS[dir_name]
var neighbor_position = current_position + direction var neighbor_position = current_position + direction
if not visited.has(neighbor_position): if not visited.has(neighbor_position):
if is_valid_direction(current_position, dir_name): if is_valid_direction(current_position, dir_name):
stack.append(neighbor_position) stack.append(neighbor_position)
return connected_nodes return connected_nodes
func is_valid_direction(position: Vector2, required_dir: String) -> bool: func is_valid_direction(position: Vector2, required_dir: String) -> bool:
var tile_data: TileData = data_layer.get_cell_tile_data(position) var tile_data: TileData = data_layer.get_cell_tile_data(position)
if tile_data == null: if tile_data == null:
return false return false
var is_walkable: bool = tile_data.get_custom_data("is_walkable") var is_walkable: bool = tile_data.get_custom_data("is_walkable")
var walk_dir: String = tile_data.get_custom_data("walk_dir") var walk_dir: String = tile_data.get_custom_data("walk_dir")
if walk_dir == "": if walk_dir == "":
walk_dir = "any" walk_dir = "any"
# print(" L ", position, " ", is_walkable, " ", walk_dir, " ", required_dir) # print(" L ", position, " ", is_walkable, " ", walk_dir, " ", required_dir)
# Check if the tile is walkable and allows movement in the required direction # Check if the tile is walkable and allows movement in the required direction
return is_walkable and (walk_dir == required_dir or walk_dir == "any") return is_walkable and (walk_dir == required_dir or walk_dir == "any")
# the first function that evaluates the finished graph # the first function that evaluates the finished graph
@ -201,35 +205,35 @@ func is_valid_direction(position: Vector2, required_dir: String) -> bool:
# distance here is the amount of nodes to travel, not the actual distance in pixels # distance here is the amount of nodes to travel, not the actual distance in pixels
# must use the MPNavigationNode class and the navigation_graph.get_connections(node: MPNavigationNode) function # must use the MPNavigationNode class and the navigation_graph.get_connections(node: MPNavigationNode) function
func find_nodes_with_distance(start_position: Vector2, distance: int) -> Array[MPNavigationNode]: func find_nodes_with_distance(start_position: Vector2, distance: int) -> Array[MPNavigationNode]:
var start_node = node_positions.get(Vector2i(start_position)) var start_node = node_positions.get(Vector2i(start_position))
if start_node == null: if start_node == null:
print("Error: No node found at starting position ", start_position) print("Error: No node found at starting position ", start_position)
return [] return []
# Initialize BFS # Initialize BFS
var queue: Array = [[start_node, 0]] # Each element is [node, current_distance] var queue: Array = [[start_node, 0]] # Each element is [node, current_distance]
var visited: Dictionary = {start_node: true} var visited: Dictionary = {start_node: true}
var result_nodes: Array[MPNavigationNode] = [] var result_nodes: Array[MPNavigationNode] = []
while queue.size() > 0: while queue.size() > 0:
var current = queue.pop_front() var current = queue.pop_front()
var current_node: MPNavigationNode = current[0] var current_node: MPNavigationNode = current[0]
var current_distance: int = current[1] var current_distance: int = current[1]
# If the target distance is reached, add the node to the result # If the target distance is reached, add the node to the result
if current_distance == distance: if current_distance == distance:
result_nodes.append(current_node) result_nodes.append(current_node)
continue # Do not explore further from this node continue # Do not explore further from this node
# If the current distance exceeds the target, stop exploring # If the current distance exceeds the target, stop exploring
if current_distance > distance: if current_distance > distance:
break break
# Explore neighbors of the current node # Explore neighbors of the current node
var neighbors: Array[MPNavigationNode] = navigation_graph.get_connections(current_node) var neighbors: Array[MPNavigationNode] = navigation_graph.get_connections(current_node)
for neighbor in neighbors: for neighbor in neighbors:
if not visited.has(neighbor): if not visited.has(neighbor):
visited[neighbor] = true visited[neighbor] = true
queue.append([neighbor, current_distance + 1]) queue.append([neighbor, current_distance + 1])
return result_nodes return result_nodes

View File

@ -1,9 +1,17 @@
[gd_resource type="TileSet" load_steps=7 format=3 uid="uid://cm6wi7fjgfk56"] [gd_resource type="TileSet" load_steps=9 format=3 uid="uid://cm6wi7fjgfk56"]
[ext_resource type="Texture2D" uid="uid://bif0n5c12bwrh" path="res://addons/sprout_lands_tilemap/assets/Tilesets/Water.png" id="1_j6mfj"]
[ext_resource type="Texture2D" uid="uid://cmb6k735nhxmy" path="res://scenes/mario-party/img/data_layer.png" id="1_pdyr2"] [ext_resource type="Texture2D" uid="uid://cmb6k735nhxmy" path="res://scenes/mario-party/img/data_layer.png" id="1_pdyr2"]
[ext_resource type="Texture2D" uid="uid://bngfh7nslvij1" path="res://addons/sprout_lands_tilemap/assets/Tilesets/Grass.png" id="2_ev1xx"] [ext_resource type="Texture2D" uid="uid://bngfh7nslvij1" path="res://addons/sprout_lands_tilemap/assets/Tilesets/Grass.png" id="2_ev1xx"]
[ext_resource type="Texture2D" uid="uid://cvemyer4jq6we" path="res://addons/sprout_lands_tilemap/assets/Objects/Paths.png" id="3_eigvu"] [ext_resource type="Texture2D" uid="uid://cvemyer4jq6we" path="res://addons/sprout_lands_tilemap/assets/Objects/Paths.png" id="3_eigvu"]
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_wcjgp"]
texture = ExtResource("1_j6mfj")
0:0/0 = 0
1:0/0 = 0
2:0/0 = 0
3:0/0 = 0
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tp5r2"] [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tp5r2"]
texture = ExtResource("1_pdyr2") texture = ExtResource("1_pdyr2")
0:0/0 = 0 0:0/0 = 0
@ -120,3 +128,4 @@ custom_data_layer_2/type = 4
sources/1 = SubResource("TileSetAtlasSource_tp5r2") sources/1 = SubResource("TileSetAtlasSource_tp5r2")
sources/2 = SubResource("TileSetAtlasSource_m45pk") sources/2 = SubResource("TileSetAtlasSource_m45pk")
sources/3 = SubResource("TileSetAtlasSource_xi3gi") sources/3 = SubResource("TileSetAtlasSource_xi3gi")
sources/0 = SubResource("TileSetAtlasSource_wcjgp")

View File

@ -2,7 +2,6 @@ extends Node2D
@onready var floor: NavigationRegion2D = $BaseNavigationRegion2D @onready var floor: NavigationRegion2D = $BaseNavigationRegion2D
@onready var road: NavigationRegion2D = $CheapPathNavigationRegion2D @onready var road: NavigationRegion2D = $CheapPathNavigationRegion2D
# @onready var road_poly: Polygon2D = $CheapPathNavigationRegion2D/CheapPath
@onready var road_poly: Polygon2D = $BaseNavigationRegion2D/CheapPath @onready var road_poly: Polygon2D = $BaseNavigationRegion2D/CheapPath
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.

File diff suppressed because one or more lines are too long

3
state/.gitignore vendored 100644
View File

@ -0,0 +1,3 @@
# Godot 4+ specific ignores
.godot/
/android/

1
state/icon.svg 100644
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 994 B

View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://beggt5ndi6j4p"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@ -0,0 +1,15 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="state"
config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://icon.svg"

View File

@ -0,0 +1,18 @@
class_name State
extends Node
var state_machine: StateMachine
var character: CharacterBody2D
func _ready() -> void:
pass
func state_enter() -> void:
pass
func state_process(delta: float) -> void:
pass
func state_exit() -> void:
pass

View File

@ -0,0 +1,19 @@
class_name StateMachine
extends Node
var current_state: State:
set(value):
if current_state:
current_state.state_exit()
current_state = value
current_state.state_enter()
func _ready() -> void:
for child in self.get_children():
if true:
print(child)
func _process(delta: float) -> void:
pass

View File

@ -0,0 +1,25 @@
[gd_scene load_steps=5 format=3 uid="uid://cgdvptekjbpgq"]
[ext_resource type="Texture2D" uid="uid://beggt5ndi6j4p" path="res://icon.svg" id="1_jgx5y"]
[ext_resource type="Script" path="res://scenes/state/StateMachine.gd" id="2_d1xqo"]
[ext_resource type="Script" path="res://scenes/state/state_idle.gd" id="3_r1btx"]
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_tr1gq"]
radius = 60.0
height = 122.0
[node name="StateMachineWorld" type="Node2D"]
[node name="CharacterBody2D" type="CharacterBody2D" parent="."]
[node name="Sprite2D" type="Sprite2D" parent="CharacterBody2D"]
texture = ExtResource("1_jgx5y")
[node name="CollisionShape2D" type="CollisionShape2D" parent="CharacterBody2D"]
shape = SubResource("CapsuleShape2D_tr1gq")
[node name="StateMachine" type="Node" parent="CharacterBody2D"]
script = ExtResource("2_d1xqo")
[node name="idle" type="Node" parent="CharacterBody2D/StateMachine"]
script = ExtResource("3_r1btx")

View File

@ -0,0 +1,10 @@
extends State
func state_enter():
print("idle enter")
func state_process(delta: float) -> void:
print("idle process")
func state_exit() -> void:
print("idle exit")