ソースを参照

Add path-following character

Fix performance bug with 2-way connections in the Astar node
Nathan 7 年 前
コミット
2c2c8e7e73

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

@@ -1,7 +1,9 @@
-[gd_scene load_steps=3 format=2]
+[gd_scene load_steps=5 format=2]
 
 [ext_resource path="res://tileset/tileset.tres" type="TileSet" id=1]
 [ext_resource path="res://pathfind_astar.gd" type="Script" id=2]
+[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" index="0"]
 
@@ -28,4 +30,14 @@ script = ExtResource( 2 )
 _sections_unfolded = [ "Cell" ]
 map_size = Vector2( 16, 16 )
 
+[node name="Character" type="Position2D" parent="." index="1"]
+
+script = ExtResource( 3 )
+SPEED = 200.0
+
+[node name="Sprite" type="Sprite" parent="Character" index="0"]
+
+position = Vector2( 7, 0 )
+texture = ExtResource( 4 )
+
 

+ 60 - 0
2d/navigation_astar/character.gd

@@ -0,0 +1,60 @@
+extends Position2D
+
+export(float) var SPEED = 200.0
+
+enum STATES { IDLE, FOLLOW }
+var _state = null
+
+var path = []
+var target_point_world = Vector2()
+var target_position = Vector2()
+
+var velocity = Vector2()
+
+func _ready():
+	_change_state(IDLE)
+
+
+func _change_state(new_state):
+	if new_state == FOLLOW:
+		path = get_parent().get_node('TileMap').get_path(position, target_position)
+		if not path:
+			_change_state(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
+
+
+func _process(delta):
+	if not _state == 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(IDLE)
+			return
+		target_point_world = path[0]
+
+
+func move_to(world_position):
+	var MASS = 10.0
+	var ARRIVE_DISTANCE = 10.0
+
+	var desired_velocity = (world_position - position).normalized() * SPEED
+	var steering = desired_velocity - velocity
+	velocity += steering / MASS
+	position += velocity * get_process_delta_time()
+	rotation = velocity.angle()
+	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(FOLLOW)

+ 23 - 11
2d/navigation_astar/pathfind_astar.gd

@@ -27,13 +27,13 @@ func _ready():
 
 # 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.
-		self.path_start_position = world_to_map(get_global_mouse_position())
-	elif event.is_action_pressed('click'):
-		self.path_end_position = world_to_map(get_global_mouse_position())
-		
+#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.
+#		self.path_start_position = world_to_map(get_global_mouse_position())
+#	elif event.is_action_pressed('click'):
+#		self.path_end_position = world_to_map(get_global_mouse_position())
+
 
 # Loops through all cells within the map's bounds and
 # adds all points to the astar_node, except the obstacles
@@ -82,7 +82,8 @@ func astar_connect_walkable_cells(points_array):
 			# 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
-			astar_node.connect_points(point_index, point_relative_index, true)
+			# 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
@@ -110,7 +111,18 @@ func calculate_point_index(point):
 	return point.x + map_size.x * point.y
 
 
-func recalculate_path():
+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)
+	_recalculate_path()
+	var path_world = []
+	for point in _point_path:
+		var point_world = map_to_world(Vector2(point.x, point.y)) + _half_cell_size
+		path_world.append(point_world)
+	return path_world
+
+
+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)
@@ -158,7 +170,7 @@ func _set_path_start_position(value):
 	set_cell(value.x, value.y, 1)
 	path_start_position = value
 	if path_end_position and path_end_position != path_start_position:
-		recalculate_path()
+		_recalculate_path()
 
 
 func _set_path_end_position(value):
@@ -171,4 +183,4 @@ func _set_path_end_position(value):
 	set_cell(value.x, value.y, 2)
 	path_end_position = value
 	if path_start_position != value:
-		recalculate_path()
+		_recalculate_path()

BIN
2d/navigation_astar/sprites/character.png


+ 32 - 0
2d/navigation_astar/sprites/character.png.import

@@ -0,0 +1,32 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/character.png-eb70ac48a5acf508c4b7740ea4ac4fae.stex"
+
+[deps]
+
+source_file="res://sprites/character.png"
+source_md5="8746d76344ac3bad60c33b1bc43e11fd"
+
+dest_files=[ "res://.import/character.png-eb70ac48a5acf508c4b7740ea4ac4fae.stex" ]
+dest_md5="e874204705e06ca4dc2c9b0a90db7e8a"
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0