forked from noxious/client
Map editor tiles are now fully loaded from cache
This commit is contained in:
parent
367d536c52
commit
8f07cf5093
@ -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>()
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) {
|
||||
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.positionX || !worldPoint.positionY) return
|
||||
if (!worldPoint.worldPositionX || !worldPoint.worldPositionX) return
|
||||
|
||||
waypoint.value = {
|
||||
visible: true,
|
||||
x: worldPoint.positionX,
|
||||
y: worldPoint.positionY + config.tile_size.height + 15
|
||||
x: worldPoint.worldPositionX,
|
||||
y: worldPoint.worldPositionY + config.tile_size.height + 15
|
||||
}
|
||||
} else {
|
||||
waypoint.value.visible = false
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user