From ca307d4de3dcc3bc507801d462eca96c3879e770 Mon Sep 17 00:00:00 2001 From: Andrei 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 @@ 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 @@ 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 @@ @@ -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() } 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,