Map object position as tile coordinates, map objects correctly snap to each tile now when moving, and fixed bug of placing objects over eachother on the same tile

This commit is contained in:
Andrei 2025-02-03 14:53:46 -06:00
parent 90d7252784
commit 841ec0f3df
7 changed files with 65 additions and 63 deletions

View File

@ -5,15 +5,19 @@
<script setup lang="ts">
import type { PlacedMapObject, TextureData } from '@/application/types'
import { loadTexture } from '@/composables/gameComposable'
import { calculateIsometricDepth } from '@/composables/mapComposable'
import { calculateIsometricDepth, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer'
import { computed, onMounted } from 'vue'
import config from '@/application/config'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import Tilemap = Phaser.Tilemaps.Tilemap
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
const props = defineProps<{
placedMapObject: PlacedMapObject
placedMapObject: PlacedMapObject,
tileMap: Tilemap
tileMapLayer: TilemapLayer
}>()
const gameStore = useGameStore()
@ -32,12 +36,11 @@ const imageProps = computed(() => ({
}))
function calculateObjectPlacement(mapObj: PlacedMapObject) : {x: number; y: number} {
let position = { x: mapObj.positionX, y: mapObj.positionY }
let halfTileWidth = config.tile_size.width/2
let halfTileHeight = config.tile_size.height/2
let position = tileToWorldXY(props.tileMapLayer, mapObj.positionX, mapObj.positionY)
return {
x: position.x-mapObj.mapObject.frameWidth/2,
y: position.y-mapObj.mapObject.frameHeight/2-halfTileHeight
x: position.worldPositionX-mapObj.mapObject.frameWidth/2,
y: position.worldPositionY-mapObj.mapObject.frameHeight/2+config.tile_size.height
}
}

View File

@ -1,7 +1,7 @@
<template>
<MapTiles ref="mapTiles" @tileMap:create="tileMap = $event" />
<PlacedMapObjects ref="mapObjects" v-if="tileMap" :tileMap />
<MapEventTiles ref="eventTiles" v-if="tileMap" :tileMap />
<MapTiles ref="mapTiles" v-if="tileMap && tileMapLayer" :tileMapLayer :tileMap @tileMap:create="tileMap = $event" />
<PlacedMapObjects ref="mapObjects" v-if="tileMap && tileMapLayer" :tileMapLayer :tileMap />
<MapEventTiles ref="eventTiles" v-if="tileMap && tileMapLayer" :tileMapLayer :tileMap />
</template>
<script setup lang="ts">
@ -11,8 +11,11 @@ import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/Plac
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useScene } from 'phavuer'
import { onBeforeUnmount, onMounted, onUnmounted, shallowRef, useTemplateRef } from 'vue'
import { createTileLayer, createTileMap } from '@/composables/mapComposable'
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
const mapEditor = useMapEditorComposable()
const scene = useScene()
@ -72,6 +75,10 @@ function handlePointerUp(pointer: Phaser.Input.Pointer) {
}
onMounted(() => {
tileMap.value = createTileMap(scene, mapEditor.currentMap.value!)
mapTiles.value?.$emit('tileMap:create', tileMap.value)
tileMapLayer.value = createTileLayer(tileMap.value, mapEditor.currentMap.value)
addEventListener('keydown', handleKeyDown)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
@ -79,6 +86,12 @@ onMounted(() => {
})
onUnmounted(() => {
if (tileMap.value) {
tileMap.value.destroyLayer('tiles')
tileMap.value.removeAllLayers()
tileMap.value.destroy()
}
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)

View File

@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { MapEventTileType, type MapEventTile, type Map as MapT } from '@/application/types'
import { MapEventTileType, type MapEventTile, type Map as MapT, type UUID } from '@/application/types'
import { uuidv4 } from '@/application/utilities'
import { getTile, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
@ -42,7 +42,7 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
if (mapEditor.drawMode.value === 'teleport' && !mapEditor.teleportSettings.value.toMapId) return
const newEventTile = {
id: uuidv4(),
id: uuidv4() as UUID,
mapId: map.id,
map: map.id,
type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
@ -56,7 +56,7 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
toPositionY: mapEditor.teleportSettings.value.toPositionY,
toRotation: mapEditor.teleportSettings.value.toRotation
}
: undefined
: {}
}
map.mapEventTiles.push(newEventTile)

View File

@ -1,5 +1,5 @@
<template>
<Controls v-if="tileLayer" :layer="tileLayer" :depth="0" />
<Controls v-if="props.tileMapLayer" :layer="props.tileMapLayer" :depth="0" />
</template>
<script setup lang="ts">
@ -16,11 +16,13 @@ const scene = useScene()
const mapEditor = useMapEditorComposable()
const tileStorage = new TileStorage()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
defineExpose({ handlePointer, finalizeCommand, undo, redo })
const props = defineProps<{
tileMap: Phaser.Tilemaps.Tilemap
tileMapLayer: Phaser.Tilemaps.TilemapLayer
}>()
class EditorCommand {
public operation: 'draw' | 'erase' = 'draw'
public tileName: string = "blank_tile"
@ -46,14 +48,12 @@ function pencil(pointer: Phaser.Input.Pointer) {
// Check if there is a selected tile
if (!mapEditor.selectedTile.value) return
if (!tileMap.value || !tileLayer.value) return
// Check if there is a tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
const tile = getTile(props.tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return
// Place tile
placeTile(tileMap.value, tileLayer.value, tile.x, tile.y, mapEditor.selectedTile.value)
placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, mapEditor.selectedTile.value)
createCommandUpdate(tile.x, tile.y, mapEditor.selectedTile.value, 'draw')
@ -65,14 +65,12 @@ function eraser(pointer: Phaser.Input.Pointer) {
let map = mapEditor.currentMap.value
if (!map) return
if (!tileMap.value || !tileLayer.value) return
// Check if there is a tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
const tile = getTile(props.tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return
// Place tile
placeTile(tileMap.value, tileLayer.value, tile.x, tile.y, 'blank_tile')
placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, 'blank_tile')
createCommandUpdate(tile.x, tile.y, 'blank_tile', 'erase')
@ -81,10 +79,9 @@ function eraser(pointer: Phaser.Input.Pointer) {
}
function paint(pointer: Phaser.Input.Pointer) {
if (!tileMap.value || !tileLayer.value) return
// Set new tileArray with selected tile
const tileArray = createTileArray(tileMap.value.width, tileMap.value.height, mapEditor.selectedTile.value)
setLayerTiles(tileMap.value, tileLayer.value, tileArray)
const tileArray = createTileArray(props.tileMap.width, props.tileMap.height, mapEditor.selectedTile.value)
setLayerTiles(props.tileMap, props.tileMapLayer, tileArray)
// Adjust mapEditorStore.map.tiles
if (mapEditor.currentMap.value) {
@ -97,10 +94,8 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
let map = mapEditor.currentMap.value
if (!map) return
if (!tileMap.value || !tileLayer.value) return
// Check if there is a tile
const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
const tile = getTile(props.tileMapLayer, pointer.worldX, pointer.worldY)
if (!tile) return
// Select the tile
@ -108,8 +103,6 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
}
function handlePointer(pointer: Phaser.Input.Pointer) {
if (!tileMap.value || !tileLayer.value) return
// Check if left mouse button is pressed
if (!pointer.isDown && pointer.button === 0) return
@ -187,13 +180,13 @@ function applyCommands(tiles: string[][], ...commands: EditorCommand[]): string[
}
function updateMapTiles() {
if (!tileMap.value || !tileLayer.value || !mapEditor.currentMap.value) return
if (!mapEditor.currentMap.value) return
let indexedCommands = commandStack.slice(0, commandIndex.value)
let modifiedTiles = applyCommands(originTiles, ...indexedCommands)
//replaceTiles(mapEditor.currentMap.value.tiles, layer, tileMap.value.width, tileMap.value.height)
setLayerTiles(tileMap.value, tileLayer.value, modifiedTiles)
setLayerTiles(props.tileMap, props.tileMapLayer, modifiedTiles)
mapEditor.currentMap.value.tiles = modifiedTiles
}
@ -205,10 +198,10 @@ function cloneArray(arr: any[]) : any[] {
watch(
() => mapEditor.shouldClearTiles,
(shouldClear) => {
if (shouldClear && mapEditor.currentMap.value && tileMap.value && tileLayer.value) {
const blankTiles = createTileArray(tileLayer.value.width, tileLayer.value.height, 'blank_tile')
setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
replaceTiles(mapEditor.currentMap.value.tiles, blankTiles, tileLayer.value.width, tileLayer.value.height)
if (shouldClear && mapEditor.currentMap.value) {
const blankTiles = createTileArray(props.tileMapLayer.width, props.tileMapLayer.height, 'blank_tile')
setLayerTiles(props.tileMap, props.tileMapLayer, blankTiles)
replaceTiles(mapEditor.currentMap.value.tiles, blankTiles, props.tileMapLayer.width, props.tileMapLayer.height)
mapEditor.resetClearTilesFlag()
}
}
@ -230,20 +223,9 @@ onMounted(async () => {
const mapState = mapEditor.currentMap.value
//Clone
originTiles = cloneArray(mapEditor.currentMap.value.tiles)
originTiles = cloneArray(mapState.tiles)
tileMap.value = createTileMap(scene, mapEditor.currentMap.value)
emit('tileMap:create', tileMap.value)
tileLayer.value = createTileLayer(tileMap.value, mapEditor.currentMap.value)
setLayerTiles(tileMap.value, tileLayer.value, mapState.tiles)
setLayerTiles(props.tileMap, props.tileMapLayer, mapState.tiles)
})
onUnmounted(() => {
if (tileMap.value) {
tileMap.value.destroyLayer('tiles')
tileMap.value.removeAllLayers()
tileMap.value.destroy()
}
})
</script>

View File

@ -1,10 +1,10 @@
<template>
<SelectedPlacedMapObjectComponent v-if="mapEditor.selectedPlacedObject.value" :placedMapObject="mapEditor.selectedPlacedObject.value" @move="moveMapObject" @rotate="rotatePlacedMapObject" @delete="deletePlacedMapObject" />
<PlacedMapObject v-for="placedMapObject in mapEditor.currentMap.value?.placedMapObjects" :placedMapObject @pointerdown="clickPlacedMapObject(placedMapObject)" />
<PlacedMapObject :tileMapLayer :tileMap v-for="placedMapObject in mapEditor.currentMap.value?.placedMapObjects" :placedMapObject @pointerdown="clickPlacedMapObject(placedMapObject)" />
</template>
<script setup lang="ts">
import type { Map as MapT, PlacedMapObject as PlacedMapObjectT } from '@/application/types'
import type { Map as MapT, PlacedMapObject as PlacedMapObjectT, UUID } 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'
@ -13,6 +13,7 @@ import { useScene } from 'phavuer'
import { ref, watch } from 'vue'
import { getTile, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import Tilemap = Phaser.Tilemaps.Tilemap
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
const scene = useScene()
const mapEditor = useMapEditorComposable()
@ -20,7 +21,8 @@ const mapEditor = useMapEditorComposable()
defineExpose({ handlePointer })
const props = defineProps<{
tileMap: Tilemap
tileMap: Tilemap,
tileMapLayer: TilemapLayer
}>()
function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
@ -33,13 +35,13 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
if (!mapEditor.selectedMapObject.value) return
const newPlacedMapObject: PlacedMapObjectT = {
id: uuidv4(),
id: uuidv4() as UUID,
depth: 0,
map: map,
mapObject: mapEditor.selectedMapObject.value,
isRotated: false,
positionX: tileToWorldX(props.tileMap, tile.x, tile.y),
positionY: tileToWorldY(props.tileMap, tile.x, tile.y)
positionX: tile.x,
positionY: tile.y
}
// Add new object to mapObjects
@ -75,9 +77,11 @@ function moveMapObject(id: string, map: MapT) {
function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (!mapEditor.movingPlacedObject.value) return
const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY)
if (!tile) return
mapEditor.movingPlacedObject.value.positionX = pointer.worldX
mapEditor.movingPlacedObject.value.positionY = pointer.worldY
mapEditor.movingPlacedObject.value.positionX = tile.x
mapEditor.movingPlacedObject.value.positionY = tile.y
}
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
@ -103,7 +107,7 @@ function rotatePlacedMapObject(id: string, map: MapT) {
}
function deletePlacedMapObject(id: string, map: MapT) {
let mapE = mapEditor.currentMap.value
let mapE = mapEditor.currentMap.value!
mapE.placedMapObjects = map.placedMapObjects.filter((object) => object.id !== id)
mapEditor.selectedPlacedObject.value = null
}

View File

@ -105,7 +105,7 @@ let selectEraserOpen = ref(false)
let tileListShown = ref(false)
let mapObjectListShown = ref(false)
let checkboxValue = ref(false)
let checkboxValue = ref<Boolean>(false)
defineExpose({ tileListShown, mapObjectListShown })

View File

@ -4,7 +4,7 @@
<Scene name="main" @preload="preloadScene">
<div v-if="!isLoaded" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white text-3xl font-ui">Loading...</div>
<div v-else>
<Map :key="mapEditor.currentMap.value?.id" />
<Map v-if="mapEditor.currentMap.value" :key="mapEditor.currentMap.value?.id" />
<Toolbar
ref="toolbar"
@save="save"