1
0
forked from noxious/client

Map editor tiles are now fully loaded from cache

This commit is contained in:
Dennis Postma 2025-01-13 10:52:40 +01:00
parent 367d536c52
commit 8f07cf5093
6 changed files with 107 additions and 44 deletions

View File

@ -1,6 +1,6 @@
<template>
<MapTiles @tileMap:create="tileMap = $event" />
<MapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<!-- <MapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />-->
<MapEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<Toolbar @save="save" @clear="clear" />
@ -24,12 +24,15 @@ import MapSettings from '@/components/gameMaster/mapEditor/partials/MapSettings.
import TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
import Toolbar from '@/components/gameMaster/mapEditor/partials/Toolbar.vue'
import { loadAllTilesIntoScene } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { onUnmounted, shallowRef } from 'vue'
import { useScene } from 'phavuer'
import { onBeforeMount, onUnmounted, shallowRef } from 'vue'
const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore()
const scene = useScene()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()

View File

@ -1,24 +1,18 @@
<template>
<Controls :layer="tileLayer" :depth="0" />
<Controls v-if="tileLayer" :layer="tileLayer" :depth="0" />
</template>
<script setup lang="ts">
import config from '@/application/config'
import type { TextureData } from '@/application/types'
import Controls from '@/components/utilities/Controls.vue'
import {
createTileArray,
FlattenMapArray,
getTile,
loadMapTilesIntoScene,
placeTile,
setLayerTiles
} from '@/composables/mapComposable'
import { createTileArray, FlattenMapArray, getTile, loadAllTilesIntoScene, loadMapTilesIntoScene, placeTile, setLayerTiles } from '@/composables/mapComposable'
import { TileStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useScene } from 'phavuer'
import { onMounted, onUnmounted, shallowRef, watch } from 'vue'
import { TileStorage } from '@/storage/storages'
import { onBeforeMount, onMounted, onUnmounted, shallowRef, watch } from 'vue'
import Tileset = Phaser.Tilemaps.Tileset
const emit = defineEmits(['tileMap:create'])
@ -50,15 +44,11 @@ async function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap) {
const tilesetImages = []
for (const tile of tiles) {
tilesetImages.push(
currentTileMap.addTilesetImage(tile.id, tile.id, config.tile_size.width, config.tile_size.height, 1, 2, tilesetImages.length + 1, { x: 0, y: -config.tile_size.height })
)
tilesetImages.push(currentTileMap.addTilesetImage(tile.id, tile.id, config.tile_size.width, config.tile_size.height, 1, 2, tilesetImages.length + 1, { x: 0, y: -config.tile_size.height }))
}
// Add blank tile
tilesetImages.push(
currentTileMap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.width, config.tile_size.height, 1, 2, 0, { x: 0, y: -config.tile_size.height })
)
tilesetImages.push(currentTileMap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.width, config.tile_size.height, 1, 2, 0, { x: 0, y: -config.tile_size.height }))
const layer = currentTileMap.createBlankLayer('tiles', tilesetImages as Tileset[], 0, config.tile_size.height) as Phaser.Tilemaps.TilemapLayer
@ -189,7 +179,9 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
mapEditorStore.setSelectedTile(mapEditorStore.map.tiles[tile.y][tile.x])
}
watch(() => mapEditorStore.shouldClearTiles, (shouldClear) => {
watch(
() => mapEditorStore.shouldClearTiles,
(shouldClear) => {
if (shouldClear && mapEditorStore.map && tileMap.value && tileLayer.value) {
const blankTiles = createTileArray(tileMap.value.width, tileMap.value.height, 'blank_tile')
setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
@ -202,8 +194,6 @@ watch(() => mapEditorStore.shouldClearTiles, (shouldClear) => {
onMounted(async () => {
if (!mapEditorStore.map?.tiles) return
await loadMapTilesIntoScene(mapEditorStore.map.id, scene)
tileMap.value = createTileMap()
tileLayer.value = await createTileLayer(tileMap.value)
@ -228,6 +218,10 @@ onMounted(async () => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, tilePicker)
})
onBeforeMount(async () => {
await loadAllTilesIntoScene(scene)
})
onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)

View File

@ -12,6 +12,7 @@
import config from '@/application/config'
import 'phaser'
import MapEditor from '@/components/gameMaster/mapEditor/MapEditor.vue'
import { loadAllTilesIntoScene } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { Game, Scene } from 'phavuer'

View File

@ -2,7 +2,7 @@ import config from '@/application/config'
import type { HttpResponse, TextureData, UUID } from '@/application/types'
import { unduplicateArray } from '@/application/utilities'
import { loadTexture } from '@/composables/gameComposable'
import { MapStorage } from '@/storage/storages'
import { MapStorage, TileStorage } from '@/storage/storages'
import Tilemap = Phaser.Tilemaps.Tilemap
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
@ -88,19 +88,54 @@ export function FlattenMapArray(tiles: string[][]) {
}
export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) {
const tileStorage = new TileStorage()
const mapStorage = new MapStorage()
const map = await mapStorage.get(map_id)
if (!map) return
const tileArray = unduplicateArray(FlattenMapArray(map.tiles))
const tiles = await tileStorage.getByIds(tileArray)
// Load each tile into the scene
for (const tile of tileArray) {
for (const tile of tiles) {
const textureData = {
key: tile,
data: '/textures/tiles/' + tile + '.png',
key: tile.id,
data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: map.updatedAt // @TODO: Fix this
updatedAt: tile.updatedAt
} as TextureData
await loadTexture(scene, textureData)
}
}
export async function loadTilesIntoScene(tileIds: string[], scene: Phaser.Scene) {
const tileStorage = new TileStorage()
const tiles = await tileStorage.getByIds(tileIds)
// Load each tile into the scene
for (const tile of tiles) {
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 loadAllTilesIntoScene(scene: Phaser.Scene) {
const tileStorage = new TileStorage()
const tiles = await tileStorage.getAll()
// Load each tile into the scene
for (const tile of tiles) {
const textureData = {
key: tile.id,
data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: tile.updatedAt
} as TextureData
await loadTexture(scene, textureData)
}

View File

@ -2,41 +2,57 @@ import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, type Ref } from 'vue'
import { computed, ref, type Ref } from 'vue'
export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore()
const isMoveTool = computed(() => mapEditorStore.tool === 'move')
const pointerStartPosition = ref({ x: 0, y: 0 })
const dragThreshold = 5 // pixels
function updateWaypoint(pointer: Phaser.Input.Pointer) {
const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y)
const pointerTile = getTile(layer, px, py)
if (pointerTile) {
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.positionX || !worldPoint.positionY) return
waypoint.value = {
visible: true,
x: worldPoint.positionX,
y: worldPoint.positionY + config.tile_size.height + 15
}
} else {
function updateWaypoint(worldX: number, worldY: number) {
const pointerTile = getTile(layer, worldX, worldY)
if (!pointerTile) {
waypoint.value.visible = false
return
}
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.worldPositionX || !worldPoint.worldPositionX) return
waypoint.value = {
visible: true,
x: worldPoint.worldPositionX,
y: worldPoint.worldPositionY + config.tile_size.height + 15
}
}
function handlePointerDown(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
if (isMoveTool.value || pointer.event.shiftKey) {
gameStore.setPlayerDraggingCamera(true)
}
}
function dragMap(pointer: Phaser.Input.Pointer) {
if (!gameStore.game.isPlayerDraggingCamera) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
if (distance <= dragThreshold) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) {
dragMap(pointer)
}
updateWaypoint(pointer)
updateWaypoint(pointer.worldX, pointer.worldY)
}
function handlePointerUp(pointer: Phaser.Input.Pointer) {
gameStore.setPlayerDraggingCamera(false)
}
function handleZoom(pointer: Phaser.Input.Pointer) {
@ -50,12 +66,16 @@ export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.T
}
const setupPointerHandlers = () => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
}
const cleanupPointerHandlers = () => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
}

View File

@ -33,6 +33,16 @@ export class BaseStorage<T extends { id: string }> {
}
}
async getByIds(ids: string[]): Promise<T[]> {
try {
const items = await this.dexie.table(this.tableName).bulkGet(ids)
return items.filter((item) => item !== null)
} catch (error) {
console.error(`Failed to retrieve ${this.tableName} by ids:`, error)
return []
}
}
async getAll(): Promise<T[]> {
try {
return await this.dexie.table(this.tableName).toArray()