diff --git a/index.html b/index.html index 742d964..7649e46 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ <head> <meta charset="UTF-8"> <link rel="icon" href="/favicon.ico"> - <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/> + <meta name="viewport" content="width=device-width"> <title>Sylvan Quest - Play</title> </head> <body> diff --git a/package-lock.json b/package-lock.json index 83bde7a..aa49034 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.41", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", + "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", "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.80.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.1.tgz", + "integrity": "sha512-9lBwDZ7j3y/1DKj5Ec249EVGo5CVpwnzIyIj+cqlCjKkApLnzsJ/l9SnV4YnORvW9dQwQN+gQvh/mFZ8CnDs7Q==", "dev": true, "license": "MIT", "dependencies": { diff --git a/src/App.vue b/src/App.vue index 8717913..c4d4ede 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,8 +1,6 @@ <template> - <div class="overflow-hidden"> - <Notifications /> - <component :is="currentScreen" /> - </div> + <Notifications /> + <component :is="currentScreen" /> </template> <script setup lang="ts"> @@ -28,4 +26,4 @@ const currentScreen = computed(() => { // Disable right click addEventListener('contextmenu', (event) => event.preventDefault()) -</script> \ No newline at end of file +</script> diff --git a/src/assets/scss/main.scss b/src/assets/scss/main.scss index bd77ab3..fcba8d7 100644 --- a/src/assets/scss/main.scss +++ b/src/assets/scss/main.scss @@ -12,7 +12,7 @@ //Globals body { - @apply bg-black m-0 select-none overscroll-none overflow-hidden; + @apply bg-black m-0 select-none; -ms-overflow-style: none; scrollbar-width: none; diff --git a/src/components/Effects.vue b/src/components/Effects.vue index 289fd47..cb1d529 100644 --- a/src/components/Effects.vue +++ b/src/components/Effects.vue @@ -1,6 +1,5 @@ <template> - <Scene name="effects" @preload="preloadScene" @create="createScene" @update="updateScene"> - </Scene> + <Scene name="effects" @preload="preloadScene" @create="createScene" @update="updateScene"> </Scene> </template> <script setup lang="ts"> @@ -12,6 +11,8 @@ 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 @@ -48,7 +49,7 @@ const createDayNightCycle = (scene: Phaser.Scene) => { const updateDayNightCycle = (time: number) => { if (!dayNightCycle.value) return - const darkness = Math.sin((time % dayNightDuration) / dayNightDuration * Math.PI) * maxDarkness + const darkness = Math.sin(((time % dayNightDuration) / dayNightDuration) * Math.PI) * maxDarkness dayNightCycle.value.clear() dayNightCycle.value.fillStyle(0x000000, darkness) dayNightCycle.value.fillRect(0, 0, window.innerWidth, window.innerHeight) @@ -85,7 +86,7 @@ const createFogEffect = (scene: Phaser.Scene) => { const updateFogEffect = () => { if (fogSprite.value) { // Example: Oscillate fog opacity - const fogOpacity = (Math.sin(Date.now() / 5000) + 1) / 2 * 0.3 + const fogOpacity = ((Math.sin(Date.now() / 5000) + 1) / 2) * 0.3 fogSprite.value.setAlpha(fogOpacity) } } @@ -106,4 +107,4 @@ defineExpose(controlEffects) onBeforeUnmount(() => { if (sceneRef.value) sceneRef.value.scene.remove('effects') }) -</script> \ No newline at end of file +</script> diff --git a/src/components/gameMaster/GmTools.vue b/src/components/gameMaster/GmTools.vue index 565062e..4bc7bc5 100644 --- a/src/components/gameMaster/GmTools.vue +++ b/src/components/gameMaster/GmTools.vue @@ -20,7 +20,7 @@ import { onMounted, ref } from 'vue' const zoneEditorStore = useZoneEditorStore() const gameStore = useGameStore() const modalWidth = ref(200) -const modalHeight = ref(180) +const modalHeight = ref(170) let posXY = ref({ x: 0, y: 0 }) diff --git a/src/components/gameMaster/zoneEditor/EventTiles.vue b/src/components/gameMaster/zoneEditor/EventTiles.vue new file mode 100644 index 0000000..6c45e35 --- /dev/null +++ b/src/components/gameMaster/zoneEditor/EventTiles.vue @@ -0,0 +1,14 @@ +<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> diff --git a/src/components/gameMaster/zoneEditor/Objects.vue b/src/components/gameMaster/zoneEditor/Objects.vue new file mode 100644 index 0000000..152cd5b --- /dev/null +++ b/src/components/gameMaster/zoneEditor/Objects.vue @@ -0,0 +1,126 @@ +<template> + <SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" /> + <Image + v-for="object in zoneEditorStore.zone?.zoneObjects" + v-bind="getObjectImageProps(object)" + @pointerup="() => selectedZoneObject = object" + /> +</template> + +<script setup lang="ts"> +import { uuidv4 } from '@/utilities' +import { calculateIsometricDepth, getTile, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' +import { Image, useScene } from 'phavuer' +import { useZoneEditorStore } from '@/stores/zoneEditorStore' +import type { ZoneObject } from '@/types' +import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue' +import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue' + +const scene = useScene() +const zoneEditorStore = useZoneEditorStore() +const selectedZoneObject = ref<ZoneObject | null>(null) + +const props = defineProps<{ + tilemap: Phaser.Tilemaps.Tilemap +}>() + +function getObjectImageProps(object: ZoneObject) { + return { + // alpha: object.id === movingZoneObject.value?.id ? .5 : 1, + depth: calculateIsometricDepth(object.positionX, object.positionY, object.object.frameWidth, object.object.frameHeight), + tint: selectedZoneObject.value?.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), + flipX: object.isRotated, + texture: object.object.id, + originY: Number(object.object.originX), + originX: Number(object.object.originY) + } +} + +function addZoneObject(pointer: Phaser.Input.Pointer) { + if (!zoneEditorStore.zone) return + + // Check if tool is pencil + if (zoneEditorStore.tool !== 'pencil') return + + // Check if draw mode is object + if (zoneEditorStore.drawMode !== 'object') return + + // Check if left mouse button is pressed + if (!pointer.isDown) return + + // Check if there is a tile @TODO chekc if props.tilemap words + const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) + if (!tile) return + + // Check if there is a selected object + if (!zoneEditorStore.selectedObject) return + + // Check if object already exists on position + const existingObject = zoneEditorStore.zone?.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y) + if (existingObject) return + + const newObject = { + id: uuidv4(), + zoneId: zoneEditorStore.zone.id, + zone: zoneEditorStore.zone, + object: zoneEditorStore.selectedObject, + depth: 0, + isRotated: false, + positionX: tile.x, + positionY: tile.y + } + + // Add new object to zoneObjects + zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.concat(newObject as ZoneObject) +} + +onBeforeMount(() => { + scene.input.on(Phaser.Input.Events.POINTER_DOWN, addZoneObject) + scene.input.on(Phaser.Input.Events.POINTER_MOVE, addZoneObject) +}) + +onBeforeUnmount(() => { + scene.input.off(Phaser.Input.Events.POINTER_DOWN, addZoneObject) + scene.input.off(Phaser.Input.Events.POINTER_MOVE, addZoneObject) +}) + +// watch zoneEditorStore.objectList and update originX and originY of objects in zoneObjects +watch( + zoneEditorStore.objectList, + (newObjects) => { + // Check if zoneEditorStore.zone is set + if (!zoneEditorStore.zone) return + + // Update zoneObjects + zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.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's set + 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 } +) +</script> diff --git a/src/components/gameMaster/zoneEditor/Tiles.vue b/src/components/gameMaster/zoneEditor/Tiles.vue new file mode 100644 index 0000000..77e898d --- /dev/null +++ b/src/components/gameMaster/zoneEditor/Tiles.vue @@ -0,0 +1,91 @@ +<template> + <Controls :layer="tiles" :depth="0" /> +</template> + +<script setup lang="ts"> +import config from '@/config' +import { useScene } from 'phavuer' +import { useGameStore } from '@/stores/gameStore' +import { useZoneEditorStore } from '@/stores/zoneEditorStore' +import { onBeforeMount, onBeforeUnmount } from 'vue' +import { getTile, placeTile, setAllTiles } from '@/composables/zoneComposable' +import Controls from '@/components/utilities/Controls.vue' + +const emit = defineEmits(['tilemap:create']) + +const scene = useScene() +const gameStore = useGameStore() +const zoneEditorStore = useZoneEditorStore() + +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 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) + 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 draw mode is tile + if (zoneEditorStore.drawMode !== 'tile') return + + // Check if left mouse button is pressed + if (!pointer.isDown) return + + // Check if there is a tile + const tile = getTile(tiles, pointer.worldX, pointer.worldY) + if (!tile) return + + // Check if there is a selected tile + if (!zoneEditorStore.selectedTile) return + + placeTile(zoneTilemap, tiles, 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_MOVE, handleTileClick) +}) + +onBeforeUnmount(() => { + scene.input.off(Phaser.Input.Events.POINTER_MOVE, 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/SelectedZoneObject.vue b/src/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue index 5cb1fc7..37d1a55 100644 --- a/src/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue +++ b/src/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue @@ -1,5 +1,5 @@ <template> - <div class="flex flex-col items-center py-5 px-3 fixed bottom-14 right-0" v-if="zoneEditorStore.selectedZoneObject"> + <div class="flex flex-col items-center py-5 px-3 fixed bottom-14 right-0"> <div class="self-end mt-2 flex gap-2"> <div> <label class="mb-1.5 font-titles block text-sm text-gray-700 hidden" for="depth">Depth</label> @@ -42,7 +42,7 @@ const handleRotate = () => { } const handleMove = () => { - emit('move', zoneEditorStore.selectedZoneObject?.id); + emit('move', zoneEditorStore.selectedZoneObject?.id) } const handleDelete = () => { 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..bc8c0b0 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']) +const emit = defineEmits(['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() @@ -176,16 +124,16 @@ function handleClick(tool: string) { } function cycleToolMode(tool: 'pencil' | 'eraser') { - const modes = ['tile', 'object', 'teleport', 'blocking tile']; - const currentMode = tool === 'pencil' ? zoneEditorStore.drawMode : zoneEditorStore.eraserMode; - const currentIndex = modes.indexOf(currentMode); - const nextIndex = (currentIndex + 1) % modes.length; - const nextMode = modes[nextIndex]; + const modes = ['tile', 'object', 'teleport', 'blocking tile'] + const currentMode = tool === 'pencil' ? zoneEditorStore.drawMode : zoneEditorStore.eraserMode + const currentIndex = modes.indexOf(currentMode) + const nextIndex = (currentIndex + 1) % modes.length + const nextMode = modes[nextIndex] if (tool === 'pencil') { - setDrawMode(nextMode); + setDrawMode(nextMode) } else { - setEraserMode(nextMode); + setEraserMode(nextMode) } } @@ -203,19 +151,26 @@ function initKeyShortcuts(event: KeyboardEvent) { } if (keyActions.hasOwnProperty(event.key)) { - const tool = keyActions[event.key]; + const tool = keyActions[event.key] if ((tool === 'pencil' || tool === 'eraser') && zoneEditorStore.tool === tool) { - cycleToolMode(tool); + cycleToolMode(tool) } else { - handleClick(tool); + handleClick(tool) } } } -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/gui/Chat.vue b/src/components/gui/Chat.vue index 66d4dff..dbdd9e3 100644 --- a/src/components/gui/Chat.vue +++ b/src/components/gui/Chat.vue @@ -2,7 +2,7 @@ <div class="w-full md:min-w-[350px] max-w-[750px] flex flex-col absolute left-1/2 -translate-x-1/2 bottom-5"> <div ref="chatWindow" class="w-full overflow-auto h-32 mb-5 bg-gray rounded-md border-2 border-solid border-gray-500 text-gray-300" v-show="gameStore.uiSettings.isChatOpen"> <div v-for="message in chats" class="flex-col py-2 items-center p-3"> - <span class="text-ellipsis overflow-hidden whitespace-nowrap text-sm" :class="{'text-cyan-300': gameStore.character?.role == 'gm'}">{{ message.character.name }}</span> + <span class="text-ellipsis overflow-hidden whitespace-nowrap text-sm" :class="{ 'text-cyan-300': gameStore.character?.role == 'gm' }">{{ message.character.name }}</span> <p class="text-gray-50 m-0">{{ message.message }}</p> </div> </div> diff --git a/src/components/gui/ExpBar.vue b/src/components/gui/ExpBar.vue index b5b6215..75bdb13 100644 --- a/src/components/gui/ExpBar.vue +++ b/src/components/gui/ExpBar.vue @@ -1,9 +1,7 @@ -<template> - -</template> +<template></template> <script setup lang="ts"> import { useGameStore } from '@/stores/gameStore' const gameStore = useGameStore() -</script> \ No newline at end of file +</script> diff --git a/src/components/gui/Menu.vue b/src/components/gui/Menu.vue index a450751..8e8d2c4 100644 --- a/src/components/gui/Menu.vue +++ b/src/components/gui/Menu.vue @@ -53,5 +53,5 @@ import { useGameStore } from '@/stores/gameStore' const gameStore = useGameStore() -let characterLevel = gameStore.character?.level.toString().padStart(2, '0'); +let characterLevel = gameStore.character?.level.toString().padStart(2, '0') </script> diff --git a/src/components/zone/Objects.vue b/src/components/zone/Objects.vue index 0298637..cbb347f 100644 --- a/src/components/zone/Objects.vue +++ b/src/components/zone/Objects.vue @@ -1,6 +1,5 @@ <template> - <Image v-for="object in zoneStore.zone?.zoneObjects" :key="object.id" v-bind="getObjectImageProps(object)" /> - <!-- <Text v-for="object in zoneStore.zone?.zoneObjects" :key="object.id" :depth="99999" :text="Math.ceil(calculateIsometricDepth(object.positionX, object.positionY, object.object.frameWidth, object.object.frameHeight))" v-bind="getObjectProps(object)" />--> + <Image v-for="object in zoneStore.zone?.zoneObjects" v-bind="getObjectImageProps(object)" /> </template> <script setup lang="ts"> 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/pointerHandlers/useGamePointerHandlers.ts b/src/composables/pointerHandlers/useGamePointerHandlers.ts index cf4f987..9d66147 100644 --- a/src/composables/pointerHandlers/useGamePointerHandlers.ts +++ b/src/composables/pointerHandlers/useGamePointerHandlers.ts @@ -9,7 +9,7 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema const dragThreshold = 5 // pixels function updateWaypoint(worldX: number, worldY: number) { - const pointerTile = getTile(worldX, worldY, layer) + const pointerTile = getTile(layer, worldX, worldY) if (pointerTile) { const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y) waypoint.value = { @@ -46,7 +46,7 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y) if (distance <= dragThreshold) { - const pointerTile = getTile(pointer.worldX, pointer.worldY, layer) + const pointerTile = getTile(layer, pointer.worldX, pointer.worldY) if (pointerTile) { gameStore.connection?.emit('character:initMove', { positionX: pointerTile.x, diff --git a/src/composables/pointerHandlers/useZoneEditorPointerHandlers.ts b/src/composables/pointerHandlers/useZoneEditorPointerHandlers.ts index f7109e2..db1c0a3 100644 --- a/src/composables/pointerHandlers/useZoneEditorPointerHandlers.ts +++ b/src/composables/pointerHandlers/useZoneEditorPointerHandlers.ts @@ -11,7 +11,7 @@ export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser. function updateWaypoint(pointer: Phaser.Input.Pointer) { const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y) - const pointerTile = getTile(px, py, layer) + const pointerTile = getTile(layer, px, py) if (pointerTile) { const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y) diff --git a/src/composables/zoneComposable.ts b/src/composables/zoneComposable.ts index 5846105..17566f8 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 { - const tile: Phaser.Tilemaps.Tile = layer.getTileAtWorldXY(x, y) +export function getTile(layer: TilemapLayer | Tilemap, x: number, y: number): Tile | undefined { + const 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 } @@ -35,8 +36,8 @@ export function placeTile(zone: Tilemap, layer: TilemapLayer, x: number, y: numb } export function setAllTiles(zone: Tilemap, layer: TilemapLayer, tiles: string[][]) { - tiles.forEach((row, y) => { - row.forEach((tile, x) => { + tiles.forEach((row: string[], y: number) => { + row.forEach((tile: string, x: number) => { placeTile(zone, layer, x, y, tile) }) }) @@ -58,6 +59,8 @@ 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/screens/Characters.vue b/src/screens/Characters.vue index f82c048..f048449 100644 --- a/src/screens/Characters.vue +++ b/src/screens/Characters.vue @@ -5,12 +5,7 @@ <div class="filler"></div> <div class="flex gap-14 w-full max-h-[650px] overflow-x-auto" v-if="!isLoading"> <!-- CHARACTER LIST --> - <div - v-for="character in characters" - :key="character.id" - class="group first:ml-auto last:mr-auto m-4 w-[170px] h-[275px] flex flex-col shrink-0 relative shadow-character" - :class="{ active: selected_character == character.id }" - > + <div v-for="character in characters" :key="character.id" class="group first:ml-auto last:mr-auto m-4 w-[170px] h-[275px] flex flex-col shrink-0 relative shadow-character" :class="{ active: selected_character == character.id }"> <img src="/assets/ui-box-outer.svg" class="absolute w-full h-full" /> <img src="/assets/ui-box-inner.svg" class="absolute left-2 bottom-2 w-[calc(100%_-_16px)] h-[calc(100%_-_40px)]" /> <input class="opacity-0 h-full w-full absolute m-0 z-10" type="radio" :id="character.id" name="character" :value="character.id" v-model="selected_character" /> @@ -93,8 +88,9 @@ <h3 class="m-0 font-medium text-white">Delete character?</h3> </template> <template #modalBody> - <p class="mt-0 mb-5 text-white text-lg">Do you want to permanently delete - <span class="font-extrabold text-white">{{ deletingCharacter.name }}</span>? + <p class="mt-0 mb-5 text-white text-lg"> + Do you want to permanently delete <span class="font-extrabold text-white">{{ deletingCharacter.name }}</span + >? </p> </template> </ConfirmationModal> diff --git a/src/screens/Login.vue b/src/screens/Login.vue index 40e0278..acbb4fd 100644 --- a/src/screens/Login.vue +++ b/src/screens/Login.vue @@ -16,12 +16,12 @@ <input class="input-field xs:min-w-[350px] min-w-64" id="username-login" v-model="username" type="text" name="username" placeholder="Username" required autofocus /> <div class="relative"> <input class="input-field xs:min-w-[350px] min-w-64" id="password-login" v-model="password" :type="showPassword ? 'text' : 'password'" name="password" placeholder="Password" required /> - <button type="button" @click.prevent="showPassword = !showPassword" :class="{'eye-open': showPassword}" class="bg-[url('/assets/icons/eye.svg')] p-0 absolute right-3 w-4 h-3 top-1/2 -translate-y-1/2 bg-no-repeat"></button> + <button type="button" @click.prevent="showPassword = !showPassword" :class="{ 'eye-open': showPassword }" class="bg-[url('/assets/icons/eye.svg')] p-0 absolute right-3 w-4 h-3 top-1/2 -translate-y-1/2 bg-no-repeat"></button> </div> <span v-if="loginError" class="text-red-200 text-xs absolute top-full mt-1">{{ loginError }}</span> </div> <button class="inline-flex self-end p-0 text-cyan-300 text-base">Forgot password?</button> - <button class="btn-cyan px-0 xs:w-full" type="submit">Play now</button> + <button class="btn-cyan px-0 xs:w-full" type="submit">Play now</button> <!-- Divider shape --> <div class="absolute w-40 h-0.5 -bottom-8 left-1/2 -translate-x-1/2 flex justify-between"> @@ -42,11 +42,11 @@ <input class="input-field xs:min-w-[350px] min-w-64" id="username-register" v-model="username" type="text" name="username" placeholder="Username" required autofocus /> <div class="relative"> <input class="input-field xs:min-w-[350px] min-w-64" id="password-register" v-model="password" :type="showPassword ? 'text' : 'password'" name="password" placeholder="Password" required /> - <button type="button" @click.prevent="showPassword = !showPassword" :class="{'eye-open': showPassword}" class="bg-[url('/assets/icons/eye.svg')] p-0 absolute right-3 w-4 h-3 top-1/2 -translate-y-1/2 bg-no-repeat"></button> + <button type="button" @click.prevent="showPassword = !showPassword" :class="{ 'eye-open': showPassword }" class="bg-[url('/assets/icons/eye.svg')] p-0 absolute right-3 w-4 h-3 top-1/2 -translate-y-1/2 bg-no-repeat"></button> </div> <span v-if="loginError" class="text-red-200 text-xs absolute top-full mt-1">{{ loginError }}</span> </div> - <button class="btn-cyan xs:w-full" type="submit">Register now</button> + <button class="btn-cyan xs:w-full" type="submit">Register now</button> <!-- Divider shape --> <div class="absolute w-40 h-0.5 -bottom-8 left-1/2 -translate-x-1/2 flex justify-between"> diff --git a/src/screens/ZoneEditor.vue b/src/screens/ZoneEditor.vue index 9e8c6ff..c407878 100644 --- a/src/screens/ZoneEditor.vue +++ b/src/screens/ZoneEditor.vue @@ -5,7 +5,7 @@ <Game :config="gameConfig" @create="createGame"> <Scene name="main" @preload="preloadScene" @create="createScene"> - <ZoneEditor v-if="isLoaded" :key="JSON.stringify(`${zoneEditorStore.zone?.id}_${zoneEditorStore.zone?.createdAt}_${zoneEditorStore.zone?.updatedAt}`)" /> + <ZoneEditor v-if="isLoaded" :key="JSON.stringify(`${zoneEditorStore.zone?.id}_${zoneEditorStore.zone?.createdAt}_${zoneEditorStore.zone?.updatedAt}`)" /> </Scene> </Game> </div> diff --git a/src/stores/zoneEditorStore.ts b/src/stores/zoneEditorStore.ts index 29fa7e3..e3d3478 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', @@ -22,7 +22,6 @@ export const useZoneEditorStore = defineStore('zoneEditor', { objectList: [] as Object[], selectedTile: null as Tile | null, selectedObject: null as Object | null, - selectedZoneObject: null as ZoneObject | null, objectDepth: 0, isTileListModalShown: false, isObjectListModalShown: false, @@ -95,9 +94,6 @@ export const useZoneEditorStore = defineStore('zoneEditor', { setSelectedObject(object: any) { this.selectedObject = object }, - setSelectedZoneObject(zoneObject: ZoneObject | null) { - this.selectedZoneObject = zoneObject - }, setObjectDepth(depth: number) { this.objectDepth = depth }, @@ -114,8 +110,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 = [] @@ -123,7 +119,6 @@ export const useZoneEditorStore = defineStore('zoneEditor', { this.drawMode = 'tile' this.selectedTile = null this.selectedObject = null - this.selectedZoneObject = null this.objectDepth = 0 this.isSettingsModalShown = false this.isZoneListModalShown = false diff --git a/src/types.ts b/src/types.ts index e721151..0c73dcb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -221,4 +221,4 @@ export type WorldSettings = { isRainEnabled: boolean isFogEnabled: boolean fogDensity: number -} \ No newline at end of file +}