fixed the path rebuilding lag

This commit is contained in:
2026-02-08 02:10:23 +11:00
parent fd9b62faba
commit e441a121ff
26 changed files with 629 additions and 385 deletions

View File

@@ -3,101 +3,38 @@ extends Node3D
signal path_updated()
@export var data_file: FlowFieldData
@export var start_points: Array[Node3D]
@export var goal_points: Array[Node3D]
@export var nodes_visible: bool = false
var flow_node_scene: PackedScene = preload("res://Scenes/FlowField/flow_node.tscn")
var nodes: Array[FlowNode] = []
var start_nodes: Array[FlowNode] = []
var goal_nodes: Array[FlowNode] = []
var created_nodes: int = 0
var start_nodes: Array[FlowNodeData]
var goal_nodes: Array[FlowNodeData]
var magic_node: FlowNodeData
var data: FlowFieldData :
get():
return data
set(value):
data = value
for node: FlowNodeData in data.nodes:
if node.type == FlowNodeData.NodeType.START:
start_nodes.append(node)
if node.type == FlowNodeData.NodeType.GOAL:
goal_nodes.append(node)
func _ready() -> void:
if !nodes_visible:
for node: FlowNode in nodes:
node.visible = false
func load_from_data(data: FlowFieldData = data_file) -> void:
data_file = data
for node: FlowNode in nodes:
delete_node(node)
nodes = []
start_nodes = []
goal_nodes = []
var dict: Dictionary[FlowNodeData, FlowNode] = {}
created_nodes = 0
for node_data: FlowNodeData in data_file.nodes:
var new_flow_node: FlowNode = create_node(node_data.position)
new_flow_node.node_id = node_data.node_id
new_flow_node.grid_id = node_data.grid_id
new_flow_node.grid_x = node_data.grid_x
new_flow_node.grid_y = node_data.grid_y
new_flow_node.buildable = node_data.buildable
dict[node_data] = new_flow_node
if node_data.type == FlowNodeData.NodeType.START:
start_nodes.append(new_flow_node)
elif node_data.type == FlowNodeData.NodeType.GOAL:
goal_nodes.append(new_flow_node)
for node_data: FlowNodeData in dict.keys():
for neighbor: FlowNodeData in node_data.connected_nodes:
dict[node_data].add_connection(dict[neighbor])
@warning_ignore("unused_parameter")
func _process(delta: float) -> void:
if !nodes_visible:
return
for node: FlowNode in nodes:
if node.traversable and node.buildable:
node.set_color(Color.WEB_GRAY)
elif node.traversable and !node.buildable:
node.set_color(Color.CORAL)
else:
node.set_color(Color.BLACK)
if goal_nodes.has(node):
node.set_color(Color.BLUE)
if start_nodes.has(node):
node.set_color(Color.PINK)
if magic_node:
magic_node.set_color(Color.DEEP_PINK)
func get_closest_traversable_point(pos: Vector3) -> FlowNode:
var closest_point: FlowNode = null
func get_closest_point(pos: Vector3, traversable_required: bool = false, buildable_required: bool = false) -> FlowNodeData:
var closest_point: FlowNodeData = null
var closest_dist: float = 100000.0
for node: FlowNode in nodes:
if node.traversable and node.global_position.distance_to(pos) < closest_dist:
closest_dist = node.global_position.distance_to(pos)
closest_point = node
return closest_point
func get_closest_point_point(pos: Vector3) -> FlowNode:
var closest_point: FlowNode = null
var closest_dist: float = 100000.0
for node: FlowNode in nodes:
if node.global_position.distance_to(pos) < closest_dist:
closest_dist = node.global_position.distance_to(pos)
closest_point = node
return closest_point
func get_closest_buildable_point(pos: Vector3) -> FlowNode:
var closest_point: FlowNode = null
var closest_dist: float = 100000.0
for node: FlowNode in nodes:
if node.buildable and node.global_position.distance_to(pos) < closest_dist:
closest_dist = node.global_position.distance_to(pos)
closest_point = node
for node: FlowNodeData in data.nodes:
if node.position.distance_to(pos) < closest_dist:
if !traversable_required or node.traversable:
if !buildable_required or node.buildable:
closest_dist = node.position.distance_to(pos)
closest_point = node
return closest_point
func test_traversability() -> bool:
for node: FlowNode in start_nodes:
for node: FlowNodeData in start_nodes:
while node.best_path != null:
if node.best_path.traversable:
node = node.best_path
@@ -106,9 +43,9 @@ func test_traversability() -> bool:
return true
func iterate_search(search_frontier: Array[FlowNode], reached: Array[FlowNode]) -> void:
var current: FlowNode = search_frontier.pop_front()
for node: FlowNode in current.connections:
func iterate_search(search_frontier: Array[FlowNodeData], reached: Array[FlowNodeData]) -> void:
var current: FlowNodeData = search_frontier.pop_front()
for node: FlowNodeData in current.connected_nodes:
if !reached.has(node):
reached.append(node)
if node.traversable:
@@ -117,9 +54,9 @@ func iterate_search(search_frontier: Array[FlowNode], reached: Array[FlowNode])
func calculate() -> void:
var reached: Array[FlowNode] = []
var search_frontier: Array[FlowNode] = []
for node: FlowNode in goal_nodes:
var reached: Array[FlowNodeData] = []
var search_frontier: Array[FlowNodeData] = []
for node: FlowNodeData in goal_nodes:
node.best_path = null
reached.append(node)
search_frontier.append(node)
@@ -127,20 +64,19 @@ func calculate() -> void:
iterate_search(search_frontier, reached)
var magic_node: FlowNode = null
func traversable_after_blocking_point(point: FlowNode) -> bool:
func traversable_after_blocking_point(point: FlowNodeData) -> bool:
magic_node = null
var reached: Array[FlowNode] = [point]
var search_frontier: Array[FlowNode] = []
for node: FlowNode in point.connections:
var reached: Array[FlowNodeData] = [point]
var search_frontier: Array[FlowNodeData] = []
for node: FlowNodeData in point.connected_nodes:
if node.best_path == point and node.traversable:
reached.append(node)
search_frontier.append(node)
if search_frontier.size() == 0: # if no neighbors rely on this node, then we're all good
return true
while search_frontier.size() > 0:
var current: FlowNode = search_frontier.pop_front()
for node: FlowNode in current.connections:
var current: FlowNodeData = search_frontier.pop_front()
for node: FlowNodeData in current.connected_nodes:
if !reached.has(node):
if node.traversable and node.best_path != node and !reached.has(node.best_path):
#if we havent already seen the node this neighbor goes to,
@@ -154,33 +90,23 @@ func traversable_after_blocking_point(point: FlowNode) -> bool:
return false
## Connects many nodes to a single single node, if any connections already
## exist, this function disconnects them instead
func connect_many_nodes(common_node: FlowNode, child_nodes: Array[FlowNode]) -> void:
for node: FlowNode in child_nodes:
if common_node.connections.has(node):
disconnect_nodes(common_node, node)
else:
connect_nodes(common_node, node)
func toggle_goal(nodes_to_toggle: Array[FlowNode]) -> void:
for node: FlowNode in nodes_to_toggle:
func toggle_goal(nodes_to_toggle: Array[FlowNodeData]) -> void:
for node: FlowNodeData in nodes_to_toggle:
if goal_nodes.has(node):
goal_nodes.erase(node)
else:
goal_nodes.append(node)
func toggle_start(nodes_to_toggle: Array[FlowNode]) -> void:
for node: FlowNode in nodes_to_toggle:
func toggle_start(nodes_to_toggle: Array[FlowNodeData]) -> void:
for node: FlowNodeData in nodes_to_toggle:
if start_nodes.has(node):
start_nodes.erase(node)
else:
start_nodes.append(node)
func toggle_traversable(node: FlowNode) -> bool:
func toggle_traversable(node: FlowNodeData) -> bool:
node.traversable = !node.traversable
calculate()
#TODO: technically the path only changed if the new path IS traversable
@@ -188,64 +114,5 @@ func toggle_traversable(node: FlowNode) -> bool:
return test_traversability()
func toggle_buildable(node: FlowNode) -> void:
func toggle_buildable(node: FlowNodeData) -> void:
node.buildable = !node.buildable
func create_node(pos: Vector3 = Vector3.ZERO, grid_id: int = -1, grid_x: int = 0, grid_y: int = 0) -> FlowNode:
var node: FlowNode = flow_node_scene.instantiate()
node.node_id = created_nodes
node.grid_id = grid_id
node.grid_x = grid_x
node.grid_y = grid_y
node.position = pos
node.set_color(Color.WEB_GRAY)
nodes.append(node)
add_child(node)
node.owner = self
created_nodes += 1
return node
func delete_node(node: FlowNode) -> void:
for neighbor: FlowNode in node.connections:
node.remove_connection(neighbor)
nodes.erase(node)
node.queue_free()
func connect_nodes(node1: FlowNode, node2: FlowNode) -> void:
if node1 != node2:
node1.add_connection(node2)
node2.add_connection(node1)
func disconnect_nodes(node1: FlowNode, node2: FlowNode) -> void:
if node1 != node2:
node1.remove_connection(node2)
node2.remove_connection(node1)
func create_grid(x_size: int, y_size: int, gap: float) -> void:
data_file.grids += 1
var grid_id: int = data_file.grids
var grid: Array[Array] = []
for x: int in x_size:
var row: Array[FlowNode] = []
for y: int in y_size:
#var start_pos: Vector3 = Vector3.ZERO - (Vector3(gap * x_size, 0, gap * y_size) / 2.0)
var point_position: Vector3 = Vector3((x - floori(x_size / 2.0)) * gap, 0, (y - floori(y_size / 2.0)) * gap)
#point_position += global_position
#row.append(create_node(start_pos + Vector3(gap * x, 0, gap * y)))
row.append(create_node(point_position, grid_id, x, y))
grid.append(row)
for x: int in grid.size():
for y: int in grid[x].size():
if y > 0:
connect_nodes(grid[x][y], grid[x][y - 1])
if x > 0:
connect_nodes(grid[x][y], grid[x - 1][y])
if y < grid[x].size() - 1:
connect_nodes(grid[x][y], grid[x][y + 1])
if x < grid.size() - 1:
connect_nodes(grid[x][y], grid[x + 1][y])

View File

@@ -1,8 +1,8 @@
class_name FlowFieldData
extends Resource
extends RefCounted
@export var nodes: Array[FlowNodeData]
@export var grids: int = 0
var nodes: Array[FlowNodeData]
var grids: int = 0
func to_dict() -> Dictionary:

View File

@@ -4,10 +4,62 @@ extends Node
@export var flow_field: FlowField
func create_grid(x: int, y: int, gap: int) -> Array[FlowNode]:
#return flow_field.create_grid(x, y, gap)
return []
func create_grid(x_size: int, y_size: int, gap: float) -> Array[FlowNodeData]:
flow_field.data.grids += 1
var grid_id: int = flow_field.data.grids
var grid: Array[Array] = []
var created_nodes: Array[FlowNodeData] = []
for x: int in x_size:
var row: Array[FlowNodeData] = []
for y: int in y_size:
var point_position: Vector3 = Vector3((x - floori(x_size / 2.0)) * gap, 0, (y - floori(y_size / 2.0)) * gap)
var created_node: FlowNodeData = create_node(point_position, grid_id, x, y)
created_nodes.append(created_node)
row.append(created_node)
grid.append(row)
for x: int in grid.size():
for y: int in grid[x].size():
if y > 0:
connect_nodes(grid[x][y], grid[x][y - 1])
if x > 0:
connect_nodes(grid[x][y], grid[x - 1][y])
if y < grid[x].size() - 1:
connect_nodes(grid[x][y], grid[x][y + 1])
if x < grid.size() - 1:
connect_nodes(grid[x][y], grid[x + 1][y])
return created_nodes
func create_node(pos: Vector3 = Vector3.ZERO, grid_id: int = -1, grid_x: int = 0, grid_y: int = 0) -> FlowNode:
return flow_field.create_node(pos, grid_id, grid_x, grid_y)
func create_node(pos: Vector3 = Vector3.ZERO, grid_id: int = -1, grid_x: int = 0, grid_y: int = 0) -> FlowNodeData:
var node: FlowNodeData = FlowNodeData.new()
node.node_id = flow_field.data.nodes.size()
node.grid_id = grid_id
node.grid_x = grid_x
node.grid_y = grid_y
node.position = pos
flow_field.data.nodes.append(node)
return node
func delete_node(node: FlowNodeData) -> void:
for neighbor: FlowNodeData in node.connections:
disconnect_nodes(node, neighbor)
flow_field.data.nodes.erase(node)
func connect_nodes(a: FlowNodeData, b: FlowNodeData) -> void:
if a != b:
if a.connected_nodes.has(b):
a.connected_nodes.append(b)
if b.connected_nodes.has(a):
b.add_connection(a)
func disconnect_nodes(a: FlowNodeData, b: FlowNodeData) -> void:
if a != b:
if a.connected_nodes.has(b):
a.connected_nodes.erase(b)
if b.connected_nodes.has(a):
b.connected_nodes.erase(a)

View File

@@ -4,14 +4,17 @@ extends Node
@export_group("Basic Function")
@export var zone_list: Array[PackedScene]
@export var zone_holder: Node3D
@export var visualiser_scene: PackedScene
@export_group("Flow Field Editor")
@export var flow_field: FlowField
@export var raycast: RayCast3D
@export var project_raycast: RayCast3D
@export var camera: Camera3D
@export var camera_pivot: Node3D
@export var position_field: HBoxContainer
@export var position_x: LineEdit
@export var position_y: LineEdit
@export var position_z: LineEdit
@export var x_field: LineEdit
@export var y_field: LineEdit
@export var z_field: LineEdit
@@ -20,8 +23,10 @@ extends Node
@export var gap_field: LineEdit
@export var save_path: LineEdit
var hover: FlowNode = null
var selected: Array[FlowNode] = []
var flow_field: FlowField
var visualisers: Dictionary[FlowNodeData, FlowNodeVisualiser]
var hover: FlowNodeVisualiser = null
var selected: Array[FlowNodeVisualiser] = []
var vector_dirty: bool = false
var editing: bool = false
var selected_zone: int = -1
@@ -29,10 +34,13 @@ var level: Level
var radius: float = 0
var up_angle: float = 0
var rotate_held: bool = false
var flow_field_data: FlowFieldData
var flow_field_editor: FlowFieldEditor
var path_vfx: PathVFX
func _ready() -> void:
flow_field_editor = FlowFieldEditor.new()
add_child(flow_field_editor)
var i: int = 0
for zone: PackedScene in zone_list:
i += 1
@@ -40,6 +48,36 @@ func _ready() -> void:
$VBoxContainer2/OptionButton.select(0)
$VBoxContainer2/OptionButton.item_selected.connect(select_zone)
_on_trash_button_pressed()
path_vfx = PathVFX.new()
path_vfx.line_width = 0.4
path_vfx.material = load("res://path_material.tres")
add_child(path_vfx)
func setup_visualisers_from_flow_field_data(data: FlowFieldData) -> void:
for visualiser: FlowNodeVisualiser in visualisers.keys():
visualiser.queue_free()
visualisers = {}
for node: FlowNodeData in data.nodes:
add_visual(node)
for node: FlowNodeData in visualisers.keys():
add_visual_connections(node)
func add_visual(data: FlowNodeData) -> void:
var visual: FlowNodeVisualiser = visualiser_scene.instantiate() as FlowNodeVisualiser
visual.data = data
visual.position = data.position
add_child(visual)
visualisers[data] = visual
func add_visual_connections(data: FlowNodeData) -> void:
var connections: Array[FlowNodeVisualiser] = []
for node: FlowNodeData in data.connected_nodes:
connections.append(visualisers[node])
visualisers[data].connections = connections
visualisers[data].setup_connection_visualisers()
func select_zone(zone_index: int) -> void:
@@ -86,24 +124,23 @@ func _process(delta: float) -> void:
var y: float = Input.get_axis("Move Forward", "Move Backward")
var x: float = Input.get_axis("Move Left", "Move Right")
var input_vector: Vector2 = Input.get_vector("Move Left", "Move Right", "Move Forward", "Move Backward")
#camera_pivot.position += Vector3(x, 0, y) * delta * 30
#set_cam_position()
var movement: Vector3 = ((camera_pivot.transform.basis.z * input_vector.y) + (camera_pivot.transform.basis.x * input_vector.x))
var vec2: Vector2 = Vector2(movement.x, movement.z).normalized()
camera_pivot.position += Vector3(vec2.x, 0.0, vec2.y) * delta * 30.0
func set_node_colors() -> void:
for node: FlowNode in flow_field.nodes:
if node.traversable and node.buildable:
for node: FlowNodeVisualiser in visualisers.values():
if node.data.traversable and node.data.buildable:
node.set_color(Color.WEB_GRAY)
elif node.traversable and !node.buildable:
elif node.data.traversable and !node.data.buildable:
node.set_color(Color.CORAL)
else:
node.set_color(Color.BLACK)
if flow_field.goal_nodes.has(node):
if flow_field.goal_nodes.has(node.data):
node.set_color(Color.BLUE)
if flow_field.start_nodes.has(node):
if flow_field.start_nodes.has(node.data):
node.set_color(Color.PINK)
if selected.has(node):
node.set_color(Color.GREEN)
@@ -157,24 +194,39 @@ func _on_z_field_changed(text: String) -> void:
selected[0].global_position.z = float(text)
## Connects many nodes to a single single node, if any connections already
## exist, this function disconnects them instead
func connect_many_nodes(common_node: FlowNodeData, child_nodes: Array[FlowNodeData]) -> void:
for node: FlowNodeData in child_nodes:
if common_node.connections.has(node):
flow_field_editor.disconnect_nodes(common_node, node)
else:
flow_field_editor.connect_nodes(common_node, node)
func set_position() -> void:
for node: FlowNode in selected:
node.global_position = Vector3(float($Position/x.text), float($Position/y.text), float($Position/z.text))
for node: FlowNodeVisualiser in selected:
var vector: Vector3 = Vector3(float(position_x.text), float(position_y.text), float(position_z.text))
node.data.position = vector
node.global_position = vector
func offset_position() -> void:
for node: FlowNode in selected:
node.global_position += Vector3(float($Position/x.text), float($Position/y.text), float($Position/z.text))
for node: FlowNodeVisualiser in selected:
var vector: Vector3 = Vector3(float(position_x.text), float(position_y.text), float(position_z.text))
node.data.position += vector
node.global_position += vector
func _on_create_button_pressed() -> void:
flow_field.create_node()
add_visual(flow_field_editor.create_node())
func _on_generate_grid_button_pressed() -> void:
flow_field.create_grid(int(x_size_field.text), int(y_size_field.text), float(gap_field.text))
selected.append_array(flow_field.nodes)
create_grid_select_button(flow_field.data_file.grids)
for node: FlowNodeData in flow_field_editor.create_grid(int(x_size_field.text), int(y_size_field.text), float(gap_field.text)):
add_visual(node)
selected.append(node)
create_grid_select_button(flow_field.data.grids)
func create_grid_select_button(grid: int) -> void:
@@ -186,6 +238,13 @@ func create_grid_select_button(grid: int) -> void:
func _on_calculate_button_pressed() -> void:
flow_field.calculate()
var points: Array[Vector3] = []
var node: FlowNodeData = flow_field.get_closest_point(flow_field.start_nodes[0].position, true, false)
points.append(node.position + Vector3(0, 0.1, 0))
while node.best_path:
node = node.best_path
points.append(node.position + Vector3(0, 0.1, 0))
path_vfx.path(points)
func _on_connect_button_pressed() -> void:
@@ -193,20 +252,24 @@ func _on_connect_button_pressed() -> void:
func _on_mark_goal_button_pressed() -> void:
flow_field.toggle_goal(selected)
for node: FlowNodeVisualiser in selected:
flow_field.toggle_goal([node.data])
selected = []
vector_dirty = true
func _on_mark_start_button_pressed() -> void:
flow_field.toggle_start(selected)
for node: FlowNodeVisualiser in selected:
flow_field.toggle_start([node.data])
selected = []
vector_dirty = true
func _on_extrude_button_pressed() -> void:
if selected.size() == 1:
var node: FlowNode = flow_field.create_node(selected[0].position)
var node: FlowNodeVisualiser = visualiser_scene.instantiate() as FlowNodeVisualiser
add_child(node)
node.data = flow_field.create_node(selected[0].position)
node.add_connection(selected[0])
selected[0].add_connection(node)
selected[0].set_color(Color.WEB_GRAY)
@@ -216,61 +279,35 @@ func _on_extrude_button_pressed() -> void:
func _on_toggle_traversable_button_pressed() -> void:
for node: FlowNode in selected:
if !flow_field.toggle_traversable(node):
flow_field.toggle_traversable(node)
for node: FlowNodeVisualiser in selected:
if !flow_field.toggle_traversable(node.data):
flow_field.toggle_traversable(node.data)
selected = []
return
selected = []
func _on_toggle_buildable_button_pressed() -> void:
for node: FlowNode in selected:
flow_field.toggle_buildable(node)
for node: FlowNodeVisualiser in selected:
flow_field.toggle_buildable(node.data)
#TODO: This doesnt work as you'd expect because of physics frames
func _on_project_downwards_button_pressed() -> void:
for node: FlowNode in selected:
project_raycast.global_position = node.global_position + Vector3.UP
for node: FlowNodeVisualiser in selected:
project_raycast.position = node.position + Vector3.UP
project_raycast.target_position = Vector3.DOWN * 100.0
await get_tree().physics_frame
await get_tree().physics_frame
await get_tree().physics_frame
await get_tree().physics_frame
if project_raycast.is_colliding():
node.global_position = project_raycast.get_collision_point()
node.position = project_raycast.get_collision_point()
node.data.position = node.position
func _on_save_button_pressed() -> void:
var new_flow_field_data: FlowFieldData = FlowFieldData.new()
var dict: Dictionary[FlowNode, FlowNodeData] = {}
var grid_num: int = -1
for node: FlowNode in flow_field.nodes:
var new_flow_node_data: FlowNodeData = FlowNodeData.new()
new_flow_node_data.node_id = node.node_id
new_flow_node_data.grid_id = node.grid_id
if node.grid_id > grid_num:
grid_num += 1
new_flow_node_data.grid_x = node.grid_x
new_flow_node_data.grid_y = node.grid_y
new_flow_node_data.position = node.global_position
new_flow_node_data.buildable = node.buildable
if flow_field.start_nodes.has(node):
new_flow_node_data.type = FlowNodeData.NodeType.START
elif flow_field.goal_nodes.has(node):
new_flow_node_data.type = FlowNodeData.NodeType.GOAL
else:
new_flow_node_data.type = FlowNodeData.NodeType.STANDARD
dict[node] = new_flow_node_data
for node: FlowNode in flow_field.nodes:
var flow_node_data: FlowNodeData = dict[node]
for neighbor: FlowNode in node.connections:
flow_node_data.connected_nodes.append(dict[neighbor])
new_flow_field_data.nodes.append(flow_node_data)
new_flow_field_data.grids = grid_num
var string: String = JSON.stringify(new_flow_field_data.to_dict())
var string: String = JSON.stringify(flow_field.data.to_dict())
var path: String = save_path.text + ".json"
var dir: DirAccess = DirAccess.open("user://")
if !dir.dir_exists("pathing_graphs"):
@@ -302,48 +339,41 @@ func _on_load_button_pressed() -> void:
if parse_result == OK:
var dict: Dictionary = json.data
var flow_field_data: FlowFieldData = FlowFieldData.from_dict(dict)
flow_field.load_from_data(flow_field_data)
flow_field.data = flow_field_data
for grid: int in flow_field_data.grids:
create_grid_select_button(grid + 1)
#func _on_load_button_pressed() -> void:
#if ResourceLoader.exists(save_path.text + ".res"):
#print("file exists")
#var resource: Resource = ResourceLoader.load(save_path.text + ".res", "", ResourceLoader.CACHE_MODE_IGNORE)
#if resource is FlowFieldData:
#flow_field.load_from_data(resource)
#print("loaded some data")
#else:
#print("some error loading!")
setup_visualisers_from_flow_field_data(flow_field_data)
func _on_trash_button_pressed() -> void:
if flow_field:
flow_field.queue_free()
for visualiser: FlowNodeVisualiser in visualisers.values():
visualiser.queue_free()
visualisers = {}
for child: Node in $VBoxContainer3.get_children():
child.queue_free()
flow_field = FlowField.new()
flow_field_data = FlowFieldData.new()
flow_field.data_file = flow_field_data
flow_field.data = FlowFieldData.new()
add_child(flow_field)
flow_field_editor.flow_field = flow_field
if level:
level.flow_field = flow_field
func _on_select_all_pressed() -> void:
selected = []
for node: FlowNode in flow_field.nodes:
for node: FlowNodeVisualiser in flow_field.nodes:
selected.append(node)
func select_in_grid(grid: int) -> void:
selected = []
for node: FlowNode in flow_field.nodes:
if node.grid_id == grid:
for node: FlowNodeVisualiser in flow_field.nodes:
if node.data.grid_id == grid:
selected.append(node)
func _on_print_ids_pressed() -> void:
for node: FlowNode in selected:
print(node.node_id)
for node: FlowNodeVisualiser in selected:
print(node.data.node_id)

View File

@@ -3,20 +3,25 @@
[ext_resource type="Script" uid="uid://05c5q1v2nv8p" path="res://Scenes/FlowField/flow_field_tool.gd" id="1_e7pmn"]
[ext_resource type="PackedScene" uid="uid://y1qa1g3ic8sp" path="res://Zones/Moat/scn_moat.tscn" id="2_030xf"]
[ext_resource type="PackedScene" uid="uid://csq7if8wojp4g" path="res://Zones/Cave/scn_cave.tscn" id="3_xar7e"]
[ext_resource type="PackedScene" uid="uid://bssfvyxv5uo1f" path="res://Scenes/FlowField/flow_node.tscn" id="4_50p2d"]
[sub_resource type="Environment" id="Environment_e7pmn"]
ambient_light_source = 2
ambient_light_color = Color(0.728822, 0.728822, 0.728822, 1)
[node name="FlowFieldTool" type="Node" unique_id=897052359 node_paths=PackedStringArray("zone_holder", "raycast", "project_raycast", "camera", "camera_pivot", "position_field", "x_field", "y_field", "z_field", "x_size_field", "y_size_field", "gap_field", "save_path")]
[node name="FlowFieldTool" type="Node" unique_id=897052359 node_paths=PackedStringArray("zone_holder", "raycast", "project_raycast", "camera", "camera_pivot", "position_field", "position_x", "position_y", "position_z", "x_field", "y_field", "z_field", "x_size_field", "y_size_field", "gap_field", "save_path")]
script = ExtResource("1_e7pmn")
zone_list = Array[PackedScene]([ExtResource("2_030xf"), ExtResource("3_xar7e")])
zone_holder = NodePath("ZoneHolder")
visualiser_scene = ExtResource("4_50p2d")
raycast = NodePath("CameraFocus/Camera3D/RayCast3D")
project_raycast = NodePath("RayCast3D")
camera = NodePath("CameraFocus/Camera3D")
camera_pivot = NodePath("CameraFocus")
position_field = NodePath("Position")
position_x = NodePath("Position/x")
position_y = NodePath("Position/y")
position_z = NodePath("Position/z")
x_field = NodePath("Position/x")
y_field = NodePath("Position/y")
z_field = NodePath("Position/z")

View File

@@ -1,17 +1,11 @@
class_name FlowNode
class_name FlowNodeVisualiser
extends StaticBody3D
@export var connections: Array[FlowNode]
@export var visualisers: Array[Node3D]
@export var traversable: bool = true
@export var buildable: bool = true
var data: FlowNodeData
var connections: Array[FlowNodeVisualiser]
var visualisers: Array[Node3D]
var visual_scene: PackedScene = preload("res://Scenes/FlowField/cube2.tscn")
var node_id: int = 0
var grid_id: int = -1
var grid_x: int = 0
var grid_y: int = 0
var best_path: FlowNode :
var best_path: FlowNodeVisualiser :
get():
return best_path
set(value):
@@ -20,9 +14,9 @@ var best_path: FlowNode :
set_connector_color(best_path, Color.DARK_GREEN)
func _ready() -> void:
func setup_connection_visualisers() -> void:
visualisers = []
for node: FlowNode in connections:
for node: FlowNodeVisualiser in connections:
var visual: Node3D = visual_scene.instantiate()
add_child(visual)
visual.owner = self
@@ -45,13 +39,13 @@ func set_color(new_color: Color) -> void:
$flow_node/Sphere.material_override.albedo_color = new_color
func set_connector_color(node: FlowNode, new_color: Color) -> void:
func set_connector_color(node: FlowNodeVisualiser, new_color: Color) -> void:
if visible:
var i: int = connections.find(node)
visualisers[i].get_child(0).material_override.albedo_color = new_color
func add_connection(node: FlowNode) -> void:
func add_connection(node: FlowNodeVisualiser) -> void:
if !connections.has(node):
var visual: Node3D = visual_scene.instantiate()
add_child(visual)
@@ -61,7 +55,7 @@ func add_connection(node: FlowNode) -> void:
set_connector_color(node, Color.WEB_GRAY)
func remove_connection(node: FlowNode) -> void:
func remove_connection(node: FlowNodeVisualiser) -> void:
if connections.has(node):
var i: int = connections.find(node)
visualisers.pop_at(i).queue_free()

View File

@@ -1,21 +1,25 @@
class_name FlowNodeData
extends Resource
extends RefCounted
enum NodeType {
STANDARD = 0,
START = 1,
GOAL = 2,
OBSTACLE = 3,
}
@export var node_id: int = -1
@export var position: Vector3 = Vector3.ZERO
@export var type: NodeType = NodeType.STANDARD
@export var buildable: bool = true
@export var connected_nodes: Array[FlowNodeData]
@export var in_grid: bool = false
@export var grid_id: int = -1
@export var grid_x: int = 0
@export var grid_y: int = 0
var node_id: int = -1
var position: Vector3 = Vector3.ZERO
var type: NodeType = NodeType.STANDARD
var buildable: bool = true
var traversable: bool = true
var connected_nodes: Array[FlowNodeData]
var best_path: FlowNodeData
var in_grid: bool = false
var grid_id: int = -1
var grid_x: int = 0
var grid_y: int = 0
#This function cannot fill in the connection information until a complete set
@@ -32,6 +36,10 @@ static func from_dict(dict: Dictionary) -> FlowNodeData:
data.grid_id = dict["grid_id"]
data.grid_x = dict["grid_x"]
data.grid_y = dict["grid_y"]
if data.type == NodeType.OBSTACLE:
data.buildable = false
data.traversable = false
return data

View File

@@ -9,7 +9,7 @@ class_name TowerBase extends StaticBody3D
var game_manager: GameManager
var owner_id: int
var point: FlowNode
var point: FlowNodeData
var tower: Tower = null
var has_card: bool :
set(_value):