forked from noxious/client
Map editor improvements
This commit is contained in:
parent
ae0841889b
commit
ef807982a5
@ -15,7 +15,7 @@ export type HttpResponse<T> = {
|
|||||||
export type AssetDataT = {
|
export type AssetDataT = {
|
||||||
key: string
|
key: string
|
||||||
data: string
|
data: string
|
||||||
group: 'tiles' | 'objects' | 'sprites' | 'sprite_animations' | 'sound' | 'music' | 'ui' | 'font' | 'other'
|
group: 'tiles' | 'map_objects' | 'sprites' | 'sprite_animations' | 'sound' | 'music' | 'ui' | 'font' | 'other'
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
originX?: number
|
originX?: number
|
||||||
originY?: number
|
originY?: number
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<MapObject v-for="mapObject in mapStore.map?.mapObjects" :tilemap="tilemap" :mapObject />
|
<MapObject v-for="mapObject in mapStore.map?.mapObjects" :tilemap="tilemap" :placedMapObject />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Image v-if="gameStore.getLoadedAsset(props.mapObject.object.id)" v-bind="imageProps" />
|
<Image v-if="gameStore.getLoadedAsset(props.placedMapObject.mapObject.id)" v-bind="imageProps" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -12,29 +12,29 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
tilemap: Phaser.Tilemaps.Tilemap
|
tilemap: Phaser.Tilemaps.Tilemap
|
||||||
mapObject: PlacedMapObject
|
placedMapObject: PlacedMapObject
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
const scene = useScene()
|
const scene = useScene()
|
||||||
|
|
||||||
const imageProps = computed(() => ({
|
const imageProps = computed(() => ({
|
||||||
depth: calculateIsometricDepth(props.mapObject.positionX, props.mapObject.positionY, props.mapObject.object.frameWidth, props.mapObject.object.frameHeight),
|
depth: calculateIsometricDepth(props.placedMapObject.positionX, props.placedMapObject.positionY, props.placedMapObject.mapObject.frameWidth, props.placedMapObject.mapObject.frameHeight),
|
||||||
x: tileToWorldX(props.tilemap, props.mapObject.positionX, props.mapObject.positionY),
|
x: tileToWorldX(props.tilemap, props.placedMapObject.positionX, props.placedMapObject.positionY),
|
||||||
y: tileToWorldY(props.tilemap, props.mapObject.positionX, props.mapObject.positionY),
|
y: tileToWorldY(props.tilemap, props.placedMapObject.positionX, props.placedMapObject.positionY),
|
||||||
flipX: props.mapObject.isRotated,
|
flipX: props.placedMapObject.isRotated,
|
||||||
texture: props.mapObject.object.id,
|
texture: props.placedMapObject.mapObject.id,
|
||||||
originY: Number(props.mapObject.object.originX),
|
originY: Number(props.placedMapObject.mapObject.originX),
|
||||||
originX: Number(props.mapObject.object.originY)
|
originX: Number(props.placedMapObject.mapObject.originY)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
loadTexture(scene, {
|
loadTexture(scene, {
|
||||||
key: props.mapObject.object.id,
|
key: props.placedMapObject.mapObject.id,
|
||||||
data: '/assets/objects/' + props.mapObject.object.id + '.png',
|
data: '/assets/map_objects/' + props.placedMapObject.mapObject.id + '.png',
|
||||||
group: 'objects',
|
group: 'map_objects',
|
||||||
updatedAt: props.mapObject.object.updatedAt,
|
updatedAt: props.placedMapObject.mapObject.updatedAt,
|
||||||
frameWidth: props.mapObject.object.frameWidth,
|
frameWidth: props.placedMapObject.mapObject.frameWidth,
|
||||||
frameHeight: props.mapObject.object.frameHeight
|
frameHeight: props.placedMapObject.mapObject.frameHeight
|
||||||
} as AssetDataT).catch((error) => {
|
} as AssetDataT).catch((error) => {
|
||||||
console.error('Error loading texture:', error)
|
console.error('Error loading texture:', error)
|
||||||
})
|
})
|
||||||
|
@ -98,11 +98,11 @@ function removeObject() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshObjectList(unsetSelectedObject = true) {
|
function refreshObjectList(unsetSelectedMapObject = true) {
|
||||||
gameStore.connection?.emit('gm:mapObject:list', {}, (response: MapObject[]) => {
|
gameStore.connection?.emit('gm:mapObject:list', {}, (response: MapObject[]) => {
|
||||||
assetManagerStore.setMapObjectList(response)
|
assetManagerStore.setMapObjectList(response)
|
||||||
|
|
||||||
if (unsetSelectedObject) {
|
if (unsetSelectedMapObject) {
|
||||||
assetManagerStore.setSelectedMapObject(null)
|
assetManagerStore.setSelectedMapObject(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import MapObjects from '@/components/gameMaster/mapEditor/mapPartials/MapObjects
|
|||||||
import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue'
|
import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue'
|
||||||
import MapList from '@/components/gameMaster/mapEditor/partials/MapList.vue'
|
import MapList from '@/components/gameMaster/mapEditor/partials/MapList.vue'
|
||||||
import MapSettings from '@/components/gameMaster/mapEditor/partials/MapSettings.vue'
|
import MapSettings from '@/components/gameMaster/mapEditor/partials/MapSettings.vue'
|
||||||
import ObjectList from '@/components/gameMaster/mapEditor/partials/ObjectList.vue'
|
import ObjectList from '@/components/gameMaster/mapEditor/partials/MapObjectList.vue'
|
||||||
import TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
|
import TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
|
||||||
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
|
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
|
||||||
// Components
|
// Components
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<SelectedMapObject v-if="selectedMapObject" :mapObject="selectedMapObject" :movingMapObject="movingMapObject" @move="moveMapObject" @rotate="rotateMapObject" @delete="deleteMapObject" />
|
<SelectedMapObject v-if="selectedMapObject" :mapObject="selectedMapObject" :movingMapObject="movingMapObject" @move="moveMapObject" @rotate="rotateMapObject" @delete="deleteMapObject" />
|
||||||
<MapObject v-for="mapObject in mapEditorStore.map?.mapObjects" :tilemap="tilemap" :mapObject :selectedMapObject :movingMapObject @pointerup="clickMapObject(mapObject)" />
|
<MapObject v-for="mapObject in mapEditorStore.map?.placedMapObjects" :tilemap="tilemap" :mapObject :selectedMapObject :movingMapObject @pointerup="clickMapObject(mapObject)" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -33,7 +33,7 @@ function pencil(pointer: Phaser.Input.Pointer) {
|
|||||||
if (mapEditorStore.drawMode !== 'object') return
|
if (mapEditorStore.drawMode !== 'object') return
|
||||||
|
|
||||||
// Check if there is a selected object
|
// Check if there is a selected object
|
||||||
if (!mapEditorStore.selectedObject) return
|
if (!mapEditorStore.selectedMapObject) return
|
||||||
|
|
||||||
// Check if left mouse button is pressed
|
// Check if left mouse button is pressed
|
||||||
if (!pointer.isDown) return
|
if (!pointer.isDown) return
|
||||||
@ -56,8 +56,8 @@ function pencil(pointer: Phaser.Input.Pointer) {
|
|||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
mapId: mapEditorStore.map.id,
|
mapId: mapEditorStore.map.id,
|
||||||
map: mapEditorStore.map,
|
map: mapEditorStore.map,
|
||||||
objectId: mapEditorStore.selectedObject.id,
|
objectId: mapEditorStore.selectedMapObject.id,
|
||||||
object: mapEditorStore.selectedObject,
|
object: mapEditorStore.selectedMapObject,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
isRotated: false,
|
isRotated: false,
|
||||||
positionX: tile.x,
|
positionX: tile.x,
|
||||||
@ -123,11 +123,11 @@ function objectPicker(pointer: Phaser.Input.Pointer) {
|
|||||||
if (!tile) return
|
if (!tile) return
|
||||||
|
|
||||||
// Check if object already exists on position
|
// Check if object already exists on position
|
||||||
const existingObject = mapEditorStore.map.placedMapObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
|
const existingMapObject = mapEditorStore.map.placedMapObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
|
||||||
if (!existingObject) return
|
if (!existingMapObject) return
|
||||||
|
|
||||||
// Select the object
|
// Select the object
|
||||||
mapEditorStore.setSelectedObject(existingObject)
|
mapEditorStore.setSelectedMapObject(existingMapObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveMapObject(id: string) {
|
function moveMapObject(id: string) {
|
||||||
@ -184,7 +184,7 @@ function clickMapObject(mapObject: MapObjectT) {
|
|||||||
|
|
||||||
// If alt is pressed, select the object
|
// If alt is pressed, select the object
|
||||||
if (scene.input.activePointer.event.altKey) {
|
if (scene.input.activePointer.event.altKey) {
|
||||||
mapEditorStore.setSelectedObject(mapObject.object)
|
mapEditorStore.setSelectedMapObject(mapObject.mapObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,20 +204,20 @@ onUnmounted(() => {
|
|||||||
scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker)
|
scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker)
|
||||||
})
|
})
|
||||||
|
|
||||||
// watch mapEditorStore.objectList and update originX and originY of objects in mapObjects
|
// watch mapEditorStore.mapObjectList and update originX and originY of objects in mapObjects
|
||||||
watch(
|
watch(
|
||||||
() => mapEditorStore.objectList,
|
() => mapEditorStore.mapObjectList,
|
||||||
(newObjects) => {
|
(newObjects) => {
|
||||||
if (!mapEditorStore.map) return
|
if (!mapEditorStore.map) return
|
||||||
|
|
||||||
console.log(mapEditorStore.map.placedMapObjects)
|
console.log(mapEditorStore.map.placedMapObjects)
|
||||||
const updatedMapObjects = mapEditorStore.map.placedMapObjects.map((mapObject) => {
|
const updatedMapObjects = mapEditorStore.map.placedMapObjects.map((mapObject) => {
|
||||||
const updatedObject = newObjects.find((obj) => obj.id === mapObject.object.id)
|
const updatedObject = newObjects.find((obj) => obj.id === mapObject.mapObject.id)
|
||||||
if (updatedObject) {
|
if (updatedObject) {
|
||||||
return {
|
return {
|
||||||
...mapObject,
|
...mapObject,
|
||||||
object: {
|
object: {
|
||||||
...mapObject.object,
|
...mapObject.mapObject,
|
||||||
originX: updatedObject.originX,
|
originX: updatedObject.originX,
|
||||||
originY: updatedObject.originY
|
originY: updatedObject.originY
|
||||||
}
|
}
|
||||||
@ -232,12 +232,12 @@ watch(
|
|||||||
mapObjects: updatedMapObjects
|
mapObjects: updatedMapObjects
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update selectedObject if it's set
|
// Update selectedMapObject if it's set
|
||||||
if (mapEditorStore.selectedObject) {
|
if (mapEditorStore.selectedMapObject) {
|
||||||
const updatedObject = newObjects.find((obj) => obj.id === mapEditorStore.selectedObject?.id)
|
const updatedObject = newObjects.find((obj) => obj.id === mapEditorStore.selectedMapObject?.id)
|
||||||
if (updatedObject) {
|
if (updatedObject) {
|
||||||
mapEditorStore.setSelectedObject({
|
mapEditorStore.setSelectedMapObject({
|
||||||
...mapEditorStore.selectedObject,
|
...mapEditorStore.selectedMapObject,
|
||||||
originX: updatedObject.originX,
|
originX: updatedObject.originX,
|
||||||
originY: updatedObject.originY
|
originY: updatedObject.originY
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Map } from '@/application/types'
|
import type { Map, UUID } from '@/application/types'
|
||||||
import CreateMap from '@/components/gameMaster/mapEditor/partials/CreateMap.vue'
|
import CreateMap from '@/components/gameMaster/mapEditor/partials/CreateMap.vue'
|
||||||
import Modal from '@/components/utilities/Modal.vue'
|
import Modal from '@/components/utilities/Modal.vue'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
@ -46,14 +46,14 @@ function fetchMaps() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMap(id: number) {
|
function loadMap(id: UUID) {
|
||||||
gameStore.connection?.emit('gm:map:request', { mapId: id }, (response: Map) => {
|
gameStore.connection?.emit('gm:map:request', { mapId: id }, (response: Map) => {
|
||||||
mapEditorStore.setMap(response)
|
mapEditorStore.setMap(response)
|
||||||
})
|
})
|
||||||
mapEditorStore.toggleMapListModal()
|
mapEditorStore.toggleMapListModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteMap(id: number) {
|
function deleteMap(id: UUID) {
|
||||||
gameStore.connection?.emit('gm:map:delete', { mapId: id }, () => {
|
gameStore.connection?.emit('gm:map:delete', { mapId: id }, () => {
|
||||||
fetchMaps()
|
fetchMaps()
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal :isModalOpen="mapEditorStore.isObjectListModalShown" :modal-width="645" :modal-height="260" @modal:close="() => (mapEditorStore.isObjectListModalShown = false)" :bg-style="'none'">
|
<Modal :isModalOpen="mapEditorStore.isMapObjectListModalShown" :modal-width="645" :modal-height="260" @modal:close="() => (mapEditorStore.isMapObjectListModalShown = false)" :bg-style="'none'">
|
||||||
<template #modalHeader>
|
<template #modalHeader>
|
||||||
<h3 class="text-lg text-white">Objects</h3>
|
<h3 class="text-lg text-white">Objects</h3>
|
||||||
</template>
|
</template>
|
||||||
@ -20,16 +20,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="h-full overflow-auto">
|
<div class="h-full overflow-auto">
|
||||||
<div class="flex justify-between flex-wrap gap-2.5 items-center">
|
<div class="flex justify-between flex-wrap gap-2.5 items-center">
|
||||||
<div v-for="(object, index) in filteredObjects" :key="index" class="max-w-1/4 inline-block">
|
<div v-for="(mapObject, index) in filteredMapObjects" :key="index" class="max-w-1/4 inline-block">
|
||||||
<img
|
<img
|
||||||
class="border-2 border-solid max-w-full"
|
class="border-2 border-solid max-w-full"
|
||||||
:src="`${config.server_endpoint}/assets/objects/${object.id}.png`"
|
:src="`${config.server_endpoint}/assets/objects/${mapObject.id}.png`"
|
||||||
alt="Object"
|
alt="Object"
|
||||||
@click="mapEditorStore.setSelectedObject(object)"
|
@click="mapEditorStore.setSelectedMapObject(mapObject)"
|
||||||
:class="{
|
:class="{
|
||||||
'cursor-pointer transition-all duration-300': true,
|
'cursor-pointer transition-all duration-300': true,
|
||||||
'border-cyan shadow-lg scale-105': mapEditorStore.selectedObject?.id === object.id,
|
'border-cyan shadow-lg scale-105': mapEditorStore.selectedMapObject?.id === mapObject.id,
|
||||||
'border-transparent hover:border-gray-300': mapEditorStore.selectedObject?.id !== object.id
|
'border-transparent hover:border-gray-300': mapEditorStore.selectedMapObject?.id !== mapObject.id
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import config from '@/application/config'
|
import config from '@/application/config'
|
||||||
import type { MapObject, PlacedMapObject } from '@/application/types'
|
import type { MapObject } 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'
|
||||||
@ -55,12 +55,12 @@ const searchQuery = ref('')
|
|||||||
const selectedTags = ref<string[]>([])
|
const selectedTags = ref<string[]>([])
|
||||||
|
|
||||||
const uniqueTags = computed(() => {
|
const uniqueTags = computed(() => {
|
||||||
const allTags = mapEditorStore.objectList.flatMap((obj) => obj.tags || [])
|
const allTags = mapEditorStore.mapObjectList.flatMap((obj) => obj.tags || [])
|
||||||
return Array.from(new Set(allTags))
|
return Array.from(new Set(allTags))
|
||||||
})
|
})
|
||||||
|
|
||||||
const filteredObjects = computed(() => {
|
const filteredMapObjects = computed(() => {
|
||||||
return mapEditorStore.objectList.filter((object) => {
|
return mapEditorStore.mapObjectList.filter((object) => {
|
||||||
const matchesSearch = !searchQuery.value || object.name.toLowerCase().includes(searchQuery.value.toLowerCase())
|
const matchesSearch = !searchQuery.value || object.name.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||||||
const matchesTags = selectedTags.value.length === 0 || (object.tags && selectedTags.value.some((tag) => object.tags.includes(tag)))
|
const matchesTags = selectedTags.value.length === 0 || (object.tags && selectedTags.value.some((tag) => object.tags.includes(tag)))
|
||||||
return matchesSearch && matchesTags
|
return matchesSearch && matchesTags
|
||||||
@ -77,7 +77,7 @@ const toggleTag = (tag: string) => {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
isModalOpen.value = true
|
isModalOpen.value = true
|
||||||
gameStore.connection?.emit('gm:mapObject:list', {}, (response: MapObject[]) => {
|
gameStore.connection?.emit('', {}, (response: MapObject[]) => {
|
||||||
mapEditorStore.setMapObjectList(response)
|
mapEditorStore.setMapObjectList(response)
|
||||||
})
|
})
|
||||||
})
|
})
|
@ -33,7 +33,7 @@ export const useAssetManagerStore = defineStore('assetManager', () => {
|
|||||||
mapObjectList.value = objects
|
mapObjectList.value = objects
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSelectedObject(object: MapObject | null) {
|
function setSelectedMapObject(object: MapObject | null) {
|
||||||
selectedMapObject.value = object
|
selectedMapObject.value = object
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ export const useAssetManagerStore = defineStore('assetManager', () => {
|
|||||||
setSelectedTile,
|
setSelectedTile,
|
||||||
setMapObjectList,
|
setMapObjectList,
|
||||||
setCharacterTypeList,
|
setCharacterTypeList,
|
||||||
setSelectedMapObject: setSelectedObject,
|
setSelectedMapObject: setSelectedMapObject,
|
||||||
setSpriteList,
|
setSpriteList,
|
||||||
setSelectedSprite,
|
setSelectedSprite,
|
||||||
setSelectedCharacterType,
|
setSelectedCharacterType,
|
||||||
|
@ -21,7 +21,7 @@ export const useMapEditorStore = defineStore('mapEditor', {
|
|||||||
tileList: [] as Tile[],
|
tileList: [] as Tile[],
|
||||||
mapObjectList: [] as MapObject[],
|
mapObjectList: [] as MapObject[],
|
||||||
selectedTile: '',
|
selectedTile: '',
|
||||||
selectedObject: null as MapObject | null,
|
selectedMapObject: null as MapObject | null,
|
||||||
isTileListModalShown: false,
|
isTileListModalShown: false,
|
||||||
isMapObjectListModalShown: false,
|
isMapObjectListModalShown: false,
|
||||||
isMapListModalShown: false,
|
isMapListModalShown: false,
|
||||||
@ -91,8 +91,8 @@ export const useMapEditorStore = defineStore('mapEditor', {
|
|||||||
setSelectedTile(tile: string) {
|
setSelectedTile(tile: string) {
|
||||||
this.selectedTile = tile
|
this.selectedTile = tile
|
||||||
},
|
},
|
||||||
setSelectedObject(object: MapObject) {
|
setSelectedMapObject(object: MapObject) {
|
||||||
this.selectedObject = object
|
this.selectedMapObject = object
|
||||||
},
|
},
|
||||||
toggleSettingsModal() {
|
toggleSettingsModal() {
|
||||||
this.isSettingsModalShown = !this.isSettingsModalShown
|
this.isSettingsModalShown = !this.isSettingsModalShown
|
||||||
@ -122,7 +122,7 @@ export const useMapEditorStore = defineStore('mapEditor', {
|
|||||||
this.tool = 'move'
|
this.tool = 'move'
|
||||||
this.drawMode = 'tile'
|
this.drawMode = 'tile'
|
||||||
this.selectedTile = ''
|
this.selectedTile = ''
|
||||||
this.selectedObject = null
|
this.selectedMapObject = null
|
||||||
this.isTileListModalShown = false
|
this.isTileListModalShown = false
|
||||||
this.isMapObjectListModalShown = false
|
this.isMapObjectListModalShown = false
|
||||||
this.isSettingsModalShown = false
|
this.isSettingsModalShown = false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user