Map editor tiles are now fully loaded from cache
This commit is contained in:
parent
367d536c52
commit
8f07cf5093
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MapTiles @tileMap:create="tileMap = $event" />
|
<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" />
|
<MapEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
|
||||||
|
|
||||||
<Toolbar @save="save" @clear="clear" />
|
<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 TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
|
||||||
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
|
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
|
||||||
import Toolbar from '@/components/gameMaster/mapEditor/partials/Toolbar.vue'
|
import Toolbar from '@/components/gameMaster/mapEditor/partials/Toolbar.vue'
|
||||||
|
import { loadAllTilesIntoScene } from '@/composables/mapComposable'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
||||||
import { onUnmounted, shallowRef } from 'vue'
|
import { useScene } from 'phavuer'
|
||||||
|
import { onBeforeMount, onUnmounted, shallowRef } from 'vue'
|
||||||
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
const mapEditorStore = useMapEditorStore()
|
const mapEditorStore = useMapEditorStore()
|
||||||
|
const scene = useScene()
|
||||||
|
|
||||||
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
|
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
|
||||||
|
|
||||||
|
@ -1,24 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<Controls :layer="tileLayer" :depth="0" />
|
<Controls v-if="tileLayer" :layer="tileLayer" :depth="0" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import config from '@/application/config'
|
import config from '@/application/config'
|
||||||
import type { TextureData } from '@/application/types'
|
import type { TextureData } from '@/application/types'
|
||||||
import Controls from '@/components/utilities/Controls.vue'
|
import Controls from '@/components/utilities/Controls.vue'
|
||||||
import {
|
import { createTileArray, FlattenMapArray, getTile, loadAllTilesIntoScene, loadMapTilesIntoScene, placeTile, setLayerTiles } from '@/composables/mapComposable'
|
||||||
createTileArray,
|
import { TileStorage } from '@/storage/storages'
|
||||||
FlattenMapArray,
|
|
||||||
getTile,
|
|
||||||
loadMapTilesIntoScene,
|
|
||||||
placeTile,
|
|
||||||
setLayerTiles
|
|
||||||
} from '@/composables/mapComposable'
|
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
||||||
import { useScene } from 'phavuer'
|
import { useScene } from 'phavuer'
|
||||||
import { onMounted, onUnmounted, shallowRef, watch } from 'vue'
|
import { onBeforeMount, onMounted, onUnmounted, shallowRef, watch } from 'vue'
|
||||||
import { TileStorage } from '@/storage/storages'
|
|
||||||
import Tileset = Phaser.Tilemaps.Tileset
|
import Tileset = Phaser.Tilemaps.Tileset
|
||||||
|
|
||||||
const emit = defineEmits(['tileMap:create'])
|
const emit = defineEmits(['tileMap:create'])
|
||||||
@ -50,15 +44,11 @@ async function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap) {
|
|||||||
const tilesetImages = []
|
const tilesetImages = []
|
||||||
|
|
||||||
for (const tile of tiles) {
|
for (const tile of tiles) {
|
||||||
tilesetImages.push(
|
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 }))
|
||||||
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
|
// Add blank tile
|
||||||
tilesetImages.push(
|
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 }))
|
||||||
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
|
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])
|
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) {
|
if (shouldClear && mapEditorStore.map && tileMap.value && tileLayer.value) {
|
||||||
const blankTiles = createTileArray(tileMap.value.width, tileMap.value.height, 'blank_tile')
|
const blankTiles = createTileArray(tileMap.value.width, tileMap.value.height, 'blank_tile')
|
||||||
setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
|
setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
|
||||||
@ -202,8 +194,6 @@ watch(() => mapEditorStore.shouldClearTiles, (shouldClear) => {
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!mapEditorStore.map?.tiles) return
|
if (!mapEditorStore.map?.tiles) return
|
||||||
|
|
||||||
await loadMapTilesIntoScene(mapEditorStore.map.id, scene)
|
|
||||||
|
|
||||||
tileMap.value = createTileMap()
|
tileMap.value = createTileMap()
|
||||||
tileLayer.value = await createTileLayer(tileMap.value)
|
tileLayer.value = await createTileLayer(tileMap.value)
|
||||||
|
|
||||||
@ -228,6 +218,10 @@ onMounted(async () => {
|
|||||||
scene.input.on(Phaser.Input.Events.POINTER_DOWN, tilePicker)
|
scene.input.on(Phaser.Input.Events.POINTER_DOWN, tilePicker)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
await loadAllTilesIntoScene(scene)
|
||||||
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
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)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
import config from '@/application/config'
|
import config from '@/application/config'
|
||||||
import 'phaser'
|
import 'phaser'
|
||||||
import MapEditor from '@/components/gameMaster/mapEditor/MapEditor.vue'
|
import MapEditor from '@/components/gameMaster/mapEditor/MapEditor.vue'
|
||||||
|
import { loadAllTilesIntoScene } from '@/composables/mapComposable'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
||||||
import { Game, Scene } from 'phavuer'
|
import { Game, Scene } from 'phavuer'
|
||||||
|
@ -2,7 +2,7 @@ import config from '@/application/config'
|
|||||||
import type { HttpResponse, TextureData, UUID } from '@/application/types'
|
import type { HttpResponse, TextureData, UUID } from '@/application/types'
|
||||||
import { unduplicateArray } from '@/application/utilities'
|
import { unduplicateArray } from '@/application/utilities'
|
||||||
import { loadTexture } from '@/composables/gameComposable'
|
import { loadTexture } from '@/composables/gameComposable'
|
||||||
import { MapStorage } from '@/storage/storages'
|
import { MapStorage, TileStorage } from '@/storage/storages'
|
||||||
|
|
||||||
import Tilemap = Phaser.Tilemaps.Tilemap
|
import Tilemap = Phaser.Tilemaps.Tilemap
|
||||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
||||||
@ -88,19 +88,54 @@ export function FlattenMapArray(tiles: string[][]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) {
|
export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) {
|
||||||
|
const tileStorage = new TileStorage()
|
||||||
const mapStorage = new MapStorage()
|
const mapStorage = new MapStorage()
|
||||||
const map = await mapStorage.get(map_id)
|
const map = await mapStorage.get(map_id)
|
||||||
if (!map) return
|
if (!map) return
|
||||||
|
|
||||||
const tileArray = unduplicateArray(FlattenMapArray(map.tiles))
|
const tileArray = unduplicateArray(FlattenMapArray(map.tiles))
|
||||||
|
const tiles = await tileStorage.getByIds(tileArray)
|
||||||
|
|
||||||
// Load each tile into the scene
|
// Load each tile into the scene
|
||||||
for (const tile of tileArray) {
|
for (const tile of tiles) {
|
||||||
const textureData = {
|
const textureData = {
|
||||||
key: tile,
|
key: tile.id,
|
||||||
data: '/textures/tiles/' + tile + '.png',
|
data: '/textures/tiles/' + tile.id + '.png',
|
||||||
group: 'tiles',
|
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
|
} as TextureData
|
||||||
await loadTexture(scene, textureData)
|
await loadTexture(scene, textureData)
|
||||||
}
|
}
|
||||||
|
@ -2,41 +2,57 @@ import config from '@/application/config'
|
|||||||
import { getTile, tileToWorldXY } from '@/composables/mapComposable'
|
import { getTile, tileToWorldXY } from '@/composables/mapComposable'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useMapEditorStore } from '@/stores/mapEditorStore'
|
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) {
|
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 gameStore = useGameStore()
|
||||||
const mapEditorStore = useMapEditorStore()
|
const mapEditorStore = useMapEditorStore()
|
||||||
const isMoveTool = computed(() => mapEditorStore.tool === 'move')
|
const isMoveTool = computed(() => mapEditorStore.tool === 'move')
|
||||||
|
const pointerStartPosition = ref({ x: 0, y: 0 })
|
||||||
|
const dragThreshold = 5 // pixels
|
||||||
|
|
||||||
function updateWaypoint(pointer: Phaser.Input.Pointer) {
|
function updateWaypoint(worldX: number, worldY: number) {
|
||||||
const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y)
|
const pointerTile = getTile(layer, worldX, worldY)
|
||||||
const pointerTile = getTile(layer, px, py)
|
if (!pointerTile) {
|
||||||
|
|
||||||
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 {
|
|
||||||
waypoint.value.visible = false
|
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) {
|
function dragMap(pointer: Phaser.Input.Pointer) {
|
||||||
if (!gameStore.game.isPlayerDraggingCamera) return
|
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) {
|
function handlePointerMove(pointer: Phaser.Input.Pointer) {
|
||||||
if (isMoveTool.value || pointer.event.shiftKey) {
|
if (isMoveTool.value || pointer.event.shiftKey) {
|
||||||
dragMap(pointer)
|
dragMap(pointer)
|
||||||
}
|
}
|
||||||
updateWaypoint(pointer)
|
updateWaypoint(pointer.worldX, pointer.worldY)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePointerUp(pointer: Phaser.Input.Pointer) {
|
||||||
|
gameStore.setPlayerDraggingCamera(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleZoom(pointer: Phaser.Input.Pointer) {
|
function handleZoom(pointer: Phaser.Input.Pointer) {
|
||||||
@ -50,12 +66,16 @@ export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
const setupPointerHandlers = () => {
|
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_MOVE, handlePointerMove)
|
||||||
|
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
|
||||||
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
|
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanupPointerHandlers = () => {
|
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_MOVE, handlePointerMove)
|
||||||
|
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
|
||||||
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
|
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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[]> {
|
async getAll(): Promise<T[]> {
|
||||||
try {
|
try {
|
||||||
return await this.dexie.table(this.tableName).toArray()
|
return await this.dexie.table(this.tableName).toArray()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user