|
@@ -1,22 +1,22 @@
|
|
|
extends TileMap
|
|
|
|
|
|
-# You can only create an AStar node from code, not from the Scene tab
|
|
|
-onready var astar_node = AStar.new()
|
|
|
-# The Tilemap node doesn't have clear bounds so we're defining the map's limits here
|
|
|
+const BASE_LINE_WIDTH = 3.0
|
|
|
+const DRAW_COLOR = Color.white
|
|
|
+
|
|
|
+# The Tilemap node doesn't have clear bounds so we're defining the map's limits here.
|
|
|
export(Vector2) var map_size = Vector2(16, 16)
|
|
|
|
|
|
-# The path start and end variables use setter methods
|
|
|
-# You can find them at the bottom of the script
|
|
|
+# The path start and end variables use setter methods.
|
|
|
+# You can find them at the bottom of the script.
|
|
|
var path_start_position = Vector2() setget _set_path_start_position
|
|
|
var path_end_position = Vector2() setget _set_path_end_position
|
|
|
|
|
|
var _point_path = []
|
|
|
|
|
|
-const BASE_LINE_WIDTH = 3.0
|
|
|
-const DRAW_COLOR = Color('#fff')
|
|
|
-
|
|
|
-# get_used_cells_by_id is a method from the TileMap node
|
|
|
-# here the id 0 corresponds to the grey tile, the obstacles
|
|
|
+# You can only create an AStar node from code, not from the Scene tab.
|
|
|
+onready var astar_node = AStar.new()
|
|
|
+# get_used_cells_by_id is a method from the TileMap node.
|
|
|
+# Here the id 0 corresponds to the grey tile, the obstacles.
|
|
|
onready var obstacles = get_used_cells_by_id(0)
|
|
|
onready var _half_cell_size = cell_size / 2
|
|
|
|
|
@@ -25,8 +25,25 @@ func _ready():
|
|
|
astar_connect_walkable_cells(walkable_cells_list)
|
|
|
|
|
|
|
|
|
-# Click and Shift force the start and end position of the path to update
|
|
|
-# and the node to redraw everything
|
|
|
+func _draw():
|
|
|
+ if not _point_path:
|
|
|
+ return
|
|
|
+ var point_start = _point_path[0]
|
|
|
+ var point_end = _point_path[len(_point_path) - 1]
|
|
|
+
|
|
|
+ set_cell(point_start.x, point_start.y, 1)
|
|
|
+ set_cell(point_end.x, point_end.y, 2)
|
|
|
+
|
|
|
+ var last_point = map_to_world(Vector2(point_start.x, point_start.y)) + _half_cell_size
|
|
|
+ for index in range(1, len(_point_path)):
|
|
|
+ var current_point = map_to_world(Vector2(_point_path[index].x, _point_path[index].y)) + _half_cell_size
|
|
|
+ draw_line(last_point, current_point, DRAW_COLOR, BASE_LINE_WIDTH, true)
|
|
|
+ draw_circle(current_point, BASE_LINE_WIDTH * 2.0, DRAW_COLOR)
|
|
|
+ last_point = current_point
|
|
|
+
|
|
|
+
|
|
|
+# Click and Shift force the start and end position of the path to update,
|
|
|
+# and the node to redraw everything.
|
|
|
#func _input(event):
|
|
|
# if event.is_action_pressed('click') and Input.is_key_pressed(KEY_SHIFT):
|
|
|
# # To call the setter method from this script we have to use the explicit self.
|
|
@@ -36,37 +53,37 @@ func _ready():
|
|
|
|
|
|
|
|
|
# Loops through all cells within the map's bounds and
|
|
|
-# adds all points to the astar_node, except the obstacles
|
|
|
-func astar_add_walkable_cells(obstacles = []):
|
|
|
+# adds all points to the astar_node, except the obstacles.
|
|
|
+func astar_add_walkable_cells(obstacle_list = []):
|
|
|
var points_array = []
|
|
|
for y in range(map_size.y):
|
|
|
for x in range(map_size.x):
|
|
|
var point = Vector2(x, y)
|
|
|
- if point in obstacles:
|
|
|
+ if point in obstacle_list:
|
|
|
continue
|
|
|
|
|
|
points_array.append(point)
|
|
|
- # The AStar class references points with indices
|
|
|
+ # The AStar class references points with indices.
|
|
|
# Using a function to calculate the index from a point's coordinates
|
|
|
- # ensures we always get the same index with the same input point
|
|
|
+ # ensures we always get the same index with the same input point.
|
|
|
var point_index = calculate_point_index(point)
|
|
|
# AStar works for both 2d and 3d, so we have to convert the point
|
|
|
- # coordinates from and to Vector3s
|
|
|
+ # coordinates from and to Vector3s.
|
|
|
astar_node.add_point(point_index, Vector3(point.x, point.y, 0.0))
|
|
|
return points_array
|
|
|
|
|
|
|
|
|
-# Once you added all points to the AStar node, you've got to connect them
|
|
|
+# Once you added all points to the AStar node, you've got to connect them.
|
|
|
# The points don't have to be on a grid: you can use this class
|
|
|
-# to create walkable graphs however you'd like
|
|
|
+# to create walkable graphs however you'd like.
|
|
|
# It's a little harder to code at first, but works for 2d, 3d,
|
|
|
# orthogonal grids, hex grids, tower defense games...
|
|
|
func astar_connect_walkable_cells(points_array):
|
|
|
for point in points_array:
|
|
|
var point_index = calculate_point_index(point)
|
|
|
# For every cell in the map, we check the one to the top, right.
|
|
|
- # left and bottom of it. If it's in the map and not an obstalce,
|
|
|
- # We connect the current point with it
|
|
|
+ # left and bottom of it. If it's in the map and not an obstalce.
|
|
|
+ # We connect the current point with it.
|
|
|
var points_relative = PoolVector2Array([
|
|
|
Vector2(point.x + 1, point.y),
|
|
|
Vector2(point.x - 1, point.y),
|
|
@@ -74,20 +91,19 @@ func astar_connect_walkable_cells(points_array):
|
|
|
Vector2(point.x, point.y - 1)])
|
|
|
for point_relative in points_relative:
|
|
|
var point_relative_index = calculate_point_index(point_relative)
|
|
|
-
|
|
|
if is_outside_map_bounds(point_relative):
|
|
|
continue
|
|
|
if not astar_node.has_point(point_relative_index):
|
|
|
continue
|
|
|
# Note the 3rd argument. It tells the astar_node that we want the
|
|
|
- # connection to be bilateral: from point A to B and B to A
|
|
|
- # If you set this value to false, it becomes a one-way path
|
|
|
- # As we loop through all points we can set it to false
|
|
|
+ # connection to be bilateral: from point A to B and B to A.
|
|
|
+ # If you set this value to false, it becomes a one-way path.
|
|
|
+ # As we loop through all points we can set it to false.
|
|
|
astar_node.connect_points(point_index, point_relative_index, false)
|
|
|
|
|
|
|
|
|
-# This is a variation of the method above
|
|
|
-# It connects cells horizontally, vertically AND diagonally
|
|
|
+# This is a variation of the method above.
|
|
|
+# It connects cells horizontally, vertically AND diagonally.
|
|
|
func astar_connect_walkable_cells_diagonal(points_array):
|
|
|
for point in points_array:
|
|
|
var point_index = calculate_point_index(point)
|
|
@@ -95,7 +111,6 @@ func astar_connect_walkable_cells_diagonal(points_array):
|
|
|
for local_x in range(3):
|
|
|
var point_relative = Vector2(point.x + local_x - 1, point.y + local_y - 1)
|
|
|
var point_relative_index = calculate_point_index(point_relative)
|
|
|
-
|
|
|
if point_relative == point or is_outside_map_bounds(point_relative):
|
|
|
continue
|
|
|
if not astar_node.has_point(point_relative_index):
|
|
@@ -103,14 +118,23 @@ func astar_connect_walkable_cells_diagonal(points_array):
|
|
|
astar_node.connect_points(point_index, point_relative_index, true)
|
|
|
|
|
|
|
|
|
-func is_outside_map_bounds(point):
|
|
|
- return point.x < 0 or point.y < 0 or point.x >= map_size.x or point.y >= map_size.y
|
|
|
-
|
|
|
-
|
|
|
func calculate_point_index(point):
|
|
|
return point.x + map_size.x * point.y
|
|
|
|
|
|
|
|
|
+func clear_previous_path_drawing():
|
|
|
+ if not _point_path:
|
|
|
+ return
|
|
|
+ var point_start = _point_path[0]
|
|
|
+ var point_end = _point_path[len(_point_path) - 1]
|
|
|
+ set_cell(point_start.x, point_start.y, -1)
|
|
|
+ set_cell(point_end.x, point_end.y, -1)
|
|
|
+
|
|
|
+
|
|
|
+func is_outside_map_bounds(point):
|
|
|
+ return point.x < 0 or point.y < 0 or point.x >= map_size.x or point.y >= map_size.y
|
|
|
+
|
|
|
+
|
|
|
func _get_path(world_start, world_end):
|
|
|
self.path_start_position = world_to_map(world_start)
|
|
|
self.path_end_position = world_to_map(world_end)
|
|
@@ -126,39 +150,13 @@ func _recalculate_path():
|
|
|
clear_previous_path_drawing()
|
|
|
var start_point_index = calculate_point_index(path_start_position)
|
|
|
var end_point_index = calculate_point_index(path_end_position)
|
|
|
- # This method gives us an array of points. Note you need the start and end
|
|
|
- # points' indices as input
|
|
|
+ # This method gives us an array of points. Note you need the start and
|
|
|
+ # end points' indices as input.
|
|
|
_point_path = astar_node.get_point_path(start_point_index, end_point_index)
|
|
|
- # Redraw the lines and circles from the start to the end point
|
|
|
+ # Redraw the lines and circles from the start to the end point.
|
|
|
update()
|
|
|
|
|
|
|
|
|
-func clear_previous_path_drawing():
|
|
|
- if not _point_path:
|
|
|
- return
|
|
|
- var point_start = _point_path[0]
|
|
|
- var point_end = _point_path[len(_point_path) - 1]
|
|
|
- set_cell(point_start.x, point_start.y, -1)
|
|
|
- set_cell(point_end.x, point_end.y, -1)
|
|
|
-
|
|
|
-
|
|
|
-func _draw():
|
|
|
- if not _point_path:
|
|
|
- return
|
|
|
- var point_start = _point_path[0]
|
|
|
- var point_end = _point_path[len(_point_path) - 1]
|
|
|
-
|
|
|
- set_cell(point_start.x, point_start.y, 1)
|
|
|
- set_cell(point_end.x, point_end.y, 2)
|
|
|
-
|
|
|
- var last_point = map_to_world(Vector2(point_start.x, point_start.y)) + _half_cell_size
|
|
|
- for index in range(1, len(_point_path)):
|
|
|
- var current_point = map_to_world(Vector2(_point_path[index].x, _point_path[index].y)) + _half_cell_size
|
|
|
- draw_line(last_point, current_point, DRAW_COLOR, BASE_LINE_WIDTH, true)
|
|
|
- draw_circle(current_point, BASE_LINE_WIDTH * 2.0, DRAW_COLOR)
|
|
|
- last_point = current_point
|
|
|
-
|
|
|
-
|
|
|
# Setters for the start and end path values.
|
|
|
func _set_path_start_position(value):
|
|
|
if value in obstacles:
|