itrpg/scripts/isometric_map_renderer.gd

256 lines
10 KiB
GDScript

extends Node
class_name IsometricMapRenderer
var map_data = null
var isometric_map_layers = []
var highlighted_tiles = {} # Dictionary to store all currently highlighted tiles
var TILE_SIZE_ISOMETRIC_X = 32 # in px
var TILE_SIZE_ISOMETRIC_Y = 16 # in px
var unit_is_hovered = false
var unit_is_selected = false
var darkening_active = false
var original_modulates = {}
func darken_all_except_player(player_node):
darkening_active = true
# Store original modulate values
for layer in isometric_map_layers:
original_modulates[layer] = layer.modulate
# Darken the layer
layer.modulate = Color(0.5, 0.5, 0.5, 1.0)
# Keep player at normal brightness
player_node.modulate = Color(1.0, 1.0, 1.0, 1.0)
func reset_darkening():
darkening_active = false
# Restore original modulate values
for layer in isometric_map_layers:
if layer in original_modulates:
layer.modulate = original_modulates[layer]
func set_unit_hover_state(is_hovered):
unit_is_hovered = is_hovered
func set_unit_selected_state(is_selected):
unit_is_selected = is_selected
# Initialize with reference to a map data object and a tilemap to use as template
func _init(map_data_ref, tilemap_template):
map_data = map_data_ref
initialize_map_layers(tilemap_template)
# Initialize all the map layers for different heights
func initialize_map_layers(tilemap_template):
# Clear any existing layers
for layer in isometric_map_layers:
if is_instance_valid(layer):
layer.queue_free()
isometric_map_layers.clear()
# Create new layers for each height level
for z in map_data.GRID_SIZE_HEIGHT:
var new_layer = TileMapLayer.new()
new_layer.set_name("IsometricMapLayer_" + str(z))
new_layer.tile_set = tilemap_template.tile_set
new_layer.z_index = z # Set the z-index to match the layer's height
tilemap_template.get_parent().add_child(new_layer)
isometric_map_layers.append(new_layer)
# Draw all visible tiles on the map
func draw_visible_tiles():
# Clear all previously drawn tiles on each layer
for layer in isometric_map_layers:
layer.clear()
# Draw the map
for z in map_data.GRID_SIZE_HEIGHT:
for y in map_data.GRID_SIZE_LENGTH:
for x in map_data.GRID_SIZE_WIDTH:
var tile = map_data.get_tile(x, y, z)
if tile != null and tile["visibility"] and tile["atlas_base_position"] != null:
# Use the layer that corresponds to the tile's z-value
if z < isometric_map_layers.size():
isometric_map_layers[z].set_cell(
Vector2i(tile["x"], tile["y"]),
IsometricMapSystem.MAIN_SOURCE_ID,
tile["atlas_base_position"]
)
# Handle hovering over tiles
func handle_hover(mouse_position):
var hover_tile_position = isometric_map_layers[0].local_to_map(mouse_position)
var new_highlighted_tiles = {} # Will store tiles to highlight this frame
if unit_is_hovered:
# De-highlight all tiles
for tile_key in highlighted_tiles:
var tile_data = highlighted_tiles[tile_key]
var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z)
if tile != null and tile["visibility"] and not tile["unit"]:
if not tile["selected"]:
if tile["atlas_base_position"] != null:
isometric_map_layers[tile_data.z].set_cell(
Vector2i(tile["x"], tile["y"]),
IsometricMapSystem.MAIN_SOURCE_ID,
tile["atlas_base_position"]
)
tile["highlighted"] = false
highlighted_tiles = {}
return
# First find all tiles that should be highlighted
for z in map_data.GRID_SIZE_HEIGHT:
for x in map_data.GRID_SIZE_WIDTH:
for y in map_data.GRID_SIZE_LENGTH:
var tile = map_data.get_tile(x, y, z)
var tile_above = map_data.get_tile(x, y, z + 1)
if tile_above != null and tile_above["visibility"] and not tile_above["unit"]:
if tile["x"] == hover_tile_position.x and tile["y"] == hover_tile_position.y:
# Store this tile for highlighting
var tile_key = str(x) + "_" + str(y) + "_" + str(z)
new_highlighted_tiles[tile_key] = {
"x": x,
"y": y,
"z": z + 1
}
elif tile != null and tile["visibility"] and not tile["unit"]:
if tile["x"] == hover_tile_position.x and tile["y"] == hover_tile_position.y:
# Store this tile for highlighting
var tile_key = str(x) + "_" + str(y) + "_" + str(z)
new_highlighted_tiles[tile_key] = {
"x": x,
"y": y,
"z": z
}
# Highlight new tiles
for tile_key in new_highlighted_tiles:
var tile_data = new_highlighted_tiles[tile_key]
var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z)
if tile == null:
continue
if not tile["selected"] and not tile["unit"]:
# Only set cell if we have a valid highlight position
if tile["atlas_highlight_position"] != null:
isometric_map_layers[tile_data.z].set_cell(
Vector2i(tile["x"], tile["y"]),
IsometricMapSystem.MAIN_SOURCE_ID,
tile["atlas_highlight_position"]
)
else:
isometric_map_layers[tile_data.z].set_cell(
Vector2i(tile["x"], tile["y"]),
1,
Vector2i(3,1) #
)
tile["highlighted"] = true
# De-highlight tiles that are no longer under the cursor
for tile_key in highlighted_tiles:
if not (tile_key in new_highlighted_tiles):
var tile_data = highlighted_tiles[tile_key]
var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z)
if tile != null and tile["visibility"] and not tile["unit"]:
if not tile["selected"]:
# Only set cell if we have a valid base position
if tile["atlas_base_position"] != null:
isometric_map_layers[tile_data.z].set_cell(
Vector2i(tile["x"], tile["y"]),
IsometricMapSystem.MAIN_SOURCE_ID,
tile["atlas_base_position"] # Original appearance
)
else:
isometric_map_layers[tile_data.z].set_cell(
Vector2i(tile["x"], tile["y"]),
1,
Vector2i(0,1) #
)
tile["highlighted"] = false
# Update the highlighted tiles list
highlighted_tiles = new_highlighted_tiles
# Handle tile selection logic
func handle_tile_selection():
if unit_is_selected:
reset_darkening()
unit_is_selected = false
for z in map_data.GRID_SIZE_HEIGHT:
for x in map_data.GRID_SIZE_WIDTH:
for y in map_data.GRID_SIZE_LENGTH:
var tile = map_data.get_tile(x, y, z)
if tile == null or not tile["visibility"]:
continue
# Get valid coordinates
var tile_x = tile["x"]
var tile_y = tile["y"]
if tile["selected"] and tile["highlighted"]:
print("direct de selected: ", Vector2i(tile_x, tile_y))
isometric_map_layers[z].set_cell(
Vector2i(tile_x, tile_y),
IsometricMapSystem.MAIN_SOURCE_ID,
IsometricMapSystem.SELECTED_BLUE_ISOMETRICTILE_ATLAS_POSITION
)
tile["selected"] = false
elif tile["selected"] and not tile["highlighted"]:
print("old de selected: ", Vector2i(tile_x, tile_y))
# If there's a base position, restore it, otherwise use a default
if tile["atlas_base_position"] != null:
isometric_map_layers[z].set_cell(
Vector2i(tile_x, tile_y),
IsometricMapSystem.MAIN_SOURCE_ID,
tile["atlas_base_position"]
)
else:
isometric_map_layers[z].set_cell(
Vector2i(tile_x, tile_y),
IsometricMapSystem.MAIN_SOURCE_ID,
IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION
)
tile["selected"] = false
elif not tile["selected"] and tile["highlighted"]:
print("new selected: ", Vector2i(tile_x, tile_y))
isometric_map_layers[z].set_cell(
Vector2i(tile_x, tile_y),
IsometricMapSystem.MAIN_SOURCE_ID,
IsometricMapSystem.SELECTED_WHITE_ISOMETRICTILE_ATLAS_POSITION
)
tile["selected"] = true
# Position a unit on the map visually
func position_unit(unit, tile_x, tile_y, tile_z):
var world_pos = IsometricMapSystem.iso_to_world(
tile_x,
tile_y,
tile_z,
TILE_SIZE_ISOMETRIC_X,
TILE_SIZE_ISOMETRIC_Y
)
unit.z_index = tile_z
# Assuming unit has a set_unit_position method to handle actual positioning
if unit.has_method("set_unit_position"):
unit.set_unit_position(world_pos.x, world_pos.y, tile_z)