Răsfoiți Sursa

Update 2D navigation demos

Aaron Franke 5 ani în urmă
părinte
comite
b0e1cc0227

+ 22 - 24
2d/navigation/navigation.gd

@@ -1,46 +1,44 @@
 extends Navigation2D
 
-export(float) var CHARACTER_SPEED = 400.0
+export(float) var character_speed = 400.0
 var path = []
 
+func _process(delta):
+	var walk_distance = character_speed * delta
+	move_along_path(walk_distance)
+
+
 # The 'click' event is a custom input action defined in
-# Project > Project Settings > Input Map tab
+# Project > Project Settings > Input Map tab.
 func _input(event):
-	if not event.is_action_pressed('click'):
+	if not event.is_action_pressed("click"):
 		return
 	_update_navigation_path($Character.position, get_local_mouse_position())
 
 
-func _update_navigation_path(start_position, end_position):
-	# get_simple_path is part of the Navigation2D class
-	# it returns a PoolVector2Array of points that lead you from the
-	# start_position to the end_position
-	path = get_simple_path(start_position, end_position, true)
-	# The first point is always the start_position
-	# We don't need it in this example as it corresponds to the character's position
-	path.remove(0)
-	set_process(true)
-
-
-func _process(delta):
-	var walk_distance = CHARACTER_SPEED * delta
-	move_along_path(walk_distance)
-
-
 func move_along_path(distance):
 	var last_point = $Character.position
 	while path.size():
 		var distance_between_points = last_point.distance_to(path[0])
-
-		# the position to move to falls between two points
+		# The position to move to falls between two points.
 		if distance <= distance_between_points:
 			$Character.position = last_point.linear_interpolate(path[0], distance / distance_between_points)
 			return
-
-		# the position is past the end of the segment
+		# The position is past the end of the segment.
 		distance -= distance_between_points
 		last_point = path[0]
 		path.remove(0)
-	# the character reached the end of the path
+	# The character reached the end of the path.
 	$Character.position = last_point
 	set_process(false)
+
+
+func _update_navigation_path(start_position, end_position):
+	# get_simple_path is part of the Navigation2D class.
+	# It returns a PoolVector2Array of points that lead you
+	# from the start_position to the end_position.
+	path = get_simple_path(start_position, end_position, true)
+	# The first point is always the start_position.
+	# We don't need it in this example as it corresponds to the character's position.
+	path.remove(0)
+	set_process(true)

+ 1 - 1
2d/navigation_astar/Game.tscn

@@ -5,7 +5,7 @@
 [ext_resource path="res://character.gd" type="Script" id=3]
 [ext_resource path="res://sprites/character.png" type="Texture" id=4]
 
-[node name="Game" type="Node"]
+[node name="Game" type="Node2D"]
 
 [node name="TileMap" type="TileMap" parent="."]
 tile_set = ExtResource( 1 )

+ 25 - 25
2d/navigation_astar/character.gd

@@ -1,8 +1,8 @@
 extends Position2D
 
-export(float) var SPEED = 200.0
+enum States { IDLE, FOLLOW }
 
-enum STATES { IDLE, FOLLOW }
+export(float) var speed = 200.0
 var _state = null
 
 var path = []
@@ -12,38 +12,35 @@ var target_position = Vector2()
 var velocity = Vector2()
 
 func _ready():
-	_change_state(STATES.IDLE)
-
-
-func _change_state(new_state):
-	if new_state == STATES.FOLLOW:
-		path = get_parent().get_node('TileMap')._get_path(position, target_position)
-		if not path or len(path) == 1:
-			_change_state(STATES.IDLE)
-			return
-		# The index 0 is the starting cell
-		# we don't want the character to move back to it in this example
-		target_point_world = path[1]
-	_state = new_state
+	_change_state(States.IDLE)
 
 
 func _process(_delta):
-	if not _state == STATES.FOLLOW:
+	if not _state == States.FOLLOW:
 		return
 	var arrived_to_next_point = move_to(target_point_world)
 	if arrived_to_next_point:
 		path.remove(0)
 		if len(path) == 0:
-			_change_state(STATES.IDLE)
+			_change_state(States.IDLE)
 			return
 		target_point_world = path[0]
 
 
+func _input(event):
+	if event.is_action_pressed("click"):
+		if Input.is_key_pressed(KEY_SHIFT):
+			global_position = get_global_mouse_position()
+		else:
+			target_position = get_global_mouse_position()
+		_change_state(States.FOLLOW)
+
+
 func move_to(world_position):
 	var MASS = 10.0
 	var ARRIVE_DISTANCE = 10.0
 
-	var desired_velocity = (world_position - position).normalized() * SPEED
+	var desired_velocity = (world_position - position).normalized() * speed
 	var steering = desired_velocity - velocity
 	velocity += steering / MASS
 	position += velocity * get_process_delta_time()
@@ -51,10 +48,13 @@ func move_to(world_position):
 	return position.distance_to(world_position) < ARRIVE_DISTANCE
 
 
-func _input(event):
-	if event.is_action_pressed('click'):
-		if Input.is_key_pressed(KEY_SHIFT):
-			global_position = get_global_mouse_position()
-		else:
-			target_position = get_global_mouse_position()
-		_change_state(STATES.FOLLOW)
+func _change_state(new_state):
+	if new_state == States.FOLLOW:
+		path = get_parent().get_node("TileMap")._get_path(position, target_position)
+		if not path or len(path) == 1:
+			_change_state(States.IDLE)
+			return
+		# The index 0 is the starting cell
+		# we don't want the character to move back to it in this example
+		target_point_world = path[1]
+	_state = new_state

+ 60 - 62
2d/navigation_astar/pathfind_astar.gd

@@ -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:

+ 1 - 2
2d/navigation_astar/tileset/tileset_source.tscn

@@ -4,7 +4,7 @@
 [ext_resource path="res://sprites/path_start.png" type="Texture" id=2]
 [ext_resource path="res://sprites/path_end.png" type="Texture" id=3]
 
-[node name="Node2D" type="Node2D"]
+[node name="Tileset" type="Node2D"]
 
 [node name="Obstacle" type="Sprite" parent="."]
 position = Vector2( 32, 32 )
@@ -17,4 +17,3 @@ texture = ExtResource( 2 )
 [node name="PathEnd" type="Sprite" parent="."]
 position = Vector2( 192, 32 )
 texture = ExtResource( 3 )
-