import config from '@/application/config' import type { MapObject, Map as MapT, TextureData, Tile as TileT, UUID } from '@/application/types' import { unduplicateArray } from '@/application/utilities' import { loadTexture } from '@/services/textureService' import { MapStorage, TileStorage } from '@/storage/storages' import Tilemap = Phaser.Tilemaps.Tilemap import TilemapLayer = Phaser.Tilemaps.TilemapLayer import Tileset = Phaser.Tilemaps.Tileset import Tile = Phaser.Tilemaps.Tile export function getTile(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): Tile | null { return layer.getTileAtWorldXY(positionX, positionY) } export function tileToWorldXY(layer: TilemapLayer | Tilemap, positionX: number, positionY: number) { const worldPoint = layer.tileToWorldXY(positionX, positionY) if (!worldPoint) return { worldPositionX: 0, worldPositionY: 0 } const worldPositionX = worldPoint.x + config.tile_size.height const worldPositionY = worldPoint.y return { worldPositionX, worldPositionY } } export function tileToWorldX(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): number { const worldPoint = layer.tileToWorldXY(positionX, positionY) if (!worldPoint) return 0 return worldPoint.x + config.tile_size.width / 2 } export function tileToWorldY(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): number { const worldPoint = layer.tileToWorldXY(positionX, positionY) if (!worldPoint) return 0 return worldPoint.y + config.tile_size.height * 1.5 } /** * Can also be used to replace tiles */ export function placeTile(map: Tilemap, layer: TilemapLayer, positionX: number, positionY: number, tileName: string) { let tileImg = map.getTileset(tileName) as Tileset if (!tileImg) { tileImg = map.getTileset('blank_tile') as Tileset } layer.putTileAt(tileImg.firstgid, positionX, positionY) } export function placeTiles(map: Tilemap, layer: TilemapLayer, tiles: string[][]) { if (!map || !layer || !tiles) return tiles.forEach((row: string[], y: number) => { row.forEach((tile: string, x: number) => { placeTile(map, layer, x, y, tile) }) }) } export function createTileArray(width: number, height: number, tile: string = 'blank_tile') { return Array.from({ length: height }, () => Array.from({ length: width }, () => tile)) } export const calculateIsometricDepth = ( positionX: number, positionY: number, width: number = 0, height: number = 0, originX: number = 0, originY: number = 0 ) => { // Base depth calculation using isometric coordinates // We multiply by a large number to ensure enough space between layers const baseDepth = (positionY + positionX) * 1000 // Calculate the object's bottom-most point considering its dimensions and origin const bottomY = positionY + height - (height * originY) const rightX = positionX + width - (width * originX) // Add position-based offset to ensure objects further down and right appear on top const positionOffset = (bottomY + rightX) * 10 // For regular objects, consider their size // Larger objects should generally appear behind smaller ones at the same position const sizeOffset = (width + height) * 5 // Final depth combines all factors return baseDepth + positionOffset - sizeOffset } async function loadTileTextures(tiles: TileT[], scene: Phaser.Scene) { // Load each tile into the scene for (let tile of tiles) { if (!tile?.id || !tile?.updatedAt) continue const textureData = { key: tile.id, data: '/textures/tiles/' + tile.id + '.png', group: 'tiles', updatedAt: tile.updatedAt } as TextureData await loadTexture(scene, textureData) } } export async function loadTileTexturesFromMapTileArray(map_id: string, scene: Phaser.Scene) { const mapStorage = new MapStorage() const tileStorage = new TileStorage() const map = await mapStorage.getById(map_id) if (!map) return const tileArray = unduplicateArray(map.tiles) const tiles = await tileStorage.getByIds(tileArray) if (!tiles) return await loadTileTextures(tiles, scene) } export async function loadAllTileTextures(scene: Phaser.Scene) { const tileStorage = new TileStorage() const tiles = await tileStorage.getAll() if (!tiles) return await loadTileTextures(tiles, scene) } export async function loadMapObjectTextures(mapObjects: MapObject[], scene: Phaser.Scene) { for (const mapObject of mapObjects) { const textureData = { key: mapObject.id, data: '/textures/map_objects/' + mapObject.id + '.png', group: 'map_objects', updatedAt: mapObject.updatedAt, frameWidth: mapObject.frameWidth, frameHeight: mapObject.frameHeight } as TextureData await loadTexture(scene, textureData) } } export function createTileMap(scene: Phaser.Scene, map: MapT) { const mapConfig = new Phaser.Tilemaps.MapData({ width: map.width, height: map.height, tileWidth: config.tile_size.width, tileHeight: config.tile_size.height, orientation: Phaser.Tilemaps.Orientation.ISOMETRIC, format: Phaser.Tilemaps.Formats.ARRAY_2D }) return new Phaser.Tilemaps.Tilemap(scene, mapConfig) } export function createTileLayer(tileMap: Phaser.Tilemaps.Tilemap, tilesArray: string[]) { // Load tiles into tileset const tilesetImages = tilesArray.map((tile: string, index: number) => { return tileMap.addTilesetImage(tile, tile, config.tile_size.width, config.tile_size.height, 1, 2, index + 1, { x: 0, y: -config.tile_size.height }) }) // Add blank tile tilesetImages.push(tileMap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.width, config.tile_size.height, 1, 2, 0, { x: 0, y: -config.tile_size.height })) // Create layer const layer = tileMap.createBlankLayer('tiles', tilesetImages as Tileset[], 0, config.tile_size.height) as Phaser.Tilemaps.TilemapLayer layer.setDepth(0) layer.setCullPadding(2, 2) return layer }