Refactoring of modalShown booleans

This commit is contained in:
Andrei 2025-01-25 23:27:15 -06:00
parent 14aa696197
commit 791830fd6f
23 changed files with 377 additions and 448 deletions

View File

@ -2,7 +2,7 @@
<Debug /> <Debug />
<Notifications /> <Notifications />
<BackgroundImageLoader /> <BackgroundImageLoader />
<GmPanel v-if="gameStore.character?.role === 'gm'" /> <GmPanel v-if="gameStore.character?.role === 'gm'" @open-map-editor="isEditorShown = true"/>
<component :is="currentScreen" /> <component :is="currentScreen" />
</template> </template>
@ -17,24 +17,26 @@ import BackgroundImageLoader from '@/components/utilities/BackgroundImageLoader.
import Debug from '@/components/utilities/Debug.vue' import Debug from '@/components/utilities/Debug.vue'
import Notifications from '@/components/utilities/Notifications.vue' import Notifications from '@/components/utilities/Notifications.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, ref, useTemplateRef, watch } from 'vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { computed, watch } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditor = useMapEditorComposable()
const isEditorShown = ref(false)
const currentScreen = computed(() => { const currentScreen = computed(() => {
if (!gameStore.game.isLoaded) return Loading if (!gameStore.game.isLoaded) return Loading
if (!gameStore.connection) return Login if (!gameStore.connection) return Login
if (!gameStore.token) return Login if (!gameStore.token) return Login
if (!gameStore.character) return Characters if (!gameStore.character) return Characters
if (mapEditor.active.value) return MapEditor if (isEditorShown.value) return MapEditor
return Game return Game
}) })
// Watch mapEditor.active and empty gameStore.game.loadedAssets // Watch mapEditor.active and empty gameStore.game.loadedAssets
watch( watch(
() => mapEditor.active.value, () => isEditorShown.value,
() => { () => {
gameStore.game.loadedTextures = [] gameStore.game.loadedTextures = []
} }

View File

@ -68,7 +68,7 @@ export type Map = {
name: string name: string
width: number width: number
height: number height: number
tiles: any | null tiles: string[][]
pvp: boolean pvp: boolean
mapEffects: MapEffect[] mapEffects: MapEffect[]
mapEventTiles: MapEventTile[] mapEventTiles: MapEventTile[]
@ -105,7 +105,7 @@ export enum MapEventTileType {
export type MapEventTile = { export type MapEventTile = {
id: UUID id: UUID
map: Map mapId: UUID
type: MapEventTileType type: MapEventTileType
positionX: number positionX: number
positionY: number positionY: number

View File

@ -147,9 +147,11 @@ watch(
) )
onMounted(async () => { onMounted(async () => {
let character = props.mapCharacter.character
const characterTypeStorage = new CharacterTypeStorage() const characterTypeStorage = new CharacterTypeStorage()
const spriteId = await characterTypeStorage.getSpriteId(props.mapCharacter.character.characterType!) const spriteId = await characterTypeStorage.getSpriteId(character.characterType!)
if (!spriteId) return if (!spriteId) return
charSpriteId.value = spriteId charSpriteId.value = spriteId
@ -161,14 +163,14 @@ onMounted(async () => {
charContainer.value!.setName(props.mapCharacter.character!.name) charContainer.value!.setName(props.mapCharacter.character!.name)
if (props.mapCharacter.character.id === gameStore.character!.id) { if (character.id === gameStore.character!.id) {
mapStore.setCharacterLoaded(true) mapStore.setCharacterLoaded(true)
// #146 : Set camera position to character, need to be improved still // #146 : Set camera position to character, need to be improved still
scene.cameras.main.startFollow(charContainer.value as Phaser.GameObjects.Container) scene.cameras.main.startFollow(charContainer.value as Phaser.GameObjects.Container)
} }
updatePosition(props.mapCharacter.character.positionX, props.mapCharacter.character.positionY, props.mapCharacter.character.rotation) updatePosition(character.positionX, character.positionY, character.rotation)
}) })
onUnmounted(() => { onUnmounted(() => {

View File

@ -4,10 +4,10 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import type { UUID } from '@/application/types' import type { UUID, Map as MapT} from '@/application/types'
import { unduplicateArray } from '@/application/utilities' import { unduplicateArray } from '@/application/utilities'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
import { FlattenMapArray, loadMapTilesIntoScene, setLayerTiles } from '@/composables/mapComposable' import { loadMapTilesIntoScene, setLayerTiles } from '@/composables/mapComposable'
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
@ -23,10 +23,10 @@ const mapStorage = new MapStorage()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>() const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>() const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
function createTileMap(mapData: any) { function createTileMap(map: MapT) {
const mapConfig = new Phaser.Tilemaps.MapData({ const mapConfig = new Phaser.Tilemaps.MapData({
width: mapData?.width, width: map.width,
height: mapData?.height, height: map.height,
tileWidth: config.tile_size.width, tileWidth: config.tile_size.width,
tileHeight: config.tile_size.height, tileHeight: config.tile_size.height,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC, orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
@ -39,7 +39,7 @@ function createTileMap(mapData: any) {
} }
function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap, mapData: any) { function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap, mapData: any) {
const tilesArray = unduplicateArray(FlattenMapArray(mapData?.tiles ?? [])) const tilesArray = unduplicateArray(mapData?.tiles.flat())
const tilesetImages = tilesArray.map((tile: string, index: number) => { const tilesetImages = tilesArray.map((tile: string, index: number) => {
return currentTileMap.addTilesetImage(tile, tile, config.tile_size.width, config.tile_size.height, 1, 2, index + 1, { x: 0, y: -config.tile_size.height }) return currentTileMap.addTilesetImage(tile, tile, config.tile_size.width, config.tile_size.height, 1, 2, index + 1, { x: 0, y: -config.tile_size.height })
@ -58,9 +58,10 @@ function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap, mapData: any)
loadMapTilesIntoScene(mapStore.mapId as UUID, scene) loadMapTilesIntoScene(mapStore.mapId as UUID, scene)
.then(() => mapStorage.get(mapStore.mapId)) .then(() => mapStorage.get(mapStore.mapId))
.then((mapData) => { .then((mapData) => {
if (!mapData || !mapData?.tiles) return
tileMap.value = createTileMap(mapData) tileMap.value = createTileMap(mapData)
tileLayer.value = createTileLayer(tileMap.value, mapData) tileLayer.value = createTileLayer(tileMap.value, mapData)
setLayerTiles(tileMap.value, tileLayer.value, mapData?.tiles) setLayerTiles(tileMap.value, tileLayer.value, mapData.tiles)
}) })
.catch((error) => console.error('Failed to initialize map:', error)) .catch((error) => console.error('Failed to initialize map:', error))

View File

@ -6,7 +6,7 @@
<button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Users</button> <button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Users</button>
<button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Chats</button> <button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Chats</button>
<button @mousedown.stop class="btn-cyan active py-1.5 px-4 min-w-24">Asset manager</button> <button @mousedown.stop class="btn-cyan active py-1.5 px-4 min-w-24">Asset manager</button>
<button class="btn-cyan py-1.5 px-4 min-w-24" type="button" @click="() => mapEditor.toggleActive()">Map editor</button> <button class="btn-cyan py-1.5 px-4 min-w-24" type="button" @click="$emit('open-map-editor')">Map editor</button>
</div> </div>
</template> </template>
<template #modalBody> <template #modalBody>
@ -24,6 +24,7 @@ import { useGameStore } from '@/stores/gameStore'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { ref } from 'vue' import { ref } from 'vue'
defineEmits(['open-map-editor'])
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()

View File

@ -1,10 +1,12 @@
<template> <template>
<MapTiles @tileMap:create="tileMap = $event" /> <MapTiles ref="mapTiles" :tileMap="tileMap" @tileMap:create="tileMap = $event" />
<PlacedMapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> <PlacedMapObjects ref="mapObjects" v-if="tileMap" :tileMap="tileMap as Phaser.Tilemaps.Tilemap" />
<MapEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> <MapEventTiles ref="eventTiles" v-if="tileMap" :tileMap="tileMap as Phaser.Tilemaps.Tilemap" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config'
import type { Map as MapT } from '@/application/types'
import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue' import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue'
import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue' import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue'
import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue' import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue'
@ -14,6 +16,50 @@ import { onMounted, onUnmounted, shallowRef } from 'vue'
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>() const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const selectedMap = ref<MapT>()
const mapEditorStore = useMapEditorStore()
const mapEditor = useMapEditorComposable()
const mapTiles = useTemplateRef('mapTiles')
const mapObjects = useTemplateRef('mapObjects')
const eventTiles = useTemplateRef('eventTiles')
const scene = useScene()
function handlePointer(pointer: Phaser.Input.Pointer) {
if (!mapTiles.value || !mapObjects.value || !eventTiles.value) return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if alt is pressed
if (!pointer.event.altKey) return
// Check if draw mode is tile
switch (mapEditorStore.drawMode) {
case 'tile':
mapTiles.value.handlePointer(pointer)
// case 'map_object':
// mapObjects.value.handlePointer(pointer)
case 'event tile':
eventTiles.value.handlePointer(pointer)
}
}
watch(() => mapEditor.currentMap, async (map) => {
if (!map.value) return
selectedMap.value = map.value
})
onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointer)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointer)
})
onUnmounted(() => { onUnmounted(() => {
mapEditor.reset() mapEditor.reset()
}) })

View File

@ -1,5 +1,5 @@
<template> <template>
<Image v-for="tile in mapEditorStore.map?.mapEventTiles" v-bind="getImageProps(tile)" /> <Image v-for="tile in mapEditor.currentMap.value?.mapEventTiles" v-bind="getImageProps(tile)" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -8,62 +8,55 @@ import { uuidv4 } from '@/application/utilities'
import { getTile, tileToWorldX, tileToWorldY } from '@/composables/mapComposable' import { getTile, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { onMounted, onUnmounted } from 'vue' import { type Map as MapT } from "@/application/types"
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { shallowRef, watch } from 'vue'
const scene = useScene()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
const mapEditor = useMapEditorComposable()
defineExpose({handlePointer})
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tileMap: Phaser.Tilemaps.Tilemap
}>() }>()
const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
function getImageProps(tile: MapEventTile) { function getImageProps(tile: MapEventTile) {
return { return {
x: tileToWorldX(props.tilemap, tile.positionX, tile.positionY), x: tileToWorldX(props.tileMap, tile.positionX, tile.positionY),
y: tileToWorldY(props.tilemap, tile.positionX, tile.positionY), y: tileToWorldY(props.tileMap, tile.positionX, tile.positionY),
texture: tile.type, texture: tile.type,
depth: 999 depth: 999
} }
} }
function pencil(pointer: Phaser.Input.Pointer) { function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
// Check if map is set if (!tileLayer.value) return
if (!mapEditorStore.map) return
// Check if tool is pencil
if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is blocking tile or teleport
if (mapEditorStore.drawMode !== 'blocking tile' && mapEditorStore.drawMode !== 'teleport') return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Check if event tile already exists on position // Check if event tile already exists on position
const existingEventTile = mapEditorStore.map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y) const existingEventTile = map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y)
if (existingEventTile) return if (existingEventTile) return
// If teleport, check if there is a selected map // If teleport, check if there is a selected map
if (mapEditorStore.drawMode === 'teleport' && !mapEditorStore.teleportSettings.toMap) return if (mapEditorStore.drawMode === 'teleport' && !mapEditorStore.teleportSettings.toMapId) return
const newEventTile = { const newEventTile = {
id: uuidv4(), id: uuidv4(),
mapId: mapEditorStore.map.id, mapId: map?.id,
map: mapEditorStore.map, map: map?.id,
type: mapEditorStore.drawMode === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT, type: mapEditorStore.drawMode === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
positionX: tile.x, positionX: tile.x,
positionY: tile.y, positionY: tile.y,
teleport: teleport:
mapEditorStore.drawMode === 'teleport' mapEditorStore.drawMode === 'teleport'
? { ? {
toMap: mapEditorStore.teleportSettings.toMap, toMap: mapEditorStore.teleportSettings.toMapId,
toPositionX: mapEditorStore.teleportSettings.toPositionX, toPositionX: mapEditorStore.teleportSettings.toPositionX,
toPositionY: mapEditorStore.teleportSettings.toPositionY, toPositionY: mapEditorStore.teleportSettings.toPositionY,
toRotation: mapEditorStore.teleportSettings.toRotation toRotation: mapEditorStore.teleportSettings.toRotation
@ -71,18 +64,26 @@ function pencil(pointer: Phaser.Input.Pointer) {
: undefined : undefined
} }
mapEditorStore.map.mapEventTiles = mapEditorStore.map.mapEventTiles.concat(newEventTile as MapEventTile) map!.mapEventTiles = map!.mapEventTiles.concat(newEventTile as MapEventTile)
} }
function eraser(pointer: Phaser.Input.Pointer) { function erase(pointer: Phaser.Input.Pointer, map: MapT) {
// Check if map is set if (!tileLayer.value) return
if (!mapEditorStore.map) return // Check if there is a tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
if (!tile) return
// Check if tool is pencil // Check if event tile already exists on position
if (mapEditorStore.tool !== 'eraser') return const existingEventTile = map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y)
if (!existingEventTile) return
// Check if draw mode is blocking tile or teleport // Remove existing event tile
if (mapEditorStore.eraserMode !== 'blocking tile' && mapEditorStore.eraserMode !== 'teleport') return map.mapEventTiles = map.mapEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id)
}
function handlePointer(pointer: Phaser.Input.Pointer) {
const map = mapEditor.currentMap.value
if (!map) return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -90,29 +91,12 @@ function eraser(pointer: Phaser.Input.Pointer) {
// Check if shift is not pressed, this means we are moving the camera // Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return if (pointer.event.shiftKey) return
// Check if there is a tile if (mapEditorStore.drawMode !== 'blocking tile' && mapEditorStore.drawMode !== 'teleport') return
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
if (!tile) return
// Check if event tile already exists on position switch (mapEditorStore.tool) {
const existingEventTile = mapEditorStore.map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y) case 'pencil': pencil(pointer, map)
if (!existingEventTile) return case 'eraser': erase(pointer, map)
}
// Remove existing event tile
mapEditorStore.map.mapEventTiles = mapEditorStore.map.mapEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id)
} }
onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
})
onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)
})
</script> </script>

View File

@ -22,6 +22,8 @@ const tileStorage = new TileStorage()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>() const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>() const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
defineExpose({handlePointer})
function createTileMap() { function createTileMap() {
const mapData = new Phaser.Tilemaps.MapData({ const mapData = new Phaser.Tilemaps.MapData({
width: mapEditor.currentMap.value?.width, width: mapEditor.currentMap.value?.width,
@ -32,9 +34,7 @@ function createTileMap() {
format: Phaser.Tilemaps.Formats.ARRAY_2D format: Phaser.Tilemaps.Formats.ARRAY_2D
}) })
const newTileMap = new Phaser.Tilemaps.Tilemap(scene, mapData) return new Phaser.Tilemaps.Tilemap(scene, mapData)
emit('tileMap:create', newTileMap)
return newTileMap
} }
async function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap) { async function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap) {
@ -55,111 +55,81 @@ async function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap) {
return layer return layer
} }
function pencil(pointer: Phaser.Input.Pointer) { function pencil(pointer: Phaser.Input.Pointer, tileMap: Phaser.Tilemaps.Tilemap, tileLayer: Phaser.Tilemaps.TilemapLayer) {
if (!tileMap.value || !tileLayer.value) return var map = mapEditor.currentMap.value
if (!map) return
// Check if map is set
if (!mapEditor.currentMap.value) return
console.log(mapEditor.tool.value)
// Check if tool is pencil
if (mapEditor.tool.value !== 'pencil') return
// Check if draw mode is tile
if (mapEditor.drawMode.value !== 'tile') return
// Check if there is a selected tile
if (!mapEditor.selectedTile.value) return // Changed this line to access .value
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY) const tile = tileLayer.getTileAtWorldXY(pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Place tile // Place tile
placeTile(tileMap.value, tileLayer.value, tile.x, tile.y, mapEditor.selectedTile.value) placeTile(tileMap, tileLayer, tile.x, tile.y, mapEditorStore.selectedTile)
// Adjust mapEditor tiles // Adjust mapEditorStore.map.tiles
mapEditor.currentMap.value.tiles[tile.y][tile.x] = mapEditor.selectedTile.value tileMap.tiles[tile.y][tile.x] = map.tiles[tile.y][tile.x]
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer, tileMap: Phaser.Tilemaps.Tilemap, tileLayer: Phaser.Tilemaps.TilemapLayer) {
if (!tileMap.value || !tileLayer.value) return let map = mapEditor.currentMap.value
if (!map) return
// Check if map is set
if (!mapEditor.currentMap.value) return
// Check if tool is pencil
if (mapEditor.tool.value !== 'eraser') return
// Check if draw mode is tile
if (mapEditor.eraserMode.value !== 'tile') return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if alt is pressed
if (pointer.event.altKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY) const tile = getTile(tileLayer, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Place tile // Place tile
placeTile(tileMap.value, tileLayer.value, tile.x, tile.y, 'blank_tile') placeTile(tileMap, tileLayer, tile.x, tile.y, 'blank_tile')
// Adjust mapEditor.map.tiles // Adjust mapEditorStore.map.tiles
mapEditor.currentMap.value.tiles[tile.y][tile.x] = 'blank_tile' map.tiles[tile.y][tile.x] = 'blank_tile'
} }
function paint(pointer: Phaser.Input.Pointer) { function paint(pointer: Phaser.Input.Pointer, tileMap: Phaser.Tilemaps.Tilemap, tileLayer: Phaser.Tilemaps.TilemapLayer) {
if (!tileMap.value || !tileLayer.value) return
// Check if map is set
if (!mapEditor.currentMap.value) return
// Check if tool is pencil
if (mapEditor.tool.value !== 'paint') return
// Check if there is a selected tile
if (!mapEditor.selectedTile.value) return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if alt is pressed
if (pointer.event.altKey) return
// Set new tileArray with selected tile // Set new tileArray with selected tile
setLayerTiles(tileMap.value, tileLayer.value, createTileArray(tileMap.value.width, tileMap.value.height, mapEditor.selectedTile.value)) setLayerTiles(tileMap, tileLayer, createTileArray(tileMap.width, tileMap.height, mapEditorStore.selectedTile))
// Adjust mapEditor.map.tiles // Adjust mapEditorStore.map.tiles
mapEditor.currentMap.value.tiles = createTileArray(tileMap.value.width, tileMap.value.height, mapEditor.selectedTile.value) if (mapEditor.currentMap.value) {
mapEditor.currentMap.value.tiles = createTileArray(tileMap.width, tileMap.height, mapEditorStore.selectedTile)
}
} }
// When alt is pressed, and the pointer is down, select the tile that the pointer is over // When alt is pressed, and the pointer is down, select the tile that the pointer is over
function tilePicker(pointer: Phaser.Input.Pointer) { function tilePicker(pointer: Phaser.Input.Pointer, tileLayer: Phaser.Tilemaps.TilemapLayer) {
if (!tileMap.value || !tileLayer.value) return let map = mapEditor.currentMap.value
if (!map) return
// Check if map is set // Check if there is a tile
const tile = getTile(tileLayer, pointer.worldX, pointer.worldY)
if (!tile) return
// Select the tile
mapEditorStore.setSelectedTile(map.tiles[tile.y][tile.x])
}
watch(
() => mapEditorStore.shouldClearTiles,
(shouldClear) => {
if (shouldClear && mapEditor.currentMap.value && tileMap.value && tileLayer.value) {
const blankTiles = createTileArray(tileLayer.value.width, tileLayer.value.height, 'blank_tile')
setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
mapEditor.currentMap.value.tiles = blankTiles
mapEditorStore.resetClearTilesFlag()
}
}
)
function handlePointer(pointer: Phaser.Input.Pointer) {
if (!mapEditor.currentMap.value) return if (!mapEditor.currentMap.value) return
// Check if tool is pencil if (!tileMap.value || !tileLayer.value) return
if (mapEditor.tool.value !== 'pencil') return
// Check if draw mode is tile // Check if tool is pencil
if (mapEditor.drawMode.value !== 'tile') return if (mapEditorStore.drawMode !== 'tile') return
// Check if there is a selected tile
if (!mapEditorStore.selectedTile) return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -170,25 +140,18 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
// Check if alt is pressed // Check if alt is pressed
if (!pointer.event.altKey) return if (!pointer.event.altKey) return
// Check if there is a tile // Check if draw mode is tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY) switch (mapEditorStore.tool) {
if (!tile) return case 'pencil':
pencil(pointer, tileMap.value, tileLayer.value)
// Select the tile case 'eraser':
mapEditor.setSelectedTile(mapEditor.currentMap.value.tiles[tile.y][tile.x]) eraser(pointer, tileMap.value, tileLayer.value)
} case 'paint':
paint(pointer, tileMap.value, tileLayer.value)
watch( case 'tile picker':
() => mapEditor.shouldClearTiles.value, tilePicker(pointer, tileLayer.value)
(shouldClear) => {
if (shouldClear && mapEditor.currentMap.value && tileMap.value && tileLayer.value) {
const blankTiles = createTileArray(tileMap.value.width, tileMap.value.height, 'blank_tile')
setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
mapEditor.currentMap.value.tiles = blankTiles
mapEditor.resetClearTilesFlag()
} }
} }
)
onMounted(async () => { onMounted(async () => {
if (!mapEditor.currentMap.value?.tiles) return if (!mapEditor.currentMap.value?.tiles) return
@ -211,19 +174,9 @@ onMounted(async () => {
} }
setLayerTiles(tileMap.value, tileLayer.value, blankTiles) setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, paint)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, tilePicker)
}) })
onUnmounted(() => { onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, paint)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, tilePicker)
if (tileMap.value) { if (tileMap.value) {
tileMap.value.destroyLayer('tiles') tileMap.value.destroyLayer('tiles')
tileMap.value.removeAllLayers() tileMap.value.removeAllLayers()

View File

@ -11,7 +11,7 @@ import { Image, useScene } from 'phavuer'
import { computed } from 'vue' import { computed } from 'vue'
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tileMap: Phaser.Tilemaps.Tilemap
placedMapObject: PlacedMapObject placedMapObject: PlacedMapObject
selectedPlacedMapObject: PlacedMapObject | null selectedPlacedMapObject: PlacedMapObject | null
movingPlacedMapObject: PlacedMapObject | null movingPlacedMapObject: PlacedMapObject | null
@ -24,8 +24,8 @@ const imageProps = computed(() => ({
alpha: props.movingPlacedMapObject?.id === props.placedMapObject.id ? 0.5 : 1, alpha: props.movingPlacedMapObject?.id === props.placedMapObject.id ? 0.5 : 1,
tint: props.selectedPlacedMapObject?.id === props.placedMapObject.id ? 0x00ff00 : 0xffffff, tint: props.selectedPlacedMapObject?.id === props.placedMapObject.id ? 0x00ff00 : 0xffffff,
depth: calculateIsometricDepth(props.placedMapObject.positionX, props.placedMapObject.positionY, props.placedMapObject.mapObject.frameWidth, props.placedMapObject.mapObject.frameHeight), depth: calculateIsometricDepth(props.placedMapObject.positionX, props.placedMapObject.positionY, props.placedMapObject.mapObject.frameWidth, props.placedMapObject.mapObject.frameHeight),
x: tileToWorldX(props.tilemap, props.placedMapObject.positionX, props.placedMapObject.positionY), x: tileToWorldX(props.tileMap, props.placedMapObject.positionX, props.placedMapObject.positionY),
y: tileToWorldY(props.tilemap, props.placedMapObject.positionX, props.placedMapObject.positionY), y: tileToWorldY(props.tileMap, props.placedMapObject.positionX, props.placedMapObject.positionY),
flipX: props.placedMapObject.isRotated, flipX: props.placedMapObject.isRotated,
texture: props.placedMapObject.mapObject.id, texture: props.placedMapObject.mapObject.id,
originY: Number(props.placedMapObject.mapObject.originX), originY: Number(props.placedMapObject.mapObject.originX),

View File

@ -1,142 +1,87 @@
<template> <template>
<SelectedPlacedMapObjectComponent v-if="selectedPlacedMapObject" :placedMapObject="selectedPlacedMapObject" @move="moveMapObject" @rotate="rotatePlacedMapObject" @delete="deletePlacedMapObject" /> <SelectedPlacedMapObjectComponent v-if="selectedPlacedMapObject" :placedMapObject="selectedPlacedMapObject" @move="moveMapObject" @rotate="rotatePlacedMapObject" @delete="deletePlacedMapObject" />
<PlacedMapObject v-for="placedMapObject in mapEditorStore.map?.placedMapObjects" :tilemap="tilemap" :placedMapObject :selectedPlacedMapObject :movingPlacedMapObject @pointerup="clickPlacedMapObject(placedMapObject)" /> <PlacedMapObject v-for="placedMapObject in mapEditor.currentMap.value?.placedMapObjects" :tilemap="tileMap" :placedMapObject :selectedPlacedMapObject :movingPlacedMapObject @pointerup="clickPlacedMapObject(placedMapObject)" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { PlacedMapObject as PlacedMapObjectT } from '@/application/types' import type { Map as MapT, PlacedMapObject as PlacedMapObjectT } from '@/application/types'
import { uuidv4 } from '@/application/utilities' import { uuidv4 } from '@/application/utilities'
import PlacedMapObject from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObject.vue' import PlacedMapObject from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObject.vue'
import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue' import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue'
import { getTile } from '@/composables/mapComposable' import { getTile } from '@/composables/mapComposable'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { onMounted, onUnmounted, ref, watch } from 'vue' import { ref, watch } from 'vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
const scene = useScene() const scene = useScene()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
const mapEditor = useMapEditorComposable()
const selectedPlacedMapObject = ref<PlacedMapObjectT | null>(null) const selectedPlacedMapObject = ref<PlacedMapObjectT | null>(null)
const movingPlacedMapObject = ref<PlacedMapObjectT | null>(null) const movingPlacedMapObject = ref<PlacedMapObjectT | null>(null)
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tileMap: Phaser.Tilemaps.Tilemap
}>() }>()
function pencil(pointer: Phaser.Input.Pointer) { defineExpose({handlePointer})
// Check if map is set
if (!mapEditorStore.map) return
// Check if tool is pencil
if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is map_object
if (mapEditorStore.drawMode !== 'map_object') return
// Check if there is a selected object
if (!mapEditorStore.selectedMapObject) return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if alt is pressed, this means we are selecting the object
if (pointer.event.altKey) return
function pencil(pointer: Phaser.Input.Pointer, tileMapLayer: Phaser.Tilemaps.TilemapLayer, map: MapT) {
// Check if there is a tile // Check if there is a tile
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) const tile = getTile(tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Check if object already exists on position // Check if object already exists on position
const existingPlacedMapObject = mapEditorStore.map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y) const existingPlacedMapObject = map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y)
if (existingPlacedMapObject) return if (existingPlacedMapObject) return
const newPlacedMapObject = { const newPlacedMapObject: PlacedMapObjectT = {
id: uuidv4(), id: uuidv4(),
map: mapEditorStore.map, depth: 0,
mapObject: mapEditorStore.selectedMapObject, map: map,
mapObject: mapEditorStore.selectedMapObject!,
isRotated: false, isRotated: false,
positionX: tile.x, positionX: tile.x,
positionY: tile.y positionY: tile.y
} }
// Add new object to mapObjects // Add new object to mapObjects
mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.concat(newPlacedMapObject as PlacedMapObjectT) map.placedMapObjects.concat(newPlacedMapObject)
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer, tileMapLayer: Phaser.Tilemaps.TilemapLayer, map: MapT) {
// Check if map is set
if (!mapEditorStore.map) return
// Check if tool is eraser
if (mapEditorStore.tool !== 'eraser') return
// Check if draw mode is map_object
if (mapEditorStore.eraserMode !== 'map_object') return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// Check if alt is pressed, this means we are selecting the object
if (pointer.event.altKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) const tile = getTile(tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Check if object already exists on position // Check if object already exists on position
const existingPlacedMapObject = mapEditorStore.map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y) const existingPlacedMapObject = map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y)
if (!existingPlacedMapObject) return if (!existingPlacedMapObject) return
// Remove existing object // Remove existing object
mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.filter((placedMapObject) => placedMapObject.id !== existingPlacedMapObject.id) map.placedMapObjects = map.placedMapObjects.filter((placedMapObject) => placedMapObject.id !== existingPlacedMapObject.id)
} }
function objectPicker(pointer: Phaser.Input.Pointer) { function objectPicker(pointer: Phaser.Input.Pointer, tileMapLayer: Phaser.Tilemaps.TilemapLayer, map: MapT) {
// Check if map is set
if (!mapEditorStore.map) return
// Check if tool is pencil
if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is map_object
if (mapEditorStore.drawMode !== 'map_object') return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera
if (pointer.event.shiftKey) return
// If alt is not pressed, return
if (!pointer.event.altKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) const tile = getTile(tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Check if object already exists on position // Check if object already exists on position
const existingPlacedMapObject = mapEditorStore.map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y) const existingPlacedMapObject = map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y)
if (!existingPlacedMapObject) return if (!existingPlacedMapObject) return
// Select the object // Select the object
mapEditorStore.setSelectedMapObject(existingPlacedMapObject.mapObject) mapEditorStore.setSelectedMapObject(existingPlacedMapObject.mapObject)
} }
function moveMapObject(id: string) { function moveMapObject(id: string, tileMapLayer: Phaser.Tilemaps.TilemapLayer, map: MapT) {
// Check if map is set movingPlacedMapObject.value = map.placedMapObjects.find((object) => object.id === id) as PlacedMapObjectT
if (!mapEditorStore.map) return
movingPlacedMapObject.value = mapEditorStore.map.placedMapObjects.find((object) => object.id === id) as PlacedMapObjectT
function handlePointerMove(pointer: Phaser.Input.Pointer) { function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (!movingPlacedMapObject.value) return if (!movingPlacedMapObject.value) return
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) const tile = getTile(tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
movingPlacedMapObject.value.positionX = tile.x movingPlacedMapObject.value.positionX = tile.x
@ -153,11 +98,8 @@ function moveMapObject(id: string) {
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp) scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
} }
function rotatePlacedMapObject(id: string) { function rotatePlacedMapObject(id: string, map: MapT) {
// Check if map is set map.placedMapObjects = map.placedMapObjects.map((placedMapObject) => {
if (!mapEditorStore.map) return
mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.map((placedMapObject) => {
if (placedMapObject.id === id) { if (placedMapObject.id === id) {
return { return {
...placedMapObject, ...placedMapObject,
@ -168,11 +110,8 @@ function rotatePlacedMapObject(id: string) {
}) })
} }
function deletePlacedMapObject(id: string) { function deletePlacedMapObject(id: string, map: MapT) {
// Check if map is set map.placedMapObjects = map.placedMapObjects.filter((object) => object.id !== id)
if (!mapEditorStore.map) return
mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.filter((object) => object.id !== id)
selectedPlacedMapObject.value = null selectedPlacedMapObject.value = null
} }
@ -185,37 +124,48 @@ function clickPlacedMapObject(placedMapObject: PlacedMapObjectT) {
} }
} }
onMounted(() => { function handlePointer(pointer: Phaser.Input.Pointer, tileMapLayer: Phaser.Tilemaps.TilemapLayer) {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil) const map = mapEditor.currentMap.value
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil) if (!map) return
scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, objectPicker)
})
onUnmounted(() => { if (mapEditorStore.drawMode !== 'map_object') return
scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil) // Check if left mouse button is pressed
scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser) if (!pointer.isDown) return
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker) // Check if shift is not pressed, this means we are moving the camera
}) if (pointer.event.shiftKey) return
// Check if alt is pressed, this means we are selecting the object
if (pointer.event.altKey) return
// Check if tool is pencil
switch (mapEditorStore.tool) {
case 'pencil':
if (mapEditorStore.selectedMapObject) pencil(pointer, tileMapLayer, map)
case 'eraser':
eraser(pointer, tileMapLayer, map)
case 'object picker':
objectPicker(pointer, tileMapLayer, map)
}
}
// watch mapEditorStore.mapObjectList and update originX and originY of objects in mapObjects // watch mapEditorStore.mapObjectList and update originX and originY of objects in mapObjects
watch( watch(
() => mapEditorStore.mapObjectList, () => mapEditor.currentMap.value,
(newMapObjects) => { () => {
if (!mapEditorStore.map) return const map = mapEditor.currentMap.value
if (!map) return
const updatedMapObjects = mapEditorStore.map.placedMapObjects.map((mapObject) => { const updatedMapObjects = map.placedMapObjects.map((mapObject) => {
const updatedMapObject = newMapObjects.find((obj) => obj.id === mapObject.mapObject.id) const updatedMapObject = map.placedMapObjects.find((obj) => obj.id === mapObject.mapObject.id)
if (updatedMapObject) { if (updatedMapObject) {
return { return {
...mapObject, ...mapObject,
mapObject: { mapObject: {
...mapObject.mapObject, ...mapObject.mapObject,
originX: updatedMapObject.originX, originX: updatedMapObject.positionX,
originY: updatedMapObject.originY originY: updatedMapObject.positionY
} }
} }
} }
@ -223,19 +173,16 @@ watch(
}) })
// Update the map with the new mapObjects // Update the map with the new mapObjects
mapEditorStore.setMap({ map.placedMapObjects = [...map.placedMapObjects, ...updatedMapObjects]
...mapEditorStore.map,
placedMapObjects: updatedMapObjects
})
// Update selectedMapObject if it's set // Update mapObject if it's set
if (mapEditorStore.selectedMapObject) { if (mapEditorStore.selectedMapObject) {
const updatedMapObject = newMapObjects.find((obj) => obj.id === mapEditorStore.selectedMapObject?.id) const updatedMapObject = map.placedMapObjects.find((obj) => obj.id === mapEditorStore.selectedMapObject?.id)
if (updatedMapObject) { if (updatedMapObject) {
mapEditorStore.setSelectedMapObject({ mapEditorStore.setSelectedMapObject({
...mapEditorStore.selectedMapObject, ...mapEditorStore.selectedMapObject,
originX: updatedMapObject.originX, originX: updatedMapObject.positionX,
originY: updatedMapObject.originY originY: updatedMapObject.positionY
}) })
} }
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :isModalOpen="mapEditor.isCreateMapModalShown.value" @modal:close="() => mapEditor.toggleCreateMapModal()" :modal-width="300" :modal-height="420" :is-resizable="false" :bg-style="'none'"> <Modal ref="modalRef" :modal-width="300" :modal-height="420" :is-resizable="false" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Create new map</h3> <h3 class="m-0 font-medium shrink-0 text-white">Create new map</h3>
</template> </template>
@ -47,6 +47,7 @@ const emit = defineEmits(['create'])
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()
const mapStorage = new MapStorage() const mapStorage = new MapStorage()
const modalRef = useTemplateRef('modalRef')
const name = ref('') const name = ref('')
const width = ref(0) const width = ref(0)
@ -79,6 +80,6 @@ async function submit() {
}) })
// Close modal // Close modal
mapEditor.toggleCreateMapModal() modalRef.value?.close()
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :is-modal-open="mapEditor.isMapListModalShown.value" @modal:close="() => mapEditor.toggleMapListModal()" :is-resizable="false" :modal-width="300" :modal-height="360" :bg-style="'none'"> <Modal ref="modalRef" :is-resizable="false" :modal-width="300" :modal-height="360" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="text-lg text-white">Maps</h3> <h3 class="text-lg text-white">Maps</h3>
</template> </template>
@ -7,7 +7,7 @@
<div class="my-4 mx-auto h-full"> <div class="my-4 mx-auto h-full">
<div class="text-center mb-4 px-2 flex gap-2.5"> <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="fetchMaps">Refresh</button> <button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="fetchMaps">Refresh</button>
<button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="() => mapEditor.toggleCreateMapModal()">New</button> <button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="() => $emit('open-create-map')">New</button>
</div> </div>
<div class="overflow-y-auto h-[calc(100%-20px)]"> <div class="overflow-y-auto h-[calc(100%-20px)]">
<div class="relative p-2.5 cursor-pointer flex gap-y-2.5 gap-x-5 flex-wrap" v-for="(map, index) in mapList" :key="map.id"> <div class="relative p-2.5 cursor-pointer flex gap-y-2.5 gap-x-5 flex-wrap" v-for="(map, index) in mapList" :key="map.id">
@ -25,7 +25,7 @@
</template> </template>
</Modal> </Modal>
<CreateMap @create="fetchMaps" v-if="mapEditor.isMapListModalShown.value" /> <CreateMap @create="fetchMaps" v-if="modalRef?.isModalOpen" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -35,13 +35,21 @@ import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { onMounted, ref } from 'vue' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { onMounted, ref, useTemplateRef } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()
const mapStorage = new MapStorage() const mapStorage = new MapStorage()
const mapList = ref<Map[]>([]) const mapList = ref<Map[]>([])
const modalRef = useTemplateRef('modalRef')
defineEmits(['open-create-map'])
defineExpose({
open: () => modalRef.value?.open()
})
onMounted(async () => { onMounted(async () => {
await fetchMaps() await fetchMaps()
@ -55,7 +63,7 @@ function loadMap(id: UUID) {
gameStore.connection?.emit('gm:map:request', { mapId: id }, (response: Map) => { gameStore.connection?.emit('gm:map:request', { mapId: id }, (response: Map) => {
mapEditor.loadMap(response) mapEditor.loadMap(response)
}) })
mapEditor.toggleMapListModal() modalRef.value?.close()
} }
async function deleteMap(id: UUID) { async function deleteMap(id: UUID) {

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :isModalOpen="mapEditor.isMapObjectListModalShown.value" :modal-width="645" :modal-height="260" @modal:close="() => (mapEditor.isMapObjectListModalShown.value = false)" :bg-style="'none'"> <Modal ref="modalRef" :modal-width="645" :modal-height="260" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="text-lg text-white">Map objects</h3> <h3 class="text-lg text-white">Map objects</h3>
</template> </template>
@ -47,7 +47,7 @@ import Modal from '@/components/utilities/Modal.vue'
import { MapObjectStorage } from '@/storage/storages' import { MapObjectStorage } from '@/storage/storages'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { liveQuery } from 'dexie' import { liveQuery } from 'dexie'
import { computed, onMounted, onUnmounted, ref } from 'vue' import { computed, onMounted, onUnmounted, ref, useTemplateRef } from 'vue'
const mapObjectStorage = new MapObjectStorage() const mapObjectStorage = new MapObjectStorage()
const isModalOpen = ref(false) const isModalOpen = ref(false)
@ -55,6 +55,11 @@ const mapEditor = useMapEditorComposable()
const searchQuery = ref('') const searchQuery = ref('')
const selectedTags = ref<string[]>([]) const selectedTags = ref<string[]>([])
const mapObjectList = ref<MapObject[]>([]) const mapObjectList = ref<MapObject[]>([])
const modalRef = useTemplateRef('modalRef')
defineExpose({
open: () => modalRef.value?.open()
})
const uniqueTags = computed(() => { const uniqueTags = computed(() => {
const allTags = mapObjectList.value.flatMap((obj) => obj.tags || []) const allTags = mapObjectList.value.flatMap((obj) => obj.tags || [])

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :is-modal-open="mapEditor.isSettingsModalShown.value" @modal:close="() => mapEditor.toggleSettingsModal()" :modal-width="600" :modal-height="430" :bg-style="'none'"> <Modal ref="modalRef" :modal-width="600" :modal-height="430" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Map settings</h3> <h3 class="m-0 font-medium shrink-0 text-white">Map settings</h3>
</template> </template>
@ -61,6 +61,11 @@ const width = ref(mapEditor.currentMap.value?.width)
const height = ref(mapEditor.currentMap.value?.height) const height = ref(mapEditor.currentMap.value?.height)
const pvp = ref(mapEditor.currentMap.value?.pvp) const pvp = ref(mapEditor.currentMap.value?.pvp)
const mapEffects = ref(mapEditor.currentMap.value?.mapEffects || []) const mapEffects = ref(mapEditor.currentMap.value?.mapEffects || [])
const modalRef = useTemplateRef('modalRef')
defineExpose({
open: () => modalRef.value?.open()
})
watch(name, (value) => { watch(name, (value) => {
mapEditor.updateProperty('name', value!) mapEditor.updateProperty('name', value!)

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :is-modal-open="showTeleportModal" @modal:close="() => mapEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false" :bg-style="'none'"> <Modal ref="modalRef" @modal:close="() => mapEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3> <h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3>
</template> </template>
@ -28,7 +28,7 @@
<label for="toMap">Map to teleport to</label> <label for="toMap">Map to teleport to</label>
<select v-model="toMap" class="input-field" name="toMap" id="toMap"> <select v-model="toMap" class="input-field" name="toMap" id="toMap">
<option :value="null">Select map</option> <option :value="null">Select map</option>
<option v-for="map in mapEditorStore.mapList" :key="map.id" :value="map">{{ map.name }}</option> <option v-for="map in mapList" :key="map.id" :value="map">{{ map.name }}</option>
</select> </select>
</div> </div>
</div> </div>
@ -43,18 +43,22 @@ import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onMounted, ref, watch } from 'vue' import { computed, onMounted, ref, useTemplateRef, watch } from 'vue'
const showTeleportModal = computed(() => mapEditorStore.tool === 'pencil' && mapEditorStore.drawMode === 'teleport') const showTeleportModal = computed(() => mapEditorStore.tool === 'pencil' && mapEditorStore.drawMode === 'teleport')
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
const gameStore = useGameStore() const gameStore = useGameStore()
const mapList = ref<Map[]>([])
const modalRef = useTemplateRef('modalRef')
defineExpose({
open: () => modalRef.value?.open(),
})
onMounted(fetchMaps) onMounted(fetchMaps)
function fetchMaps() { function fetchMaps() {
gameStore.connection?.emit('gm:map:list', {}, (response: Map[]) => { gameStore.connection?.emit('gm:map:list', {}, (response: Map[]) => { mapList.value = response })
mapEditorStore.setMapList(response)
})
} }
const { toPositionX, toPositionY, toRotation, toMap } = useRefTeleportSettings() const { toPositionX, toPositionY, toRotation, toMap } = useRefTeleportSettings()
@ -65,7 +69,7 @@ function useRefTeleportSettings() {
toPositionX: ref(settings.toPositionX), toPositionX: ref(settings.toPositionX),
toPositionY: ref(settings.toPositionY), toPositionY: ref(settings.toPositionY),
toRotation: ref(settings.toRotation), toRotation: ref(settings.toRotation),
toMap: ref(settings.toMap) toMap: ref(settings.toMapId)
} }
} }
@ -76,7 +80,7 @@ function updateTeleportSettings() {
toPositionX: toPositionX.value, toPositionX: toPositionX.value,
toPositionY: toPositionY.value, toPositionY: toPositionY.value,
toRotation: toRotation.value, toRotation: toRotation.value,
toMap: toMap.value toMapId: toMap.value
}) })
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :isModalOpen="mapEditor.isTileListModalShown.value" :modal-width="645" :modal-height="600" @modal:close="() => (mapEditor.isTileListModalShown.value = false)" :bg-style="'none'"> <Modal ref="modalRef" :modal-width="645" :modal-height="600" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="text-lg text-white">Tiles</h3> <h3 class="text-lg text-white">Tiles</h3>
</template> </template>
@ -87,7 +87,7 @@ import Modal from '@/components/utilities/Modal.vue'
import { TileStorage } from '@/storage/storages' import { TileStorage } from '@/storage/storages'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { liveQuery } from 'dexie' import { liveQuery } from 'dexie'
import { computed, onMounted, onUnmounted, ref } from 'vue' import { computed, onMounted, onUnmounted, ref, useTemplateRef } from 'vue'
const tileStorage = new TileStorage() const tileStorage = new TileStorage()
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()
@ -96,6 +96,11 @@ const selectedTags = ref<string[]>([])
const tileCategories = ref<Map<string, string>>(new Map()) const tileCategories = ref<Map<string, string>>(new Map())
const selectedGroup = ref<{ parent: Tile; children: Tile[] } | null>(null) const selectedGroup = ref<{ parent: Tile; children: Tile[] } | null>(null)
const tiles = ref<Tile[]>([]) const tiles = ref<Tile[]>([])
const modalRef = useTemplateRef('modalRef')
defineExpose({
open: () => modalRef.value?.open()
})
const uniqueTags = computed(() => { const uniqueTags = computed(() => {
const allTags = tiles.value.flatMap((tile) => tile.tags || []) const allTags = tiles.value.flatMap((tile) => tile.tags || [])

View File

@ -72,10 +72,10 @@
</div> </div>
<div class="toolbar fixed bottom-0 right-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 space-x-2"> <div class="toolbar fixed bottom-0 right-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 space-x-2">
<button class="btn-cyan px-3.5" @click="() => mapEditor.toggleMapListModal()">Load</button> <button class="btn-cyan px-3.5" @click="() => emit('open-maps')">Load</button>
<button class="btn-cyan px-3.5" @click="() => emit('save')" v-if="mapEditor.currentMap.value">Save</button> <button class="btn-cyan px-3.5" @click="() => emit('save')" v-if="mapEditor.currentMap.value">Save</button>
<button class="btn-cyan px-3.5" @click="() => emit('clear')" v-if="mapEditor.currentMap.value">Clear</button> <button class="btn-cyan px-3.5" @click="() => emit('clear')" v-if="mapEditor.currentMap.value">Clear</button>
<button class="btn-cyan px-3.5" @click="() => mapEditor.toggleActive()">Exit</button> <button class="btn-cyan px-3.5" @click="() => emit('close-editor')">Exit</button>
</div> </div>
</div> </div>
</div> </div>
@ -84,11 +84,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { onClickOutside } from '@vueuse/core' import { onClickOutside } from '@vueuse/core'
import { onBeforeUnmount, onMounted, ref } from 'vue' import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()
const emit = defineEmits(['save', 'clear']) const emit = defineEmits(['save', 'clear', 'open-maps', 'open-settings', 'close-editor', 'open-tile-list', 'open-map-object-list'])
// track when clicked outside of toolbar items // track when clicked outside of toolbar items
const toolbar = ref(null) const toolbar = ref(null)
@ -97,10 +97,15 @@ const toolbar = ref(null)
let selectPencilOpen = ref(false) let selectPencilOpen = ref(false)
let selectEraserOpen = ref(false) let selectEraserOpen = ref(false)
let tileListShown = ref(false)
let mapObjectListShown = ref(false)
defineExpose({tileListShown, mapObjectListShown})
// drawMode // drawMode
function setDrawMode(value: string) { function setDrawMode(value: string) {
mapEditor.isTileListModalShown.value = value === 'tile' if (value === 'tile') emit('open-tile-list')
mapEditor.isMapObjectListModalShown.value = value === 'map_object' if (value === 'map_object') emit('open-map-object-list')
mapEditor.setDrawMode(value) mapEditor.setDrawMode(value)
selectPencilOpen.value = false selectPencilOpen.value = false
@ -108,13 +113,13 @@ function setDrawMode(value: string) {
// drawMode // drawMode
function setEraserMode(value: string) { function setEraserMode(value: string) {
mapEditor.setEraserMode(value) mapEditorStore.setTool('eraser')
selectEraserOpen.value = false selectEraserOpen.value = false
} }
function handleClick(tool: string) { function handleClick(tool: string) {
if (tool === 'settings') { if (tool === 'settings') {
mapEditor.toggleSettingsModal() emit('open-settings')
} else { } else {
mapEditor.setTool(tool) mapEditor.setTool(tool)
} }
@ -125,8 +130,7 @@ function handleClick(tool: string) {
function cycleToolMode(tool: 'pencil' | 'eraser') { function cycleToolMode(tool: 'pencil' | 'eraser') {
const modes = ['tile', 'object', 'teleport', 'blocking tile'] const modes = ['tile', 'object', 'teleport', 'blocking tile']
const currentMode = tool === 'pencil' ? mapEditor.drawMode : mapEditor.eraserMode const currentIndex = modes.indexOf(mapEditorStore.drawMode)
const currentIndex = modes.indexOf(currentMode.value)
const nextIndex = (currentIndex + 1) % modes.length const nextIndex = (currentIndex + 1) % modes.length
const nextMode = modes[nextIndex] const nextMode = modes[nextIndex]

View File

@ -4,13 +4,16 @@
<Scene name="main" @preload="preloadScene"> <Scene name="main" @preload="preloadScene">
<div v-if="!isLoaded" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white text-3xl font-ui">Loading...</div> <div v-if="!isLoaded" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white text-3xl font-ui">Loading...</div>
<div v-else> <div v-else>
<Map :key="mapEditor.currentMap.value?.id" /> <Map :key="currentMap?.id" />
<Toolbar @save="save" @clear="clear" /> <Toolbar ref="toolbar" @save="save" @clear="clear" @open-maps="mapModal?.open()" @open-settings="mapSettingsModal?.open()"
<MapList /> @close-editor="$emit('close-editor')"
<TileList /> @open-tile-list="tileModal?.open()"
<ObjectList /> @open-map-object-list="objectModal?.open()"/>
<MapSettings /> <MapList ref="mapModal" @open-create-map="mapSettingsModal?.open()"/>
<TeleportModal /> <TileList ref="tileModal"/>
<ObjectList ref="objectModal"/>
<MapSettings ref="mapSettingsModal" />
<TeleportModal ref="teleportModal" />
</div> </div>
</Scene> </Scene>
</Game> </Game>
@ -33,11 +36,20 @@ import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { Game, Scene } from 'phavuer' import { Game, Scene } from 'phavuer'
import { ref } from 'vue' import { provide, ref, useTemplateRef, watch } from 'vue'
const mapStorage = new MapStorage() const mapStorage = new MapStorage()
const mapEditor = useMapEditorComposable() const mapEditor = useMapEditorComposable()
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore()
const currentMap = ref<MapT | null>(null)
const toolbar = useTemplateRef("toolbar")
const mapModal = useTemplateRef("mapModal")
const tileModal = useTemplateRef("tileModal")
const objectModal = useTemplateRef("objectModal")
const mapSettingsModal = useTemplateRef("mapSettingsModal")
const teleportModal = useTemplateRef("teleportModal")
const isLoaded = ref(false) const isLoaded = ref(false)
@ -76,22 +88,18 @@ const preloadScene = async (scene: Phaser.Scene) => {
} }
function save() { function save() {
if (!mapEditor.currentMap.value) return if (!currentMap.value) return
const data = { const data = {
mapId: mapEditor.currentMap.value.id, mapId: currentMap.value.id,
name: mapEditor.currentMap.value.name, name: currentMap.value.name,
width: mapEditor.currentMap.value.width, width: currentMap.value.width,
height: mapEditor.currentMap.value.height, height: currentMap.value.height,
tiles: mapEditor.currentMap.value.tiles, tiles: currentMap.value.tiles,
pvp: mapEditor.currentMap.value.pvp, pvp: currentMap.value.pvp,
mapEffects: mapEditor.currentMap.value.mapEffects?.map(({ id, effect, strength }) => ({ id, effect, strength })) ?? [], mapEffects: currentMap.value.mapEffects?.map(({ id, effect, strength }) => ({ id, effect, strength })) ?? [],
mapEventTiles: mapEditor.currentMap.value.mapEventTiles?.map(({ id, type, positionX, positionY, teleport }) => ({ id, type, positionX, positionY, teleport })) ?? [], mapEventTiles: currentMap.value.mapEventTiles?.map(({ id, type, positionX, positionY, teleport }) => ({ id, type, positionX, positionY, teleport })) ?? [],
placedMapObjects: mapEditor.currentMap.value.placedMapObjects?.map(({ id, mapObject, depth, isRotated, positionX, positionY }) => ({ id, mapObject, depth, isRotated, positionX, positionY })) ?? [] placedMapObjects: currentMap.value.placedMapObjects?.map(({ id, mapObject, depth, isRotated, positionX, positionY }) => ({ id, mapObject, depth, isRotated, positionX, positionY })) ?? []
}
if (mapEditor.isSettingsModalShown.value) {
mapEditor.toggleSettingsModal()
} }
gameStore.connection?.emit('gm:map:update', data, (response: MapT) => { gameStore.connection?.emit('gm:map:update', data, (response: MapT) => {
@ -99,8 +107,10 @@ function save() {
}) })
} }
watch(() => mapEditor.currentMap, (value) => { currentMap.value = value.value })
function clear() { function clear() {
if (!mapEditor.currentMap.value) return if (!currentMap.value) return
// Clear placed objects, event tiles and tiles // Clear placed objects, event tiles and tiles
mapEditor.clearMap() mapEditor.clearMap()

View File

@ -17,7 +17,7 @@
<button v-if="canFullScreen" @click="toggleFullScreen" class="w-5 h-5 m-0 p-0 relative hover:scale-110 transition-transform duration-300 ease-in-out"> <button v-if="canFullScreen" @click="toggleFullScreen" class="w-5 h-5 m-0 p-0 relative hover:scale-110 transition-transform duration-300 ease-in-out">
<img :alt="isFullScreen ? 'exit full-screen' : 'full-screen'" :src="isFullScreen ? '/assets/icons/modal/minimize.svg' : '/assets/icons/modal/increase-size-option.svg'" class="w-3.5 h-3.5 invert" draggable="false" /> <img :alt="isFullScreen ? 'exit full-screen' : 'full-screen'" :src="isFullScreen ? '/assets/icons/modal/minimize.svg' : '/assets/icons/modal/increase-size-option.svg'" class="w-3.5 h-3.5 invert" draggable="false" />
</button> </button>
<button v-if="closable" @click="emit('modal:close')" class="w-3.5 h-3.5 m-0 p-0 relative hover:rotate-180 transition-transform duration-300 ease-in-out"> <button v-if="closable" @click="isModalOpenRef=false" class="w-3.5 h-3.5 m-0 p-0 relative hover:rotate-180 transition-transform duration-300 ease-in-out">
<img alt="close" src="/assets/icons/modal/close-button-white.svg" class="w-full h-full" draggable="false" /> <img alt="close" src="/assets/icons/modal/close-button-white.svg" class="w-full h-full" draggable="false" />
</button> </button>
</div> </div>
@ -46,7 +46,7 @@
import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
interface ModalProps { interface ModalProps {
isModalOpen: boolean isModalOpen?: boolean
closable?: boolean closable?: boolean
isResizable?: boolean isResizable?: boolean
isFullScreen?: boolean isFullScreen?: boolean
@ -79,10 +79,18 @@ const props = withDefaults(defineProps<ModalProps>(), {
}) })
const emit = defineEmits<{ const emit = defineEmits<{
'modal:open': []
'modal:close': [] 'modal:close': []
'character:create': [] 'character:create': []
}>() }>()
defineExpose(
{
open: () => isModalOpenRef.value = true,
close: () => isModalOpenRef.value = false,
toggle: () => isModalOpenRef.value = !isModalOpenRef.value,
})
const isModalOpenRef = ref(props.isModalOpen) const isModalOpenRef = ref(props.isModalOpen)
const width = ref(props.modalWidth) const width = ref(props.modalWidth)
const height = ref(props.modalHeight) const height = ref(props.modalHeight)

View File

@ -9,10 +9,10 @@ import TilemapLayer = Phaser.Tilemaps.TilemapLayer
import Tileset = Phaser.Tilemaps.Tileset import Tileset = Phaser.Tilemaps.Tileset
import Tile = Phaser.Tilemaps.Tile import Tile = Phaser.Tilemaps.Tile
import type { Tile as TileT } from '@/application/types'
export function getTile(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): Tile | null { export function getTile(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): Tile | null {
const tile = layer?.getTileAtWorldXY(positionX, positionY) return layer.getTileAtWorldXY(positionX, positionY)
if (!tile) return null
return tile
} }
export function tileToWorldXY(layer: TilemapLayer | Tilemap, positionX: number, positionY: number) { export function tileToWorldXY(layer: TilemapLayer | Tilemap, positionX: number, positionY: number) {
@ -77,14 +77,18 @@ export const calculateIsometricDepth = (positionX: number, positionY: number, wi
return baseDepth + (width + height) / (2 * config.tile_size.width) return baseDepth + (width + height) / (2 * config.tile_size.width)
} }
export function FlattenMapArray(tiles: string[][]) { async function getTiles(tiles: TileT[], scene: Phaser.Scene) {
const normalArray = [] // Load each tile into the scene
for (const tile of tiles) {
for (const row of tiles) { if (!tile) continue
normalArray.push(...row) const textureData = {
key: tile.id,
data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: tile.updatedAt
} as TextureData
await loadTexture(scene, textureData)
} }
return normalArray
} }
export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) { export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) {
@ -93,50 +97,22 @@ export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) {
const map = await mapStorage.get(map_id) const map = await mapStorage.get(map_id)
if (!map) return if (!map) return
const tileArray = unduplicateArray(FlattenMapArray(map.tiles)) const tileArray = unduplicateArray(map.tiles)
const tiles = await tileStorage.getByIds(tileArray) const tiles = await tileStorage.getByIds(tileArray)
// Load each tile into the scene await getTiles(tiles, 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 loadTilesIntoScene(tileIds: string[], scene: Phaser.Scene) { export async function loadTilesIntoScene(tileIds: string[], scene: Phaser.Scene) {
const tileStorage = new TileStorage() const tileStorage = new TileStorage()
const tiles = await tileStorage.getByIds(tileIds) const tiles = await tileStorage.getByIds(tileIds)
// Load each tile into the scene await getTiles(tiles, 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) { export async function loadAllTilesIntoScene(scene: Phaser.Scene) {
const tileStorage = new TileStorage() const tileStorage = new TileStorage()
const tiles = await tileStorage.getAll() const tiles = await tileStorage.getAll()
// Load each tile into the scene getTiles(tiles, scene)
for (const tile of tiles) {
const textureData = {
key: tile.id,
data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: tile.updatedAt
} as TextureData
await loadTexture(scene, textureData)
}
} }

View File

@ -25,7 +25,7 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
} }
function handlePointerDown(pointer: Phaser.Input.Pointer) { function handlePointerDown(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = { x: pointer.x, y: pointer.y } pointerStartPosition.value = pointer.position
gameStore.setPlayerDraggingCamera(true) gameStore.setPlayerDraggingCamera(true)
} }
@ -34,10 +34,9 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
if (!gameStore.game.isPlayerDraggingCamera) return if (!gameStore.game.isPlayerDraggingCamera) return
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
// If the distance is less than the drag threshold, return // If the distance is less than the drag threshold, return
// We do this to prevent the camera from scrolling too quickly // We do this to prevent the camera from scrolling too quickly
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
if (distance <= dragThreshold) return if (distance <= dragThreshold) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom) camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
@ -46,12 +45,6 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
function handlePointerUp(pointer: Phaser.Input.Pointer) { function handlePointerUp(pointer: Phaser.Input.Pointer) {
gameStore.setPlayerDraggingCamera(false) gameStore.setPlayerDraggingCamera(false)
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
// If the distance is greater than the drag threshold, return
// We do this to prevent the camera from scrolling too quickly
if (distance > dragThreshold) return
const pointerTile = getTile(layer, pointer.worldX, pointer.worldY) const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
if (!pointerTile) return if (!pointerTile) return

View File

@ -28,7 +28,7 @@ export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.T
} }
function handlePointerDown(pointer: Phaser.Input.Pointer) { function handlePointerDown(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = { x: pointer.x, y: pointer.y } pointerStartPosition.value = pointer.position
if (isMoveTool.value || pointer.event.shiftKey) { if (isMoveTool.value || pointer.event.shiftKey) {
gameStore.setPlayerDraggingCamera(true) gameStore.setPlayerDraggingCamera(true)
} }
@ -37,8 +37,9 @@ export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.T
function dragMap(pointer: Phaser.Input.Pointer) { function dragMap(pointer: Phaser.Input.Pointer) {
if (!gameStore.game.isPlayerDraggingCamera) return if (!gameStore.game.isPlayerDraggingCamera) return
// If the distance is less than the drag threshold, return
// We do this to prevent the camera from scrolling too quickly
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y) const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
if (distance <= dragThreshold) return if (distance <= dragThreshold) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom) camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)

View File

@ -1,5 +1,6 @@
import type { MapObject } from '@/application/types' import type { MapObject } from '@/application/types'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { Map as MapT } from '@/application/types'
export type TeleportSettings = { export type TeleportSettings = {
toMapId: string toMapId: string
@ -11,17 +12,11 @@ export type TeleportSettings = {
export const useMapEditorStore = defineStore('mapEditor', { export const useMapEditorStore = defineStore('mapEditor', {
state: () => { state: () => {
return { return {
active: false, active: true,
tool: 'move', tool: 'move',
drawMode: 'tile', drawMode: 'tile',
eraserMode: 'tile',
selectedTile: '', selectedTile: '',
selectedMapObject: null as MapObject | null, selectedMapObject: null as MapObject | null,
isTileListModalShown: false,
isMapObjectListModalShown: false,
isMapListModalShown: false,
isCreateMapModalShown: false,
isSettingsModalShown: false,
shouldClearTiles: false, shouldClearTiles: false,
teleportSettings: { teleportSettings: {
toMapId: '', toMapId: '',
@ -32,35 +27,18 @@ export const useMapEditorStore = defineStore('mapEditor', {
} }
}, },
actions: { actions: {
toggleActive() {
if (this.active) this.reset()
this.active = !this.active
},
setTool(tool: string) { setTool(tool: string) {
this.tool = tool this.tool = tool
}, },
setDrawMode(mode: string) { setDrawMode(mode: string) {
this.drawMode = mode this.drawMode = mode
}, },
setEraserMode(mode: string) {
this.eraserMode = mode
},
setSelectedTile(tile: string) { setSelectedTile(tile: string) {
this.selectedTile = tile this.selectedTile = tile
}, },
setSelectedMapObject(object: MapObject) { setSelectedMapObject(object: MapObject) {
this.selectedMapObject = object this.selectedMapObject = object
}, },
toggleSettingsModal() {
this.isSettingsModalShown = !this.isSettingsModalShown
},
toggleMapListModal() {
this.isMapListModalShown = !this.isMapListModalShown
this.isCreateMapModalShown = false
},
toggleCreateMapModal() {
this.isCreateMapModalShown = !this.isCreateMapModalShown
},
setTeleportSettings(teleportSettings: TeleportSettings) { setTeleportSettings(teleportSettings: TeleportSettings) {
this.teleportSettings = teleportSettings this.teleportSettings = teleportSettings
}, },
@ -75,11 +53,6 @@ export const useMapEditorStore = defineStore('mapEditor', {
this.drawMode = 'tile' this.drawMode = 'tile'
this.selectedTile = '' this.selectedTile = ''
this.selectedMapObject = null this.selectedMapObject = null
this.isTileListModalShown = false
this.isMapObjectListModalShown = false
this.isSettingsModalShown = false
this.isMapListModalShown = false
this.isCreateMapModalShown = false
this.shouldClearTiles = false this.shouldClearTiles = false
} }
} }