extends Resource class_name IsometricMapData var GRID_SIZE_WIDTH = 50 # play area size x var GRID_SIZE_LENGTH = 30 # play area size y var GRID_SIZE_HEIGHT = 30 # play area size z var OFFSET = 0 var MAX_ARRAY_SIZE = 0 # The actual map data array var map_data = [] func _init(width = 50, length = 30, height = 30, offset = 0): GRID_SIZE_WIDTH = width GRID_SIZE_LENGTH = length GRID_SIZE_HEIGHT = height OFFSET = offset _set_max_array_size() initialize_map_data() func _set_max_array_size(): MAX_ARRAY_SIZE = 0 if MAX_ARRAY_SIZE < GRID_SIZE_WIDTH: MAX_ARRAY_SIZE = GRID_SIZE_WIDTH if MAX_ARRAY_SIZE < GRID_SIZE_LENGTH: MAX_ARRAY_SIZE = GRID_SIZE_LENGTH if MAX_ARRAY_SIZE < GRID_SIZE_HEIGHT: MAX_ARRAY_SIZE = GRID_SIZE_HEIGHT func is_array_tile_valid(array_pos: Vector3i): if 0 < array_pos.x and array_pos.x < MAX_ARRAY_SIZE and 0 < array_pos.y and array_pos.y < MAX_ARRAY_SIZE and 0 < array_pos.z and array_pos.z < MAX_ARRAY_SIZE: return true return false func get_array_neighbors(array_pos: Vector3i, movement_range: int) -> Array: var neighbors = [] var visited = {array_pos: true} # Using a dictionary for faster lookups var directions = [ Vector3i(0, 0, 1), # up Vector3i(0, 0, -1), # down Vector3i(0, 1, 0), # left Vector3i(0, -1, 0), # right Vector3i(1, 0, 0), # forward Vector3i(-1, 0, 0), # backward ] # Use a breadth-first search approach var current_level = [array_pos] for distance in range(1, movement_range + 1): var next_level = [] for current_pos in current_level: for dir in directions: var neighbor_pos = current_pos + dir # Check if we've already processed this position or if it's invalid if neighbor_pos in visited or not is_array_tile_valid(neighbor_pos): continue # Mark as visited and add to results visited[neighbor_pos] = true neighbors.append(neighbor_pos) next_level.append(neighbor_pos) # Move to the next level of neighbors current_level = next_level # If no more positions to check at this level, we can stop early if current_level.is_empty(): break return neighbors func initialize_map_data(): # Initialize empty map structure map_data = [] for x in MAX_ARRAY_SIZE: var y_array = [] for y in MAX_ARRAY_SIZE: var z_array = [] for z in MAX_ARRAY_SIZE: z_array.append(null) y_array.append(z_array) map_data.append(y_array) # Get a tile at specific coordinates, return null if out of bounds func get_tile(x, y, z): if x < 0 or x >= MAX_ARRAY_SIZE or y < 0 or y >= MAX_ARRAY_SIZE or z < 0 or z >= MAX_ARRAY_SIZE: return null return map_data[x][y][z] # Set a tile at specific coordinates func set_tile(x, y, z, tile_data): if x < 0 or x >= MAX_ARRAY_SIZE or y < 0 or y >= MAX_ARRAY_SIZE or z < 0 or z >= MAX_ARRAY_SIZE: return map_data[x][y][z] = tile_data # Generate the isometric coordinates for a tile func generate_iso_coords(x, y, z): var coord_x = x + (-1 * z) + OFFSET var coord_y = y + (-1 * z) - OFFSET return Vector2i(coord_x, coord_y) # Create a map with default configuration func create_default_map(): # First initialize all tiles with null values for z in GRID_SIZE_HEIGHT: for y in GRID_SIZE_LENGTH: for x in GRID_SIZE_WIDTH: var iso_coords = generate_iso_coords(x, y, z) var tile_data = IsometricMapSystem.create_tile_data( iso_coords.x, iso_coords.y, z, # Give all tiles valid default atlas positions to avoid null errors IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION, IsometricMapSystem.WHITE_ISOMETRICTILE_ATLAS_POSITION ) # By default, tiles are not visible tile_data["visibility"] = false map_data[x][y][z] = tile_data # Set ground floor visible with blue tiles for y in GRID_SIZE_LENGTH: for x in GRID_SIZE_WIDTH: var tile = map_data[x][y][0] tile["atlas_base_position"] = IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION tile["atlas_highlight_position"] = IsometricMapSystem.WHITE_ISOMETRICTILE_ATLAS_POSITION tile["visibility"] = true # Add a vertical column of red tiles for demonstration # Make sure coords are within bounds if 5 < GRID_SIZE_WIDTH and 5 < GRID_SIZE_LENGTH: for i in range(1, min(10, GRID_SIZE_HEIGHT)): var tile = map_data[5][5][i] if tile != null: tile["atlas_base_position"] = IsometricMapSystem.RED_ISOMETRICTILE_ATLAS_POSITION tile["atlas_highlight_position"] = IsometricMapSystem.WHITE_ISOMETRICTILE_ATLAS_POSITION tile["visibility"] = true IsometricMapSystem.debug_print("Created red tile at 5,5," + str(i)) #var tile = map_data[10][10][1] #if tile != null: # tile["atlas_base_position"] = IsometricMapSystem.BLACK_ISOMETRICTILE_ATLAS_POSITION # tile["atlas_highlight_position"] = IsometricMapSystem.GREEN_ISOMETRICTILE_ATLAS_POSITION # tile["visibility"] = true # IsometricMapSystem.debug_print("Created black tile at 10,10," + str(1)) # Rotate map around X axis func rotate_around_x_axis(rotation_steps = 1): rotation_steps = rotation_steps % 4 if rotation_steps == 0: return var temp_map = [] # Initialize temp_map with same structure for x in MAX_ARRAY_SIZE: var y_array = [] for y in MAX_ARRAY_SIZE: var z_array = [] for z in MAX_ARRAY_SIZE: z_array.append(null) y_array.append(z_array) temp_map.append(y_array) # Create a new map with adjusted dimensions var new_height = int(GRID_SIZE_LENGTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_HEIGHT) var new_length = int(GRID_SIZE_HEIGHT) if rotation_steps % 2 == 1 else int(GRID_SIZE_LENGTH) # Store the original dimensions var original_height = GRID_SIZE_HEIGHT var original_length = GRID_SIZE_LENGTH # Temporarily adjust grid dimensions for coordinate calculation GRID_SIZE_HEIGHT = new_height GRID_SIZE_LENGTH = new_length for x in GRID_SIZE_WIDTH: for y in original_length: for z in original_height: if map_data[x][y][z] == null: continue var new_y = 0 var new_z = 0 match rotation_steps: 1: # 90 degrees new_y = z new_z = original_length - 1 - y 2: # 180 degrees new_y = original_length - 1 - y new_z = original_height - 1 - z 3: # 270 degrees new_y = original_height - 1 - z new_z = y if new_y >= 0 and new_y < new_length and new_z >= 0 and new_z < new_height: temp_map[x][new_y][new_z] = map_data[x][y][z].duplicate() var new_coord_x = x + (-1 * new_z) + OFFSET var new_coord_y = new_y + (-1 * new_z) - OFFSET temp_map[x][new_y][new_z]["x"] = new_coord_x temp_map[x][new_y][new_z]["y"] = new_coord_y temp_map[x][new_y][new_z]["z"] = new_z temp_map[x][new_y][new_z]["highlighted"] = false # Update the grid dimensions GRID_SIZE_HEIGHT = new_height GRID_SIZE_LENGTH = new_length map_data = temp_map # Rotate map around Y axis func rotate_around_y_axis(rotation_steps = 1): rotation_steps = rotation_steps % 4 if rotation_steps == 0: return var temp_map = [] # Initialize temp_map with same structure for x in MAX_ARRAY_SIZE: var y_array = [] for y in MAX_ARRAY_SIZE: var z_array = [] for z in MAX_ARRAY_SIZE: z_array.append(null) y_array.append(z_array) temp_map.append(y_array) # Create a new map with adjusted dimensions var new_width = int(GRID_SIZE_HEIGHT) if rotation_steps % 2 == 1 else int(GRID_SIZE_WIDTH) var new_height = int(GRID_SIZE_WIDTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_HEIGHT) # Store the original dimensions var original_width = GRID_SIZE_WIDTH var original_height = GRID_SIZE_HEIGHT # Temporarily adjust grid dimensions for coordinate calculation GRID_SIZE_WIDTH = new_width GRID_SIZE_HEIGHT = new_height for x in original_width: for y in GRID_SIZE_LENGTH: for z in original_height: if map_data[x][y][z] == null: continue var new_x = 0 var new_z = 0 match rotation_steps: 1: # 90 degrees clockwise around Y axis new_x = original_height - 1 - z new_z = x 2: # 180 degrees new_x = original_width - 1 - x new_z = original_height - 1 - z 3: # 270 degrees new_x = z new_z = original_width - 1 - x if new_x >= 0 and new_x < new_width and new_z >= 0 and new_z < new_height: temp_map[new_x][y][new_z] = map_data[x][y][z].duplicate() var new_coord_x = new_x + (-1 * new_z) + OFFSET var new_coord_y = y + (-1 * new_z) - OFFSET temp_map[new_x][y][new_z]["x"] = new_coord_x temp_map[new_x][y][new_z]["y"] = new_coord_y temp_map[new_x][y][new_z]["z"] = new_z temp_map[new_x][y][new_z]["highlighted"] = false # Update the grid dimensions GRID_SIZE_WIDTH = new_width GRID_SIZE_HEIGHT = new_height map_data = temp_map # Rotate map around Z axis func rotate_around_z_axis(rotation_steps = 1): rotation_steps = rotation_steps % 4 if rotation_steps == 0: return var temp_map = [] # Initialize temp_map with same structure for x in MAX_ARRAY_SIZE: var y_array = [] for y in MAX_ARRAY_SIZE: var z_array = [] for z in MAX_ARRAY_SIZE: z_array.append(null) y_array.append(z_array) temp_map.append(y_array) # Create a new map with adjusted dimensions based on rotation var new_width = int(GRID_SIZE_LENGTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_WIDTH) var new_length = int(GRID_SIZE_WIDTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_LENGTH) # Store the original dimensions var original_width = GRID_SIZE_WIDTH var original_length = GRID_SIZE_LENGTH # Temporarily adjust grid dimensions for coordinate calculation GRID_SIZE_WIDTH = new_width GRID_SIZE_LENGTH = new_length for x in original_width: for y in original_length: for z in GRID_SIZE_HEIGHT: if map_data[x][y][z] == null: continue var new_x = 0 var new_y = 0 match rotation_steps: 1: # 90 degrees new_x = y new_y = original_width - 1 - x 2: # 180 degrees new_x = original_width - 1 - x new_y = original_length - 1 - y 3: # 270 degrees new_x = original_length - 1 - y new_y = x if new_x >= 0 and new_x < new_width and new_y >= 0 and new_y < new_length: temp_map[new_x][new_y][z] = map_data[x][y][z].duplicate() var new_coord_x = new_x + (-1 * z) + OFFSET var new_coord_y = new_y + (-1 * z) - OFFSET temp_map[new_x][new_y][z]["x"] = new_coord_x temp_map[new_x][new_y][z]["y"] = new_coord_y temp_map[new_x][new_y][z]["z"] = z temp_map[new_x][new_y][z]["highlighted"] = false # Update the grid dimensions GRID_SIZE_WIDTH = new_width GRID_SIZE_LENGTH = new_length map_data = temp_map # Find a tile containing a specific unit func find_unit_tile(unit_type = null): for z in GRID_SIZE_HEIGHT: for x in GRID_SIZE_WIDTH: for y in GRID_SIZE_LENGTH: var tile = map_data[x][y][z] if tile and tile["unit"] != null: if unit_type == null or tile["unit_type"] == unit_type: return {"tile": tile, "x": x, "y": y, "z": z} return null # Move a unit from one position to another func move_unit(from_x, from_y, from_z, to_x, to_y, to_z): # Get the source and destination tiles safely var from_tile = get_tile(from_x, from_y, from_z) var to_tile = get_tile(to_x, to_y, to_z) # Debug information print("Moving unit from [", from_x, ",", from_y, ",", from_z, "] to [", to_x, ",", to_y, ",", to_z, "]") # Validate that both tiles exist and source has a unit if from_tile == null: print("Source tile doesn't exist") return false if to_tile == null: print("Destination tile doesn't exist") return false if from_tile["unit"] == null: print("No unit at source tile") return false # Valid move - transfer the unit to_tile["unit"] = from_tile["unit"] to_tile["unit_type"] = from_tile["unit_type"] to_tile["visibility"] = true # Clear the source tile from_tile["unit"] = null from_tile["unit_type"] = null # Keep source tile visible from_tile["visibility"] = true print("Unit moved successfully") return true