forked from 2121578/gai-ca2
124 lines
4.6 KiB
GDScript
124 lines
4.6 KiB
GDScript
class_name World
|
|
extends Node2D
|
|
|
|
var tilemap_ground: TileMapLayerAccess = TileMapLayerAccess.new()
|
|
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_types: TileMapTileTypes = TileMapTileTypes.new()
|
|
|
|
|
|
func _ready() -> void:
|
|
tilemap_ground.sid = 0
|
|
tilemap_ground.tilemap = $GroundLayer
|
|
tilemap_non_interactive.sid = 1
|
|
tilemap_non_interactive.tilemap = $NonInteractiveObjectsLayer
|
|
tilemap_interactive.sid = 1
|
|
tilemap_interactive.tilemap = $InteractiveObjectsLayer
|
|
tilemap_player.sid = 3
|
|
tilemap_player.tilemap = $PlayerLayer
|
|
tilemap_temperature.sid = 2
|
|
tilemap_temperature.tilemap = $TemperatureLayer
|
|
|
|
tilemap_ground.setup()
|
|
tilemap_non_interactive.setup()
|
|
tilemap_interactive.setup()
|
|
tilemap_player.setup()
|
|
tilemap_temperature.setup()
|
|
|
|
|
|
# example usage
|
|
# tilemap_temperature.fill_area(Vector2i(0, 0), Vector2i(10, 10), tilemap_types.TEMPERATURE_COLD_1)
|
|
# tilemap_temperature.fill_area(Vector2i(4, 4), Vector2i(6, 6), tilemap_types.TEMPERATURE_NORMAL)
|
|
# print(tilemap_non_interactive.get_cells_by_custom_data("walkable", true))
|
|
# tilemap_ground.clear_cells()
|
|
# tilemap_ground.set_cell(Vector2i(0, 0), tilemap_types.GROUND_GRASS)
|
|
# print(tilemap_ground.local_to_cell(get_local_mouse_position()))
|
|
|
|
func local_mouse_position() -> Vector2:
|
|
return get_local_mouse_position()
|
|
|
|
|
|
func tilemap_mouse_position() -> Vector2i:
|
|
return tilemap_ground.local_to_cell(get_local_mouse_position())
|
|
|
|
|
|
func is_walkable(position: Vector2i) -> bool:
|
|
var ground_tile_walkable: bool = tilemap_ground.get_custom_data(position, "walkable", false)
|
|
var non_interactive_walkable: bool = tilemap_non_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
|
|
|
|
|
|
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 []
|
|
|