Minor improvements, more work on dynamic asset loading

This commit is contained in:
Dennis Postma 2024-10-26 02:41:16 +02:00
parent 70fb732051
commit 7db2ba322c
9 changed files with 105 additions and 68 deletions

View File

@ -8,7 +8,7 @@ import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { getTile, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' import { getTile, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
import { uuidv4 } from '@/utilities' import { uuidv4 } from '@/utilities'
import { onBeforeMount, onBeforeUnmount } from 'vue' import { onMounted, onUnmounted } from 'vue'
const scene = useScene() const scene = useScene()
const zoneEditorStore = useZoneEditorStore() const zoneEditorStore = useZoneEditorStore()
@ -102,14 +102,14 @@ function eraser(pointer: Phaser.Input.Pointer) {
zoneEditorStore.zone.zoneEventTiles = zoneEditorStore.zone.zoneEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id) zoneEditorStore.zone.zoneEventTiles = zoneEditorStore.zone.zoneEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id)
} }
onBeforeMount(() => { onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil) scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil) scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser) scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser) scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
}) })
onBeforeUnmount(() => { onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil) scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil) scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser) scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser)

View File

@ -10,7 +10,7 @@ import { Image, useScene } from 'phavuer'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import type { ZoneObject } from '@/types' import type { ZoneObject } from '@/types'
import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue' import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue'
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue' import { onMounted, onUnmounted, ref, watch } from 'vue'
const scene = useScene() const scene = useScene()
const zoneEditorStore = useZoneEditorStore() const zoneEditorStore = useZoneEditorStore()
@ -155,14 +155,14 @@ function deleteZoneObject(id: string) {
selectedZoneObject.value = null selectedZoneObject.value = null
} }
onBeforeMount(() => { onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil) scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil) scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser) scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser) scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
}) })
onBeforeUnmount(() => { onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil) scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil) scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser) scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser)

View File

@ -7,7 +7,7 @@ import config from '@/config'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import { onBeforeMount, onBeforeUnmount } from 'vue' import { onMounted, onUnmounted } from 'vue'
import { createTileArray, getTile, placeTile, setLayerTiles } from '@/composables/zoneComposable' import { createTileArray, getTile, placeTile, setLayerTiles } from '@/composables/zoneComposable'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
@ -123,7 +123,7 @@ function paint(pointer: Phaser.Input.Pointer) {
zoneEditorStore.zone.tiles = createTileArray(zoneTilemap.width, zoneTilemap.height, zoneEditorStore.selectedTile.id) zoneEditorStore.zone.tiles = createTileArray(zoneTilemap.width, zoneTilemap.height, zoneEditorStore.selectedTile.id)
} }
onBeforeMount(() => { onMounted(() => {
if (!zoneEditorStore.zone?.tiles) { if (!zoneEditorStore.zone?.tiles) {
return return
} }
@ -134,7 +134,7 @@ onBeforeMount(() => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, paint) scene.input.on(Phaser.Input.Events.POINTER_DOWN, paint)
}) })
onBeforeUnmount(() => { onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil) scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser) scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, paint) scene.input.off(Phaser.Input.Events.POINTER_DOWN, paint)

View File

@ -12,7 +12,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { onBeforeMount, onBeforeUnmount, watch } from 'vue' import { onBeforeMount, onBeforeUnmount, onMounted, onUnmounted, watch } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
@ -34,7 +34,7 @@ function setupNotificationListener(connection: any) {
}) })
} }
onBeforeMount(() => { onMounted(() => {
const connection = gameStore.connection const connection = gameStore.connection
if (connection) { if (connection) {
setupNotificationListener(connection) setupNotificationListener(connection)
@ -49,7 +49,7 @@ onBeforeMount(() => {
} }
}) })
onBeforeUnmount(() => { onUnmounted(() => {
const connection = gameStore.connection const connection = gameStore.connection
if (connection) { if (connection) {
connection.off('notification') connection.off('notification')

View File

@ -7,7 +7,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore' import { useZoneStore } from '@/stores/zoneStore'
import { onBeforeUnmount, ref, onBeforeMount } from 'vue' import { ref, onUnmounted, onMounted } from 'vue'
import type { Character as CharacterT, Zone as ZoneT, ExtendedCharacter as ExtendedCharacterT } from '@/types' import type { Character as CharacterT, Zone as ZoneT, ExtendedCharacter as ExtendedCharacterT } from '@/types'
import ZoneTiles from '@/components/zone/ZoneTiles.vue' import ZoneTiles from '@/components/zone/ZoneTiles.vue'
import ZoneObjects from '@/components/zone/ZoneObjects.vue' import ZoneObjects from '@/components/zone/ZoneObjects.vue'
@ -51,15 +51,15 @@ gameStore.connection!.on('character:move', (data: ExtendedCharacterT) => {
zoneStore.updateCharacter(data) zoneStore.updateCharacter(data)
}) })
onBeforeMount(async () => { onMounted(async () => {
// Emit zone:character:join event to server and wait for response, then set zone and characters
gameStore!.connection!.emit('zone:character:join', async (response: zoneLoadData) => { gameStore!.connection!.emit('zone:character:join', async (response: zoneLoadData) => {
// Set zone and characters
zoneStore.setZone(response.zone) zoneStore.setZone(response.zone)
zoneStore.setCharacters(response.characters) zoneStore.setCharacters(response.characters)
}) })
}) })
onBeforeUnmount(() => { onUnmounted(() => {
zoneStore.reset() zoneStore.reset()
gameStore.connection!.off('zone:character:teleport') gameStore.connection!.off('zone:character:teleport')
gameStore.connection!.off('zone:character:join') gameStore.connection!.off('zone:character:join')

View File

@ -6,17 +6,34 @@
import config from '@/config' import config from '@/config'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { useZoneStore } from '@/stores/zoneStore' import { useZoneStore } from '@/stores/zoneStore'
import { onBeforeMount, onBeforeUnmount } from 'vue' import { onBeforeUnmount } from 'vue'
import { setLayerTiles } from '@/composables/zoneComposable' import { setLayerTiles, loadZoneTileTexture } from '@/composables/zoneComposable'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
const emit = defineEmits(['tilemap:create']) const emit = defineEmits(['tilemap:create'])
const zoneStore = useZoneStore() const zoneStore = useZoneStore()
const scene = useScene() const scene = useScene()
const tilesFromZone = zoneStore.zone?.tiles
const uniqueTiles = new Set(tilesFromZone.flat().filter(Boolean))
/**
* @TODO fix this
*/
for (const tile of uniqueTiles) {
console.log(tile)
await loadZoneTileTexture(scene, tile, new Date())
}
const zoneTilemap = createTilemap() const zoneTilemap = createTilemap()
const tiles = createTileLayer() const tiles = createTileLayer()
/**
* A Tilemap is a container for Tilemap data.
* This isn't a display object, rather, it holds data about the map and allows you to add tilesets and tilemap layers to it.
* A map can have one or more tilemap layers, which are the display objects that actually render the tiles.
*/
function createTilemap() { function createTilemap() {
const zoneData = new Phaser.Tilemaps.MapData({ const zoneData = new Phaser.Tilemaps.MapData({
width: zoneStore.zone?.width, width: zoneStore.zone?.width,
@ -31,6 +48,9 @@ function createTilemap() {
return tilemap return tilemap
} }
/**
* A Tileset is a combination of a single image containing the tiles and a container for data about each tile.
*/
function createTileLayer() { function createTileLayer() {
const tilesFromZone = zoneStore.zone?.tiles || [] const tilesFromZone = zoneStore.zone?.tiles || []
const uniqueTiles = new Set(tilesFromZone.flat().filter(Boolean)) const uniqueTiles = new Set(tilesFromZone.flat().filter(Boolean))
@ -49,12 +69,7 @@ function createTileLayer() {
return layer return layer
} }
onBeforeMount(() => { setLayerTiles(zoneTilemap, tiles, zoneStore.zone?.tiles)
if (!zoneStore.zone?.tiles) {
return
}
setLayerTiles(zoneTilemap, tiles, zoneStore.zone.tiles)
})
onBeforeUnmount(() => { onBeforeUnmount(() => {
zoneTilemap.destroyLayer('tiles') zoneTilemap.destroyLayer('tiles')

View File

@ -3,14 +3,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed } from 'vue' import { ref, computed } from 'vue'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { import { calculateIsometricDepth, loadZoneObjectTexture, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
calculateIsometricDepth,
loadZoneObjectTexture,
tileToWorldX,
tileToWorldY
} from '@/composables/zoneComposable'
import type { ZoneObject } from '@/types' import type { ZoneObject } from '@/types'
const props = defineProps<{ const props = defineProps<{
@ -31,7 +26,6 @@ const imageProps = computed(() => ({
originX: Number(props.zoneObject.object.originY) originX: Number(props.zoneObject.object.originY)
})) }))
onMounted(() => {
loadZoneObjectTexture(scene, props.zoneObject.object.id, props.zoneObject.object.updatedAt) loadZoneObjectTexture(scene, props.zoneObject.object.id, props.zoneObject.object.updatedAt)
.then((loaded) => { .then((loaded) => {
isTextureLoaded.value = loaded isTextureLoaded.value = loaded
@ -39,5 +33,4 @@ onMounted(() => {
.catch((error) => { .catch((error) => {
console.error('Error loading texture:', error) console.error('Error loading texture:', error)
}) })
})
</script> </script>

View File

@ -52,6 +52,8 @@ export function placeTile(zone: Tilemap, layer: TilemapLayer, x: number, y: numb
} }
export function setLayerTiles(zone: Tilemap, layer: TilemapLayer, tiles: string[][]) { export function setLayerTiles(zone: Tilemap, layer: TilemapLayer, tiles: string[][]) {
if (!tiles) return
tiles.forEach((row: string[], y: number) => { tiles.forEach((row: string[], y: number) => {
row.forEach((tile: string, x: number) => { row.forEach((tile: string, x: number) => {
placeTile(zone, layer, x, y, tile) placeTile(zone, layer, x, y, tile)
@ -71,6 +73,33 @@ export const calculateIsometricDepth = (x: number, y: number, width: number = 0,
return baseDepth + (width + height) / (2 * config.tile_size.x) return baseDepth + (width + height) / (2 * config.tile_size.x)
} }
export async function loadZoneTileTexture(scene: Phaser.Scene, textureId: string, updatedAt: Date): Promise<boolean> {
const assetManager = useAssetManager
// Check if the texture is already loaded in Phaser
if (scene.textures.exists(textureId)) {
return true
}
let assetData = await assetManager.getAsset(textureId)
if (!assetData) {
await assetManager.downloadAsset(textureId, `/assets/tiles/${textureId}.png`, 'tiles', updatedAt)
assetData = await assetManager.getAsset(textureId)
}
if (assetData) {
return new Promise<boolean>((resolve) => {
scene.textures.addBase64(textureId, assetData.data)
scene.textures.once(`addtexture-${textureId}`, () => {
resolve(true)
})
})
}
return false
}
export async function loadZoneObjectTexture(scene: Phaser.Scene, textureId: string, updatedAt: Date): Promise<boolean> { export async function loadZoneObjectTexture(scene: Phaser.Scene, textureId: string, updatedAt: Date): Promise<boolean> {
const assetManager = useAssetManager const assetManager = useAssetManager

View File

@ -83,24 +83,24 @@ function preloadScene(scene: Phaser.Scene) {
* We're using rex-await-loader to load assets asynchronously * We're using rex-await-loader to load assets asynchronously
* Phaser does not support this out of the box, so we're using this plugin * Phaser does not support this out of the box, so we're using this plugin
*/ */
scene.load.rexAwait(async function (successCallback) { // scene.load.rexAwait(async function (successCallback) {
await assetManager.getAssetsByGroup('tiles').then((assets) => { // await assetManager.getAssetsByGroup('tiles').then((assets) => {
assets.forEach((asset) => { // assets.forEach((asset) => {
if (scene.load.textureManager.exists(asset.key)) return // if (scene.load.textureManager.exists(asset.key)) return
scene.textures.addBase64(asset.key, asset.data) // scene.textures.addBase64(asset.key, asset.data)
}) // })
}) // })
//
// Load objects // // Load objects
await assetManager.getAssetsByGroup('objects').then((assets) => { // await assetManager.getAssetsByGroup('objects').then((assets) => {
assets.forEach((asset) => { // assets.forEach((asset) => {
if (scene.load.textureManager.exists(asset.key)) return // if (scene.load.textureManager.exists(asset.key)) return
scene.textures.addBase64(asset.key, asset.data) // scene.textures.addBase64(asset.key, asset.data)
}) // })
}) // })
//
successCallback() // successCallback()
}) // })
} }
function createScene(scene: Phaser.Scene) { function createScene(scene: Phaser.Scene) {
@ -108,15 +108,15 @@ function createScene(scene: Phaser.Scene) {
* Create sprite animations * Create sprite animations
* This is done here because phaser forces us to * This is done here because phaser forces us to
*/ */
assetManager.getAssetsByGroup('sprite_animations').then((assets) => { // assetManager.getAssetsByGroup('sprite_animations').then((assets) => {
assets.forEach((asset) => { // assets.forEach((asset) => {
scene.anims.create({ // scene.anims.create({
key: asset.key, // key: asset.key,
frameRate: 7, // frameRate: 7,
frames: scene.anims.generateFrameNumbers(asset.key, { start: 0, end: asset.frameCount! - 1 }), // frames: scene.anims.generateFrameNumbers(asset.key, { start: 0, end: asset.frameCount! - 1 }),
repeat: -1 // repeat: -1
}) // })
}) // })
}) // })
} }
</script> </script>