From ca307d4de3dcc3bc507801d462eca96c3879e770 Mon Sep 17 00:00:00 2001 From: Andrei <amborn02@gmail.com> Date: Sat, 8 Feb 2025 15:07:21 -0600 Subject: [PATCH 1/2] Teleport modal restored, and expanded undo/redo to include all placed and erase edits across each map element type (map object advanced actions WIP) --- src/components/gameMaster/mapEditor/Map.vue | 115 ++++++++++++-- .../mapEditor/mapPartials/MapEventTiles.vue | 66 +++++++- .../mapEditor/mapPartials/MapTiles.vue | 145 ++++++------------ .../mapPartials/PlacedMapObjects.vue | 96 +++++++++++- .../gameMaster/mapEditor/partials/Toolbar.vue | 4 +- src/components/screens/MapEditor.vue | 11 +- src/services/mapService.ts | 5 + 7 files changed, 316 insertions(+), 126 deletions(-) diff --git a/src/components/gameMaster/mapEditor/Map.vue b/src/components/gameMaster/mapEditor/Map.vue index 2a926ae..7acceb7 100644 --- a/src/components/gameMaster/mapEditor/Map.vue +++ b/src/components/gameMaster/mapEditor/Map.vue @@ -1,30 +1,109 @@ <template> - <MapTiles ref="mapTiles" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> - <PlacedMapObjects ref="mapObjects" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> - <MapEventTiles ref="eventTiles" v-if="tileMap" :tileMap /> + <MapTiles ref="mapTiles" @createCommand="addCommand" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> + <PlacedMapObjects ref="mapObjects" @createCommand="addCommand" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> + <MapEventTiles ref="eventTiles" @createCommand="addCommand" v-if="tileMap" :tileMap /> </template> <script setup lang="ts"> + import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue' import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue' import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue' import { useMapEditorComposable } from '@/composables/useMapEditorComposable' -import { createTileLayer, createTileMap } from '@/services/mapService' +import { cloneArray, createTileLayer, createTileMap, placeTiles } from '@/services/mapService' import { TileStorage } from '@/storage/storages' import { useScene } from 'phavuer' -import { onBeforeUnmount, onMounted, onUnmounted, shallowRef, useTemplateRef } from 'vue' + +import { onBeforeUnmount, onMounted, onUnmounted, ref, shallowRef, useTemplateRef, watch } from 'vue' +import type { MapEventTile, PlacedMapObject as PlacedMapObjectT } from '@/application/types' const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>() const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>() const mapEditor = useMapEditorComposable() - const scene = useScene() const mapTiles = useTemplateRef('mapTiles') const mapObjects = useTemplateRef('mapObjects') const eventTiles = useTemplateRef('eventTiles') +//Record of commands +let commandStack: EditorCommand[] = [] +let commandIndex = ref(0) + +let originTiles: string[][] = [] +let originEventTiles: MapEventTile[] = [] +let originObjects: PlacedMapObjectT[] = [] + +//Command Pattern basic interface, extended to store what elements have been changed by each edit +export interface EditorCommand { + apply: (elements: any[]) => any[] + type: 'tile' | 'map_object' | 'event_tile' + operation: 'draw' | 'erase' | 'place' | 'move' | 'delete' | 'rotate' +} + +function applyCommands(tiles: any[], ...commands: EditorCommand[]): any[] { + let tileVersion = cloneArray(tiles) + for (let command of commands) { + tileVersion = command.apply(tileVersion) + } + return tileVersion +} + +watch(() => commandIndex.value!, (val) => { + if (val !== undefined) { + update(commandStack.slice(0, val)) + } +}) + +function update(commands: EditorCommand[]) { + if (!mapEditor.currentMap.value) return + + const tileCommands = commands.filter((command) => command.type === 'tile') + const eventTileCommands = commands.filter((command) => command.type === 'event_tile') + const objectCommands = commands.filter((command) => command.type === 'map_object') + + let modifiedTiles = applyCommands(originTiles, ...tileCommands) + placeTiles(tileMap.value!, tileMapLayer.value!, modifiedTiles) + + mapEditor.currentMap.value.tiles = modifiedTiles + mapEditor.currentMap.value.mapEventTiles = applyCommands(originEventTiles, ...eventTileCommands) + mapEditor.currentMap.value.placedMapObjects = applyCommands(originObjects, ...objectCommands) +} + +function addCommand(command: EditorCommand) { + commandStack = commandStack.slice(0, commandIndex.value) + commandStack.push(command) + + if (commandStack.length >= 9) { + switch (commandStack[0].type) { + case 'tile': + originTiles = commandStack.shift()?.apply(originTiles) as string[][] + break + case 'map_object': + originObjects = commandStack.shift()?.apply(originObjects) as PlacedMapObjectT[] + break + case 'event_tile': + originEventTiles = commandStack.shift()?.apply(originEventTiles) as MapEventTile[] + break + } + } + + commandIndex.value = commandStack.length +} + +function undo() { + if (commandIndex.value > 0) { + commandIndex.value-- + } +} + +function redo() { + if (commandIndex.value <= 9 && commandIndex.value <= commandStack.length) { + commandIndex.value++ + } +} + function handlePointerDown(pointer: Phaser.Input.Pointer) { if (!mapTiles.value || !mapObjects.value || !eventTiles.value) return @@ -54,12 +133,12 @@ function handlePointerDown(pointer: Phaser.Input.Pointer) { function handleKeyDown(event: KeyboardEvent) { //CTRL+Y if (event.key === 'y' && event.ctrlKey) { - mapTiles.value!.redo() + redo() } //CTRL+Z if (event.key === 'z' && event.ctrlKey) { - mapTiles.value!.undo() + undo() } } @@ -70,8 +149,19 @@ function handlePointerMove(pointer: Phaser.Input.Pointer) { } function handlePointerUp(pointer: Phaser.Input.Pointer) { - if (mapEditor.drawMode.value === 'tile') { - mapTiles.value?.finalizeCommand() + switch(mapEditor.drawMode.value) { + case 'tile': + mapTiles.value!.finalizeCommand() + break + case 'map_object': + mapObjects.value!.finalizeCommand() + break + case 'teleport': + eventTiles.value!.finalizeCommand() + break + case 'blocking tile': + eventTiles.value!.finalizeCommand() + break } } @@ -79,6 +169,11 @@ onMounted(async () => { let mapValue = mapEditor.currentMap.value if (!mapValue) return + //Clone + originTiles = cloneArray(mapValue.tiles) + originObjects = cloneArray(mapValue.placedMapObjects) + originEventTiles = cloneArray(mapValue.mapEventTiles) + const tileStorage = new TileStorage() const allTiles = await tileStorage.getAll() const allTileIds = allTiles.map((tile) => tile.id) diff --git a/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue b/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue index ca613b9..77db3a2 100644 --- a/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue +++ b/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue @@ -3,22 +3,72 @@ </template> <script setup lang="ts"> + import { MapEventTileType, type MapEventTile, type Map as MapT, type UUID } from '@/application/types' import { uuidv4 } from '@/application/utilities' import { useMapEditorComposable } from '@/composables/useMapEditorComposable' -import { getTile, tileToWorldX, tileToWorldY } from '@/services/mapService' +import { cloneArray, getTile, tileToWorldX, tileToWorldY } from '@/services/mapService' import { Image } from 'phavuer' -import { shallowRef } from 'vue' +import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue' const mapEditor = useMapEditorComposable() -defineExpose({ handlePointer }) +defineExpose({ handlePointer, finalizeCommand }) + +const emit = defineEmits(['createCommand']) const props = defineProps<{ tileMap: Phaser.Tilemaps.Tilemap }>() -const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>() + +// *** COMMAND STATE *** + +let currentCommand: EventTileCommand | null = null + +class EventTileCommand implements EditorCommand { + public operation: 'draw' | 'erase' = 'draw' + public type: 'event_tile' = 'event_tile' + public affectedTiles: MapEventTile[] = [] + + apply(elements: MapEventTile[]) { + let tileVersion = cloneArray(elements) as MapEventTile[] + if (this.operation === 'draw') { + tileVersion = tileVersion.concat(this.affectedTiles) + } + else if (this.operation === 'erase') { + tileVersion = tileVersion.filter((v) => !this.affectedTiles.includes(v)) + } + return tileVersion + } + + constructor(operation: 'draw' | 'erase') { + this.operation = operation + } +} + +function createCommandUpdate(tile: MapEventTile, operation: 'draw' | 'erase') { + if (!currentCommand) { + currentCommand = new EventTileCommand(operation) + } + + //If position is already in, do not proceed + for (const priorTile of currentCommand.affectedTiles) { + if (priorTile.positionX === tile.positionX && priorTile.positionY == tile.positionY) return + } + + currentCommand.affectedTiles.push(tile) +} + +function finalizeCommand() { + if (!currentCommand) return + emit('createCommand', currentCommand) + currentCommand = null +} + + +// *** HANDLERS *** + function getImageProps(tile: MapEventTile) { return { @@ -44,7 +94,7 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) { const newEventTile = { id: uuidv4() as UUID, mapId: map.id, - map: map.id, + map: map, type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT, positionX: tile.x, positionY: tile.y, @@ -59,6 +109,8 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) { : undefined } + createCommandUpdate(newEventTile, 'draw') + map.mapEventTiles.push(newEventTile) } @@ -70,12 +122,14 @@ function erase(pointer: Phaser.Input.Pointer, map: MapT) { // Check if event tile already exists on position const existingEventTile = map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y) if (!existingEventTile) return - + if (mapEditor.drawMode.value !== existingEventTile.type.toLowerCase()) { if (mapEditor.drawMode.value === 'blocking tile' && existingEventTile.type === MapEventTileType.BLOCK) null //skip this case else return; } + createCommandUpdate(existingEventTile, 'erase') + // Remove existing event tile map.mapEventTiles = map.mapEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id) } diff --git a/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue b/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue index 755b3ef..671e8b0 100644 --- a/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue +++ b/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue @@ -5,57 +5,70 @@ <script setup lang="ts"> import Controls from '@/components/utilities/Controls.vue' import { useMapEditorComposable } from '@/composables/useMapEditorComposable' -import { createTileArray, getTile, placeTile, placeTiles } from '@/services/mapService' +import { cloneArray, createTileArray, getTile, placeTile, placeTiles } from '@/services/mapService' import { onMounted, ref, watch } from 'vue' +import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue' const mapEditor = useMapEditorComposable() -defineExpose({ handlePointer, finalizeCommand, undo, redo }) +defineExpose({ handlePointer, finalizeCommand }) + +const emit = defineEmits(['createCommand']) const props = defineProps<{ tileMap: Phaser.Tilemaps.Tilemap tileMapLayer: Phaser.Tilemaps.TilemapLayer }>() -class EditorCommand { + +// *** COMMAND STATE *** + +let currentCommand: TileCommand | null = null + +class TileCommand implements EditorCommand { public operation: 'draw' | 'erase' = 'draw' + public type: 'tile' = 'tile' public tileName: string = 'blank_tile' - public affectedTiles: number[][] + public affectedTiles: number[][] = [] + + apply(elements: string[][]) { + let tileVersion = cloneArray(elements) as string[][] + for (const position of this.affectedTiles) { + tileVersion[position[1]][position[0]] = this.tileName + } + return tileVersion + } constructor(operation: 'draw' | 'erase', tileName: string) { this.operation = operation this.tileName = tileName - this.affectedTiles = [] } } -//Record of commands -let commandStack: EditorCommand[] = [] -let currentCommand: EditorCommand | null = null -let commandIndex = ref(0) -let originTiles: string[][] = [] +function createCommandUpdate(x: number, y: number, tileName: string, operation: 'draw' | 'erase') { + if (!currentCommand) { + currentCommand = new TileCommand(operation, tileName) + } -function pencil(pointer: Phaser.Input.Pointer) { - let map = mapEditor.currentMap.value - if (!map) return + //If position is already in, do not proceed + for (const vec of currentCommand.affectedTiles) { + if (vec[0] === x && vec[1] === y) return + } - // Check if there is a selected tile - if (!mapEditor.selectedTile.value) return - - // Check if there is a tile - const tile = getTile(props.tileMapLayer, pointer.worldX, pointer.worldY) - if (!tile) return - - // Place tile - placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, mapEditor.selectedTile.value) - - createCommandUpdate(tile.x, tile.y, mapEditor.selectedTile.value, 'draw') - - // Adjust mapEditorStore.map.tiles - map.tiles[tile.y][tile.x] = mapEditor.selectedTile.value + currentCommand.affectedTiles.push([x, y]) } -function eraser(pointer: Phaser.Input.Pointer) { +function finalizeCommand() { + if (!currentCommand) return + emit('createCommand', currentCommand) + currentCommand = null +} + + +// *** HANDLERS *** + + +function draw(pointer: Phaser.Input.Pointer, tileName: string) { let map = mapEditor.currentMap.value if (!map) return @@ -64,12 +77,12 @@ function eraser(pointer: Phaser.Input.Pointer) { if (!tile) return // Place tile - placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, 'blank_tile') + placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, tileName) - createCommandUpdate(tile.x, tile.y, 'blank_tile', 'erase') + createCommandUpdate(tile.x, tile.y, tileName, tileName === 'blank_tile' ? 'erase': 'draw') // Adjust mapEditorStore.map.tiles - map.tiles[tile.y][tile.x] = 'blank_tile' + map.tiles[tile.y][tile.x] = tileName } function paint(pointer: Phaser.Input.Pointer) { @@ -113,10 +126,10 @@ function handlePointer(pointer: Phaser.Input.Pointer) { // Check if draw mode is tile switch (mapEditor.tool.value) { case 'pencil': - pencil(pointer) + draw(pointer, mapEditor.selectedTile.value!) break case 'eraser': - eraser(pointer) + draw(pointer, 'blank_tile') break case 'paint': paint(pointer) @@ -124,70 +137,9 @@ function handlePointer(pointer: Phaser.Input.Pointer) { } } -function createCommandUpdate(x: number, y: number, tileName: string, operation: 'draw' | 'erase') { - if (!currentCommand) { - currentCommand = new EditorCommand(operation, tileName) - } - //If position is already in, do not proceed - for (const vec of currentCommand.affectedTiles) { - if (vec[0] === x && vec[1] === y) return - } +// *** LIFECYCLE *** - currentCommand.affectedTiles.push([x, y]) -} - -function finalizeCommand() { - if (!currentCommand) return - //Cut the stack so the current edit is the last - commandStack = commandStack.slice(0, commandIndex.value) - commandStack.push(currentCommand) - if (commandStack.length >= 9) { - originTiles = applyCommands(originTiles, commandStack.shift()!) - } - - commandIndex.value = commandStack.length - currentCommand = null -} - -function undo() { - if (commandIndex.value > 0) { - commandIndex.value-- - updateMapTiles() - } -} - -function redo() { - if (commandIndex.value <= 9 && commandIndex.value <= commandStack.length) { - commandIndex.value++ - updateMapTiles() - } -} - -function applyCommands(tiles: string[][], ...commands: EditorCommand[]): string[][] { - let tileVersion = cloneArray(tiles) - for (let command of commands) { - for (const position of command.affectedTiles) { - tileVersion[position[1]][position[0]] = command.tileName - } - } - return tileVersion -} - -function updateMapTiles() { - if (!mapEditor.currentMap.value) return - - let indexedCommands = commandStack.slice(0, commandIndex.value) - let modifiedTiles = applyCommands(originTiles, ...indexedCommands) - - placeTiles(props.tileMap, props.tileMapLayer, modifiedTiles) - mapEditor.currentMap.value.tiles = modifiedTiles -} - -//Recursive Array Clone -function cloneArray(arr: any[]): any[] { - return arr.map((item) => (item instanceof Array ? cloneArray(item) : item)) -} watch( () => mapEditor.shouldClearTiles.value, @@ -205,9 +157,6 @@ onMounted(async () => { if (!mapEditor.currentMap.value) return const mapState = mapEditor.currentMap.value - //Clone - originTiles = cloneArray(mapState.tiles) - placeTiles(props.tileMap, props.tileMapLayer, mapState.tiles) }) </script> diff --git a/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue b/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue index 63096e1..81aabfe 100644 --- a/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue +++ b/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue @@ -4,29 +4,98 @@ </template> <script setup lang="ts"> -import type { MapObject, Map as MapT, PlacedMapObject as PlacedMapObjectT, UUID } from '@/application/types' +import type { + MapObject, + Map as MapT, + PlacedMapObject as PlacedMapObjectT, + UUID, + MapEventTile +} from '@/application/types' import { uuidv4 } from '@/application/utilities' import PlacedMapObject from '@/components/game/map/partials/PlacedMapObject.vue' import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue' import { useMapEditorComposable } from '@/composables/useMapEditorComposable' -import { getTile } from '@/services/mapService' +import { cloneArray, getTile } from '@/services/mapService' import { useScene } from 'phavuer' import Tilemap = Phaser.Tilemaps.Tilemap import TilemapLayer = Phaser.Tilemaps.TilemapLayer import { computed } from 'vue' +import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue' +import Vector2 = Phaser.Math.Vector2 +import Tile = Phaser.Tilemaps.Tile const scene = useScene() const mapEditor = useMapEditorComposable() -const map = computed(() => mapEditor.currentMap.value) +const map = computed(() => mapEditor.currentMap.value!) -defineExpose({ handlePointer }) +defineExpose({ handlePointer, finalizeCommand }) + +const emit = defineEmits(['createCommand']) const props = defineProps<{ tileMap: Tilemap tileMapLayer: TilemapLayer }>() + +// *** COMMAND STATE *** + +let currentCommand: MapObjectCommand | null = null + +class MapObjectCommand implements EditorCommand { + public operation: 'place' | 'move' | 'delete' | 'rotate' = 'place' + public type: 'map_object' = 'map_object' + public affectedTiles: PlacedMapObjectT[] = [] + public targetPosition?: Phaser.Math.Vector2 + + apply(elements: PlacedMapObjectT[]) { + let tileVersion = cloneArray(elements) as PlacedMapObjectT[] + if (this.operation === 'place') { + tileVersion = tileVersion.concat(this.affectedTiles) + } + else if (this.operation === 'delete') { + tileVersion = tileVersion.filter((v) => !this.affectedTiles.includes(v)) + } + else if (this.operation === 'move') { + const targetObject = tileVersion.find((v) => this.affectedTiles[0].id === v.id) + if (targetObject) { + targetObject.positionX = this.targetPosition!.x + targetObject.positionY = this.targetPosition!.y + } + } + + return tileVersion + } + + constructor(operation: 'place' | 'move' | 'delete' | 'rotate') { + this.operation = operation + } +} + +function createCommandUpdate(object: PlacedMapObjectT, operation: 'place' | 'move' | 'delete' | 'rotate', targetPosition?: Phaser.Math.Vector2) { + if (!currentCommand) { + currentCommand = new MapObjectCommand(operation) + } + else { + if (targetPosition) { + currentCommand.targetPosition = targetPosition + } + } + + currentCommand.affectedTiles.push(object) +} + +function finalizeCommand() { + if (!currentCommand) return + emit('createCommand', currentCommand) + currentCommand = null +} + + +// *** HANDLERS *** + + function pencil(pointer: Phaser.Input.Pointer, map: MapT) { const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY) if (!tile) return @@ -47,6 +116,9 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) { // Add new object to mapObjects map.placedMapObjects.push(newPlacedMapObject) + + createCommandUpdate(newPlacedMapObject, 'place') + mapEditor.selectedPlacedObject.value = newPlacedMapObject } @@ -55,6 +127,8 @@ function eraser(pointer: Phaser.Input.Pointer, map: MapT) { const existingPlacedMapObject = findObjectByPointer(pointer, map) if (!existingPlacedMapObject) return + createCommandUpdate(existingPlacedMapObject, 'delete') + // Remove existing object map.placedMapObjects = map.placedMapObjects.filter((placedMapObject) => placedMapObject.id !== existingPlacedMapObject.id) } @@ -78,11 +152,15 @@ function objectPicker(pointer: Phaser.Input.Pointer, map: MapT) { function moveMapObject(id: string, map: MapT) { mapEditor.movingPlacedObject.value = map.placedMapObjects.find((object) => object.id === id) as PlacedMapObjectT + let t: Tile + function handlePointerMove(pointer: Phaser.Input.Pointer) { if (!mapEditor.movingPlacedObject.value) return const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY) if (!tile) return + t = tile + mapEditor.movingPlacedObject.value.positionX = tile.x mapEditor.movingPlacedObject.value.positionY = tile.y } @@ -92,6 +170,9 @@ function moveMapObject(id: string, map: MapT) { function handlePointerUp() { scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) mapEditor.movingPlacedObject.value = null + + createCommandUpdate(mapEditor.movingPlacedObject.value!, 'move', new Vector2(t.x, t.y)) + finalizeCommand() } scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp) @@ -104,6 +185,13 @@ function rotatePlacedMapObject(id: string, map: MapT) { function deletePlacedMapObject(id: string, map: MapT) { let mapE = mapEditor.currentMap.value! + + const foundObject = mapE.placedMapObjects.find((obj) => obj.id === id) + if (!foundObject) return + + createCommandUpdate(foundObject, 'delete') + finalizeCommand() + mapE.placedMapObjects = map.placedMapObjects.filter((object) => object.id !== id) mapEditor.selectedPlacedObject.value = null } diff --git a/src/components/gameMaster/mapEditor/partials/Toolbar.vue b/src/components/gameMaster/mapEditor/partials/Toolbar.vue index 8a92fca..9e40f46 100644 --- a/src/components/gameMaster/mapEditor/partials/Toolbar.vue +++ b/src/components/gameMaster/mapEditor/partials/Toolbar.vue @@ -93,7 +93,7 @@ import { onBeforeUnmount, onMounted, ref } from 'vue' const mapEditor = useMapEditorComposable() -const emit = defineEmits(['save', 'clear', 'open-maps', 'open-settings', 'close-editor', 'open-tile-list', 'open-map-object-list', 'close-lists']) +const emit = defineEmits(['save', 'clear', 'open-maps', 'open-settings', 'open-teleport-settings', 'close-editor', 'open-tile-list', 'open-map-object-list', 'close-lists']) // track when clicked outside of toolbar items const toolbar = ref(null) @@ -115,6 +115,7 @@ function setDrawMode(value: string) { emit('close-lists') if (value === 'tile') emit('open-tile-list') if (value === 'map_object') emit('open-map-object-list') + if (value === 'teleport') emit('open-teleport-settings') } mapEditor.setDrawMode(value) @@ -155,6 +156,7 @@ function handleClick(tool: string) { selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false selectEraserOpen.value = tool === 'eraser' ? !selectEraserOpen.value : false + } function cycleToolMode(tool: 'pencil' | 'eraser') { diff --git a/src/components/screens/MapEditor.vue b/src/components/screens/MapEditor.vue index c518393..df868ea 100644 --- a/src/components/screens/MapEditor.vue +++ b/src/components/screens/MapEditor.vue @@ -11,6 +11,7 @@ @clear="clear" @open-maps="mapModal?.open" @open-settings="mapSettingsModal?.open" + @open-teleport-settings="teleportModal?.open" @close-editor="mapEditor.toggleActive" @close-lists="tileList?.close" @closeLists="objectList?.close" @@ -45,6 +46,7 @@ import { MapStorage } from '@/storage/storages' import { useGameStore } from '@/stores/gameStore' import { Game, Scene } from 'phavuer' import { ref, useTemplateRef } from 'vue' +import teleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue' const mapStorage = new MapStorage() const mapEditor = useMapEditorComposable() @@ -54,6 +56,7 @@ const mapModal = useTemplateRef('mapModal') const tileList = useTemplateRef('tileList') const objectList = useTemplateRef('objectList') const mapSettingsModal = useTemplateRef('mapSettingsModal') +const teleportSettings = useTemplateRef('teleportModal') const isLoaded = ref(false) @@ -96,14 +99,8 @@ function save() { if (!currentMap) return const data = { + ...currentMap, mapId: currentMap.id, - name: currentMap.name, - width: currentMap.width, - height: currentMap.height, - tiles: currentMap.tiles, - pvp: currentMap.pvp, - mapEffects: currentMap.mapEffects, - mapEventTiles: currentMap.mapEventTiles, placedMapObjects: currentMap.placedMapObjects.map(({ id, mapObject, depth, isRotated, positionX, positionY }) => ({ id, mapObject, depth, isRotated, positionX, positionY })) ?? [] } diff --git a/src/services/mapService.ts b/src/services/mapService.ts index 3d89795..2691180 100644 --- a/src/services/mapService.ts +++ b/src/services/mapService.ts @@ -147,3 +147,8 @@ export function createTileLayer(tileMap: Phaser.Tilemaps.Tilemap, tilesArray: st return layer } + +//Recursive Array Clone +export function cloneArray(arr: any[]): any[] { + return arr.map((item) => (item instanceof Array ? cloneArray(item) : item)) +} \ No newline at end of file From 94596394978589e023e85cc5422202de37b6e182 Mon Sep 17 00:00:00 2001 From: Andrei <amborn02@gmail.com> Date: Mon, 10 Feb 2025 16:02:38 -0600 Subject: [PATCH 2/2] Best undo/redo function across all map editor elements --- src/components/gameMaster/mapEditor/Map.vue | 122 +++++++++++------ .../mapEditor/mapPartials/MapEventTiles.vue | 18 ++- .../mapEditor/mapPartials/MapTiles.vue | 40 +++--- .../mapPartials/PlacedMapObjects.vue | 125 +++++------------- src/components/screens/MapEditor.vue | 1 - src/composables/useMapEditorComposable.ts | 7 - 6 files changed, 147 insertions(+), 166 deletions(-) diff --git a/src/components/gameMaster/mapEditor/Map.vue b/src/components/gameMaster/mapEditor/Map.vue index 7acceb7..d55c0ba 100644 --- a/src/components/gameMaster/mapEditor/Map.vue +++ b/src/components/gameMaster/mapEditor/Map.vue @@ -1,6 +1,6 @@ <template> <MapTiles ref="mapTiles" @createCommand="addCommand" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> - <PlacedMapObjects ref="mapObjects" @createCommand="addCommand" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> + <PlacedMapObjects ref="mapObjects" @update="updateMapObjects" @updateAndCommit="updateAndCommit" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer /> <MapEventTiles ref="eventTiles" @createCommand="addCommand" v-if="tileMap" :tileMap /> </template> @@ -10,12 +10,13 @@ import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEven import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue' import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue' import { useMapEditorComposable } from '@/composables/useMapEditorComposable' -import { cloneArray, createTileLayer, createTileMap, placeTiles } from '@/services/mapService' +import { cloneArray, createTileArray, createTileLayer, createTileMap, placeTiles } from '@/services/mapService' import { TileStorage } from '@/storage/storages' import { useScene } from 'phavuer' import { onBeforeUnmount, onMounted, onUnmounted, ref, shallowRef, useTemplateRef, watch } from 'vue' -import type { MapEventTile, PlacedMapObject as PlacedMapObjectT } from '@/application/types' +import type { PlacedMapObject as PlacedMapObjectT, Map as MapT, MapEventTile } from '@/application/types' +import { useManualRefHistory, useRefHistory } from '@vueuse/core' const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>() const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>() @@ -28,18 +29,20 @@ const mapObjects = useTemplateRef('mapObjects') const eventTiles = useTemplateRef('eventTiles') //Record of commands -let commandStack: EditorCommand[] = [] +let commandStack: (EditorCommand | number) [] = [] let commandIndex = ref(0) let originTiles: string[][] = [] let originEventTiles: MapEventTile[] = [] -let originObjects: PlacedMapObjectT[] = [] +let originObjects = ref<PlacedMapObjectT[]>(mapEditor.currentMap.value.placedMapObjects) + +const {undo, redo, commit, reset, history, canUndo, canRedo} = useRefHistory(originObjects, {clone:true, deep:true, capacity:9}) //Command Pattern basic interface, extended to store what elements have been changed by each edit export interface EditorCommand { apply: (elements: any[]) => any[] type: 'tile' | 'map_object' | 'event_tile' - operation: 'draw' | 'erase' | 'place' | 'move' | 'delete' | 'rotate' + operation: 'draw' | 'erase' | 'clear' } function applyCommands(tiles: any[], ...commands: EditorCommand[]): any[] { @@ -50,57 +53,95 @@ function applyCommands(tiles: any[], ...commands: EditorCommand[]): any[] { return tileVersion } -watch(() => commandIndex.value!, (val) => { - if (val !== undefined) { - update(commandStack.slice(0, val)) +watch( + () => mapEditor.shouldClearTiles.value, + (shouldClear) => { + if (shouldClear && mapEditor.currentMap.value) { + mapTiles.value!.clearTiles() + eventTiles.value!.clearTiles() + mapEditor.currentMap.value.placedMapObjects = [] + updateAndCommit(mapEditor.currentMap.value) + mapEditor.resetClearTilesFlag() + } } -}) +) -function update(commands: EditorCommand[]) { +function update(commands: (EditorCommand | number)[]) { if (!mapEditor.currentMap.value) return - const tileCommands = commands.filter((command) => command.type === 'tile') - const eventTileCommands = commands.filter((command) => command.type === 'event_tile') - const objectCommands = commands.filter((command) => command.type === 'map_object') + if (commandStack.length >= 9) { + if (typeof commandStack[0] !== 'number') { + const base = commandStack.shift() as EditorCommand + if (base.operation !== 'clear') { + switch (base.type) { + case 'tile': + originTiles = base.apply(originTiles) as string[][] + break + case 'event_tile': + originEventTiles = base.apply(originEventTiles) as MapEventTile[] + break + } + } + else { + commandStack.shift() + } + } + else if (typeof commandStack[0] === 'number') { + commandStack.shift() + } + } + + let tileCommands = commands.filter((item) => typeof item !== 'number' && item.type === 'tile') as EditorCommand[] + let eventTileCommands = commands.filter((item) => typeof item !== 'number' && item.type === 'event_tile') as EditorCommand[] let modifiedTiles = applyCommands(originTiles, ...tileCommands) placeTiles(tileMap.value!, tileMapLayer.value!, modifiedTiles) + let eventTiles = applyCommands(originEventTiles, ...eventTileCommands) + mapEditor.currentMap.value.tiles = modifiedTiles - mapEditor.currentMap.value.mapEventTiles = applyCommands(originEventTiles, ...eventTileCommands) - mapEditor.currentMap.value.placedMapObjects = applyCommands(originObjects, ...objectCommands) + mapEditor.currentMap.value.mapEventTiles = eventTiles +} + +function updateMapObjects(map: MapT) { + originObjects.value = map.placedMapObjects +} + +function updateAndCommit(map?: MapT) { + commandStack = commandStack.slice(0, commandIndex.value) + if (map) updateMapObjects(map) + commit() + commandStack.push(0) + commandIndex.value = commandStack.length + + console.log(history.value) + console.log(commandStack) + console.log(commandIndex.value) } function addCommand(command: EditorCommand) { commandStack = commandStack.slice(0, commandIndex.value) commandStack.push(command) - - if (commandStack.length >= 9) { - switch (commandStack[0].type) { - case 'tile': - originTiles = commandStack.shift()?.apply(originTiles) as string[][] - break - case 'map_object': - originObjects = commandStack.shift()?.apply(originObjects) as PlacedMapObjectT[] - break - case 'event_tile': - originEventTiles = commandStack.shift()?.apply(originEventTiles) as MapEventTile[] - break - } - } - commandIndex.value = commandStack.length } -function undo() { +function undoEdit() { if (commandIndex.value > 0) { - commandIndex.value-- + if (typeof(commandStack[--commandIndex.value]) === 'number' && canUndo) { + undo() + mapEditor.currentMap.value.placedMapObjects = originObjects.value + } + update(commandStack.slice(0, commandIndex.value)) } } -function redo() { - if (commandIndex.value <= 9 && commandIndex.value <= commandStack.length) { - commandIndex.value++ +function redoEdit() { + if (commandIndex.value <= 9 && commandIndex.value < commandStack.length) { + if (typeof(commandStack[commandIndex.value++]) === 'number' && canRedo) { + redo() + mapEditor.currentMap.value.placedMapObjects = originObjects.value + } + update(commandStack.slice(0, commandIndex.value)) } } @@ -133,12 +174,12 @@ function handlePointerDown(pointer: Phaser.Input.Pointer) { function handleKeyDown(event: KeyboardEvent) { //CTRL+Y if (event.key === 'y' && event.ctrlKey) { - redo() + redoEdit() } //CTRL+Z if (event.key === 'z' && event.ctrlKey) { - undo() + undoEdit() } } @@ -154,7 +195,7 @@ function handlePointerUp(pointer: Phaser.Input.Pointer) { mapTiles.value!.finalizeCommand() break case 'map_object': - mapObjects.value!.finalizeCommand() + updateAndCommit() break case 'teleport': eventTiles.value!.finalizeCommand() @@ -171,9 +212,10 @@ onMounted(async () => { //Clone originTiles = cloneArray(mapValue.tiles) - originObjects = cloneArray(mapValue.placedMapObjects) originEventTiles = cloneArray(mapValue.mapEventTiles) + commit() + const tileStorage = new TileStorage() const allTiles = await tileStorage.getAll() const allTileIds = allTiles.map((tile) => tile.id) diff --git a/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue b/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue index 77db3a2..2a23ebb 100644 --- a/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue +++ b/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue @@ -13,7 +13,7 @@ import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue' const mapEditor = useMapEditorComposable() -defineExpose({ handlePointer, finalizeCommand }) +defineExpose({ handlePointer, finalizeCommand, clearTiles}) const emit = defineEmits(['createCommand']) @@ -27,7 +27,7 @@ const props = defineProps<{ let currentCommand: EventTileCommand | null = null class EventTileCommand implements EditorCommand { - public operation: 'draw' | 'erase' = 'draw' + public operation: 'draw' | 'erase' | 'clear' = 'draw' public type: 'event_tile' = 'event_tile' public affectedTiles: MapEventTile[] = [] @@ -39,15 +39,18 @@ class EventTileCommand implements EditorCommand { else if (this.operation === 'erase') { tileVersion = tileVersion.filter((v) => !this.affectedTiles.includes(v)) } + else if (this.operation === 'clear') { + tileVersion = [] + } return tileVersion } - constructor(operation: 'draw' | 'erase') { + constructor(operation: 'draw' | 'erase' | 'clear') { this.operation = operation } } -function createCommandUpdate(tile: MapEventTile, operation: 'draw' | 'erase') { +function createCommandUpdate(tile?: MapEventTile, operation: 'draw' | 'erase' | 'clear') { if (!currentCommand) { currentCommand = new EventTileCommand(operation) } @@ -149,4 +152,11 @@ function handlePointer(pointer: Phaser.Input.Pointer) { break } } + +function clearTiles() { + if (mapEditor.currentMap.value.mapEventTiles.length === 0) return + createCommandUpdate(null, 'clear') + finalizeCommand() +} + </script> diff --git a/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue b/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue index 671e8b0..2d0e524 100644 --- a/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue +++ b/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue @@ -11,7 +11,7 @@ import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue' const mapEditor = useMapEditorComposable() -defineExpose({ handlePointer, finalizeCommand }) +defineExpose({ handlePointer, finalizeCommand, clearTiles }) const emit = defineEmits(['createCommand']) @@ -20,32 +20,37 @@ const props = defineProps<{ tileMapLayer: Phaser.Tilemaps.TilemapLayer }>() - // *** COMMAND STATE *** let currentCommand: TileCommand | null = null class TileCommand implements EditorCommand { - public operation: 'draw' | 'erase' = 'draw' + public operation: 'draw' | 'erase' | 'clear' = 'draw' public type: 'tile' = 'tile' public tileName: string = 'blank_tile' public affectedTiles: number[][] = [] apply(elements: string[][]) { - let tileVersion = cloneArray(elements) as string[][] - for (const position of this.affectedTiles) { - tileVersion[position[1]][position[0]] = this.tileName + let tileVersion + if (this.operation === 'clear') { + tileVersion = createTileArray(props.tileMapLayer.width, props.tileMapLayer.height, 'blank_tile') + } + else { + tileVersion = cloneArray(elements) as string[][] + for (const position of this.affectedTiles) { + tileVersion[position[1]][position[0]] = this.tileName + } } return tileVersion } - constructor(operation: 'draw' | 'erase', tileName: string) { + constructor(operation: 'draw' | 'erase' | 'clear', tileName: string) { this.operation = operation this.tileName = tileName } } -function createCommandUpdate(x: number, y: number, tileName: string, operation: 'draw' | 'erase') { +function createCommandUpdate(x: number, y: number, tileName: string, operation: 'draw' | 'erase' | 'clear') { if (!currentCommand) { currentCommand = new TileCommand(operation, tileName) } @@ -137,21 +142,14 @@ function handlePointer(pointer: Phaser.Input.Pointer) { } } - // *** LIFECYCLE *** - -watch( - () => mapEditor.shouldClearTiles.value, - (shouldClear) => { - if (shouldClear && mapEditor.currentMap.value) { - const blankTiles = createTileArray(props.tileMapLayer.width, props.tileMapLayer.height, 'blank_tile') - placeTiles(props.tileMap, props.tileMapLayer, blankTiles) - mapEditor.currentMap.value.tiles = blankTiles - mapEditor.resetClearTilesFlag() - } - } -) +function clearTiles() { + const tileArray = createTileArray(props.tileMap.width, props.tileMap.height, 'blank_tile') + placeTiles(props.tileMap, props.tileMapLayer, tileArray) + createCommandUpdate(0,0,"blank_tile",'clear') + finalizeCommand() +} onMounted(async () => { if (!mapEditor.currentMap.value) return diff --git a/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue b/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue index 81aabfe..ba6a1ff 100644 --- a/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue +++ b/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue @@ -1,5 +1,5 @@ <template> - <SelectedPlacedMapObjectComponent v-if="mapEditor.selectedPlacedObject.value" :map :placedMapObject="mapEditor.selectedPlacedObject.value" @move="moveMapObject" @rotate="rotatePlacedMapObject" @delete="deletePlacedMapObject" /> + <SelectedPlacedMapObjectComponent v-if="mapEditor.selectedPlacedObject.value" :map="mapEditor.currentMap.value!" :placedMapObject="mapEditor.selectedPlacedObject.value" @move="moveMapObject" @rotate="rotatePlacedMapObject" @delete="deletePlacedMapObject" /> <PlacedMapObject v-for="placedMapObject in mapEditor.currentMap.value?.placedMapObjects" :tileMap :tileMapLayer :placedMapObject @pointerdown="clickPlacedMapObject(placedMapObject)" /> </template> @@ -7,101 +7,38 @@ import type { MapObject, Map as MapT, - PlacedMapObject as PlacedMapObjectT, - UUID, - MapEventTile + PlacedMapObject as PlacedMapObjectT } from '@/application/types' import { uuidv4 } from '@/application/utilities' import PlacedMapObject from '@/components/game/map/partials/PlacedMapObject.vue' import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue' import { useMapEditorComposable } from '@/composables/useMapEditorComposable' -import { cloneArray, getTile } from '@/services/mapService' +import { getTile } from '@/services/mapService' import { useScene } from 'phavuer' import Tilemap = Phaser.Tilemaps.Tilemap import TilemapLayer = Phaser.Tilemaps.TilemapLayer -import { computed } from 'vue' -import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue' -import Vector2 = Phaser.Math.Vector2 -import Tile = Phaser.Tilemaps.Tile const scene = useScene() const mapEditor = useMapEditorComposable() -const map = computed(() => mapEditor.currentMap.value!) -defineExpose({ handlePointer, finalizeCommand }) +const emit = defineEmits<{(e: 'update', map: MapT): void, (e: 'updateAndCommit', map: MapT): void}>() -const emit = defineEmits(['createCommand']) +defineExpose({ handlePointer }) const props = defineProps<{ tileMap: Tilemap tileMapLayer: TilemapLayer }>() - -// *** COMMAND STATE *** - -let currentCommand: MapObjectCommand | null = null - -class MapObjectCommand implements EditorCommand { - public operation: 'place' | 'move' | 'delete' | 'rotate' = 'place' - public type: 'map_object' = 'map_object' - public affectedTiles: PlacedMapObjectT[] = [] - public targetPosition?: Phaser.Math.Vector2 - - apply(elements: PlacedMapObjectT[]) { - let tileVersion = cloneArray(elements) as PlacedMapObjectT[] - if (this.operation === 'place') { - tileVersion = tileVersion.concat(this.affectedTiles) - } - else if (this.operation === 'delete') { - tileVersion = tileVersion.filter((v) => !this.affectedTiles.includes(v)) - } - else if (this.operation === 'move') { - const targetObject = tileVersion.find((v) => this.affectedTiles[0].id === v.id) - if (targetObject) { - targetObject.positionX = this.targetPosition!.x - targetObject.positionY = this.targetPosition!.y - } - } - - return tileVersion - } - - constructor(operation: 'place' | 'move' | 'delete' | 'rotate') { - this.operation = operation - } -} - -function createCommandUpdate(object: PlacedMapObjectT, operation: 'place' | 'move' | 'delete' | 'rotate', targetPosition?: Phaser.Math.Vector2) { - if (!currentCommand) { - currentCommand = new MapObjectCommand(operation) - } - else { - if (targetPosition) { - currentCommand.targetPosition = targetPosition - } - } - - currentCommand.affectedTiles.push(object) -} - -function finalizeCommand() { - if (!currentCommand) return - emit('createCommand', currentCommand) - currentCommand = null -} - - // *** HANDLERS *** - function pencil(pointer: Phaser.Input.Pointer, map: MapT) { const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY) if (!tile) return // Check if object already exists on position - const existingPlacedMapObject = findObjectByPointer(pointer, map) + const existingPlacedMapObject = findObjectByPointer(pointer, mapEditor.currentMap.value!) if (existingPlacedMapObject) return if (!mapEditor.selectedMapObject.value) return @@ -115,11 +52,10 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) { } // Add new object to mapObjects + mapEditor.selectedPlacedObject.value = newPlacedMapObject map.placedMapObjects.push(newPlacedMapObject) - createCommandUpdate(newPlacedMapObject, 'place') - - mapEditor.selectedPlacedObject.value = newPlacedMapObject + emit('update', map) } function eraser(pointer: Phaser.Input.Pointer, map: MapT) { @@ -127,10 +63,10 @@ function eraser(pointer: Phaser.Input.Pointer, map: MapT) { const existingPlacedMapObject = findObjectByPointer(pointer, map) if (!existingPlacedMapObject) return - createCommandUpdate(existingPlacedMapObject, 'delete') - // Remove existing object map.placedMapObjects = map.placedMapObjects.filter((placedMapObject) => placedMapObject.id !== existingPlacedMapObject.id) + + emit('update', map) } function findObjectByPointer(pointer: Phaser.Input.Pointer, map: MapT): PlacedMapObjectT | undefined { @@ -152,48 +88,51 @@ function objectPicker(pointer: Phaser.Input.Pointer, map: MapT) { function moveMapObject(id: string, map: MapT) { mapEditor.movingPlacedObject.value = map.placedMapObjects.find((object) => object.id === id) as PlacedMapObjectT - let t: Tile - function handlePointerMove(pointer: Phaser.Input.Pointer) { if (!mapEditor.movingPlacedObject.value) return const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY) if (!tile) return - t = tile - mapEditor.movingPlacedObject.value.positionX = tile.x mapEditor.movingPlacedObject.value.positionY = tile.y } scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) - function handlePointerUp() { + function handlePointerUp(pointer: Phaser.Input.Pointer) { scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) - mapEditor.movingPlacedObject.value = null - createCommandUpdate(mapEditor.movingPlacedObject.value!, 'move', new Vector2(t.x, t.y)) - finalizeCommand() + const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY) + if (!tile) return + + map.placedMapObjects.map((placed) => { + if (placed.id === id) { + placed.positionX = tile.x + placed.positionY = tile.y + }}) + + mapEditor.movingPlacedObject.value = null } + emit('updateAndCommit', map) scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp) } function rotatePlacedMapObject(id: string, map: MapT) { - const matchingObject = map.placedMapObjects.find((placedMapObject) => placedMapObject.id === id) - matchingObject!.isRotated = !matchingObject!.isRotated + + map.placedMapObjects.map((placed) => { + if (placed.id === id) { + console.log(placed.id) + placed.isRotated = !placed.isRotated + }}) + + emit('updateAndCommit', map) } function deletePlacedMapObject(id: string, map: MapT) { - let mapE = mapEditor.currentMap.value! - - const foundObject = mapE.placedMapObjects.find((obj) => obj.id === id) - if (!foundObject) return - - createCommandUpdate(foundObject, 'delete') - finalizeCommand() - - mapE.placedMapObjects = map.placedMapObjects.filter((object) => object.id !== id) + map.placedMapObjects = map.placedMapObjects.filter((object) => object.id !== id) mapEditor.selectedPlacedObject.value = null + emit('updateAndCommit', map) } function clickPlacedMapObject(placedMapObject: PlacedMapObjectT) { diff --git a/src/components/screens/MapEditor.vue b/src/components/screens/MapEditor.vue index df868ea..0175fe5 100644 --- a/src/components/screens/MapEditor.vue +++ b/src/components/screens/MapEditor.vue @@ -113,7 +113,6 @@ function clear() { if (!mapEditor.currentMap.value) return // Clear placed objects, event tiles and tiles - mapEditor.clearMap() mapEditor.triggerClearTiles() } </script> diff --git a/src/composables/useMapEditorComposable.ts b/src/composables/useMapEditorComposable.ts index 4b095ae..73ede23 100644 --- a/src/composables/useMapEditorComposable.ts +++ b/src/composables/useMapEditorComposable.ts @@ -36,12 +36,6 @@ export function useMapEditorComposable() { } } - const clearMap = () => { - if (!currentMap.value) return - currentMap.value.placedMapObjects = [] - currentMap.value.mapEventTiles = [] - } - const toggleActive = () => { if (active.value) reset() active.value = !active.value @@ -105,7 +99,6 @@ export function useMapEditorComposable() { // Methods loadMap, updateProperty, - clearMap, toggleActive, setTool, setDrawMode,