forked from 2121578/gai-ca2
Added walk up to tile feature and navigation visualization
parent
22fa9eb33e
commit
51a04ca403
Binary file not shown.
|
@ -1 +1 @@
|
|||
{"height":320,"filename":"tilemaps.aseprite","frames":[{"duration":0.1}],"width":320,"layers":[{"name":"ground","cels":[{"image":"tilemaps\\tilemap_ground.png","frame":0}]},{"name":"objects","cels":[{"image":"tilemaps\\tilemap_objects.png","frame":0}]},{"name":"temperature","cels":[{"image":"tilemaps\\tilemap_temperature.png","frame":0}]},{"name":"player","cels":[{"image":"tilemaps\\tilemap_player.png","frame":0}]}]}
|
||||
{"width":320,"height":320,"layers":[{"name":"ground","cels":[{"image":"tilemaps\\tilemap_ground.png","frame":0}]},{"name":"objects","cels":[{"image":"tilemaps\\tilemap_objects.png","frame":0}]},{"name":"temperature","cels":[{"image":"tilemaps\\tilemap_temperature.png","frame":0}]},{"name":"player","cels":[{"image":"tilemaps\\tilemap_player.png","frame":0}]}],"frames":[{"duration":0.1}],"filename":"tilemaps.aseprite"}
|
Binary file not shown.
Before Width: | Height: | Size: 98 B After Width: | Height: | Size: 163 B |
|
@ -30,11 +30,9 @@ texture = ExtResource("2_15xge")
|
|||
2:0/0 = 0
|
||||
0:1/0 = 0
|
||||
0:2/0 = 0
|
||||
0:3/0 = 0
|
||||
1:3/0 = 0
|
||||
0:4/size_in_atlas = Vector2i(2, 1)
|
||||
0:4/0 = 0
|
||||
0:5/0 = 0
|
||||
0:6/0 = 0
|
||||
0:7/0 = 0
|
||||
3:0/0 = 0
|
||||
1:1/0 = 0
|
||||
|
@ -44,6 +42,19 @@ texture = ExtResource("2_15xge")
|
|||
2:2/0 = 0
|
||||
3:2/0 = 0
|
||||
4:2/0 = 0
|
||||
2:4/size_in_atlas = Vector2i(2, 1)
|
||||
2:4/0 = 0
|
||||
4:4/size_in_atlas = Vector2i(2, 1)
|
||||
4:4/0 = 0
|
||||
6:4/size_in_atlas = Vector2i(2, 1)
|
||||
6:4/0 = 0
|
||||
6:2/0 = 0
|
||||
1:5/0 = 0
|
||||
0:6/size_in_atlas = Vector2i(2, 1)
|
||||
0:6/0 = 0
|
||||
5:1/0 = 0
|
||||
6:1/0 = 0
|
||||
7:1/0 = 0
|
||||
4:0/size_in_atlas = Vector2i(1, 2)
|
||||
4:0/0 = 0
|
||||
|
||||
|
@ -53,6 +64,9 @@ texture = ExtResource("3_xap0v")
|
|||
0:0/0/custom_data_1 = 10
|
||||
1:0/0 = 0
|
||||
1:0/0/custom_data_1 = 20
|
||||
2:1/0 = 0
|
||||
1:1/0 = 0
|
||||
0:1/0 = 0
|
||||
|
||||
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_i41cv"]
|
||||
texture = ExtResource("4_f38wc")
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -104,5 +104,6 @@ key_6={
|
|||
|
||||
[rendering]
|
||||
|
||||
textures/canvas_textures/default_texture_filter=0
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
|
|
|
@ -5,9 +5,11 @@ extends Node
|
|||
@onready var player: PlayerManager = $PlayerManager
|
||||
@onready var camera: Camera2D = $Camera2D
|
||||
@onready var game_ticker: Timer = $GameTick
|
||||
|
||||
var tilemap_navigation: TilemapNavigation = TilemapNavigation.new()
|
||||
|
||||
func _ready() -> void:
|
||||
tilemap_navigation.world = world
|
||||
tilemap_navigation.player = player
|
||||
player.game_manager = self
|
||||
game_ticker.start()
|
||||
|
||||
|
@ -30,6 +32,8 @@ func player_health_depleted():
|
|||
|
||||
func _on_game_tick_timeout() -> void:
|
||||
var timer_on_game_tick_timeout: PerformanceTimer = PerformanceTimer.new()
|
||||
timer_on_game_tick_timeout.display_name = "_on_game_tick_timeout"
|
||||
timer_on_game_tick_timeout.display_name = "game tick duration"
|
||||
tilemap_navigation.game_tick_start()
|
||||
player.game_tick()
|
||||
tilemap_navigation.game_tick_end()
|
||||
timer_on_game_tick_timeout.stop()
|
||||
|
|
|
@ -10,8 +10,13 @@ extends Node
|
|||
|
||||
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
||||
#
|
||||
var game_manager: GameManager = null
|
||||
var board_position: Vector2i = Vector2i(8, 10)
|
||||
var game_manager: GameManager = null
|
||||
var last_board_position: Vector2i = Vector2i(0, 0)
|
||||
var board_position: Vector2i = Vector2i(8, 10):
|
||||
set(value):
|
||||
last_board_position = board_position
|
||||
board_position = value
|
||||
update_board()
|
||||
|
||||
@onready var behavior_tree: BehaviorTree = $BehaviorTree
|
||||
|
||||
|
@ -20,7 +25,10 @@ var food: int = 0
|
|||
var temperature_timer: int = 0
|
||||
var health: int = 0
|
||||
#
|
||||
var inventory_slot: Vector2i = tilemap_types.EMPTY
|
||||
var inventory_slot: Vector2i = tilemap_types.EMPTY:
|
||||
set(value):
|
||||
inventory_slot = value
|
||||
update_board()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
@ -38,19 +46,19 @@ func _process(delta: float) -> void:
|
|||
if Input.is_action_just_pressed("key_5"):
|
||||
pick_up_item(Vector2i(5, 8))
|
||||
pick_up_item(Vector2i(9, 9))
|
||||
update_board()
|
||||
if Input.is_action_just_pressed("key_4"):
|
||||
var nearest: Vector2i = find_nearest_object([game_manager.world.tilemap_types.OBJECT_I_TREE_1])
|
||||
# nearest.x = nearest.x - 1
|
||||
walk_towards(nearest)
|
||||
update_board()
|
||||
|
||||
|
||||
# SECTION: board access/mangement
|
||||
|
||||
func update_board() -> void:
|
||||
game_manager.world.tilemap_player.clear_cells()
|
||||
game_manager.world.tilemap_player.set_cell(board_position, tilemap_types.PLAYER)
|
||||
# decide what direction the player is facing tilemap_types.PLAYER_DOWN, ...
|
||||
var direction: Vector2i = find_direction(last_board_position, board_position)
|
||||
game_manager.world.tilemap_player.set_cell(board_position, tilemap_types.player_sprite_from_direction(direction))
|
||||
if inventory_slot and inventory_slot != tilemap_types.EMPTY:
|
||||
inventory_label.text = str(inventory_slot)
|
||||
else:
|
||||
|
@ -101,7 +109,7 @@ func pick_up_item(tilemap_pos: Vector2i) -> void:
|
|||
# SECTION: player movement
|
||||
|
||||
func walk_towards(position: Vector2i) -> void:
|
||||
var path: Array[Vector2i] = game_manager.world.find_path(board_position, position)
|
||||
var path: Array[Vector2i] = game_manager.tilemap_navigation.find_path(board_position, position)
|
||||
walk_along(path)
|
||||
|
||||
|
||||
|
@ -110,6 +118,7 @@ func walk_along(path: Array[Vector2i]) -> void:
|
|||
var next_position: Vector2i = path[1]
|
||||
var direction: Vector2i = find_direction(board_position, next_position)
|
||||
move_player(direction)
|
||||
game_manager.tilemap_navigation.chosen_path = path
|
||||
else:
|
||||
push_warning("walk_along path is empty")
|
||||
|
||||
|
@ -136,7 +145,7 @@ func find_nearest_object(object_collection: Array[Vector2i]) -> Vector2i:
|
|||
var shortest_distance: float = 99999999
|
||||
|
||||
for position in object_positions:
|
||||
var distance: float = game_manager.world.manhattan_distance(board_position, position)
|
||||
var distance: float = game_manager.tilemap_navigation.manhattan_distance(board_position, position)
|
||||
if closest_object == tilemap_types.NO_TILE_FOUND or distance < shortest_distance:
|
||||
closest_object = position
|
||||
shortest_distance = distance
|
||||
|
@ -178,7 +187,7 @@ func tick_handle_food():
|
|||
func game_tick() -> void:
|
||||
behavior_tree.game_tick()
|
||||
|
||||
var player_positon_array: Array[Vector2i] = game_manager.world.tilemap_player.get_cells_by_type(tilemap_types.PLAYER)
|
||||
var player_positon_array: Array[Vector2i] = game_manager.world.tilemap_player.get_cells_by_type(tilemap_types.PLAYER_DOWN)
|
||||
if len(player_positon_array) > 0:
|
||||
var player_positon: Vector2i = player_positon_array[0]
|
||||
var cell_temperature: int = game_manager.world.tilemap_temperature.get_custom_data(player_positon, "temperature", 0) as int
|
||||
|
|
|
@ -22,6 +22,7 @@ func populate_blackboard():
|
|||
blackboard["world"] = game_manager.world
|
||||
blackboard["player"] = game_manager.player
|
||||
blackboard["camera"] = game_manager.camera
|
||||
blackboard["navigation"] = game_manager.tilemap_navigation
|
||||
|
||||
|
||||
func game_tick() -> void:
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
class_name WalkToMouse
|
||||
extends Task
|
||||
|
||||
func run(p_blackboard: Dictionary) -> void:
|
||||
var world: World = p_blackboard["world"]
|
||||
var player: PlayerManager = p_blackboard["player"]
|
||||
|
||||
world.tilemap_temperature.clear_cells()
|
||||
var path: Array[Vector2i] = world.find_path(player.board_position, world.tilemap_mouse_position(), 200)
|
||||
if len(path) == 0:
|
||||
status = FAILURE
|
||||
|
||||
for pos in path:
|
||||
world.tilemap_temperature.set_cell(pos, tilemap_types.TEMPERATURE_COLD_1)
|
||||
player.walk_along(path)
|
||||
status = SUCCESS
|
|
@ -0,0 +1,17 @@
|
|||
class_name WalkToMouse
|
||||
extends Task
|
||||
|
||||
func run(p_blackboard: Dictionary) -> void:
|
||||
var world: World = p_blackboard["world"]
|
||||
var player: PlayerManager = p_blackboard["player"]
|
||||
var tilemap_navigation: TilemapNavigation = p_blackboard["navigation"]
|
||||
|
||||
world.tilemap_temperature.clear_cells()
|
||||
var path: Array[Vector2i] = tilemap_navigation.find_path(player.board_position, world.tilemap_mouse_position(), player.view_distance)
|
||||
if len(path) == 0:
|
||||
status = FAILURE
|
||||
|
||||
for pos in path:
|
||||
world.tilemap_temperature.set_cell(pos, tilemap_types.TEMPERATURE_COLD_1)
|
||||
player.walk_along(path)
|
||||
status = SUCCESS
|
|
@ -0,0 +1,17 @@
|
|||
class_name WalkUpToMouse
|
||||
extends Task
|
||||
|
||||
func run(p_blackboard: Dictionary) -> void:
|
||||
var world: World = p_blackboard["world"]
|
||||
var player: PlayerManager = p_blackboard["player"]
|
||||
var tilemap_navigation: TilemapNavigation = p_blackboard["navigation"]
|
||||
|
||||
world.tilemap_temperature.clear_cells()
|
||||
var path: Array[Vector2i] = tilemap_navigation.find_path_allow_neighbors(player.board_position, world.tilemap_mouse_position(), player.view_distance)
|
||||
if len(path) == 0:
|
||||
status = FAILURE
|
||||
|
||||
for pos in path:
|
||||
world.tilemap_temperature.set_cell(pos, tilemap_types.TEMPERATURE_COLD_1)
|
||||
player.walk_along(path)
|
||||
status = SUCCESS
|
|
@ -40,6 +40,10 @@ func get_cell(position: Vector2i) -> TileData:
|
|||
return tilemap.get_cell_tile_data(position)
|
||||
|
||||
|
||||
func get_cell_atlas_coords(position: Vector2i) -> Vector2i:
|
||||
return tilemap.get_cell_atlas_coords(position)
|
||||
|
||||
|
||||
func set_cell(position: Vector2i, atlas_coords: Vector2i) -> void:
|
||||
tilemap.set_cell(position, sid, atlas_coords)
|
||||
|
||||
|
|
|
@ -13,40 +13,58 @@ const GROUND_DOCK: Vector2i = Vector2i(3, 0)
|
|||
#
|
||||
# objects, sid = 1
|
||||
# NI = not interactive
|
||||
const OBJECT_NI_RANDOM_1: Vector2i = Vector2i(0, 0) # testing only, to be removed
|
||||
const OBJECT_NI_RANDOM_2: Vector2i = Vector2i(1, 0) # testing only, to be removed
|
||||
const OBJECT_NI_ROCK_1: Vector2i = Vector2i(2, 0)
|
||||
const OBJECT_NI_FIREPIT_ON: Vector2i = Vector2i(7, 1)
|
||||
const OBJECT_NI_TREE_CUT: Vector2i = Vector2i(2, 0)
|
||||
const OBJECT_NI_BOAT_NO_ENIGNE: Vector2i= Vector2i(4, 4)
|
||||
|
||||
|
||||
const OBJECT_NI_RANDOM_1: Vector2i = Vector2i(0, 0) # testing only, to be removed
|
||||
const OBJECT_NI_RANDOM_2: Vector2i = Vector2i(1, 0) # testing only, to be removed
|
||||
const OBJECT_NI_ROCK_1: Vector2i = Vector2i(2, 0)
|
||||
const OBJECT_NI_FIREPIT_ON: Vector2i = Vector2i(7, 1)
|
||||
const OBJECT_NI_TREE_CUT: Vector2i = Vector2i(2, 0)
|
||||
const OBJECT_NI_BOAT_NO_ENIGNE: Vector2i = Vector2i(4, 4)
|
||||
#
|
||||
# I = interactive
|
||||
const OBJECT_I_BOAT_ENGINE: Vector2i = Vector2i(0, 1)
|
||||
const OBJECT_I_FUEL: Vector2i = Vector2i(1, 1)
|
||||
const OBJECT_I_ANCHOR: Vector2i = Vector2i(2, 1)
|
||||
const OBJECT_I_EMPTY_BUSH: Vector2i = Vector2i(3, 0)
|
||||
const OBJECT_I_FILLED_BUSH: Vector2i = Vector2i(3, 1)
|
||||
const OBJECT_I_BERRY: Vector2i = Vector2i(0, 5)
|
||||
const OBJECT_I_STICK: Vector2i = Vector2i(1, 5)
|
||||
const OBJECT_I_TREE_1: Vector2i = Vector2i(4, 0)
|
||||
const OBJECT_I_CHEST: Vector2i = Vector2i(0, 2)
|
||||
const OBJECT_I_GEARS: Vector2i = Vector2i(1, 2)
|
||||
const OBJECT_I_MEDIKIT: Vector2i = Vector2i(2, 2)
|
||||
const OBJECT_I_PADDLE: Vector2i = Vector2i(3, 2)
|
||||
const OBJECT_I_GAS_STOVE: Vector2i = Vector2i(4, 2)
|
||||
const OBJECT_I_TENT: Vector2i = Vector2i(6, 2)
|
||||
|
||||
const OBJECT_I_BOAT_WITH_ENGINE: Vector2i = Vector2i(6,4)
|
||||
const OBJECT_I_FIREPIT_OFF: Vector2i = Vector2i(6, 1)
|
||||
|
||||
const OBJECT_I_BOAT_ENGINE: Vector2i = Vector2i(0, 1)
|
||||
const OBJECT_I_FUEL: Vector2i = Vector2i(1, 1)
|
||||
const OBJECT_I_ANCHOR: Vector2i = Vector2i(2, 1)
|
||||
const OBJECT_I_EMPTY_BUSH: Vector2i = Vector2i(3, 0)
|
||||
const OBJECT_I_FILLED_BUSH: Vector2i = Vector2i(3, 1)
|
||||
const OBJECT_I_BERRY: Vector2i = Vector2i(0, 5)
|
||||
const OBJECT_I_STICK: Vector2i = Vector2i(1, 5)
|
||||
const OBJECT_I_TREE_1: Vector2i = Vector2i(4, 0)
|
||||
const OBJECT_I_CHEST: Vector2i = Vector2i(0, 2)
|
||||
const OBJECT_I_GEARS: Vector2i = Vector2i(1, 2)
|
||||
const OBJECT_I_MEDIKIT: Vector2i = Vector2i(2, 2)
|
||||
const OBJECT_I_PADDLE: Vector2i = Vector2i(3, 2)
|
||||
const OBJECT_I_GAS_STOVE: Vector2i = Vector2i(4, 2)
|
||||
const OBJECT_I_TENT: Vector2i = Vector2i(6, 2)
|
||||
const OBJECT_I_BOAT_WITH_ENGINE: Vector2i = Vector2i(6, 4)
|
||||
const OBJECT_I_FIREPIT_OFF: Vector2i = Vector2i(6, 1)
|
||||
# collections
|
||||
const OBJECT_COLLECTION_BERRY_SOURCE: Array[Vector2i] = [OBJECT_I_FILLED_BUSH, OBJECT_I_BERRY]
|
||||
#
|
||||
# temperature, sid = 2
|
||||
const TEMPERATURE_NORMAL: Vector2i = Vector2i(-1, -1)
|
||||
const TEMPERATURE_NORMAL: Vector2i = EMPTY
|
||||
const TEMPERATURE_COLD_1: Vector2i = Vector2i(0, 0)
|
||||
const TEMPERATURE_COLD_2: Vector2i = Vector2i(1, 0)
|
||||
#
|
||||
const NAVIGATION_CHECKED: Vector2i = Vector2i(0, 1)
|
||||
const NAVIGATION_CHOSEN: Vector2i = Vector2i(1, 1)
|
||||
const NAVIGATION_FAILED: Vector2i = Vector2i(2, 1)
|
||||
#
|
||||
# player, sid = 3
|
||||
const PLAYER: Vector2i = Vector2i(0, 0)
|
||||
const PLAYER_DOWN: Vector2i = Vector2i(0, 0)
|
||||
const PLAYER_UP: Vector2i = Vector2i(1, 0)
|
||||
const PLAYER_LEFT: Vector2i = Vector2i(2, 0)
|
||||
const PLAYER_RIGHT: Vector2i = Vector2i(3, 0)
|
||||
#
|
||||
const PLAYER_COLLECTION: Array[Vector2i] = [PLAYER_DOWN, PLAYER_UP, PLAYER_LEFT, PLAYER_RIGHT]
|
||||
|
||||
|
||||
func player_sprite_from_direction(direction: Vector2i) -> Vector2i:
|
||||
if direction == Vector2i(0, 1):
|
||||
return PLAYER_DOWN
|
||||
if direction == Vector2i(0, -1):
|
||||
return PLAYER_UP
|
||||
if direction == Vector2i(-1, 0):
|
||||
return PLAYER_LEFT
|
||||
if direction == Vector2i(1, 0):
|
||||
return PLAYER_RIGHT
|
||||
return PLAYER_DOWN
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
class_name TilemapNavigation
|
||||
extends Node
|
||||
|
||||
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
||||
#
|
||||
var world: World = null
|
||||
var player: PlayerManager = null
|
||||
#
|
||||
# Dictionary[Vector2i, Array[Vector2i]] (target, path)
|
||||
var found_paths: Dictionary = {}
|
||||
var failed_positions: Array[Vector2i] = []
|
||||
var chosen_path: Array[Vector2i] = []
|
||||
|
||||
|
||||
func game_tick_start() -> void:
|
||||
found_paths = {}
|
||||
failed_positions = []
|
||||
chosen_path = []
|
||||
|
||||
|
||||
func game_tick_end() -> void:
|
||||
world.tilemap_nav_vis.clear_cells()
|
||||
# use tilemap_types.NAVIGATION_CHECKED, tilemap_types.NAVIGATION_FAILED and tilemap_types.NAVIGATION_CHOSEN
|
||||
for path in found_paths.values():
|
||||
for pos in path:
|
||||
world.tilemap_nav_vis.set_cell(pos, tilemap_types.NAVIGATION_CHECKED)
|
||||
for pos in failed_positions:
|
||||
world.tilemap_nav_vis.set_cell(pos, tilemap_types.NAVIGATION_FAILED)
|
||||
for pos in chosen_path:
|
||||
world.tilemap_nav_vis.set_cell(pos, tilemap_types.NAVIGATION_CHOSEN)
|
||||
|
||||
|
||||
func is_within_radius(position: Vector2i, center: Vector2i, radius: int) -> bool:
|
||||
return manhattan_distance(position, center) <= radius
|
||||
|
||||
|
||||
func manhattan_distance(a: Vector2i, b: Vector2i) -> int:
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
||||
|
||||
var walking_directions: Array[Vector2i] = [Vector2i(0, -1), Vector2i(0, 1), Vector2i(-1, 0), Vector2i(1, 0)]
|
||||
var f_score: Dictionary = {}
|
||||
|
||||
|
||||
func find_path_allow_neighbors(start_position: Vector2i, end_position: Vector2i, max_radius: int = -1) -> Array[Vector2i]:
|
||||
if world.is_walkable(end_position):
|
||||
# check the tile itself first, then check the four surrounding tiles
|
||||
var path: Array[Vector2i] = find_path(start_position, end_position, max_radius)
|
||||
if path.size() != 0:
|
||||
return path
|
||||
|
||||
else:
|
||||
for direction in walking_directions:
|
||||
var neighbor: Vector2i = end_position + direction
|
||||
var path: Array[Vector2i] = find_path(start_position, neighbor, max_radius)
|
||||
if path.size() != 0:
|
||||
return path
|
||||
|
||||
return []
|
||||
|
||||
|
||||
func find_path(start_position: Vector2i, end_position: Vector2i, max_radius: int = -1) -> Array[Vector2i]:
|
||||
var path: Array[Vector2i] = _find_path_internal(start_position, end_position, max_radius)
|
||||
if path.size() > 0:
|
||||
found_paths[end_position] = path
|
||||
else:
|
||||
failed_positions.append(end_position)
|
||||
return path
|
||||
|
||||
|
||||
func _find_path_internal(start_position: Vector2i, end_position: Vector2i, max_radius: int = -1) -> Array[Vector2i]:
|
||||
if max_radius > -1 and not is_within_radius(end_position, start_position, max_radius):
|
||||
return []
|
||||
if not world.is_walkable(end_position):
|
||||
return []
|
||||
|
||||
var check_nodes = PriorityQueue.new() # lowest f_score
|
||||
var came_from: Dictionary = {}
|
||||
var g_score: Dictionary = {}
|
||||
var walkable_cache: Dictionary = {}
|
||||
f_score = {}
|
||||
|
||||
var visited_nodes: Dictionary = {}
|
||||
|
||||
check_nodes.insert(start_position, 0)
|
||||
g_score[start_position] = 0
|
||||
f_score[start_position] = manhattan_distance(start_position, end_position) * 1.1 # Heuristic weighting
|
||||
|
||||
while not check_nodes.empty():
|
||||
var current: Vector2i = check_nodes.extract()
|
||||
|
||||
if current == end_position:
|
||||
var path: Array[Vector2i] = []
|
||||
while current in came_from:
|
||||
path.insert(0, current)
|
||||
current = came_from[current]
|
||||
path.insert(0, start_position)
|
||||
return path
|
||||
|
||||
visited_nodes[current] = true
|
||||
|
||||
for direction in walking_directions:
|
||||
var neighbor: Vector2i = current + direction
|
||||
|
||||
# Combine checks for early skipping
|
||||
if neighbor in visited_nodes or (max_radius > -1 and not is_within_radius(neighbor, start_position, max_radius)):
|
||||
continue
|
||||
|
||||
if not walkable_cache.has(neighbor):
|
||||
walkable_cache[neighbor] = world.is_walkable(neighbor)
|
||||
|
||||
if not walkable_cache[neighbor]:
|
||||
continue
|
||||
|
||||
var cost: int = world.tilemap_ground.get_custom_data(neighbor, "cost", 1)
|
||||
var tentative_g_score: int = g_score.get(current, INF) + cost
|
||||
|
||||
if tentative_g_score < g_score.get(neighbor, INF):
|
||||
came_from[neighbor] = current
|
||||
g_score[neighbor] = tentative_g_score
|
||||
f_score[neighbor] = tentative_g_score + manhattan_distance(neighbor, end_position) * 1.1 # Heuristic weighting
|
||||
if not check_nodes.contains(neighbor):
|
||||
check_nodes.insert(neighbor, f_score[neighbor])
|
||||
|
||||
return []
|
|
@ -6,6 +6,7 @@ var tilemap_non_interactive: TileMapLayerAccess = TileMapLayerAccess.new()
|
|||
var tilemap_interactive: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||
var tilemap_player: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||
var tilemap_temperature: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||
var tilemap_nav_vis: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||
#
|
||||
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
||||
|
||||
|
@ -21,6 +22,8 @@ func _ready() -> void:
|
|||
tilemap_player.tilemap = $PlayerLayer
|
||||
tilemap_temperature.sid = 2
|
||||
tilemap_temperature.tilemap = $TemperatureLayer
|
||||
tilemap_nav_vis.sid = 2
|
||||
tilemap_nav_vis.tilemap = $NavigationVisualization
|
||||
|
||||
tilemap_ground.setup()
|
||||
tilemap_non_interactive.setup()
|
||||
|
@ -28,6 +31,8 @@ func _ready() -> void:
|
|||
tilemap_player.setup()
|
||||
tilemap_temperature.setup()
|
||||
|
||||
print(tilemap_interactive.get_cell_atlas_coords(Vector2i(17, 6)))
|
||||
|
||||
|
||||
# example usage
|
||||
# tilemap_temperature.fill_area(Vector2i(0, 0), Vector2i(10, 10), tilemap_types.TEMPERATURE_COLD_1)
|
||||
|
@ -56,73 +61,3 @@ func is_walkable(position: Vector2i) -> bool:
|
|||
var interactive_walkable: bool = tilemap_interactive.get_custom_data(position, "walkable", true)
|
||||
|
||||
return ground_tile_walkable and non_interactive_walkable and interactive_walkable
|
||||
|
||||
|
||||
func is_within_radius(position: Vector2i, center: Vector2i, radius: int) -> bool:
|
||||
return manhattan_distance(position, center) <= radius
|
||||
|
||||
|
||||
func manhattan_distance(a: Vector2i, b: Vector2i) -> int:
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
||||
|
||||
var walking_directions: Array[Vector2i] = [Vector2i(0, -1), Vector2i(0, 1), Vector2i(-1, 0), Vector2i(1, 0)]
|
||||
var f_score: Dictionary = {}
|
||||
|
||||
|
||||
func find_path(start_position: Vector2i, end_position: Vector2i, max_radius: int = -1) -> Array[Vector2i]:
|
||||
if max_radius > -1 and not is_within_radius(end_position, start_position, max_radius):
|
||||
return []
|
||||
if not is_walkable(end_position):
|
||||
return []
|
||||
|
||||
var check_nodes = PriorityQueue.new() # lowest f_score
|
||||
var came_from: Dictionary = {}
|
||||
var g_score: Dictionary = {}
|
||||
var walkable_cache: Dictionary = {}
|
||||
f_score = {}
|
||||
|
||||
var visited_nodes: Dictionary = {}
|
||||
|
||||
check_nodes.insert(start_position, 0)
|
||||
g_score[start_position] = 0
|
||||
f_score[start_position] = manhattan_distance(start_position, end_position) * 1.1 # Heuristic weighting
|
||||
|
||||
while not check_nodes.empty():
|
||||
var current: Vector2i = check_nodes.extract()
|
||||
|
||||
if current == end_position:
|
||||
var path: Array[Vector2i] = []
|
||||
while current in came_from:
|
||||
path.insert(0, current)
|
||||
current = came_from[current]
|
||||
path.insert(0, start_position)
|
||||
return path
|
||||
|
||||
visited_nodes[current] = true
|
||||
|
||||
for direction in walking_directions:
|
||||
var neighbor: Vector2i = current + direction
|
||||
|
||||
# Combine checks for early skipping
|
||||
if neighbor in visited_nodes or (max_radius > -1 and not is_within_radius(neighbor, start_position, max_radius)):
|
||||
continue
|
||||
|
||||
if not walkable_cache.has(neighbor):
|
||||
walkable_cache[neighbor] = is_walkable(neighbor)
|
||||
|
||||
if not walkable_cache[neighbor]:
|
||||
continue
|
||||
|
||||
var cost: int = tilemap_ground.get_custom_data(neighbor, "cost", 1)
|
||||
var tentative_g_score: int = g_score.get(current, INF) + cost
|
||||
|
||||
if tentative_g_score < g_score.get(neighbor, INF):
|
||||
came_from[neighbor] = current
|
||||
g_score[neighbor] = tentative_g_score
|
||||
f_score[neighbor] = tentative_g_score + manhattan_distance(neighbor, end_position) * 1.1 # Heuristic weighting
|
||||
if not check_nodes.contains(neighbor):
|
||||
check_nodes.insert(neighbor, f_score[neighbor])
|
||||
|
||||
return []
|
||||
|
||||
|
|
Loading…
Reference in New Issue