diff --git a/apps/cryptothrone.com/src/components/game/scene/SandCity.tsx b/apps/cryptothrone.com/src/components/game/scene/SandCity.tsx index ec8aef5d8..d955cff90 100644 --- a/apps/cryptothrone.com/src/components/game/scene/SandCity.tsx +++ b/apps/cryptothrone.com/src/components/game/scene/SandCity.tsx @@ -1,204 +1,210 @@ import { Scene } from 'phaser'; import Phaser from 'phaser'; import { - Quadtree, - type Bounds, - type Range, - PlayerController, - eventEmitterInstance as EventEmitter, - type CharacterEventData, - notificationType, - ULIDFactory, - npcDatabase, - mapDatabase, - Debug, + Quadtree, + type Bounds, + type Range, + PlayerController, + eventEmitterInstance as EventEmitter, + type CharacterEventData, + notificationType, + ULIDFactory, + npcDatabase, + mapDatabase, + Debug, } from '@kbve/laser'; declare global { - interface Window { - __GRID_ENGINE__?: any; - } + interface Window { + __GRID_ENGINE__?: any; + } } export class SandCity extends Scene { - cursor: Phaser.Types.Input.Keyboard.CursorKeys | undefined; - gridEngine: any; - quadtree: Quadtree | undefined; - playerController: PlayerController | undefined; - - constructor() { - super({ key: 'SandCity' }); - } - - preload() { - EventEmitter.emit('notification', { - title: 'Success', - message: `You arrived safely to SandCity Passport: ${ULIDFactory().toString()}`, - notificationType: notificationType.success, - }); - } - - async create() { - let cloudCityTilemap: Phaser.Tilemaps.Tilemap | null = null; - - try { - await mapDatabase.prepareMapLoad('cloud-city-map'); - cloudCityTilemap = await mapDatabase.loadNewMap(this, 'cloud-city-map'); - } catch (error) { - Debug.error('Failed to load map:', error); - return; - } - - if (!cloudCityTilemap) { - Debug.error('Tilemap could not be loaded.'); - return; - } - - if(cloudCityTilemap) - { - Debug.log('New Tilemap Loaded'); - } - - const bounds = await mapDatabase.getBounds('cloud-city-map'); - if (bounds) { - this.quadtree = new Quadtree(bounds); - } else { - Debug.error('Bounds could not be retrieved.'); - return; - } - - const playerSprite = this.add.sprite(0, 0, 'player'); - playerSprite.scale = 1.5; - - const playerBounds = playerSprite.getBounds(); - - const targetX = playerBounds.centerX + (playerSprite.width * 3); - const targetY = playerBounds.centerY + (playerSprite.height * 3); - - this.cameras.main.pan(targetX, targetY, 1000, 'Power2'); - - this.cameras.main.once('camerapancomplete', () => { - this.cameras.main.startFollow(playerSprite, true); - this.cameras.main.setFollowOffset( - -playerSprite.width, - -playerSprite.height, - ); - }); - - const gridEngineConfig = { - characters: [ - { - id: 'player', - sprite: playerSprite, - walkingAnimationMapping: 6, - startPosition: { x: 5, y: 12 }, - }, - ], - numberOfDirections: 8, - }; - - this.gridEngine.create(cloudCityTilemap, gridEngineConfig); - this.loadRanges(); - - this.playerController = new PlayerController( - this, - this.gridEngine, - this.quadtree, - ); - - // Retrieve NPCs from mapDatabase - const npcs = await mapDatabase.getNpcsFromTilesetKey('cloud-city-map'); - - if (npcs) { - for (const npc of npcs) { - try { - await npcDatabase.loadCharacter( - this, - npc.ulid, - npc.position.x, - npc.position.y, - ); - } catch (error) { - Debug.error(`Failed to load NPC with ULID: ${npc.ulid}`, error); - } - } - } - - // await npcDatabase.loadCharacter(this, '01J2DT4G871KJ0VNSHCNC5REDM', 6, 6); - // await npcDatabase.loadCharacter(this, '01J2HCTMQ58JBMJGW9YA3FBQCG', 8, 8); - // await npcDatabase.loadCharacter(this, '01J2HQJBMBGEEMWDBDWATRCY3T', 8, 15); - - window.__GRID_ENGINE__ = this.gridEngine; - } - - loadRanges() { - const ranges: Range[] = [ - { - name: 'well', - bounds: { xMin: 2, xMax: 5, yMin: 10, yMax: 14 }, - action: () => { - const eventData: CharacterEventData = { - message: - 'Seems like there are no fish in the sand pits. You know null, this area could be fixed up a bit too.', - }; - EventEmitter.emit('charEvent', eventData); - }, - }, - { - name: 'sign', - bounds: { xMin: 2, xMax: 5, yMin: 2, yMax: 5 }, - action: () => { - const eventData = { - message: 'Sign does not have much to say.', - character_name: 'Evee The BarKeep', - character_image: '/assets/npc/barkeep.webp', - background_image: '/assets/background/woodensign.webp', - }; - EventEmitter.emit('charEvent', eventData); - }, - }, - { - name: 'building', - bounds: { xMin: 13, xMax: 13, yMin: 6, yMax: 7 }, - action: () => { - const eventData: CharacterEventData = { - message: 'Sorry, we are closed!', - character_name: 'Evee The BarKeep', - character_image: '/assets/npc/barkeep.webp', - background_image: '/assets/background/animebar.webp', - }; - EventEmitter.emit('charEvent', eventData); - }, - }, - { - name: 'tombstone', - bounds: { xMin: 7, xMax: 10, yMin: 9, yMax: 10 }, - action: () => { - const eventData: CharacterEventData = { - message: - 'Samson the Great was an amazing sailer, died drinking dat drank.', - character_name: 'Samson Statue', - character_image: '/assets/npc/samson.png', - background_image: '/assets/background/animetombstone.webp', - }; - EventEmitter.emit('charEvent', eventData); - }, - }, - ]; - - for (const range of ranges) { - if (this.quadtree != undefined) this.quadtree.insert(range); - } - } - - update() { - this.playerController?.handleMovement(); - // mapDatabase.updateVisibleChunks( - // this, - // 'cloud-city-map', // tilemap key - // this.playerController?.getPlayerCoordsX() || 0, - // this.playerController?.getPlayerCoordsY() || 0, - // 1 - // ); - } + cursor: Phaser.Types.Input.Keyboard.CursorKeys | undefined; + gridEngine: any; + quadtree: Quadtree | undefined; + playerController: PlayerController | undefined; + + constructor() { + super({ key: 'SandCity' }); + } + + preload() { + EventEmitter.emit('notification', { + title: 'Success', + message: `You arrived safely to SandCity Passport: ${ULIDFactory().toString()}`, + notificationType: notificationType.success, + }); + } + + async create() { + let cloudCityTilemap: Phaser.Tilemaps.Tilemap | null = null; + + try { + await mapDatabase.prepareMapLoad('cloud-city-map'); + cloudCityTilemap = await mapDatabase.loadNewMap( + this, + 'cloud-city-map', + ); + } catch (error) { + Debug.error('Failed to load map:', error); + return; + } + + if (!cloudCityTilemap) { + Debug.error('Tilemap could not be loaded.'); + return; + } + + if (cloudCityTilemap) { + Debug.log('New Tilemap Loaded'); + } + + const bounds = await mapDatabase.getBounds('cloud-city-map'); + if (bounds) { + this.quadtree = new Quadtree(bounds); + } else { + Debug.error('Bounds could not be retrieved.'); + return; + } + + const playerSprite = this.add.sprite(0, 0, 'player'); + playerSprite.scale = 1.5; + + const playerBounds = playerSprite.getBounds(); + + const targetX = playerBounds.centerX + playerSprite.width * 3; + const targetY = playerBounds.centerY + playerSprite.height * 3; + + this.cameras.main.pan(targetX, targetY, 1000, 'Power2'); + + this.cameras.main.once('camerapancomplete', () => { + this.cameras.main.startFollow(playerSprite, true); + this.cameras.main.setFollowOffset( + -playerSprite.width, + -playerSprite.height, + ); + }); + + const gridEngineConfig = { + characters: [ + { + id: 'player', + sprite: playerSprite, + walkingAnimationMapping: 6, + startPosition: { x: 5, y: 12 }, + }, + ], + numberOfDirections: 8, + }; + + this.gridEngine.create(cloudCityTilemap, gridEngineConfig); + this.loadRanges(); + + this.playerController = new PlayerController( + this, + this.gridEngine, + this.quadtree, + ); + + // Retrieve NPCs from mapDatabase + const npcs = await mapDatabase.getNpcsFromTilesetKey('cloud-city-map'); + + if (npcs) { + for (const npc of npcs) { + try { + await npcDatabase.loadCharacter( + this, + npc.ulid, + npc.position.x, + npc.position.y, + ); + } catch (error) { + Debug.error( + `Failed to load NPC with ULID: ${npc.ulid}`, + error, + ); + } + } + } + + // await npcDatabase.loadCharacter(this, '01J2DT4G871KJ0VNSHCNC5REDM', 6, 6); + // await npcDatabase.loadCharacter(this, '01J2HCTMQ58JBMJGW9YA3FBQCG', 8, 8); + // await npcDatabase.loadCharacter(this, '01J2HQJBMBGEEMWDBDWATRCY3T', 8, 15); + + window.__GRID_ENGINE__ = this.gridEngine; + } + + loadRanges() { + const ranges: Range[] = [ + { + name: 'well', + bounds: { xMin: 2, xMax: 5, yMin: 10, yMax: 14 }, + action: () => { + const eventData: CharacterEventData = { + message: + 'Seems like there are no fish in the sand pits. You know null, this area could be fixed up a bit too.', + }; + EventEmitter.emit('charEvent', eventData); + }, + }, + { + name: 'sign', + bounds: { xMin: 2, xMax: 5, yMin: 2, yMax: 5 }, + action: () => { + const eventData = { + message: 'Sign does not have much to say.', + character_name: 'Evee The BarKeep', + character_image: '/assets/npc/barkeep.webp', + background_image: '/assets/background/woodensign.webp', + }; + EventEmitter.emit('charEvent', eventData); + }, + }, + { + name: 'building', + bounds: { xMin: 13, xMax: 13, yMin: 6, yMax: 7 }, + action: () => { + const eventData: CharacterEventData = { + message: 'Sorry, we are closed!', + character_name: 'Evee The BarKeep', + character_image: '/assets/npc/barkeep.webp', + background_image: '/assets/background/animebar.webp', + }; + EventEmitter.emit('charEvent', eventData); + }, + }, + { + name: 'tombstone', + bounds: { xMin: 7, xMax: 10, yMin: 9, yMax: 10 }, + action: () => { + const eventData: CharacterEventData = { + message: + 'Samson the Great was an amazing sailer, died drinking dat drank.', + character_name: 'Samson Statue', + character_image: '/assets/npc/samson.png', + background_image: + '/assets/background/animetombstone.webp', + }; + EventEmitter.emit('charEvent', eventData); + }, + }, + ]; + + for (const range of ranges) { + if (this.quadtree != undefined) this.quadtree.insert(range); + } + } + + update() { + this.playerController?.handleMovement(); + // mapDatabase.updateVisibleChunks( + // this, + // 'cloud-city-map', // tilemap key + // this.playerController?.getPlayerCoordsX() || 0, + // this.playerController?.getPlayerCoordsY() || 0, + // 1 + // ); + } } diff --git a/packages/laser/src/lib/phaser/map/mapdatabase.ts b/packages/laser/src/lib/phaser/map/mapdatabase.ts index ab087dcd7..54b7e4a0f 100644 --- a/packages/laser/src/lib/phaser/map/mapdatabase.ts +++ b/packages/laser/src/lib/phaser/map/mapdatabase.ts @@ -908,7 +908,7 @@ class MapDatabase extends Dexie { /** * Load map data and set tile dimensions and scale based on JSON data. - * @param {any} scene - Phaser Scene + * @param {Phaser.Scene} scene - Phaser Scene * @param {string} tilemapKey - The map identifier. */ async loadNewMap( @@ -920,7 +920,7 @@ class MapDatabase extends Dexie { const mapData = await this.getMap(tilemapKey); Debug.log( - `Map data retrieved for ${tilemapKey}: ${JSON.stringify(mapData)}`, + `Map data loaded for ${tilemapKey}: ${JSON.stringify(mapData)}`, ); if (!mapData) { Debug.error(`Map data not found for ${tilemapKey}`); @@ -932,57 +932,68 @@ class MapDatabase extends Dexie { Debug.error(`Parsed JSON data for ${tilemapKey} not found.`); return null; } else { - Debug.log(`Loaded the getParsedJsonData chunk data ${tilemapKey}`); - } - - if (mapData && jsonData) { - this.tileWidth = jsonData.tilewidth || 32; - this.tileHeight = jsonData.tileheight || 32; - this.scale = mapData.scale || 1; - - this.chunkWidth = this.tileWidth * this.chunkSizeX; - this.chunkHeight = this.tileHeight * this.chunkSizeY; - - this.nbChunksX = Math.ceil(jsonData.width / this.chunkSizeX); - this.nbChunksY = Math.ceil(jsonData.height / this.chunkSizeY); - - const tilesetKey = mapData.tilesetKey; - if (!scene.textures.exists(tilesetKey)) { - const tilesetImage = await this.getTilesetImage(tilemapKey); - if (tilesetImage) { - const tilesetImageUrl = URL.createObjectURL(tilesetImage); - scene.load.image(tilesetKey, tilesetImageUrl); - await new Promise((resolve) => - scene.load.once('complete', resolve), - ); - scene.load.start(); - } - } + Debug.log(`Loaded JSON data for ${tilemapKey}`); + } - // Create and return the tilemap in the scene - const map = scene.make.tilemap({ key: tilemapKey }); - const tileset = map.addTilesetImage( - mapData.tilesetName, - tilesetKey, - ); - if (tileset) { - for (let i = 0; i < map.layers.length; i++) { - const layer = map.createLayer(i, tileset, 0, 0); - if (layer) { - layer.setScale(this.scale); - } - } - return map; // Return the created tilemap + this.tileWidth = jsonData.tilewidth || 32; + this.tileHeight = jsonData.tileheight || 32; + this.scale = mapData.scale || 1; + this.chunkWidth = this.tileWidth * this.chunkSizeX; + this.chunkHeight = this.tileHeight * this.chunkSizeY; + this.nbChunksX = Math.ceil(jsonData.width / this.chunkSizeX); + this.nbChunksY = Math.ceil(jsonData.height / this.chunkSizeY); + + const tilesetKey = mapData.tilesetKey; + + // Load tileset image if not already in the texture cache + if (!scene.textures.exists(tilesetKey)) { + const tilesetImage = await this.getTilesetImage(tilemapKey); + if (tilesetImage) { + const tilesetImageUrl = URL.createObjectURL(tilesetImage); + Debug.log( + `Created object URL for tileset image: ${tilesetImageUrl}`, + ); + scene.load.image(tilesetKey, tilesetImageUrl); + + // Wait for Phaser to load the image + await new Promise((resolve) => { + scene.load.once('complete', () => { + Debug.log(`Image loading complete for ${tilesetKey}`); + resolve(true); + }); + scene.load.start(); + }); } else { - Debug.error(`Tileset ${tilesetKey} could not be created.`); + Debug.error(`Failed to load tileset image for ${tilesetKey}`); return null; } - } else { - Debug.error( - `Map data or JSON entry for tilemap key ${tilemapKey} not found.`, - ); + } + + // Create the tilemap and add tileset + const map = scene.make.tilemap({ key: tilemapKey }); + if (!map) { + Debug.error(`Tilemap could not be created for key: ${tilemapKey}`); return null; } + + const tileset = map.addTilesetImage(mapData.tilesetName, tilesetKey); + if (!tileset) { + Debug.error(`Tileset ${tilesetKey} could not be added to tilemap.`); + return null; + } + + // Add and scale each layer + for (let i = 0; i < map.layers.length; i++) { + const layer = map.createLayer(i, tileset, 0, 0); + if (layer) { + layer.setScale(this.scale); + Debug.log(`Layer ${i} created and scaled.`); + } else { + Debug.error(`Layer ${i} could not be created.`); + } + } + + return map; // Return the created tilemap } }