diff --git a/package-lock.json b/package-lock.json index 83bde7a..f79b9e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1991,9 +1991,9 @@ } }, "node_modules/@types/node": { - "version": "20.16.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz", - "integrity": "sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==", + "version": "20.16.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.12.tgz", + "integrity": "sha512-LfPFB0zOeCeCNQV3i+67rcoVvoN5n0NVuR2vLG0O5ySQMgchuZlC4lgz546ZOJyDtj5KIgOxy+lacOimfqZAIA==", "dev": true, "license": "MIT", "dependencies": { @@ -3642,9 +3642,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.39", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.39.tgz", - "integrity": "sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg==", + "version": "1.5.40", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.40.tgz", + "integrity": "sha512-LYm78o6if4zTasnYclgQzxEcgMoIcybWOhkATWepN95uwVVWV0/IW10v+2sIeHE+bIYWipLneTftVyQm45UY7g==", "dev": true, "license": "ISC" }, @@ -5798,9 +5798,9 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { @@ -6409,9 +6409,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.79.5", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.5.tgz", - "integrity": "sha512-W1h5kp6bdhqFh2tk3DsI771MoEJjvrSY/2ihJRJS4pjIyfJCw0nTsxqhnrUzaLMOJjFchj8rOvraI/YUVjtx5g==", + "version": "1.79.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.6.tgz", + "integrity": "sha512-PVVjeeiUGx6Nj4PtEE/ecwu8ltwfPKzHxbbVmmLj4l1FYHhOyfA0scuVF8sVaa+b+VY4z7BVKjKq0cPUQdUU3g==", "dev": true, "license": "MIT", "dependencies": { diff --git a/src/components/Effects.vue b/src/components/Effects.vue index 289fd47..44968b4 100644 --- a/src/components/Effects.vue +++ b/src/components/Effects.vue @@ -12,6 +12,11 @@ import { onBeforeMount, onBeforeUnmount, ref } from 'vue' const gameStore = useGameStore() const zoneEditorStore = useZoneEditorStore() + + + +// See if there's a dat + const sceneRef = ref<Phaser.Scene | null>(null) // Effect-related refs diff --git a/src/components/gameMaster/zoneEditor/EventTiles.vue b/src/components/gameMaster/zoneEditor/EventTiles.vue new file mode 100644 index 0000000..f314c7c --- /dev/null +++ b/src/components/gameMaster/zoneEditor/EventTiles.vue @@ -0,0 +1,18 @@ +<template> + +</template> + +<script setup lang="ts"> + + +import type { ZoneEventTile } from '@/types' +import { tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' + +function getEventTileImageProps(tile: ZoneEventTile) { + return { + x: tileToWorldX(zoneTilemap as any, tile.positionX, tile.positionY), + y: tileToWorldY(zoneTilemap as any, tile.positionX, tile.positionY), + texture: tile.type + } +} +</script> \ No newline at end of file diff --git a/src/components/gameMaster/zoneEditor/Objects.vue b/src/components/gameMaster/zoneEditor/Objects.vue new file mode 100644 index 0000000..640a22e --- /dev/null +++ b/src/components/gameMaster/zoneEditor/Objects.vue @@ -0,0 +1,31 @@ +<template> + <SelectedZoneObject v-if="zoneEditorStore.selectedZoneObject" /> + <Image v-for="object in zoneEditorStore.zone?.zoneObjects" :key="object.id" v-bind="getObjectImageProps(object)" /> +</template> + +<script setup lang="ts"> +import { tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' +import { Image } from 'phavuer' +import { useZoneEditorStore } from '@/stores/zoneEditorStore' +import type { ZoneObject } from '@/types' +import { ZoneEventTileType } from '@/types' +import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue' + +const zoneEditorStore = useZoneEditorStore() + +const props = defineProps<{ + tilemap: Phaser.Tilemaps.Tilemap +}>() + +function getObjectImageProps(object: ZoneObject) { + return { + // alpha: object.id === movingZoneObject.value?.id ? .5 : 1, + tint: zoneEditorStore.selectedZoneObject?.id === object.id ? 0x00ff00 : 0xffffff, + x: tileToWorldX(props.tilemap as any, object.positionX, object.positionY), + y: tileToWorldY(props.tilemap as any, object.positionX, object.positionY), + texture: object.object.id, + originY: Number(object.object.originX), + originX: Number(object.object.originY) + } +} +</script> diff --git a/src/components/gameMaster/zoneEditor/Tiles.vue b/src/components/gameMaster/zoneEditor/Tiles.vue new file mode 100644 index 0000000..1e5051f --- /dev/null +++ b/src/components/gameMaster/zoneEditor/Tiles.vue @@ -0,0 +1,95 @@ +<template> + <Controls :layer="tiles" :depth="0" /> +</template> + +<script setup lang="ts"> +import config from '@/config' +import { useScene } from 'phavuer' +import { useZoneEditorStore } from '@/stores/zoneEditorStore' +import { onBeforeMount, onBeforeUnmount } from 'vue' +import { getTile, placeTile, setAllTiles } from '@/composables/zoneComposable' +import Controls from '@/components/utilities/Controls.vue' +import { z } from 'zod' +import Tilemap = Phaser.Tilemaps.Tilemap +import TilemapLayer = Phaser.Tilemaps.TilemapLayer + +const emit = defineEmits(['tilemap:create']) + +const zoneEditorStore = useZoneEditorStore() +const scene = useScene() + +const zoneTilemap = createTilemap() +const tiles = createTileLayer() +let tileArray = createTileArray() + +function createTilemap() { + const zoneData = new Phaser.Tilemaps.MapData({ + width: zoneEditorStore.zone?.width, + height: zoneEditorStore.zone?.height, + tileWidth: config.tile_size.x, + tileHeight: config.tile_size.y, + orientation: Phaser.Tilemaps.Orientation.ISOMETRIC, + format: Phaser.Tilemaps.Formats.ARRAY_2D + }) + const tilemap = new Phaser.Tilemaps.Tilemap(scene, zoneData) + emit('tilemap:create', tilemap) + return tilemap +} + +function createTileLayer() { + const tilesFromZone = zoneEditorStore.zone?.tiles || [] + const uniqueTiles = new Set(tilesFromZone.flat().filter(Boolean)) + + const tilesetImages = Array.from(uniqueTiles).map((tile, index) => { + return zoneTilemap.addTilesetImage(tile, tile, config.tile_size.x, config.tile_size.y, 1, 2, index + 1, { x: 0, y: -config.tile_size.y }) + }) as any + + // Add blank tile + tilesetImages.push(zoneTilemap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.x, config.tile_size.y, 1, 2, 0, { x: 0, y: -config.tile_size.y })) + const layer = zoneTilemap.createBlankLayer('tiles', tilesetImages, 0, config.tile_size.y) as Phaser.Tilemaps.TilemapLayer + + layer.setDepth(0) + layer.setCullPadding(2, 2) + + return layer +} + +function createTileArray() { + return Array.from({ length: zoneTilemap.height || 0 }, () => Array.from({ length: zoneTilemap.width || 0 }, () => 'blank_tile')) +} + +function handleTileClick(pointer: Phaser.Input.Pointer) { + // Check if tool is pencil + if (zoneEditorStore.tool !== 'pencil') return + + // Check if there is a tile + const tile = getTile(pointer.worldX, pointer.worldY, tiles) + if (!tile) return + + if (!zoneEditorStore.selectedTile) { + return + } + + console.log('yolo') + + placeTile(zoneTilemap as Tilemap, tiles as TilemapLayer, tile.x, tile.y, zoneEditorStore.selectedTile.id) +} + +onBeforeMount(() => { + if (!zoneEditorStore.zone?.tiles) { + return + } + setAllTiles(zoneTilemap, tiles, zoneEditorStore.zone.tiles) + tileArray = zoneEditorStore.zone.tiles.map((row) => row.map((tileId) => tileId || 'blank_tile')) + + scene.input.on(Phaser.Input.Events.POINTER_DOWN, handleTileClick) +}) + +onBeforeUnmount(() => { + scene.input.off(Phaser.Input.Events.POINTER_DOWN, handleTileClick) + + zoneTilemap.destroyLayer('tiles') + zoneTilemap.removeAllLayers() + zoneTilemap.destroy() +}) +</script> diff --git a/src/components/gameMaster/zoneEditor/ZoneEditor.vue b/src/components/gameMaster/zoneEditor/ZoneEditor.vue index 2659ede..3b0fb1b 100644 --- a/src/components/gameMaster/zoneEditor/ZoneEditor.vue +++ b/src/components/gameMaster/zoneEditor/ZoneEditor.vue @@ -1,229 +1,56 @@ <template> - <Toolbar :layer="tiles" @eraser="eraser" @move="move" @pencil="pencil" @paint="paint" @clear="clear" @save="save" /> - <ZoneList v-if="zoneEditorStore.isZoneListModalShown" /> + <Tiles @tilemap:create="tileMap = $event" /> + <Objects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> + <EventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> - <template v-if="zoneEditorStore.zone"> - <Controls :layer="tiles as TilemapLayer" /> + <Toolbar @save="save" /> - <Tiles /> - <Objects /> + <ZoneList /> + <TileList /> + <ObjectList /> - <ZoneSettings /> - <TeleportModal v-if="shouldShowTeleportModal" /> - - <Container :depth="2"> - <Image v-for="object in zoneObjects" :depth="calculateIsometricDepth(object.positionX, object.positionY, 0)" :key="object.id" v-bind="getObjectImageProps(object)" @pointerup="() => setSelectedZoneObject(object)" :flipX="object.isRotated" /> - </Container> - - <Container :depth="3"> - <Image v-for="tile in zoneEventTiles" :key="tile.id" v-bind="getEventTileImageProps(tile)" /> - </Container> - - <SelectedZoneObject v-if="zoneEditorStore.selectedZoneObject" @update_depth="updateZoneObjectDepth" @delete="deleteZoneObject" @move="handleMove" @rotate="handleRotate" /> - </template> + <ZoneSettings /> + <TeleportModal /> </template> <script setup lang="ts"> -import { computed, onBeforeMount, onMounted, onUnmounted, ref, watch } from 'vue' -import { Container, Image, useScene } from 'phavuer' -import { storeToRefs } from 'pinia' +import { onBeforeMount, onUnmounted, ref } from 'vue' +import { useScene } from 'phavuer' import { useGameStore } from '@/stores/gameStore' import { useZoneEditorStore } from '@/stores/zoneEditorStore' -import { - calculateIsometricDepth, - getTile, - loadAssets, - placeTile, - setAllTiles, - sortByIsometricDepth, - tileToWorldX, - tileToWorldY -} from '@/composables/zoneComposable' -import { ZoneEventTileType, type ZoneObject, type ZoneEventTile, type Zone } from '@/types' -import { uuidv4 } from '@/utilities' -import config from '@/config' +import { loadAssets } from '@/composables/zoneComposable' +import { type ZoneObject, type ZoneEventTile, type Zone } from '@/types' // Components -import Controls from '@/components/utilities/Controls.vue' import Toolbar from '@/components/gameMaster/zoneEditor/partials/Toolbar.vue' -import Tiles from '@/components/gameMaster/zoneEditor/partials/TileList.vue' -import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue' +import TileList from '@/components/gameMaster/zoneEditor/partials/TileList.vue' +import ObjectList from '@/components/gameMaster/zoneEditor/partials/ObjectList.vue' import ZoneSettings from '@/components/gameMaster/zoneEditor/partials/ZoneSettings.vue' -import Objects from '@/components/gameMaster/zoneEditor/partials/ObjectList.vue' import ZoneList from '@/components/gameMaster/zoneEditor/partials/ZoneList.vue' import TeleportModal from '@/components/gameMaster/zoneEditor/partials/TeleportModal.vue' -import Tilemap = Phaser.Tilemaps.Tilemap -import TilemapLayer = Phaser.Tilemaps.TilemapLayer -import InputManager = Phaser.Input.InputManager -import MouseManager = Phaser.Input.Mouse.MouseManager - -/** - * @TODO: - * Clean all the code in this file - */ +import Tiles from '@/components/gameMaster/zoneEditor/Tiles.vue' +import Objects from '@/components/gameMaster/zoneEditor/Objects.vue' +import EventTiles from '@/components/gameMaster/zoneEditor/EventTiles.vue' const scene = useScene() const gameStore = useGameStore() const zoneEditorStore = useZoneEditorStore() -const { objectList, zone, selectedTile, selectedObject, selectedZoneObject, eraserMode, drawMode } = storeToRefs(zoneEditorStore) - -const movingZoneObject = ref<ZoneObject|null>(null); -const zoneTilemap = createTilemap() -const tiles = createTileLayer() +const tileMap = ref(null as Phaser.Tilemaps.Tilemap | null) +const tileArray = ref<string[][]>([]) const zoneObjects = ref<ZoneObject[]>([]) const zoneEventTiles = ref<ZoneEventTile[]>([]) -let tileArray = createTileArray() -const shouldShowTeleportModal = computed(() => zoneEditorStore.tool === 'pencil' && drawMode.value === 'teleport') - -function createTilemap() { - const zoneData = new Phaser.Tilemaps.MapData({ - width: zone.value?.width ?? 10, - height: zone.value?.height ?? 10, - tileWidth: config.tile_size.x, - tileHeight: config.tile_size.y, - orientation: Phaser.Tilemaps.Orientation.ISOMETRIC, - format: Phaser.Tilemaps.Formats.ARRAY_2D - }) - const tilemap = new Phaser.Tilemaps.Tilemap(scene, zoneData) - return tilemap -} - -function createTileLayer() { - const tilesetImages = gameStore.assets.filter((asset) => asset.group === 'tiles').map((asset, index) => zoneTilemap.addTilesetImage(asset.key, asset.key, config.tile_size.x, config.tile_size.y, 1, 2, index + 1, { x: 0, y: -config.tile_size.y })) - tilesetImages.push(zoneTilemap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.x, config.tile_size.y, 1, 2, 0, { x: 0, y: -config.tile_size.y })) - - const layer = zoneTilemap.createBlankLayer('tiles', tilesetImages as any, 0, config.tile_size.y) as Phaser.Tilemaps.TilemapLayer - - layer.setDepth(0) - - return layer -} - -function createTileArray() { - return Array.from({ length: zoneTilemap.height || 0 }, () => Array.from({ length: zoneTilemap.width || 0 }, () => 'blank_tile')) -} - -function getObjectImageProps(object: ZoneObject) { - return { - alpha: object.id === movingZoneObject.value?.id ? .5 : 1, - tint: selectedZoneObject.value?.id === object.id ? 0x00ff00 : 0xffffff, - x: tileToWorldX(zoneTilemap as any, object.positionX, object.positionY), - y: tileToWorldY(zoneTilemap as any, object.positionX, object.positionY), - texture: object.object.id, - originY: Number(object.object.originX), - originX: Number(object.object.originY) - } -} - -function getEventTileImageProps(tile: ZoneEventTile) { - return { - x: tileToWorldX(zoneTilemap as any, tile.positionX, tile.positionY), - y: tileToWorldY(zoneTilemap as any, tile.positionX, tile.positionY), - texture: tile.type - } -} - -function eraser(tile: Phaser.Tilemaps.Tile) { - if (eraserMode.value === 'tile') { - placeTile(zoneTilemap as Tilemap, tiles as TilemapLayer, tile.x, tile.y, 'blank_tile') - tileArray[tile.y][tile.x] = 'blank_tile' - } else if (eraserMode.value === 'object') { - zoneObjects.value = zoneObjects.value.filter((object) => object.positionX !== tile.x || object.positionY !== tile.y) - } else if (eraserMode.value === 'blocking tile' || eraserMode.value === 'teleport') { - zoneEventTiles.value = zoneEventTiles.value.filter((eventTile) => eventTile.positionX !== tile.x || eventTile.positionY !== tile.y || (eraserMode.value === 'teleport' && eventTile.type !== ZoneEventTileType.TELEPORT)) - } -} - -function move(_tile: Phaser.Tilemaps.Tile) { - movingZoneObject.value = null; -} - -function pencil(tile: Phaser.Tilemaps.Tile) { - if (drawMode.value === 'tile' && selectedTile.value) { - placeTile(zoneTilemap as Tilemap, tiles as TilemapLayer, tile.x, tile.y, selectedTile.value.id) - tileArray[tile.y][tile.x] = selectedTile.value.id - } else if (drawMode.value === 'object' && selectedObject.value) { - addZoneObject(tile) - } else if (drawMode.value === 'blocking tile' || drawMode.value === 'teleport') { - addZoneEventTile(tile) - } -} - -function addZoneObject(tile: Phaser.Tilemaps.Tile) { - // Check if object already exists on position - const existingObject = zoneObjects.value.find((object) => object.positionX === tile.x && object.positionY === tile.y) - if (existingObject) return - - const newObject = { - id: uuidv4(), - zoneId: zone.value!.id, - zone: zone.value!, - objectId: selectedObject.value!.id, - object: selectedObject.value!, - depth: 0, - isRotated: false, - positionX: tile.x, - positionY: tile.y - } - // Add new object to zoneObjects - zoneObjects.value = zoneObjects.value.concat(newObject) -} - -function addZoneEventTile(tile: Phaser.Tilemaps.Tile) { - // Check if event tile already exists on position - const existingEventTile = zoneEventTiles.value.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y) - if (existingEventTile) return - - const newEventTile = { - id: uuidv4(), - zoneId: zone.value!.id, - zone: zone.value!, - type: drawMode.value === 'blocking tile' ? ZoneEventTileType.BLOCK : ZoneEventTileType.TELEPORT, - positionX: tile.x, - positionY: tile.y, - teleport: - drawMode.value === 'teleport' - ? { - toZoneId: zoneEditorStore.teleportSettings.toZoneId, - toPositionX: zoneEditorStore.teleportSettings.toPositionX, - toPositionY: zoneEditorStore.teleportSettings.toPositionY, - toRotation: zoneEditorStore.teleportSettings.toRotation - } - : undefined - } - zoneEventTiles.value = zoneEventTiles.value.concat(newEventTile as any) -} - -function paint() { - if (!selectedTile.value) return - - // Ensure tileArray is initialized with correct dimensions - if (!tileArray || tileArray.length !== zoneTilemap.height) { - tileArray = Array.from({ length: zoneTilemap.height }, () => Array.from({ length: zoneTilemap.width }, () => 'blank_tile')) - } - - // Set all tiles in the tilemap to the selected tile's id - for (let y = 0; y < zoneTilemap.height; y++) { - if (!tileArray[y]) { - tileArray[y] = Array(zoneTilemap.width).fill('blank_tile') - } - for (let x = 0; x < zoneTilemap.width; x++) { - placeTile(zoneTilemap as Tilemap, tiles as TilemapLayer, x, y, selectedTile.value.id) - tileArray[y][x] = selectedTile.value.id - } - } -} function save() { - if (!zone.value) return + if (!zoneEditorStore.zone) return + const data = { - zoneId: zone.value.id, + zoneId: zoneEditorStore.zone.id, name: zoneEditorStore.zoneSettings.name, width: zoneEditorStore.zoneSettings.width, height: zoneEditorStore.zoneSettings.height, tiles: tileArray, - pvp: zone.value.pvp, + pvp: zoneEditorStore.zone.pvp, zoneEventTiles: zoneEventTiles.value.map(({ id, zoneId, type, positionX, positionY, teleport }) => ({ id, zoneId, type, positionX, positionY, teleport })), zoneObjects: zoneObjects.value.map(({ id, zoneId, objectId, depth, isRotated, positionX, positionY }) => ({ id, zoneId, objectId, depth, isRotated, positionX, positionY })) } @@ -233,130 +60,16 @@ function save() { } gameStore.connection?.emit('gm:zone_editor:zone:update', data, (response: Zone) => { - console.log('zone updated') zoneEditorStore.setZone(response) }) } -function clear() { - for (let y = 0; y < zoneTilemap.height; y++) { - if (!tileArray[y]) { - tileArray[y] = Array(zoneTilemap.width).fill('blank_tile') - } - for (let x = 0; x < zoneTilemap.width; x++) { - placeTile(zoneTilemap as Tilemap, tiles as TilemapLayer, x, y, 'blank_tile') - tileArray[y][x] = 'blank_tile' - } - } - - zoneEventTiles.value = [] - zoneObjects.value = [] -} - -function updateZoneObjectDepth(depth: number) { - zoneObjects.value = zoneObjects.value.map((object) => (object.id === selectedZoneObject.value?.id ? { ...object, depth } : object)) -} - -function deleteZoneObject(objectId: string) { - zoneObjects.value = zoneObjects.value.filter((object) => object.id !== objectId) -} - -function handleMove(objectId: string) { - const object = zoneObjects.value.find((obj) => obj.id === objectId) - if (object) { - movingZoneObject.value = object; - } -} - -function handleRotate(objectId: string) { - const object = zoneObjects.value.find((obj) => obj.id === objectId) - if (object) { - object.isRotated = !object.isRotated - } -} - -// watch zoneEditorStore.objectList and update originX and originY of objects in zoneObjects -watch( - objectList, - (newObjects) => { - zoneObjects.value = zoneObjects.value.map((zoneObject) => { - const updatedObject = newObjects.find((obj) => obj.id === zoneObject.objectId) - if (updatedObject) { - return { - ...zoneObject, - object: { - ...zoneObject.object, - originX: updatedObject.originX, - originY: updatedObject.originY - } - } - } - return zoneObject - }) - - // Update selectedObject if it exists - if (zoneEditorStore.selectedObject) { - const updatedObject = newObjects.find((obj) => obj.id === zoneEditorStore.selectedObject?.id) - if (updatedObject) { - zoneEditorStore.setSelectedObject({ - ...zoneEditorStore.selectedObject, - originX: updatedObject.originX, - originY: updatedObject.originY - }) - } - } - }, - { deep: true } -) - -const setSelectedZoneObject = (zoneObject: ZoneObject | null) => { - if (!zoneObject) return - if (zoneEditorStore.tool !== 'move') return - zoneEditorStore.setSelectedZoneObject(zoneObject) -} - onBeforeMount(async () => { await gameStore.fetchAllZoneAssets() await loadAssets(scene) - console.log('loaded assets') - - tileArray.forEach((row, y) => row.forEach((_, x) => placeTile(zoneTilemap, tiles, x, y, 'blank_tile'))) - - if (zone.value?.tiles) { - setAllTiles(zoneTilemap, tiles, zone.value.tiles) - tileArray = zone.value.tiles.map((row) => row.map((tileId) => tileId || 'blank_tile')) - - function handlePointerMove(pointer: Phaser.Input.Pointer) { - const { x: px, y: py } = scene.cameras.main.getWorldPoint(pointer.x, pointer.y) - const pointerTile = getTile(px, py, zoneTilemap as any) - if (pointerTile) { - console.log(pointerTile.x, pointerTile.y) - if(movingZoneObject.value) { - movingZoneObject.value.positionX = pointerTile.x - movingZoneObject.value.positionY = pointerTile.y - } - } - } - setTimeout(() => { - scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) - }) - } - - zoneEventTiles.value = zone.value?.zoneEventTiles ?? [] - zoneObjects.value = sortByIsometricDepth(zone.value?.zoneObjects ?? []) - - // Center camera - const centerY = (zoneTilemap.height * zoneTilemap.tileHeight) / 2 - const centerX = (zoneTilemap.width * zoneTilemap.tileWidth) / 2 - scene.cameras.main.centerOn(centerX, centerY) }) onUnmounted(() => { - zoneEventTiles.value = [] - zoneObjects.value = [] - tiles?.destroy() - zoneTilemap?.removeAllLayers() - zoneTilemap?.destroy() zoneEditorStore.reset() }) </script> diff --git a/src/components/gameMaster/zoneEditor/partials/TeleportModal.vue b/src/components/gameMaster/zoneEditor/partials/TeleportModal.vue index ec8d76e..bcdd865 100644 --- a/src/components/gameMaster/zoneEditor/partials/TeleportModal.vue +++ b/src/components/gameMaster/zoneEditor/partials/TeleportModal.vue @@ -1,9 +1,8 @@ <template> - <Modal :is-modal-open="true" @modal:close="() => zoneEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false"> + <Modal :is-modal-open="showTeleportModal" @modal:close="() => zoneEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false"> <template #modalHeader> <h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3> </template> - <template #modalBody> <div class="m-4"> <form method="post" @submit.prevent="" class="inline"> @@ -40,12 +39,13 @@ </template> <script setup lang="ts"> -import { onMounted, ref, watch } from 'vue' +import { computed, onMounted, ref, watch } from 'vue' import Modal from '@/components/utilities/Modal.vue' import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useGameStore } from '@/stores/gameStore' import type { Zone } from '@/types' +const showTeleportModal = computed(() => zoneEditorStore.tool === 'pencil' && zoneEditorStore.drawMode === 'teleport') const zoneEditorStore = useZoneEditorStore() const gameStore = useGameStore() diff --git a/src/components/gameMaster/zoneEditor/partials/Toolbar.vue b/src/components/gameMaster/zoneEditor/partials/Toolbar.vue index f138203..6315166 100644 --- a/src/components/gameMaster/zoneEditor/partials/Toolbar.vue +++ b/src/components/gameMaster/zoneEditor/partials/Toolbar.vue @@ -1,7 +1,7 @@ <template> <div class="flex justify-center p-5"> <div class="toolbar fixed bottom-0 left-0 m-3 rounded flex bg-gray solid border-solid border-2 border-gray-500 text-gray-300 p-1.5 px-3 h-10"> - <div ref="clickOutsideElement" class="tools flex gap-2.5" v-if="zoneEditorStore.zone"> + <div ref="toolbar" class="tools flex gap-2.5" v-if="zoneEditorStore.zone"> <button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': zoneEditorStore.tool === 'move' }" @click="handleClick('move')"> <img class="invert w-5 h-5" src="/assets/icons/zoneEditor/move.svg" alt="Move camera" /> <span :class="{ 'ml-2.5': zoneEditorStore.tool !== 'move' }">(M)</span> </button> @@ -83,22 +83,15 @@ <script setup lang="ts"> import { onBeforeUnmount, onMounted, ref } from 'vue' -import { useScene } from 'phavuer' -import { getTile } from '@/composables/zoneComposable' import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { onClickOutside } from '@vueuse/core' -import TilemapLayer = Phaser.Tilemaps.TilemapLayer const zoneEditorStore = useZoneEditorStore() -const props = defineProps({ - layer: Phaser.Tilemaps.TilemapLayer -}) -const scene = useScene() const emit = defineEmits(['move', 'eraser', 'pencil', 'paint', 'save', 'clear']) // track when clicked outside of toolbar items -const clickOutsideElement = ref(null) +const toolbar = ref(null) // track select state let selectPencilOpen = ref(false) @@ -119,51 +112,6 @@ function setEraserMode(value: string) { selectEraserOpen.value = false } -function clickTile(pointer: Phaser.Input.Pointer) { - if (zoneEditorStore.tool !== 'eraser' && zoneEditorStore.tool !== 'move' && zoneEditorStore.tool !== 'pencil' && zoneEditorStore.tool !== 'paint') return - if (pointer.event.shiftKey) return - - const px = scene.cameras.main.worldView.x + pointer.x - const py = scene.cameras.main.worldView.y + pointer.y - - const pointer_tile = getTile(px, py, props.layer as TilemapLayer) as Phaser.Tilemaps.Tile - if (!pointer_tile) return - - if (zoneEditorStore.tool === 'move') { - emit('move', pointer_tile) - } - - if (zoneEditorStore.tool === 'eraser') { - emit('eraser', pointer_tile) - } - - if (zoneEditorStore.tool === 'pencil') { - emit('pencil', pointer_tile) - } - - if (zoneEditorStore.tool === 'paint') { - emit('paint', pointer_tile) - } -} - -function drawTiles(pointer: Phaser.Input.Pointer) { - if (!pointer.isDown) return - clickTile(pointer) -} - -scene.input.on(Phaser.Input.Events.POINTER_UP, clickTile) -scene.input.on(Phaser.Input.Events.POINTER_MOVE, drawTiles) - -onMounted(() => { - addEventListener('keydown', initKeyShortcuts) -}) - -onBeforeUnmount(() => { - scene.input.off(Phaser.Input.Events.POINTER_UP, clickTile) - scene.input.off(Phaser.Input.Events.POINTER_MOVE, drawTiles) - removeEventListener('keydown', initKeyShortcuts) -}) - function handleClick(tool: string) { if (tool === 'settings') { zoneEditorStore.toggleSettingsModal() @@ -212,10 +160,17 @@ function initKeyShortcuts(event: KeyboardEvent) { } } -onClickOutside(clickOutsideElement, handleClickOutside) - function handleClickOutside() { selectPencilOpen.value = false selectEraserOpen.value = false } +onClickOutside(toolbar, handleClickOutside) + +onMounted(() => { + addEventListener('keydown', initKeyShortcuts) +}) + +onBeforeUnmount(() => { + removeEventListener('keydown', initKeyShortcuts) +}) </script> diff --git a/src/components/gameMaster/zoneEditor/partials/ZoneList.vue b/src/components/gameMaster/zoneEditor/partials/ZoneList.vue index 9777283..9e4b5f5 100644 --- a/src/components/gameMaster/zoneEditor/partials/ZoneList.vue +++ b/src/components/gameMaster/zoneEditor/partials/ZoneList.vue @@ -1,31 +1,28 @@ <template> <CreateZone v-if="zoneEditorStore.isCreateZoneModalShown" /> - - <Teleport to="body"> - <Modal @modal:close="() => zoneEditorStore.toggleZoneListModal()" :is-resizable="false" :is-modal-open="true" :modal-width="300" :modal-height="360"> - <template #modalHeader> - <h3 class="text-lg text-white">Zones</h3> - </template> - <template #modalBody> - <div class="my-4 mx-auto"> - <div class="text-center mb-4 px-2 flex gap-2.5"> - <button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="fetchZones">Refresh</button> - <button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="() => zoneEditorStore.toggleCreateZoneModal()">New</button> - </div> - <div class="relative p-2.5 cursor-pointer flex gap-y-2.5 gap-x-5 flex-wrap" v-for="(zone, index) in zoneEditorStore.zoneList" :key="zone.id"> - <div class="absolute left-0 top-0 w-full h-px bg-gray-500" v-if="index === 0"></div> - <div class="flex gap-3 items-center w-full" @click="() => loadZone(zone.id)"> - <span>{{ zone.name }}</span> - <span class="ml-auto gap-1 flex"> - <button class="btn-red w-11 h-11 z-50" @click.stop="() => deleteZone(zone.id)">X</button> - </span> - </div> - <div class="absolute left-0 bottom-0 w-full h-px bg-gray-500"></div> - </div> + <Modal :is-modal-open="zoneEditorStore.isZoneListModalShown" @modal:close="() => zoneEditorStore.toggleZoneListModal()" :is-resizable="false" :modal-width="300" :modal-height="360"> + <template #modalHeader> + <h3 class="text-lg text-white">Zones</h3> + </template> + <template #modalBody> + <div class="my-4 mx-auto"> + <div class="text-center mb-4 px-2 flex gap-2.5"> + <button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="fetchZones">Refresh</button> + <button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="() => zoneEditorStore.toggleCreateZoneModal()">New</button> </div> - </template> - </Modal> - </Teleport> + <div class="relative p-2.5 cursor-pointer flex gap-y-2.5 gap-x-5 flex-wrap" v-for="(zone, index) in zoneEditorStore.zoneList" :key="zone.id"> + <div class="absolute left-0 top-0 w-full h-px bg-gray-500" v-if="index === 0"></div> + <div class="flex gap-3 items-center w-full" @click="() => loadZone(zone.id)"> + <span>{{ zone.name }}</span> + <span class="ml-auto gap-1 flex"> + <button class="btn-red w-11 h-11 z-50" @click.stop="() => deleteZone(zone.id)">X</button> + </span> + </div> + <div class="absolute left-0 bottom-0 w-full h-px bg-gray-500"></div> + </div> + </div> + </template> + </Modal> </template> <script setup lang="ts"> diff --git a/src/components/gameMaster/zoneEditor/partials/ZoneSettings.vue b/src/components/gameMaster/zoneEditor/partials/ZoneSettings.vue index 1e8a7e8..f6f305a 100644 --- a/src/components/gameMaster/zoneEditor/partials/ZoneSettings.vue +++ b/src/components/gameMaster/zoneEditor/partials/ZoneSettings.vue @@ -41,15 +41,15 @@ import { useZoneEditorStore } from '@/stores/zoneEditorStore' const zoneEditorStore = useZoneEditorStore() -zoneEditorStore.setZoneName(zoneEditorStore.zone.name) -zoneEditorStore.setZoneWidth(zoneEditorStore.zone.width) -zoneEditorStore.setZoneHeight(zoneEditorStore.zone.height) -zoneEditorStore.setZonePvp(zoneEditorStore.zone.pvp) +zoneEditorStore.setZoneName(zoneEditorStore.zone?.name) +zoneEditorStore.setZoneWidth(zoneEditorStore.zone?.width) +zoneEditorStore.setZoneHeight(zoneEditorStore.zone?.height) +zoneEditorStore.setZonePvp(zoneEditorStore.zone?.pvp) -const name = ref(zoneEditorStore.zoneSettings.name) -const width = ref(zoneEditorStore.zoneSettings.width) -const height = ref(zoneEditorStore.zoneSettings.height) -const pvp = ref(zoneEditorStore.zoneSettings.pvp) +const name = ref(zoneEditorStore.zoneSettings?.name) +const width = ref(zoneEditorStore.zoneSettings?.width) +const height = ref(zoneEditorStore.zoneSettings?.height) +const pvp = ref(zoneEditorStore.zoneSettings?.pvp) watch(name, (value) => { zoneEditorStore.setZoneName(value) diff --git a/src/components/zone/Tiles.vue b/src/components/zone/Tiles.vue index c1aae44..2c43527 100644 --- a/src/components/zone/Tiles.vue +++ b/src/components/zone/Tiles.vue @@ -52,16 +52,15 @@ function createTileLayer() { } function createTileArray() { - return Array.from({ length: zoneStore.zone?.width ?? 0 }, () => Array.from({ length: zoneStore.zone?.height ?? 0 }, () => 'blank_tile')) + return Array.from({ length: zoneTilemap.height || 0 }, () => Array.from({ length: zoneTilemap.width || 0 }, () => 'blank_tile')) } onBeforeMount(() => { - if (zoneStore.zone?.tiles) { - setAllTiles(zoneTilemap, tiles, zoneStore.zone.tiles) - tileArray = zoneStore.zone.tiles.map((row) => row.map((tileId) => tileId || 'blank_tile')) - } else { - tileArray.forEach((row, y) => row.forEach((_, x) => placeTile(zoneTilemap, tiles, x, y, 'blank_tile'))) + if (!zoneStore.zone?.tiles) { + return } + setAllTiles(zoneTilemap, tiles, zoneStore.zone.tiles) + tileArray = zoneStore.zone.tiles.map((row) => row.map((tileId) => tileId || 'blank_tile')) }) onBeforeUnmount(() => { diff --git a/src/composables/zoneComposable.ts b/src/composables/zoneComposable.ts index 5846105..f3bbde3 100644 --- a/src/composables/zoneComposable.ts +++ b/src/composables/zoneComposable.ts @@ -2,15 +2,16 @@ import config from '@/config' import Tilemap = Phaser.Tilemaps.Tilemap import TilemapLayer = Phaser.Tilemaps.TilemapLayer import Tileset = Phaser.Tilemaps.Tileset +import Tile = Phaser.Tilemaps.Tile import { useGameStore } from '@/stores/gameStore' -export function getTile(x: number, y: number, layer: Phaser.Tilemaps.TilemapLayer): Phaser.Tilemaps.Tile | undefined { +export function getTile(x: number, y: number, layer: TilemapLayer): Tile | undefined { const tile: Phaser.Tilemaps.Tile = layer.getTileAtWorldXY(x, y) if (!tile) return undefined return tile } -export function tileToWorldXY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number, pos_y: number) { +export function tileToWorldXY(layer: TilemapLayer, pos_x: number, pos_y: number) { const worldPoint = layer.tileToWorldXY(pos_x, pos_y) const positionX = worldPoint.x + config.tile_size.y const positionY = worldPoint.y @@ -18,7 +19,7 @@ export function tileToWorldXY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number return { positionX, positionY } } -export function tileToWorldX(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number, pos_y: number): number { +export function tileToWorldX(layer: TilemapLayer, pos_x: number, pos_y: number): number { const worldPoint = layer.tileToWorldXY(pos_x, pos_y) return worldPoint.x + config.tile_size.x / 2 } @@ -58,6 +59,10 @@ export const sortByIsometricDepth = <T extends { positionX: number; positionY: n }) } +export const clearAssets = (scene: Phaser.Scene) => { + +} + export const loadAssets = (scene: Phaser.Scene): Promise<void> => { return new Promise((resolve) => { const gameStore = useGameStore() diff --git a/src/stores/zoneEditorStore.ts b/src/stores/zoneEditorStore.ts index 29fa7e3..8a10686 100644 --- a/src/stores/zoneEditorStore.ts +++ b/src/stores/zoneEditorStore.ts @@ -12,7 +12,7 @@ export type TeleportSettings = { export const useZoneEditorStore = defineStore('zoneEditor', { state: () => { return { - active: false, + active: true, zone: null as Zone | null, tool: 'move', drawMode: 'tile', @@ -114,8 +114,8 @@ export const useZoneEditorStore = defineStore('zoneEditor', { setTeleportSettings(teleportSettings: TeleportSettings) { this.teleportSettings = teleportSettings }, - reset() { - // this.zone = null + reset(resetZone = false) { + if (resetZone) this.zone = null this.zoneList = [] this.tileList = [] this.objectList = []