163 lines
4.8 KiB
Vue

<template>
<Image v-for="tile in mapEditor.currentMap.value?.mapEventTiles" v-bind="getImageProps(tile)" />
</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 { cloneArray, getTile, tileToWorldX, tileToWorldY } from '@/services/mapService'
import { Image } from 'phavuer'
import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue'
const mapEditor = useMapEditorComposable()
defineExpose({ handlePointer, finalizeCommand, clearTiles})
const emit = defineEmits(['createCommand'])
const props = defineProps<{
tileMap: Phaser.Tilemaps.Tilemap
}>()
// *** COMMAND STATE ***
let currentCommand: EventTileCommand | null = null
class EventTileCommand implements EditorCommand {
public operation: 'draw' | 'erase' | 'clear' = '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))
}
else if (this.operation === 'clear') {
tileVersion = []
}
return tileVersion
}
constructor(operation: 'draw' | 'erase' | 'clear') {
this.operation = operation
}
}
function createCommandUpdate(tile?: MapEventTile, operation: 'draw' | 'erase' | 'clear') {
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 {
x: tileToWorldX(props.tileMap, tile.positionX, tile.positionY),
y: tileToWorldY(props.tileMap, tile.positionX, tile.positionY),
texture: tile.type,
depth: 999
}
}
function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
// Check if there is a tile
const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY)
if (!tile) return
// 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 teleport, check if there is a selected map
if (mapEditor.drawMode.value === 'teleport' && !mapEditor.teleportSettings.value.toMapId) return
const newEventTile = {
id: uuidv4() as UUID,
mapId: map.id,
map: map,
type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
positionX: tile.x,
positionY: tile.y,
teleport:
mapEditor.drawMode.value === 'teleport'
? {
toMap: mapEditor.teleportSettings.value.toMapId,
toPositionX: mapEditor.teleportSettings.value.toPositionX,
toPositionY: mapEditor.teleportSettings.value.toPositionY,
toRotation: mapEditor.teleportSettings.value.toRotation
}
: undefined
}
createCommandUpdate(newEventTile, 'draw')
map.mapEventTiles.push(newEventTile)
}
function erase(pointer: Phaser.Input.Pointer, map: MapT) {
// Check if there is a tile
const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY)
if (!tile) return
// 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)
}
function handlePointer(pointer: Phaser.Input.Pointer) {
const map = mapEditor.currentMap.value
if (!map) return
if (pointer.event.altKey) return
switch (mapEditor.tool.value) {
case 'pencil':
pencil(pointer, map)
break
case 'eraser':
erase(pointer, map)
break
}
}
function clearTiles() {
if (mapEditor.currentMap.value.mapEventTiles.length === 0) return
createCommandUpdate(null, 'clear')
finalizeCommand()
}
</script>