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
|
2:0/0 = 0
|
||||||
0:1/0 = 0
|
0:1/0 = 0
|
||||||
0:2/0 = 0
|
0:2/0 = 0
|
||||||
0:3/0 = 0
|
0:4/size_in_atlas = Vector2i(2, 1)
|
||||||
1:3/0 = 0
|
|
||||||
0:4/0 = 0
|
0:4/0 = 0
|
||||||
0:5/0 = 0
|
0:5/0 = 0
|
||||||
0:6/0 = 0
|
|
||||||
0:7/0 = 0
|
0:7/0 = 0
|
||||||
3:0/0 = 0
|
3:0/0 = 0
|
||||||
1:1/0 = 0
|
1:1/0 = 0
|
||||||
|
@ -44,6 +42,19 @@ texture = ExtResource("2_15xge")
|
||||||
2:2/0 = 0
|
2:2/0 = 0
|
||||||
3:2/0 = 0
|
3:2/0 = 0
|
||||||
4: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/size_in_atlas = Vector2i(1, 2)
|
||||||
4:0/0 = 0
|
4:0/0 = 0
|
||||||
|
|
||||||
|
@ -53,6 +64,9 @@ texture = ExtResource("3_xap0v")
|
||||||
0:0/0/custom_data_1 = 10
|
0:0/0/custom_data_1 = 10
|
||||||
1:0/0 = 0
|
1:0/0 = 0
|
||||||
1:0/0/custom_data_1 = 20
|
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"]
|
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_i41cv"]
|
||||||
texture = ExtResource("4_f38wc")
|
texture = ExtResource("4_f38wc")
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -104,5 +104,6 @@ key_6={
|
||||||
|
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
|
textures/canvas_textures/default_texture_filter=0
|
||||||
renderer/rendering_method="gl_compatibility"
|
renderer/rendering_method="gl_compatibility"
|
||||||
renderer/rendering_method.mobile="gl_compatibility"
|
renderer/rendering_method.mobile="gl_compatibility"
|
||||||
|
|
|
@ -5,9 +5,11 @@ extends Node
|
||||||
@onready var player: PlayerManager = $PlayerManager
|
@onready var player: PlayerManager = $PlayerManager
|
||||||
@onready var camera: Camera2D = $Camera2D
|
@onready var camera: Camera2D = $Camera2D
|
||||||
@onready var game_ticker: Timer = $GameTick
|
@onready var game_ticker: Timer = $GameTick
|
||||||
|
var tilemap_navigation: TilemapNavigation = TilemapNavigation.new()
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
tilemap_navigation.world = world
|
||||||
|
tilemap_navigation.player = player
|
||||||
player.game_manager = self
|
player.game_manager = self
|
||||||
game_ticker.start()
|
game_ticker.start()
|
||||||
|
|
||||||
|
@ -30,6 +32,8 @@ func player_health_depleted():
|
||||||
|
|
||||||
func _on_game_tick_timeout() -> void:
|
func _on_game_tick_timeout() -> void:
|
||||||
var timer_on_game_tick_timeout: PerformanceTimer = PerformanceTimer.new()
|
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()
|
player.game_tick()
|
||||||
|
tilemap_navigation.game_tick_end()
|
||||||
timer_on_game_tick_timeout.stop()
|
timer_on_game_tick_timeout.stop()
|
||||||
|
|
|
@ -10,8 +10,13 @@ extends Node
|
||||||
|
|
||||||
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
||||||
#
|
#
|
||||||
var game_manager: GameManager = null
|
var game_manager: GameManager = null
|
||||||
var board_position: Vector2i = Vector2i(8, 10)
|
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
|
@onready var behavior_tree: BehaviorTree = $BehaviorTree
|
||||||
|
|
||||||
|
@ -20,7 +25,10 @@ var food: int = 0
|
||||||
var temperature_timer: int = 0
|
var temperature_timer: int = 0
|
||||||
var health: 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:
|
func _ready() -> void:
|
||||||
|
@ -38,19 +46,19 @@ func _process(delta: float) -> void:
|
||||||
if Input.is_action_just_pressed("key_5"):
|
if Input.is_action_just_pressed("key_5"):
|
||||||
pick_up_item(Vector2i(5, 8))
|
pick_up_item(Vector2i(5, 8))
|
||||||
pick_up_item(Vector2i(9, 9))
|
pick_up_item(Vector2i(9, 9))
|
||||||
update_board()
|
|
||||||
if Input.is_action_just_pressed("key_4"):
|
if Input.is_action_just_pressed("key_4"):
|
||||||
var nearest: Vector2i = find_nearest_object([game_manager.world.tilemap_types.OBJECT_I_TREE_1])
|
var nearest: Vector2i = find_nearest_object([game_manager.world.tilemap_types.OBJECT_I_TREE_1])
|
||||||
# nearest.x = nearest.x - 1
|
# nearest.x = nearest.x - 1
|
||||||
walk_towards(nearest)
|
walk_towards(nearest)
|
||||||
update_board()
|
|
||||||
|
|
||||||
|
|
||||||
# SECTION: board access/mangement
|
# SECTION: board access/mangement
|
||||||
|
|
||||||
func update_board() -> void:
|
func update_board() -> void:
|
||||||
game_manager.world.tilemap_player.clear_cells()
|
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:
|
if inventory_slot and inventory_slot != tilemap_types.EMPTY:
|
||||||
inventory_label.text = str(inventory_slot)
|
inventory_label.text = str(inventory_slot)
|
||||||
else:
|
else:
|
||||||
|
@ -101,7 +109,7 @@ func pick_up_item(tilemap_pos: Vector2i) -> void:
|
||||||
# SECTION: player movement
|
# SECTION: player movement
|
||||||
|
|
||||||
func walk_towards(position: Vector2i) -> void:
|
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)
|
walk_along(path)
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,6 +118,7 @@ func walk_along(path: Array[Vector2i]) -> void:
|
||||||
var next_position: Vector2i = path[1]
|
var next_position: Vector2i = path[1]
|
||||||
var direction: Vector2i = find_direction(board_position, next_position)
|
var direction: Vector2i = find_direction(board_position, next_position)
|
||||||
move_player(direction)
|
move_player(direction)
|
||||||
|
game_manager.tilemap_navigation.chosen_path = path
|
||||||
else:
|
else:
|
||||||
push_warning("walk_along path is empty")
|
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
|
var shortest_distance: float = 99999999
|
||||||
|
|
||||||
for position in object_positions:
|
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:
|
if closest_object == tilemap_types.NO_TILE_FOUND or distance < shortest_distance:
|
||||||
closest_object = position
|
closest_object = position
|
||||||
shortest_distance = distance
|
shortest_distance = distance
|
||||||
|
@ -178,7 +187,7 @@ func tick_handle_food():
|
||||||
func game_tick() -> void:
|
func game_tick() -> void:
|
||||||
behavior_tree.game_tick()
|
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:
|
if len(player_positon_array) > 0:
|
||||||
var player_positon: Vector2i = 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
|
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["world"] = game_manager.world
|
||||||
blackboard["player"] = game_manager.player
|
blackboard["player"] = game_manager.player
|
||||||
blackboard["camera"] = game_manager.camera
|
blackboard["camera"] = game_manager.camera
|
||||||
|
blackboard["navigation"] = game_manager.tilemap_navigation
|
||||||
|
|
||||||
|
|
||||||
func game_tick() -> void:
|
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)
|
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:
|
func set_cell(position: Vector2i, atlas_coords: Vector2i) -> void:
|
||||||
tilemap.set_cell(position, sid, atlas_coords)
|
tilemap.set_cell(position, sid, atlas_coords)
|
||||||
|
|
||||||
|
|
|
@ -13,40 +13,58 @@ const GROUND_DOCK: Vector2i = Vector2i(3, 0)
|
||||||
#
|
#
|
||||||
# objects, sid = 1
|
# objects, sid = 1
|
||||||
# NI = not interactive
|
# NI = not interactive
|
||||||
const OBJECT_NI_RANDOM_1: Vector2i = Vector2i(0, 0) # testing only, to be removed
|
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_RANDOM_2: Vector2i = Vector2i(1, 0) # testing only, to be removed
|
||||||
const OBJECT_NI_ROCK_1: Vector2i = Vector2i(2, 0)
|
const OBJECT_NI_ROCK_1: Vector2i = Vector2i(2, 0)
|
||||||
const OBJECT_NI_FIREPIT_ON: Vector2i = Vector2i(7, 1)
|
const OBJECT_NI_FIREPIT_ON: Vector2i = Vector2i(7, 1)
|
||||||
const OBJECT_NI_TREE_CUT: Vector2i = Vector2i(2, 0)
|
const OBJECT_NI_TREE_CUT: Vector2i = Vector2i(2, 0)
|
||||||
const OBJECT_NI_BOAT_NO_ENIGNE: Vector2i= Vector2i(4, 4)
|
const OBJECT_NI_BOAT_NO_ENIGNE: Vector2i = Vector2i(4, 4)
|
||||||
|
#
|
||||||
|
|
||||||
# I = interactive
|
# I = interactive
|
||||||
const OBJECT_I_BOAT_ENGINE: Vector2i = Vector2i(0, 1)
|
const OBJECT_I_BOAT_ENGINE: Vector2i = Vector2i(0, 1)
|
||||||
const OBJECT_I_FUEL: Vector2i = Vector2i(1, 1)
|
const OBJECT_I_FUEL: Vector2i = Vector2i(1, 1)
|
||||||
const OBJECT_I_ANCHOR: Vector2i = Vector2i(2, 1)
|
const OBJECT_I_ANCHOR: Vector2i = Vector2i(2, 1)
|
||||||
const OBJECT_I_EMPTY_BUSH: Vector2i = Vector2i(3, 0)
|
const OBJECT_I_EMPTY_BUSH: Vector2i = Vector2i(3, 0)
|
||||||
const OBJECT_I_FILLED_BUSH: Vector2i = Vector2i(3, 1)
|
const OBJECT_I_FILLED_BUSH: Vector2i = Vector2i(3, 1)
|
||||||
const OBJECT_I_BERRY: Vector2i = Vector2i(0, 5)
|
const OBJECT_I_BERRY: Vector2i = Vector2i(0, 5)
|
||||||
const OBJECT_I_STICK: Vector2i = Vector2i(1, 5)
|
const OBJECT_I_STICK: Vector2i = Vector2i(1, 5)
|
||||||
const OBJECT_I_TREE_1: Vector2i = Vector2i(4, 0)
|
const OBJECT_I_TREE_1: Vector2i = Vector2i(4, 0)
|
||||||
const OBJECT_I_CHEST: Vector2i = Vector2i(0, 2)
|
const OBJECT_I_CHEST: Vector2i = Vector2i(0, 2)
|
||||||
const OBJECT_I_GEARS: Vector2i = Vector2i(1, 2)
|
const OBJECT_I_GEARS: Vector2i = Vector2i(1, 2)
|
||||||
const OBJECT_I_MEDIKIT: Vector2i = Vector2i(2, 2)
|
const OBJECT_I_MEDIKIT: Vector2i = Vector2i(2, 2)
|
||||||
const OBJECT_I_PADDLE: Vector2i = Vector2i(3, 2)
|
const OBJECT_I_PADDLE: Vector2i = Vector2i(3, 2)
|
||||||
const OBJECT_I_GAS_STOVE: Vector2i = Vector2i(4, 2)
|
const OBJECT_I_GAS_STOVE: Vector2i = Vector2i(4, 2)
|
||||||
const OBJECT_I_TENT: Vector2i = Vector2i(6, 2)
|
const OBJECT_I_TENT: Vector2i = Vector2i(6, 2)
|
||||||
|
const OBJECT_I_BOAT_WITH_ENGINE: Vector2i = Vector2i(6, 4)
|
||||||
const OBJECT_I_BOAT_WITH_ENGINE: Vector2i = Vector2i(6,4)
|
const OBJECT_I_FIREPIT_OFF: Vector2i = Vector2i(6, 1)
|
||||||
const OBJECT_I_FIREPIT_OFF: Vector2i = Vector2i(6, 1)
|
|
||||||
|
|
||||||
# collections
|
# collections
|
||||||
const OBJECT_COLLECTION_BERRY_SOURCE: Array[Vector2i] = [OBJECT_I_FILLED_BUSH, OBJECT_I_BERRY]
|
const OBJECT_COLLECTION_BERRY_SOURCE: Array[Vector2i] = [OBJECT_I_FILLED_BUSH, OBJECT_I_BERRY]
|
||||||
#
|
#
|
||||||
# temperature, sid = 2
|
# 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_1: Vector2i = Vector2i(0, 0)
|
||||||
const TEMPERATURE_COLD_2: Vector2i = Vector2i(1, 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
|
# 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_interactive: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||||
var tilemap_player: TileMapLayerAccess = TileMapLayerAccess.new()
|
var tilemap_player: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||||
var tilemap_temperature: TileMapLayerAccess = TileMapLayerAccess.new()
|
var tilemap_temperature: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||||
|
var tilemap_nav_vis: TileMapLayerAccess = TileMapLayerAccess.new()
|
||||||
#
|
#
|
||||||
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
||||||
|
|
||||||
|
@ -21,6 +22,8 @@ func _ready() -> void:
|
||||||
tilemap_player.tilemap = $PlayerLayer
|
tilemap_player.tilemap = $PlayerLayer
|
||||||
tilemap_temperature.sid = 2
|
tilemap_temperature.sid = 2
|
||||||
tilemap_temperature.tilemap = $TemperatureLayer
|
tilemap_temperature.tilemap = $TemperatureLayer
|
||||||
|
tilemap_nav_vis.sid = 2
|
||||||
|
tilemap_nav_vis.tilemap = $NavigationVisualization
|
||||||
|
|
||||||
tilemap_ground.setup()
|
tilemap_ground.setup()
|
||||||
tilemap_non_interactive.setup()
|
tilemap_non_interactive.setup()
|
||||||
|
@ -28,6 +31,8 @@ func _ready() -> void:
|
||||||
tilemap_player.setup()
|
tilemap_player.setup()
|
||||||
tilemap_temperature.setup()
|
tilemap_temperature.setup()
|
||||||
|
|
||||||
|
print(tilemap_interactive.get_cell_atlas_coords(Vector2i(17, 6)))
|
||||||
|
|
||||||
|
|
||||||
# example usage
|
# example usage
|
||||||
# tilemap_temperature.fill_area(Vector2i(0, 0), Vector2i(10, 10), tilemap_types.TEMPERATURE_COLD_1)
|
# 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)
|
var interactive_walkable: bool = tilemap_interactive.get_custom_data(position, "walkable", true)
|
||||||
|
|
||||||
return ground_tile_walkable and non_interactive_walkable and interactive_walkable
|
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