Skip to content

Commit 2c2c8e7

Browse files
committed
Add path-following character
Fix performance bug with 2-way connections in the Astar node
1 parent b8fc28b commit 2c2c8e7

File tree

5 files changed

+128
-12
lines changed

5 files changed

+128
-12
lines changed

2d/navigation_astar/Game.tscn

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
[gd_scene load_steps=3 format=2]
1+
[gd_scene load_steps=5 format=2]
22

33
[ext_resource path="res://tileset/tileset.tres" type="TileSet" id=1]
44
[ext_resource path="res://pathfind_astar.gd" type="Script" id=2]
5+
[ext_resource path="res://character.gd" type="Script" id=3]
6+
[ext_resource path="res://sprites/character.png" type="Texture" id=4]
57

68
[node name="Game" type="Node" index="0"]
79

@@ -28,4 +30,14 @@ script = ExtResource( 2 )
2830
_sections_unfolded = [ "Cell" ]
2931
map_size = Vector2( 16, 16 )
3032

33+
[node name="Character" type="Position2D" parent="." index="1"]
34+
35+
script = ExtResource( 3 )
36+
SPEED = 200.0
37+
38+
[node name="Sprite" type="Sprite" parent="Character" index="0"]
39+
40+
position = Vector2( 7, 0 )
41+
texture = ExtResource( 4 )
42+
3143

2d/navigation_astar/character.gd

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
extends Position2D
2+
3+
export(float) var SPEED = 200.0
4+
5+
enum STATES { IDLE, FOLLOW }
6+
var _state = null
7+
8+
var path = []
9+
var target_point_world = Vector2()
10+
var target_position = Vector2()
11+
12+
var velocity = Vector2()
13+
14+
func _ready():
15+
_change_state(IDLE)
16+
17+
18+
func _change_state(new_state):
19+
if new_state == FOLLOW:
20+
path = get_parent().get_node('TileMap').get_path(position, target_position)
21+
if not path:
22+
_change_state(IDLE)
23+
return
24+
# The index 0 is the starting cell
25+
# we don't want the character to move back to it in this example
26+
target_point_world = path[1]
27+
_state = new_state
28+
29+
30+
func _process(delta):
31+
if not _state == FOLLOW:
32+
return
33+
var arrived_to_next_point = move_to(target_point_world)
34+
if arrived_to_next_point:
35+
path.remove(0)
36+
if len(path) == 0:
37+
_change_state(IDLE)
38+
return
39+
target_point_world = path[0]
40+
41+
42+
func move_to(world_position):
43+
var MASS = 10.0
44+
var ARRIVE_DISTANCE = 10.0
45+
46+
var desired_velocity = (world_position - position).normalized() * SPEED
47+
var steering = desired_velocity - velocity
48+
velocity += steering / MASS
49+
position += velocity * get_process_delta_time()
50+
rotation = velocity.angle()
51+
return position.distance_to(world_position) < ARRIVE_DISTANCE
52+
53+
54+
func _input(event):
55+
if event.is_action_pressed('click'):
56+
if Input.is_key_pressed(KEY_SHIFT):
57+
global_position = get_global_mouse_position()
58+
else:
59+
target_position = get_global_mouse_position()
60+
_change_state(FOLLOW)

2d/navigation_astar/pathfind_astar.gd

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ func _ready():
2727

2828
# Click and Shift force the start and end position of the path to update
2929
# and the node to redraw everything
30-
func _input(event):
31-
if event.is_action_pressed('click') and Input.is_key_pressed(KEY_SHIFT):
32-
# To call the setter method from this script we have to use the explicit self.
33-
self.path_start_position = world_to_map(get_global_mouse_position())
34-
elif event.is_action_pressed('click'):
35-
self.path_end_position = world_to_map(get_global_mouse_position())
36-
30+
#func _input(event):
31+
# if event.is_action_pressed('click') and Input.is_key_pressed(KEY_SHIFT):
32+
# # To call the setter method from this script we have to use the explicit self.
33+
# self.path_start_position = world_to_map(get_global_mouse_position())
34+
# elif event.is_action_pressed('click'):
35+
# self.path_end_position = world_to_map(get_global_mouse_position())
36+
3737

3838
# Loops through all cells within the map's bounds and
3939
# adds all points to the astar_node, except the obstacles
@@ -82,7 +82,8 @@ func astar_connect_walkable_cells(points_array):
8282
# Note the 3rd argument. It tells the astar_node that we want the
8383
# connection to be bilateral: from point A to B and B to A
8484
# If you set this value to false, it becomes a one-way path
85-
astar_node.connect_points(point_index, point_relative_index, true)
85+
# As we loop through all points we can set it to false
86+
astar_node.connect_points(point_index, point_relative_index, false)
8687

8788

8889
# This is a variation of the method above
@@ -110,7 +111,18 @@ func calculate_point_index(point):
110111
return point.x + map_size.x * point.y
111112

112113

113-
func recalculate_path():
114+
func get_path(world_start, world_end):
115+
self.path_start_position = world_to_map(world_start)
116+
self.path_end_position = world_to_map(world_end)
117+
_recalculate_path()
118+
var path_world = []
119+
for point in _point_path:
120+
var point_world = map_to_world(Vector2(point.x, point.y)) + _half_cell_size
121+
path_world.append(point_world)
122+
return path_world
123+
124+
125+
func _recalculate_path():
114126
clear_previous_path_drawing()
115127
var start_point_index = calculate_point_index(path_start_position)
116128
var end_point_index = calculate_point_index(path_end_position)
@@ -158,7 +170,7 @@ func _set_path_start_position(value):
158170
set_cell(value.x, value.y, 1)
159171
path_start_position = value
160172
if path_end_position and path_end_position != path_start_position:
161-
recalculate_path()
173+
_recalculate_path()
162174

163175

164176
func _set_path_end_position(value):
@@ -171,4 +183,4 @@ func _set_path_end_position(value):
171183
set_cell(value.x, value.y, 2)
172184
path_end_position = value
173185
if path_start_position != value:
174-
recalculate_path()
186+
_recalculate_path()
1.17 KB
Loading
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="StreamTexture"
5+
path="res://.import/character.png-eb70ac48a5acf508c4b7740ea4ac4fae.stex"
6+
7+
[deps]
8+
9+
source_file="res://sprites/character.png"
10+
source_md5="8746d76344ac3bad60c33b1bc43e11fd"
11+
12+
dest_files=[ "res://.import/character.png-eb70ac48a5acf508c4b7740ea4ac4fae.stex" ]
13+
dest_md5="e874204705e06ca4dc2c9b0a90db7e8a"
14+
15+
[params]
16+
17+
compress/mode=0
18+
compress/lossy_quality=0.7
19+
compress/hdr_mode=0
20+
compress/normal_map=0
21+
flags/repeat=0
22+
flags/filter=true
23+
flags/mipmaps=false
24+
flags/anisotropic=false
25+
flags/srgb=2
26+
process/fix_alpha_border=true
27+
process/premult_alpha=false
28+
process/HDR_as_SRGB=false
29+
stream=false
30+
size_limit=0
31+
detect_3d=true
32+
svg/scale=1.0

0 commit comments

Comments
 (0)