Skip to content

Commit 96f8c5c

Browse files
food-pleaseNathanLovato
authored andcommitted
Reimplement AIPathController
1 parent ab337b1 commit 96f8c5c

File tree

14 files changed

+513
-354
lines changed

14 files changed

+513
-354
lines changed

src/Main2.tscn

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
[gd_scene load_steps=17 format=4 uid="uid://dve3nxx0ohm1g"]
1+
[gd_scene load_steps=19 format=4 uid="uid://dve3nxx0ohm1g"]
22

33
[ext_resource type="Script" uid="uid://ccm6jxmjt0frp" path="res://src/main_2.gd" id="1_d0xvx"]
44
[ext_resource type="Script" uid="uid://bt8owd5e0ns68" path="res://src/field/gameboard/gameboard_layer.gd" id="2_08ad2"]
5+
[ext_resource type="Script" uid="uid://drugj534rnwxw" path="res://src/map.gd" id="2_dn3vx"]
56
[ext_resource type="Texture2D" uid="uid://d2qfi5sncf72b" path="res://assets/terrain/town_tilemap.png" id="2_dsdwj"]
67
[ext_resource type="PackedScene" uid="uid://b626e0bngfvjj" path="res://src/field/gamepieces/gamepiece.tscn" id="2_nevdf"]
78
[ext_resource type="PackedScene" uid="uid://qxua6ekob7fa" path="res://assets/characters/gobot_gfx.tscn" id="3_08ad2"]
@@ -12,6 +13,7 @@
1213
[ext_resource type="TileSet" uid="uid://cnlvvllr0ici" path="res://src/field/gamepieces/controllers/cursor/tileset_cursor.tres" id="8_vw0ml"]
1314
[ext_resource type="Script" uid="uid://dwq2jtul5j1rc" path="res://src/field/gamepieces/controllers/cursor/field_cursor.gd" id="9_xqwga"]
1415
[ext_resource type="Script" uid="uid://vnofet0hi8mx" path="res://src/field/gamepieces/player_controller.gd" id="10_7v0vs"]
16+
[ext_resource type="Script" uid="uid://bm5b3nr6vn3da" path="res://src/field/gamepieces/controllers/path_loop_ai_controller.gd" id="13_xqwga"]
1517

1618
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_u7xvm"]
1719
texture = ExtResource("2_dsdwj")
@@ -41,6 +43,8 @@ script = ExtResource("1_d0xvx")
4143
metadata/_edit_lock_ = true
4244

4345
[node name="Map" type="Node2D" parent="."]
46+
script = ExtResource("2_dn3vx")
47+
gameboard_properties = ExtResource("7_7v0vs")
4448
metadata/_edit_lock_ = true
4549

4650
[node name="TileMapLayer" type="TileMapLayer" parent="Map"]
@@ -60,30 +64,40 @@ script = ExtResource("3_ppad8")
6064

6165
[node name="OccupancyGrid" type="TileMapLayer" parent="Map/DebugMoveGrid"]
6266

63-
[node name="DebugBoundaries" type="Node2D" parent="Map/DebugMoveGrid"]
64-
script = ExtResource("6_ndalr")
65-
gameboard_properties = ExtResource("7_7v0vs")
66-
6767
[node name="Cursor" type="TileMapLayer" parent="Map"]
6868
tile_set = ExtResource("8_vw0ml")
6969
script = ExtResource("9_xqwga")
7070

71+
[node name="DebugBoundaries" type="Node2D" parent="Map"]
72+
script = ExtResource("6_ndalr")
73+
gameboard_properties = ExtResource("7_7v0vs")
74+
7175
[node name="Gamepieces" type="Node2D" parent="."]
7276

7377
[node name="Gamepiece" parent="Gamepieces" instance=ExtResource("2_nevdf")]
74-
position = Vector2(72.4, 38.6)
78+
position = Vector2(87.6, 55.8)
7579
animation_scene = ExtResource("3_08ad2")
76-
move_speed = 128.0
80+
move_speed = 640.0
7781

7882
[node name="Camera2D" type="Camera2D" parent="Gamepieces/Gamepiece"]
7983
metadata/_edit_lock_ = true
8084

8185
[node name="Controller" type="Node2D" parent="Gamepieces/Gamepiece"]
8286
position = Vector2(-7.62939e-06, -7.62939e-06)
83-
scale = Vector2(1, 1)
8487
script = ExtResource("10_7v0vs")
8588
metadata/_edit_lock_ = true
8689

8790
[node name="Gamepiece2" parent="Gamepieces" instance=ExtResource("2_nevdf")]
88-
position = Vector2(270.8, 118.8)
91+
position = Vector2(56, 69.8)
8992
animation_scene = ExtResource("3_08ad2")
93+
94+
[node name="PathLoopController" type="Node2D" parent="Gamepieces/Gamepiece2" node_paths=PackedStringArray("path_to_follow")]
95+
script = ExtResource("13_xqwga")
96+
path_to_follow = NodePath("Line2D")
97+
98+
[node name="Line2D" type="Line2D" parent="Gamepieces/Gamepiece2/PathLoopController"]
99+
points = PackedVector2Array(-0.400002, 2.2, 15, 2, 14.4, -46, -1.4, -45.8)
100+
width = 2.0
101+
102+
[node name="WaitTimer" type="Timer" parent="Gamepieces/Gamepiece2/PathLoopController"]
103+
wait_time = 2.0

src/field/gameboard/gameboard.gd

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,11 @@ const INVALID_CELL: = Vector2i(-1, -1)
1919

2020
const INVALID_INDEX: = -1
2121

22-
## A reference to the Pathfinder for the current playable area.
23-
var pathfinder: Pathfinder = null
24-
2522
## Determines the [member GameboardProperties.extents] of the Gameboard, among other details.
2623
var properties: GameboardProperties = null
2724

28-
29-
func _ready() -> void:
30-
pathfinder = Pathfinder.new()
25+
## A reference to the Pathfinder for the current playable area.
26+
@onready var pathfinder: Pathfinder = Pathfinder.new()
3127

3228

3329
## Convert cell coordinates to pixel coordinates.
@@ -124,6 +120,10 @@ func _add_cells_to_pathfinder(cleared_cells: Array[Vector2i]) -> Dictionary[int,
124120
var uid: = cell_to_index(cell)
125121
pathfinder.add_point(uid, cell)
126122
added_cells[uid] = cell
123+
124+
# Flag the cell as disabled if it is occupied.
125+
if GamepieceRegistry.get_gamepiece(cell):
126+
pathfinder.set_point_disabled(uid)
127127
return added_cells
128128

129129

src/field/gameboard/pathfinder.gd

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ class_name Pathfinder
55
extends AStar2D
66

77

8+
func _init() -> void:
9+
# Disable/re-enable occupied cells whenever a gamepiece moves.
10+
GamepieceRegistry.gamepiece_moved.connect(
11+
func _on_gamepiece_moved(_gp: Gamepiece, new_cell: Vector2i, old_cell: Vector2i) -> void:
12+
var new_cell_id: = Gameboard.cell_to_index(new_cell)
13+
if has_point(new_cell_id):
14+
set_point_disabled(new_cell_id, true)
15+
16+
var old_cell_id: = Gameboard.cell_to_index(old_cell)
17+
if has_point(old_cell_id):
18+
set_point_disabled(old_cell_id, false)
19+
)
20+
21+
822
## Returns true if the coordinate is found in the Pathfinder.
923
func has_cell(coord: Vector2i) -> bool:
1024
return has_point(Gameboard.cell_to_index(coord))
@@ -17,15 +31,38 @@ func can_move_to(coord: Vector2i) -> bool:
1731

1832

1933
## Find a path between two cells. Returns an empty array if no path is available.
20-
func get_path_to_cell(source_coord: Vector2i, target_coord: Vector2i) -> Array[Vector2i]:
34+
## If allow_blocked_source or allow_blocked_target are false, the pathinder wlil fail if a gamepiece
35+
## occupies the source or target cells, respectively.
36+
func get_path_to_cell(source_coord: Vector2i, target_coord: Vector2i,
37+
allow_disabled_source: = true, allow_disabled_target: = false) -> Array[Vector2i]:
38+
# Store the return value in a variable.
2139
var move_path: Array[Vector2i] = []
2240

41+
# Find the source/target IDs and keep track of whether or not the cells are occupied.
2342
var source_id: = Gameboard.cell_to_index(source_coord)
2443
var target_id: = Gameboard.cell_to_index(target_coord)
44+
2545
if has_point(source_id) and has_point(target_id):
46+
# Check to see if we want to un-disable the source/target cells.
47+
var is_source_disabled: = is_point_disabled(source_id)
48+
var is_target_disabled: = is_point_disabled(target_id)
49+
if allow_disabled_source:
50+
set_point_disabled(source_id, false)
51+
if allow_disabled_target:
52+
set_point_disabled(target_id, false)
53+
2654
for path_coord: Vector2i in get_point_path(source_id, target_id):
2755
if path_coord != source_coord: # Don't include the source as the first path element.
2856
move_path.append(path_coord)
57+
58+
# If the source/target cells had originally been disabled, re-disable them here.
59+
if allow_disabled_source:
60+
set_point_disabled(source_id, is_source_disabled)
61+
if allow_disabled_target:
62+
set_point_disabled(target_id, is_target_disabled)
63+
64+
65+
#set_point_disabled(source_id, is_source_disabled)
2966

3067
return move_path
3168

@@ -47,9 +84,15 @@ func get_path_cells_to_adjacent_cell(source_coord: Vector2i,
4784
return shortest_path
4885

4986

87+
# Format the pathfinder so that it may be easily debugged with print.
5088
func _to_string() -> String:
5189
var value: = "\nPathfinder:"
5290
for index in get_point_ids():
53-
value += "\n%s - Id: %d; Linked to: %s" % [str(Gameboard.index_to_cell(index)), index,
54-
get_point_connections(index)]
91+
var cell_header: = "\n%s - Id: %d;" % [str(Gameboard.index_to_cell(index)), index]
92+
93+
var is_disabled: = "\t\t\t"
94+
if is_point_disabled(index):
95+
is_disabled = " (disabled)\t"
96+
97+
value += (cell_header + is_disabled + "Linked to: %s" % get_point_connections(index))
5598
return value + "\n"

src/field/gamepieces/controller.gd

Lines changed: 33 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,10 @@ var move_path: Array[Vector2i] = []:
1111
set = move_along_path
1212
var _current_waypoint: Vector2i
1313

14-
## An active controller will receive input events and process at idle and physics frames. An
15-
## inactive controller will not.
14+
## An active controller will receive inputs (player or otherwise). An inactive controller does
15+
## nothing. This is useful, for example, when toggling of gamepiece movement during cutscenes.
1616
var is_active: = false:
17-
set(value):
18-
is_active = value
19-
20-
set_process(is_active)
21-
set_physics_process(is_active)
22-
set_process_input(is_active)
23-
set_process_unhandled_input(is_active)
17+
set = set_is_active
2418

2519

2620
func _ready() -> void:
@@ -36,39 +30,6 @@ func _ready() -> void:
3630
#FieldEvents.input_paused.connect(_on_input_paused)
3731

3832

39-
func _process(_delta: float) -> void:
40-
if _gamepiece.is_moving():
41-
return
42-
43-
var input_direction: = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
44-
if input_direction:
45-
if not _gamepiece.is_moving():
46-
var source_cell: = GamepieceRegistry.get_cell(_gamepiece)
47-
var target_cell: = Vector2i.ZERO
48-
49-
# Unless using 8-direction movement, one movement axis must be preferred.
50-
# Default to the x-axis.
51-
if not is_zero_approx(input_direction.x):
52-
input_direction = Vector2(input_direction.x, 0)
53-
else:
54-
input_direction = Vector2(0, input_direction.y)
55-
target_cell = Gameboard.pixel_to_cell(_gamepiece.position) + Vector2i(input_direction)
56-
57-
# Try to get a path to destination (will fail if cell is occupied)
58-
var new_move_path: = Gameboard.pathfinder.get_path_to_cell(source_cell, target_cell)
59-
60-
# Path is invalid. Bump animation?
61-
if new_move_path.size() <= 1:
62-
pass
63-
64-
else:
65-
GamepieceRegistry.move_gamepiece(_gamepiece, target_cell)
66-
_gamepiece.move_to(Gameboard.cell_to_pixel(target_cell))
67-
print(new_move_path)
68-
#print(Gameboard.pathfinder.get_path_to_cell())
69-
# If path is valid, move.
70-
71-
7233
#func _unhandled_input(event: InputEvent) -> void:
7334
#if event.is_action_released("select"):
7435
#var source_cell: = GamepieceRegistry.get_cell(_gamepiece)
@@ -105,14 +66,35 @@ func _notification(what: int) -> void:
10566

10667
func move_along_path(value: Array[Vector2i]) -> void:
10768
move_path = value
108-
if move_path.size() >= 1 and Gameboard.pathfinder.can_move_to(move_path[0]):
109-
_current_waypoint = move_path.pop_front()
110-
_gamepiece.move_to(Gameboard.cell_to_pixel(_current_waypoint))
111-
112-
GamepieceRegistry.move_gamepiece(_gamepiece, _current_waypoint)
69+
_move_to_next_waypoint()
70+
71+
72+
## Set whether or not the controller may exert control over the gamepiece.
73+
## There are a number of occasions (such as cutscenes or combat) where gamepieces are inactive.
74+
func set_is_active(value: bool) -> void:
75+
is_active = value
76+
_move_to_next_waypoint() # Will only affect the gamepiece if is_active == true.
77+
78+
79+
# Finds the [member move_path]'s waypoint using [method Array.pop_front] and begins moveing the
80+
# gamepiece towards it.
81+
# The method will do nothing if the controller is currently inactive.
82+
# Returns the distance (in pixels) to the next waypoint.
83+
func _move_to_next_waypoint() -> float:
84+
var distance_to_point: = 0.0
85+
86+
if is_active:
87+
if move_path.size() >= 1 and Gameboard.pathfinder.can_move_to(move_path[0]):
88+
_current_waypoint = move_path.pop_front()
89+
var destination = Gameboard.cell_to_pixel(_current_waypoint)
90+
91+
# Report how far away the waypoint is.
92+
distance_to_point = _gamepiece.position.distance_to(destination)
93+
_gamepiece.move_to(Gameboard.cell_to_pixel(_current_waypoint))
94+
95+
GamepieceRegistry.move_gamepiece(_gamepiece, _current_waypoint)
11396

114-
else:
115-
move_path.clear()
97+
return distance_to_point
11698

11799

118100
# The controller's gamepiece will finish travelling this frame unless it is extended. When following
@@ -123,19 +105,11 @@ func _on_gamepiece_arriving(excess_distance: float) -> void:
123105
if not move_path.is_empty() and is_active:
124106
# Fast gamepieces could jump several waypoints at once, so check to see which waypoint is
125107
# next in line.
126-
while not move_path.is_empty() and excess_distance > 0:
108+
while not move_path.is_empty() and excess_distance > 0.0:
127109
if not Gameboard.pathfinder.can_move_to(move_path[0]):
128-
print("Can't move to ", move_path[0])
129110
return
130111

131-
_current_waypoint = move_path.pop_front()
132-
var destination = Gameboard.cell_to_pixel(_current_waypoint)
133-
var distance_to_waypoint: = \
134-
_gamepiece.position.distance_to(destination)
135-
136-
_gamepiece.move_to(destination)
137-
GamepieceRegistry.move_gamepiece(_gamepiece, _current_waypoint)
138-
112+
var distance_to_waypoint: = _move_to_next_waypoint()
139113
excess_distance -= distance_to_waypoint
140114

141115

0 commit comments

Comments
 (0)