1
0
forked from noxious/client

#216: Added tile & object picker in map editor

This commit is contained in:
Dennis Postma 2024-11-03 01:26:13 +01:00
parent 6f40c774ea
commit adf86d369b
6 changed files with 105 additions and 29 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" :movingZoneObject="movingZoneObject" @move="moveZoneObject" @rotate="rotateZoneObject" @delete="deleteZoneObject" /> <SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" :movingZoneObject="movingZoneObject" @move="moveZoneObject" @rotate="rotateZoneObject" @delete="deleteZoneObject" />
<ZoneObject v-for="zoneObject in zoneEditorStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject :selectedZoneObject :movingZoneObject @pointerup="() => (selectedZoneObject = zoneObject)" /> <ZoneObject v-for="zoneObject in zoneEditorStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject :selectedZoneObject :movingZoneObject @pointerup="clickZoneObject(zoneObject)" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -41,6 +41,9 @@ function pencil(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 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(props.tilemap, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
@ -53,7 +56,7 @@ function pencil(pointer: Phaser.Input.Pointer) {
id: uuidv4(), id: uuidv4(),
zoneId: zoneEditorStore.zone.id, zoneId: zoneEditorStore.zone.id,
zone: zoneEditorStore.zone, zone: zoneEditorStore.zone,
objectId: zoneEditorStore.selectedObject.id, objectId: zoneEditorStore.selectedObject,
object: zoneEditorStore.selectedObject, object: zoneEditorStore.selectedObject,
depth: 0, depth: 0,
isRotated: false, isRotated: false,
@ -81,6 +84,9 @@ 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 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(props.tilemap, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
@ -93,6 +99,37 @@ function eraser(pointer: Phaser.Input.Pointer) {
zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.filter((object) => object.id !== existingObject.id) zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.filter((object) => object.id !== existingObject.id)
} }
function objectPicker(pointer: Phaser.Input.Pointer) {
// Check if zone is set
if (!zoneEditorStore.zone) return
// Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return
// Check if draw mode is object
if (zoneEditorStore.drawMode !== 'object') return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if 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
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
if (!tile) return
// Check if object already exists on position
const existingObject = zoneEditorStore.zone.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
if (!existingObject) return
// Select the object
zoneEditorStore.setSelectedObject(existingObject)
}
function moveZoneObject(id: string) { function moveZoneObject(id: string) {
// Check if zone is set // Check if zone is set
if (!zoneEditorStore.zone) return if (!zoneEditorStore.zone) return
@ -142,11 +179,21 @@ function deleteZoneObject(id: string) {
selectedZoneObject.value = null selectedZoneObject.value = null
} }
function clickZoneObject(zoneObject: ZoneObjectT) {
selectedZoneObject.value = zoneObject
// If alt is pressed, select the object
if (scene.input.activePointer.event.altKey) {
zoneEditorStore.setSelectedObject(zoneObject.object)
}
}
onMounted(() => { onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil) 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_MOVE, pencil)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser) 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_MOVE, eraser)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, objectPicker)
}) })
onUnmounted(() => { onUnmounted(() => {
@ -154,6 +201,7 @@ onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, 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_DOWN, eraser)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser) scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker)
}) })
// watch zoneEditorStore.objectList and update originX and originY of objects in zoneObjects // watch zoneEditorStore.objectList and update originX and originY of objects in zoneObjects

View File

@ -83,10 +83,10 @@ function pencil(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Place tile // Place tile
placeTile(zoneTilemap, tiles, tile.x, tile.y, zoneEditorStore.selectedTile.id) placeTile(zoneTilemap, tiles, tile.x, tile.y, zoneEditorStore.selectedTile)
// Adjust zoneEditorStore.zone.tiles // Adjust zoneEditorStore.zone.tiles
zoneEditorStore.zone.tiles[tile.y][tile.x] = zoneEditorStore.selectedTile.id zoneEditorStore.zone.tiles[tile.y][tile.x] = zoneEditorStore.selectedTile
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer) {
@ -105,6 +105,9 @@ 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 alt is pressed
if (pointer.event.altKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(tiles, pointer.worldX, pointer.worldY) const tile = getTile(tiles, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
@ -129,6 +132,12 @@ function paint(pointer: Phaser.Input.Pointer) {
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return 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(zoneTilemap, tiles, createTileArray(zoneTilemap.width, zoneTilemap.height, zoneEditorStore.selectedTile.id)) setLayerTiles(zoneTilemap, tiles, createTileArray(zoneTilemap.width, zoneTilemap.height, zoneEditorStore.selectedTile.id))
@ -136,6 +145,34 @@ function paint(pointer: Phaser.Input.Pointer) {
zoneEditorStore.zone.tiles = createTileArray(zoneTilemap.width, zoneTilemap.height, zoneEditorStore.selectedTile.id) zoneEditorStore.zone.tiles = createTileArray(zoneTilemap.width, zoneTilemap.height, zoneEditorStore.selectedTile.id)
} }
// When alt is pressed, and the pointer is down, select the tile that the pointer is over
function tilePicker(pointer: Phaser.Input.Pointer) {
// Check if zone is set
if (!zoneEditorStore.zone) return
// Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return
// Check if draw mode is tile
if (zoneEditorStore.drawMode !== 'tile') return
// Check if left mouse button is pressed
if (!pointer.isDown) return
// Check if 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
const tile = getTile(tiles, pointer.worldX, pointer.worldY)
if (!tile) return
// Select the tile
zoneEditorStore.setSelectedTile(zoneEditorStore.zone.tiles[tile.y][tile.x])
}
onMounted(() => { onMounted(() => {
if (!zoneEditorStore.zone?.tiles) { if (!zoneEditorStore.zone?.tiles) {
return return
@ -145,12 +182,14 @@ onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil) 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_MOVE, eraser)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, paint) 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, pencil)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser) 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, paint)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, tilePicker)
zoneTilemap.destroyLayer('tiles') zoneTilemap.destroyLayer('tiles')
zoneTilemap.removeAllLayers() zoneTilemap.removeAllLayers()

View File

@ -42,23 +42,18 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/config' import config from '@/config'
import { ref, onMounted, computed, watch } from 'vue' import { ref, onMounted, computed } from 'vue'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import type { Object } from '@/types' import type { Object, ZoneObject } from '@/types'
const gameStore = useGameStore() const gameStore = useGameStore()
const isModalOpen = ref(false) const isModalOpen = ref(false)
const zoneEditorStore = useZoneEditorStore() const zoneEditorStore = useZoneEditorStore()
const searchQuery = ref('') const searchQuery = ref('')
// const objectDepth = ref(0)
const selectedTags = ref<string[]>([]) const selectedTags = ref<string[]>([])
// watch(objectDepth, (depth) => {
// zoneEditorStore.setObjectDepth(depth)
// })
const uniqueTags = computed(() => { const uniqueTags = computed(() => {
const allTags = zoneEditorStore.objectList.flatMap((obj) => obj.tags || []) const allTags = zoneEditorStore.objectList.flatMap((obj) => obj.tags || [])
return Array.from(new Set(allTags)) return Array.from(new Set(allTags))
@ -81,8 +76,6 @@ const toggleTag = (tag: string) => {
} }
onMounted(async () => { onMounted(async () => {
zoneEditorStore.setObjectDepth(0)
isModalOpen.value = true isModalOpen.value = true
gameStore.connection?.emit('gm:object:list', {}, (response: Object[]) => { gameStore.connection?.emit('gm:object:list', {}, (response: Object[]) => {
zoneEditorStore.setObjectList(response) zoneEditorStore.setObjectList(response)

View File

@ -52,7 +52,7 @@
class="max-w-full max-h-full border-2 border-solid cursor-pointer transition-all duration-300" class="max-w-full max-h-full border-2 border-solid cursor-pointer transition-all duration-300"
:src="`${config.server_endpoint}/assets/tiles/${selectedGroup.parent.id}.png`" :src="`${config.server_endpoint}/assets/tiles/${selectedGroup.parent.id}.png`"
:alt="selectedGroup.parent.name" :alt="selectedGroup.parent.name"
@click="selectTile(selectedGroup.parent)" @click="selectTile(selectedGroup.parent.id)"
:class="{ :class="{
'border-cyan shadow-lg scale-105': isActiveTile(selectedGroup.parent), 'border-cyan shadow-lg scale-105': isActiveTile(selectedGroup.parent),
'border-transparent hover:border-gray-300': !isActiveTile(selectedGroup.parent) 'border-transparent hover:border-gray-300': !isActiveTile(selectedGroup.parent)
@ -65,7 +65,7 @@
class="max-w-full max-h-full border-2 border-solid cursor-pointer transition-all duration-300" class="max-w-full max-h-full border-2 border-solid cursor-pointer transition-all duration-300"
:src="`${config.server_endpoint}/assets/tiles/${childTile.id}.png`" :src="`${config.server_endpoint}/assets/tiles/${childTile.id}.png`"
:alt="childTile.name" :alt="childTile.name"
@click="selectTile(childTile)" @click="selectTile(childTile.id)"
:class="{ :class="{
'border-cyan shadow-lg scale-105': isActiveTile(childTile), 'border-cyan shadow-lg scale-105': isActiveTile(childTile),
'border-transparent hover:border-gray-300': !isActiveTile(childTile) 'border-transparent hover:border-gray-300': !isActiveTile(childTile)
@ -218,7 +218,7 @@ function closeGroup() {
selectedGroup.value = null selectedGroup.value = null
} }
function selectTile(tile: Tile) { function selectTile(tile: string) {
zoneEditorStore.setSelectedTile(tile) zoneEditorStore.setSelectedTile(tile)
} }

View File

@ -1,13 +1,14 @@
<template> <template>
<Image v-if="isTextureLoaded" v-bind="imageProps" /> <Image v-if="gameStore.getLoadedAsset(props.zoneObject.object.id)" v-bind="imageProps" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { computed } from 'vue'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
import { loadTexture } from '@/composables/gameComposable' import { loadTexture } from '@/composables/gameComposable'
import type { AssetDataT, ZoneObject } from '@/types' import type { AssetDataT, ZoneObject } from '@/types'
import { useGameStore } from '@/stores/gameStore'
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tilemap: Phaser.Tilemaps.Tilemap
@ -16,8 +17,8 @@ const props = defineProps<{
movingZoneObject: ZoneObject | null movingZoneObject: ZoneObject | null
}>() }>()
const gameStore = useGameStore()
const scene = useScene() const scene = useScene()
const isTextureLoaded = ref(false)
const imageProps = computed(() => ({ const imageProps = computed(() => ({
alpha: props.movingZoneObject?.id === props.zoneObject.id ? 0.5 : 1, alpha: props.movingZoneObject?.id === props.zoneObject.id ? 0.5 : 1,

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import type { Zone, Object, Tile, ZoneEffect } from '@/types' import type { Zone, Object, Tile, ZoneEffect, ZoneObject } from '@/types'
export type TeleportSettings = { export type TeleportSettings = {
toZoneId: number toZoneId: number
@ -20,9 +20,8 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
zoneList: [] as Zone[], zoneList: [] as Zone[],
tileList: [] as Tile[], tileList: [] as Tile[],
objectList: [] as Object[], objectList: [] as Object[],
selectedTile: null as Tile | null, selectedTile: '',
selectedObject: null as Object | null, selectedObject: null as Object | null,
objectDepth: 0,
isTileListModalShown: false, isTileListModalShown: false,
isObjectListModalShown: false, isObjectListModalShown: false,
isZoneListModalShown: false, isZoneListModalShown: false,
@ -88,15 +87,12 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
setObjectList(objects: Object[]) { setObjectList(objects: Object[]) {
this.objectList = objects this.objectList = objects
}, },
setSelectedTile(tile: Tile) { setSelectedTile(tile: string) {
this.selectedTile = tile this.selectedTile = tile
}, },
setSelectedObject(object: any) { setSelectedObject(object: Object) {
this.selectedObject = object this.selectedObject = object
}, },
setObjectDepth(depth: number) {
this.objectDepth = depth
},
toggleSettingsModal() { toggleSettingsModal() {
this.isSettingsModalShown = !this.isSettingsModalShown this.isSettingsModalShown = !this.isSettingsModalShown
}, },
@ -117,9 +113,8 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
this.objectList = [] this.objectList = []
this.tool = 'move' this.tool = 'move'
this.drawMode = 'tile' this.drawMode = 'tile'
this.selectedTile = null this.selectedTile = ''
this.selectedObject = null this.selectedObject = null
this.objectDepth = 0
this.isSettingsModalShown = false this.isSettingsModalShown = false
this.isZoneListModalShown = false this.isZoneListModalShown = false
this.isCreateZoneModalShown = false this.isCreateZoneModalShown = false