Loading world works
This commit is contained in:
parent
79bef033f3
commit
0fcd5c4d76
18
src/App.vue
18
src/App.vue
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
<Notifications />
|
<Notifications />
|
||||||
<Login v-if="screen === 'login'" />
|
<Login v-if="screen === 'login'" />
|
||||||
<Register v-if="screen === 'register'" />
|
<Register v-if="screen === 'register'" />
|
||||||
<Characters v-if="screen === 'characters'" />
|
<Characters v-if="screen === 'characters'" />
|
||||||
<Game v-if="screen === 'game'" />
|
<Game v-if="screen === 'game'" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -18,27 +18,27 @@ import Game from '@/screens/Game.vue'
|
|||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
const {screen} = storeToRefs(gameStore);
|
const { screen } = storeToRefs(gameStore)
|
||||||
|
|
||||||
gameStore.$subscribe(
|
gameStore.$subscribe(
|
||||||
(mutation, state) => {
|
(mutation, state) => {
|
||||||
let newScreen = screen.value;
|
let newScreen = screen.value
|
||||||
|
|
||||||
if (!state.connection) {
|
if (!state.connection) {
|
||||||
newScreen = 'login';
|
newScreen = 'login'
|
||||||
} else if (state.token && state.connection) {
|
} else if (state.token && state.connection) {
|
||||||
newScreen = 'characters';
|
newScreen = 'characters'
|
||||||
|
|
||||||
if (state.character) {
|
if (state.character) {
|
||||||
newScreen = 'game';
|
newScreen = 'game'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update screen.value only if it's different from the new state
|
// Update screen.value only if it's different from the new state
|
||||||
if (screen.value !== newScreen) {
|
if (screen.value !== newScreen) {
|
||||||
screen.value = newScreen;
|
screen.value = newScreen
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ detached: true }
|
{ detached: true }
|
||||||
);
|
)
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,104 +1,165 @@
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<TilemapLayerC :tilemap="tileMap" :tileset="zoneStore.tiles" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" />
|
<TilemapLayerC :tilemap="zoneTilemap" :tileset="exampleTilesArray" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" />
|
||||||
<Controls :layer="layer" />
|
<Controls :layer="tiles" />
|
||||||
<Container>
|
|
||||||
<Character :layer="layer" v-for="character in zoneStore.characters" :key="character.id" :character="character" />
|
<Container :depth="2">
|
||||||
|
<Image
|
||||||
|
v-for="object in zoneObjects"
|
||||||
|
:depth="object.depth"
|
||||||
|
:key="object.object.id"
|
||||||
|
:x="tileToWorldX(zoneTilemap, object.position_x, object.position_y)"
|
||||||
|
:y="tileToWorldY(zoneTilemap, object.position_x, object.position_y)"
|
||||||
|
:texture="object.object.id"
|
||||||
|
:originY="Number(object.object.origin_x)"
|
||||||
|
:originX="Number(object.object.origin_y)"
|
||||||
|
/>
|
||||||
|
<Character :layer="zoneTilemap" v-for="character in zoneStore.characters" :key="character.id" :character="character" />
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Container :depth="3">
|
||||||
|
<Image v-for="zoneEventTile in zoneEventTiles" :key="zoneEventTile.id" :x="tileToWorldX(zoneTilemap, zoneEventTile.position_x, zoneEventTile.position_y)" :y="tileToWorldY(zoneTilemap, zoneEventTile.position_x, zoneEventTile.position_y)" :texture="zoneEventTile.type" />
|
||||||
</Container>
|
</Container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
import Tileset = Phaser.Tilemaps.Tileset
|
import { Container, Image, TilemapLayer as TilemapLayerC, useScene } from 'phavuer'
|
||||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
import { onBeforeMount, onBeforeUnmount, ref, toRaw, watch } from 'vue'
|
||||||
import { Container, TilemapLayer as TilemapLayerC, useScene } from 'phavuer'
|
|
||||||
import Character from '@/components/sprites/Character.vue'
|
|
||||||
import { type Character as CharacterType } from '@/types'
|
|
||||||
import { onBeforeMount, onBeforeUnmount, ref, type Ref, watch } from 'vue'
|
|
||||||
import Controls from '@/components/utilities/Controls.vue'
|
import Controls from '@/components/utilities/Controls.vue'
|
||||||
import { useGameStore } from '@/stores/game'
|
import { useGameStore } from '@/stores/game'
|
||||||
|
import Toolbar from '@/components/utilities/zoneEditor/Toolbar.vue'
|
||||||
|
import Tiles from '@/components/utilities/zoneEditor/Tiles.vue'
|
||||||
|
import { useZoneEditorStore } from '@/stores/zoneEditor'
|
||||||
|
import ZoneSettings from '@/components/utilities/zoneEditor/ZoneSettings.vue'
|
||||||
|
import { placeTile, setAllTiles, tileToWorldX, tileToWorldY } from '@/services/zone'
|
||||||
|
import { useAssetStore } from '@/stores/assets'
|
||||||
|
import Objects from '@/components/utilities/zoneEditor/Objects.vue'
|
||||||
|
import type { Zone, ZoneEventTile, ZoneObject, Character as CharacterT } from '@/types'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import ZoneList from '@/components/utilities/zoneEditor/ZoneList.vue'
|
||||||
|
import Tileset = Phaser.Tilemaps.Tileset
|
||||||
|
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
||||||
import { useZoneStore } from '@/stores/zone'
|
import { useZoneStore } from '@/stores/zone'
|
||||||
|
import Character from '@/components/sprites/Character.vue'
|
||||||
|
|
||||||
// Phavuer logic
|
const scene = useScene()
|
||||||
let scene = useScene()
|
|
||||||
let tilemapLayer = ref()
|
|
||||||
|
|
||||||
const tileMap = null
|
|
||||||
let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset
|
|
||||||
let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer
|
|
||||||
|
|
||||||
// center camera
|
|
||||||
const centerY = (tileMap.height * tileMap.tileHeight) / 2
|
|
||||||
const centerX = (tileMap.width * tileMap.tileWidth) / 2
|
|
||||||
scene.cameras.main.centerOn(centerX, centerY)
|
|
||||||
|
|
||||||
// Multiplayer / server logics
|
|
||||||
const zoneStore = useZoneStore()
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
|
const assetStore = useAssetStore()
|
||||||
|
const zoneStore = useZoneStore()
|
||||||
|
|
||||||
// Watch for changes in the zoneStore and update the layer
|
const zoneData = new Phaser.Tilemaps.MapData({
|
||||||
watch(
|
width: zoneStore.zone?.width ?? 10,
|
||||||
() => zoneStore.tiles,
|
height: zoneStore.zone?.height ?? 10,
|
||||||
() => {
|
tileWidth: config.tile_size.x,
|
||||||
// @TODO : change to zone for when loading other maps
|
tileHeight: config.tile_size.y,
|
||||||
zoneStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y)))
|
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
|
||||||
},
|
format: Phaser.Tilemaps.Formats.ARRAY_2D
|
||||||
{ deep: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
// Load the zone from the server
|
|
||||||
onBeforeMount(() => {
|
|
||||||
gameStore.connection.emit('character:zone:request', { zoneId: gameStore.character.zoneId })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Listen for the zone event from the server and load the zone
|
/**
|
||||||
gameStore.connection.on('character:zone:load', (data) => {
|
* These variables are used to store the tileset images and the tilemap
|
||||||
console.log('character:zone:load', data)
|
* The tilesetImages are used to store the tileset images
|
||||||
zoneStore.setTiles(data.zone.tiles)
|
* The zoneTilemap is used to store the tilemap
|
||||||
|
* The zoneTiles are used to store the tile data
|
||||||
|
* The zoneObjects are used to store the object data
|
||||||
|
*/
|
||||||
|
const tilesetImages: Tileset[] = []
|
||||||
|
const zoneTilemap = new Phaser.Tilemaps.Tilemap(scene, zoneData)
|
||||||
|
let zoneTiles = [] as string[][]
|
||||||
|
const zoneObjects = ref<ZoneObject[]>([])
|
||||||
|
const zoneEventTiles = ref<ZoneEventTile[]>([])
|
||||||
|
|
||||||
let characters = data.characters
|
/**
|
||||||
zoneStore.setCharacters(characters)
|
* Walk through object and add them to the zone as tilesetImages
|
||||||
|
*/
|
||||||
|
let tileCount = 1
|
||||||
|
toRaw(assetStore.assets).forEach((asset) => {
|
||||||
|
if (asset.group !== 'tiles') return
|
||||||
|
tilesetImages.push(zoneTilemap.addTilesetImage(asset.key, asset.key, config.tile_size.x, config.tile_size.y, 0, 0, tileCount++) as Tileset)
|
||||||
})
|
})
|
||||||
|
tilesetImages.push(zoneTilemap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.x, config.tile_size.y, 0, 0, 0) as Tileset)
|
||||||
|
|
||||||
|
const tiles = zoneTilemap.createBlankLayer('tiles', tilesetImages, 0, config.tile_size.y) as TilemapLayer
|
||||||
|
const exampleTilesArray = Array.from({ length: zoneStore.zone?.width ?? 0 }, () => Array.from({ length: zoneStore.zone?.height ?? 0 }, () => 'blank_tile'))
|
||||||
|
|
||||||
// Listen for player join events
|
// Listen for player join events
|
||||||
gameStore.connection.on('zone:character:join', (data: CharacterType) => {
|
gameStore.connection?.on('zone:character:join', (data: CharacterT) => {
|
||||||
console.log('character:zone:join', data)
|
console.log('character:zone:join', data)
|
||||||
zoneStore.addCharacter(data)
|
zoneStore.addCharacter(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Listen for user:disconnect
|
// Listen for user:disconnect
|
||||||
gameStore.connection.on('zone:character:leave', (data: CharacterType) => {
|
gameStore.connection?.on('zone:character:leave', (data: CharacterT) => {
|
||||||
zoneStore.removeCharacter(data)
|
zoneStore.removeCharacter(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
gameStore.connection.on('character:moved', (data: CharacterType) => {
|
gameStore.connection?.on('character:moved', (data: CharacterT) => {
|
||||||
console.log('character:moved', data)
|
console.log('character:moved', data)
|
||||||
zoneStore.updateCharacter(data)
|
zoneStore.updateCharacter(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeMount(() => {
|
||||||
zoneStore.reset()
|
exampleTilesArray.forEach((row, y) => row.forEach((tile, x) => placeTile(zoneTilemap, tiles, x, y, 'blank_tile')))
|
||||||
gameStore.connection.emit('character:zone:leave')
|
zoneTiles = exampleTilesArray
|
||||||
gameStore.connection.off('character:zone:load')
|
|
||||||
gameStore.connection.off('zone:character:join')
|
if (zoneStore.zone && zoneStore.zone.tiles) {
|
||||||
gameStore.connection.off('user:disconnect')
|
setAllTiles(zoneTilemap, tiles, zoneStore.zone.tiles)
|
||||||
gameStore.connection.off('character:moved')
|
zoneTiles = zoneStore.zone.tiles
|
||||||
|
|
||||||
|
// Determine the current zone dimensions
|
||||||
|
const currentZoneWidth = zoneStore.zone.width ?? 0
|
||||||
|
const currentZoneHeight = zoneStore.zone.height ?? 0
|
||||||
|
|
||||||
|
// Ensure zoneTiles matches the current zone dimensions, filling new spaces with 'blank_tile'
|
||||||
|
for (let y = 0; y < currentZoneHeight; y++) {
|
||||||
|
zoneTiles[y] = zoneTiles[y] || [] // Ensure the row exists
|
||||||
|
for (let x = 0; x < currentZoneWidth; x++) {
|
||||||
|
zoneTiles[y][x] = zoneTiles[y][x] || 'blank_tile' // Fill missing tiles with 'blank_tile'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the tilemap with any new 'blank_tile' entries
|
||||||
|
zoneTiles.forEach((row, y) => {
|
||||||
|
row.forEach((tileId, x) => {
|
||||||
|
placeTile(zoneTilemap, tiles, x, y, tileId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneObjects.value = zoneStore.zone?.zoneObjects ?? []
|
||||||
|
|
||||||
|
// Original
|
||||||
|
type TResponse = {
|
||||||
|
zone: Zone
|
||||||
|
characters: CharacterT[]
|
||||||
|
}
|
||||||
|
|
||||||
|
gameStore.connection?.emit('character:zone:request', { zoneId: gameStore.character?.zoneId }, (response: TResponse) => {
|
||||||
|
console.log(response)
|
||||||
|
zoneStore.setZone(response.zone)
|
||||||
|
zoneStore.setCharacters(response.characters)
|
||||||
|
setAllTiles(zoneTilemap, tiles, response.zone.tiles)
|
||||||
|
zoneObjects.value = response.zone.zoneObjects
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
onBeforeUnmount(() => {
|
||||||
* 1 tile is 64x32
|
zoneEventTiles.value = []
|
||||||
* the zone is 10x10
|
zoneObjects.value = []
|
||||||
* so the zone is 640x320
|
tiles.destroy()
|
||||||
*/
|
zoneTilemap.removeAllLayers()
|
||||||
/**
|
zoneTilemap.destroy()
|
||||||
* Resources
|
zoneStore.reset()
|
||||||
* https://clintbellanger.net/articles/isometric_math/
|
|
||||||
* https://gist.github.com/veleek/3be73dc61d5f5a80abc0f72c3ffe390e
|
gameStore.connection?.emit('character:zone:leave')
|
||||||
* https://gamedev.stackexchange.com/questions/116485/how-to-center-a-tilemap-in-phaser
|
gameStore.connection?.off('character:zone:load')
|
||||||
* https://github.com/Nulligma/phaser-isometric-test/blob/master/src/main.ts
|
gameStore.connection?.off('zone:character:join')
|
||||||
* https://github.com/neki-dev/isometric-snippets
|
gameStore.connection?.off('user:disconnect')
|
||||||
* https://github.com/itsezc/CycloneIO/blob/next/packages/client/games/HabboEngine.ts
|
gameStore.connection?.off('character:moved')
|
||||||
* https://github.com/daan93/phaser-isometric-demo/tree/main
|
})
|
||||||
*/
|
|
||||||
|
// center camera
|
||||||
|
const centerY = (zoneTilemap.height * zoneTilemap.tileHeight) / 2
|
||||||
|
const centerX = (zoneTilemap.width * zoneTilemap.tileWidth) / 2
|
||||||
|
scene.cameras.main.centerOn(centerX, centerY)
|
||||||
</script>
|
</script>
|
||||||
|
@ -7,22 +7,22 @@
|
|||||||
<div class="absolute top-0 left-[30px] w-[280px] h-[84px] z-10 bg-[url('/assets/shapes/hud-shape-empty.svg')] bg-center bg-[length:cover] bg-no-repeat">
|
<div class="absolute top-0 left-[30px] w-[280px] h-[84px] z-10 bg-[url('/assets/shapes/hud-shape-empty.svg')] bg-center bg-[length:cover] bg-no-repeat">
|
||||||
<div class="h-[64px] flex flex-col items-end py-[10px] pl-[50px] pr-[20px]">
|
<div class="h-[64px] flex flex-col items-end py-[10px] pl-[50px] pr-[20px]">
|
||||||
<div class="w-full flex items-center justify-between mb-1.5">
|
<div class="w-full flex items-center justify-between mb-1.5">
|
||||||
<span class="text-ellipsis overflow-hidden whitespace-nowrap max-w-[125px] text-sm">{{ game.character.name }}</span>
|
<span class="text-ellipsis overflow-hidden whitespace-nowrap max-w-[125px] text-sm">{{ gameStore.character.name }}</span>
|
||||||
<span class="text-sm">lvl. {{ game.character.level }}</span>
|
<span class="text-sm">lvl. {{ gameStore.character.level }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex items-center justify-between">
|
<div class="w-full flex items-center justify-between">
|
||||||
<label class="text-sm" for="hp">HP</label>
|
<label class="text-sm" for="hp">HP</label>
|
||||||
<progress class="h-2 rounded-lg w-full max-w-[175px] appearance-none accent-red" id="hp" :value="game.character.hitpoints" max="100">{{ socket.character.hitpoints }}%</progress>
|
<progress class="h-2 rounded-lg w-full max-w-[175px] appearance-none accent-red" id="hp" :value="gameStore.character.hitpoints" max="100">{{ gameStore.character.hitpoints }}%</progress>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex items-center justify-between">
|
<div class="w-full flex items-center justify-between">
|
||||||
<label class="text-sm" for="mp">MP</label>
|
<label class="text-sm" for="mp">MP</label>
|
||||||
<progress class="h-2 rounded-lg w-full max-w-[175px] appearance-none accent-blue" id="mp" :value="game.character.mana" max="100">{{ socket.character.mana }}%</progress>
|
<progress class="h-2 rounded-lg w-full max-w-[175px] appearance-none accent-blue" id="mp" :value="gameStore.character.mana" max="100">{{ gameStore.character.mana }}%</progress>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TODO: Replace socket.character with other (selected) player's -->
|
<!-- TODO: Replace gameStore.character with other (selected) player's -->
|
||||||
<div class="hud-wrapper other-player relative right-0 w-[310px] h-[84px]">
|
<div class="hud-wrapper other-player relative right-0 w-[310px] h-[84px]">
|
||||||
<div class="absolute w-[54px] h-[54px] bg-white/80 rounded-full border-3 border-solid border-white top-1/2 translate-y-[-50%] right-0 z-20">
|
<div class="absolute w-[54px] h-[54px] bg-white/80 rounded-full border-3 border-solid border-white top-1/2 translate-y-[-50%] right-0 z-20">
|
||||||
<img class="w-[28px] absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] scale-x-[-1]" draggable="false" src="/assets/avatar/default/head.png" />
|
<img class="w-[28px] absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] scale-x-[-1]" draggable="false" src="/assets/avatar/default/head.png" />
|
||||||
@ -31,12 +31,12 @@
|
|||||||
<div class="absolute top-0 right-[30px] w-[280px] h-[84px] z-10 scale-x-[-1] bg-[url('/assets/shapes/hud-shape-empty.svg')] bg-center bg-[length:cover] bg-no-repeat">
|
<div class="absolute top-0 right-[30px] w-[280px] h-[84px] z-10 scale-x-[-1] bg-[url('/assets/shapes/hud-shape-empty.svg')] bg-center bg-[length:cover] bg-no-repeat">
|
||||||
<div class="h-[64px] flex flex-col items-end scale-x-[-1] py-[10px] pr-[50px] pl-[20px]">
|
<div class="h-[64px] flex flex-col items-end scale-x-[-1] py-[10px] pr-[50px] pl-[20px]">
|
||||||
<div class="w-full flex items-center justify-between mb-1.5">
|
<div class="w-full flex items-center justify-between mb-1.5">
|
||||||
<span class="text-ellipsis overflow-hidden whitespace-nowrap max-w-[125px] text-sm">{{ game.character.name }}</span>
|
<span class="text-ellipsis overflow-hidden whitespace-nowrap max-w-[125px] text-sm">{{ gameStore.character.name }}</span>
|
||||||
<span class="text-sm">lvl. {{ socket.character.level }}</span>
|
<span class="text-sm">lvl. {{ gameStore.character.level }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex items-center justify-between">
|
<div class="w-full flex items-center justify-between">
|
||||||
<label class="text-sm" for="hp">HP</label>
|
<label class="text-sm" for="hp">HP</label>
|
||||||
<progress class="h-2 rounded-lg w-full max-w-[175px] appearance-none accent-red" id="hp" :value="game.character.hitpoints" max="100">{{ socket.character.hitpoints }}%</progress>
|
<progress class="h-2 rounded-lg w-full max-w-[175px] appearance-none accent-red" id="hp" :value="gameStore.character.hitpoints" max="100">{{ gameStore.character.hitpoints }}%</progress>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<Container>
|
<Container>
|
||||||
<Rectangle :x="tileToWorldX(layer, props.character?.position_x)" :y="tileToWorldY(layer, props.character?.position_y)" :origin-x="0.5" :origin-y="10.5" :fillColor="0xffffff" :width="74" :height="8">
|
<Rectangle :x="tileToWorldX(layer, props.character?.position_x, props.character?.position_y)" :y="tileToWorldY(layer, props.character?.position_x, props.character?.position_y)" :origin-x="0.5" :origin-y="10.5" :fillColor="0xffffff" :width="74" :height="8">
|
||||||
<Rectangle :x="tileToWorldX(layer, props.character?.position_x)" :y="tileToWorldY(layer, props.character?.position_y)" :origin-x="0.5" :origin-y="20.5" :fillColor="0x09ad19" :width="70" :height="4" />
|
<Rectangle :x="tileToWorldX(layer, props.character?.position_x, props.character?.position_y)" :y="tileToWorldY(layer, props.character?.position_x, props.character?.position_y)" :origin-x="0.5" :origin-y="20.5" :fillColor="0x09ad19" :width="70" :height="4" />
|
||||||
</Rectangle>
|
</Rectangle>
|
||||||
<Text
|
<Text
|
||||||
@create="createText"
|
@create="createText"
|
||||||
:text="props.character?.name"
|
:text="props.character?.name"
|
||||||
:x="tileToWorldX(layer, props.character?.position_x)"
|
:x="tileToWorldX(layer, props.character?.position_x, props.character?.position_y)"
|
||||||
:y="tileToWorldY(layer, props.character?.position_y)"
|
:y="tileToWorldY(layer, props.character?.position_x, props.character?.position_y)"
|
||||||
:origin-x="0.5"
|
:origin-x="0.5"
|
||||||
:origin-y="4.5"
|
:origin-y="4.5"
|
||||||
:style="{
|
:style="{
|
||||||
@ -16,7 +16,7 @@
|
|||||||
fontSize: '14px'
|
fontSize: '14px'
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<Sprite ref="sprite" :x="tileToWorldX(layer, props.character?.position_x)" :y="tileToWorldY(layer, props.character?.position_y)" play="walk" />
|
<Sprite ref="sprite" :x="tileToWorldX(layer, props.character?.position_x, props.character?.position_y)" :y="tileToWorldY(layer, props.character?.position_x, props.character?.position_y)" play="walk" />
|
||||||
</Container>
|
</Container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const scene = useScene()
|
const scene = useScene()
|
||||||
const isSelf = props.character.id === socket.character.id
|
const isSelf = props.character?.id === gameStore.character?.id
|
||||||
|
|
||||||
const createText = (text: Phaser.GameObjects.Text) => {
|
const createText = (text: Phaser.GameObjects.Text) => {
|
||||||
text.setLetterSpacing(1.5)
|
text.setLetterSpacing(1.5)
|
||||||
@ -60,7 +60,7 @@ function onPointerClick(pointer: Phaser.Input.Pointer) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gameStore.connection.emit('character:move', { position_x: pointer_tile.x, position_y: pointer_tile.y })
|
gameStore.connection?.emit('character:move', { position_x: pointer_tile.x, position_y: pointer_tile.y })
|
||||||
|
|
||||||
//Directions for player sprites + animations
|
//Directions for player sprites + animations
|
||||||
if (px < 0 && py > 0) {
|
if (px < 0 && py > 0) {
|
||||||
|
@ -88,7 +88,7 @@ function saveTile() {
|
|||||||
{
|
{
|
||||||
id: selectedTile.value.id,
|
id: selectedTile.value.id,
|
||||||
name: tileName.value,
|
name: tileName.value,
|
||||||
tags: tileTags.value,
|
tags: tileTags.value
|
||||||
},
|
},
|
||||||
(response: boolean) => {
|
(response: boolean) => {
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
@ -7,14 +7,7 @@
|
|||||||
<div class="w-full flex gap-1.5 flex-row">
|
<div class="w-full flex gap-1.5 flex-row">
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 font-titles hidden" for="search">Search...</label>
|
<label class="mb-1.5 font-titles hidden" for="search">Search...</label>
|
||||||
<input
|
<input @mousedown.stop class="input-cyan" type="text" name="search" placeholder="Search" v-model="searchQuery" />
|
||||||
@mousedown.stop
|
|
||||||
class="input-cyan"
|
|
||||||
type="text"
|
|
||||||
name="search"
|
|
||||||
placeholder="Search"
|
|
||||||
v-model="searchQuery"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 font-titles hidden" for="depth">Depth</label>
|
<label class="mb-1.5 font-titles hidden" for="depth">Depth</label>
|
||||||
@ -68,9 +61,7 @@ const filteredObjects = computed(() => {
|
|||||||
if (!searchQuery.value) {
|
if (!searchQuery.value) {
|
||||||
return zoneEditorStore.objectList
|
return zoneEditorStore.objectList
|
||||||
}
|
}
|
||||||
return zoneEditorStore.objectList.filter(object =>
|
return zoneEditorStore.objectList.filter((object) => object.name.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
||||||
object.name.toLowerCase().includes(searchQuery.value.toLowerCase())
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
@ -7,14 +7,7 @@
|
|||||||
<div class="w-full flex gap-1.5 flex-row">
|
<div class="w-full flex gap-1.5 flex-row">
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1.5 font-titles hidden" for="search">Search...</label>
|
<label class="mb-1.5 font-titles hidden" for="search">Search...</label>
|
||||||
<input
|
<input @mousedown.stop class="input-cyan" type="text" name="search" placeholder="Search" v-model="searchQuery" />
|
||||||
@mousedown.stop
|
|
||||||
class="input-cyan"
|
|
||||||
type="text"
|
|
||||||
name="search"
|
|
||||||
placeholder="Search"
|
|
||||||
v-model="searchQuery"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -59,9 +52,7 @@ const filteredTiles = computed(() => {
|
|||||||
if (!searchQuery.value) {
|
if (!searchQuery.value) {
|
||||||
return zoneEditorStore.tileList
|
return zoneEditorStore.tileList
|
||||||
}
|
}
|
||||||
return zoneEditorStore.tileList.filter(tile =>
|
return zoneEditorStore.tileList.filter((tile) => tile.name.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
||||||
tile.name.toLowerCase().includes(searchQuery.value.toLowerCase())
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
@ -149,7 +149,7 @@ scene.input.on(Phaser.Input.Events.POINTER_MOVE, drawTiles)
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
addEventListener('keydown', initKeyShortcuts)
|
addEventListener('keydown', initKeyShortcuts)
|
||||||
});
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
scene.input.off(Phaser.Input.Events.POINTER_UP, drawTile)
|
scene.input.off(Phaser.Input.Events.POINTER_UP, drawTile)
|
||||||
@ -157,9 +157,8 @@ onBeforeUnmount(() => {
|
|||||||
removeEventListener('keydown', initKeyShortcuts)
|
removeEventListener('keydown', initKeyShortcuts)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Key bindings
|
// Key bindings
|
||||||
function initKeyShortcuts (event: KeyboardEvent) {
|
function initKeyShortcuts(event: KeyboardEvent) {
|
||||||
if (!zoneEditorStore.zone) return
|
if (!zoneEditorStore.zone) return
|
||||||
|
|
||||||
// prevent if focussed on input
|
// prevent if focussed on input
|
||||||
|
@ -3,7 +3,16 @@
|
|||||||
<Controls :layer="tiles" />
|
<Controls :layer="tiles" />
|
||||||
|
|
||||||
<Container :depth="2">
|
<Container :depth="2">
|
||||||
<Image v-for="object in zoneObjects" :depth="object.depth" :key="object.object.id" :x="tileToWorldX(zoneTilemap, object.position_x, object.position_y)" :y="tileToWorldY(zoneTilemap, object.position_x, object.position_y)" :texture="object.object.id" :originY="Number(object.object.origin_x)" :originX="Number(object.object.origin_y)" />
|
<Image
|
||||||
|
v-for="object in zoneObjects"
|
||||||
|
:depth="object.depth"
|
||||||
|
:key="object.object.id"
|
||||||
|
:x="tileToWorldX(zoneTilemap, object.position_x, object.position_y)"
|
||||||
|
:y="tileToWorldY(zoneTilemap, object.position_x, object.position_y)"
|
||||||
|
:texture="object.object.id"
|
||||||
|
:originY="Number(object.object.origin_x)"
|
||||||
|
:originX="Number(object.object.origin_y)"
|
||||||
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Container :depth="3">
|
<Container :depth="3">
|
||||||
@ -37,9 +46,7 @@ import Tileset = Phaser.Tilemaps.Tileset
|
|||||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
||||||
|
|
||||||
function uuidv4() {
|
function uuidv4() {
|
||||||
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
|
return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => (+c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))).toString(16))
|
||||||
(+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const scene = useScene()
|
const scene = useScene()
|
||||||
@ -65,7 +72,7 @@ const zoneData = new Phaser.Tilemaps.MapData({
|
|||||||
*/
|
*/
|
||||||
const tilesetImages: Tileset[] = []
|
const tilesetImages: Tileset[] = []
|
||||||
const zoneTilemap = new Phaser.Tilemaps.Tilemap(scene, zoneData)
|
const zoneTilemap = new Phaser.Tilemaps.Tilemap(scene, zoneData)
|
||||||
let zoneTiles = [] as string[][];
|
let zoneTiles = [] as string[][]
|
||||||
const zoneObjects = ref<ZoneObject[]>([])
|
const zoneObjects = ref<ZoneObject[]>([])
|
||||||
const zoneEventTiles = ref<ZoneEventTile[]>([])
|
const zoneEventTiles = ref<ZoneEventTile[]>([])
|
||||||
|
|
||||||
@ -163,7 +170,7 @@ function pencil(tile: Phaser.Tilemaps.Tile) {
|
|||||||
function paint(tile: Phaser.Tilemaps.Tile) {
|
function paint(tile: Phaser.Tilemaps.Tile) {
|
||||||
if (zoneEditorStore.selectedTile === null) return
|
if (zoneEditorStore.selectedTile === null) return
|
||||||
exampleTilesArray.forEach((row, y) => row.forEach((tile, x) => placeTile(zoneTilemap, tiles, x, y, zoneEditorStore.selectedTile.id)))
|
exampleTilesArray.forEach((row, y) => row.forEach((tile, x) => placeTile(zoneTilemap, tiles, x, y, zoneEditorStore.selectedTile.id)))
|
||||||
zoneTiles.forEach((row, y) => row.forEach((tile, x) => zoneTiles[y][x] = zoneEditorStore.selectedTile.id))
|
zoneTiles.forEach((row, y) => row.forEach((tile, x) => (zoneTiles[y][x] = zoneEditorStore.selectedTile.id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
@ -175,14 +182,14 @@ function save() {
|
|||||||
width: zoneEditorStore.zone.width,
|
width: zoneEditorStore.zone.width,
|
||||||
height: zoneEditorStore.zone.height,
|
height: zoneEditorStore.zone.height,
|
||||||
tiles: zoneTiles,
|
tiles: zoneTiles,
|
||||||
zoneEventTiles: toRaw(zoneEventTiles.value).map(tile => ({
|
zoneEventTiles: toRaw(zoneEventTiles.value).map((tile) => ({
|
||||||
id: tile.id,
|
id: tile.id,
|
||||||
zoneId: tile.zoneId,
|
zoneId: tile.zoneId,
|
||||||
type: tile.type,
|
type: tile.type,
|
||||||
position_x: tile.position_x,
|
position_x: tile.position_x,
|
||||||
position_y: tile.position_y
|
position_y: tile.position_y
|
||||||
})),
|
})),
|
||||||
zoneObjects: toRaw(zoneObjects.value).map(obj => ({
|
zoneObjects: toRaw(zoneObjects.value).map((obj) => ({
|
||||||
id: obj.id,
|
id: obj.id,
|
||||||
zoneId: obj.zoneId,
|
zoneId: obj.zoneId,
|
||||||
objectId: obj.objectId,
|
objectId: obj.objectId,
|
||||||
@ -190,13 +197,13 @@ function save() {
|
|||||||
position_x: obj.position_x,
|
position_x: obj.position_x,
|
||||||
position_y: obj.position_y
|
position_y: obj.position_y
|
||||||
}))
|
}))
|
||||||
};
|
}
|
||||||
|
|
||||||
gameStore.connection.emit('gm:zone_editor:zone:update', data);
|
gameStore.connection.emit('gm:zone_editor:zone:update', data)
|
||||||
|
|
||||||
gameStore.connection.emit('gm:zone_editor:zone:request', { zoneId: zoneEditorStore.zone.id }, (response: Zone) => {
|
gameStore.connection.emit('gm:zone_editor:zone:request', { zoneId: zoneEditorStore.zone.id }, (response: Zone) => {
|
||||||
zoneEditorStore.setZone(response)
|
zoneEditorStore.setZone(response)
|
||||||
});
|
})
|
||||||
|
|
||||||
if (zoneEditorStore.isSettingsModalShown) {
|
if (zoneEditorStore.isSettingsModalShown) {
|
||||||
zoneEditorStore.toggleSettingsModal()
|
zoneEditorStore.toggleSettingsModal()
|
||||||
@ -215,27 +222,27 @@ onBeforeMount(() => {
|
|||||||
zoneTiles = exampleTilesArray
|
zoneTiles = exampleTilesArray
|
||||||
|
|
||||||
if (zoneEditorStore.zone && zoneEditorStore.zone.tiles) {
|
if (zoneEditorStore.zone && zoneEditorStore.zone.tiles) {
|
||||||
setAllTiles(zoneTilemap, tiles, zoneEditorStore.zone.tiles);
|
setAllTiles(zoneTilemap, tiles, zoneEditorStore.zone.tiles)
|
||||||
zoneTiles = zoneEditorStore.zone.tiles;
|
zoneTiles = zoneEditorStore.zone.tiles
|
||||||
|
|
||||||
// Determine the current zone dimensions
|
// Determine the current zone dimensions
|
||||||
const currentZoneWidth = zoneEditorStore.zone.width ?? 0;
|
const currentZoneWidth = zoneEditorStore.zone.width ?? 0
|
||||||
const currentZoneHeight = zoneEditorStore.zone.height ?? 0;
|
const currentZoneHeight = zoneEditorStore.zone.height ?? 0
|
||||||
|
|
||||||
// Ensure zoneTiles matches the current zone dimensions, filling new spaces with 'blank_tile'
|
// Ensure zoneTiles matches the current zone dimensions, filling new spaces with 'blank_tile'
|
||||||
for (let y = 0; y < currentZoneHeight; y++) {
|
for (let y = 0; y < currentZoneHeight; y++) {
|
||||||
zoneTiles[y] = zoneTiles[y] || []; // Ensure the row exists
|
zoneTiles[y] = zoneTiles[y] || [] // Ensure the row exists
|
||||||
for (let x = 0; x < currentZoneWidth; x++) {
|
for (let x = 0; x < currentZoneWidth; x++) {
|
||||||
zoneTiles[y][x] = zoneTiles[y][x] || 'blank_tile'; // Fill missing tiles with 'blank_tile'
|
zoneTiles[y][x] = zoneTiles[y][x] || 'blank_tile' // Fill missing tiles with 'blank_tile'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the tilemap with any new 'blank_tile' entries
|
// Update the tilemap with any new 'blank_tile' entries
|
||||||
zoneTiles.forEach((row, y) => {
|
zoneTiles.forEach((row, y) => {
|
||||||
row.forEach((tileId, x) => {
|
row.forEach((tileId, x) => {
|
||||||
placeTile(zoneTilemap, tiles, x, y, tileId);
|
placeTile(zoneTilemap, tiles, x, y, tileId)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
zoneEventTiles.value = zoneEditorStore.zone?.zoneEventTiles ?? []
|
zoneEventTiles.value = zoneEditorStore.zone?.zoneEventTiles ?? []
|
||||||
|
@ -53,7 +53,7 @@ function loadZone(id: number) {
|
|||||||
console.log('loadZone', id)
|
console.log('loadZone', id)
|
||||||
gameStore.connection.emit('gm:zone_editor:zone:request', { zoneId: id }, (response: Zone) => {
|
gameStore.connection.emit('gm:zone_editor:zone:request', { zoneId: id }, (response: Zone) => {
|
||||||
zoneEditorStore.setZone(response)
|
zoneEditorStore.setZone(response)
|
||||||
});
|
})
|
||||||
zoneEditorStore.toggleZoneListModal()
|
zoneEditorStore.toggleZoneListModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const dev: boolean = true;
|
const dev: boolean = true
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'New Quest',
|
name: 'New Quest',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex justify-center items-center h-dvh p-[30px] relative">
|
<div class="flex justify-center items-center h-dvh p-[30px] relative">
|
||||||
<GmTools v-if="isLoaded" />
|
<GmTools v-if="isLoaded && gameStore.character?.role === 'gm'" />
|
||||||
<GmPanel v-if="isLoaded" />
|
<GmPanel v-if="isLoaded && gameStore.character?.role === 'gm'" />
|
||||||
|
|
||||||
<Game :config="gameConfig" @create="createGame" v-if="!zoneEditorStore.active">
|
<Game :config="gameConfig" @create="createGame" v-if="!zoneEditorStore.active">
|
||||||
<Scene name="main" @preload="preloadScene" @create="createScene">
|
<Scene name="main" @preload="preloadScene" @create="createScene">
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<Hud />
|
<Hud />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isLoaded">
|
<div v-if="isLoaded">
|
||||||
<World />
|
<World :key="gameStore.character?.zoneId ?? 1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex absolute justify-between left-0 right-0 bottom-[100px] h-[100px] mx-[48px] my-0" v-if="isLoaded">
|
<div class="flex absolute justify-between left-0 right-0 bottom-[100px] h-[100px] mx-[48px] my-0" v-if="isLoaded">
|
||||||
<Chat />
|
<Chat />
|
||||||
@ -28,10 +28,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
import 'phaser'
|
import 'phaser'
|
||||||
import { onUnmounted, toRaw, watch, ref } from 'vue'
|
import { onUnmounted, watch, ref } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { Game, Scene } from 'phavuer'
|
import { Game, Scene } from 'phavuer'
|
||||||
import { useGameStore } from '@/stores/game'
|
import { useGameStore } from '@/stores/game'
|
||||||
|
import { useZoneStore } from '@/stores/zone'
|
||||||
import { useZoneEditorStore } from '@/stores/zoneEditor'
|
import { useZoneEditorStore } from '@/stores/zoneEditor'
|
||||||
import { useAssetStore } from '@/stores/assets'
|
import { useAssetStore } from '@/stores/assets'
|
||||||
import World from '@/components/World.vue'
|
import World from '@/components/World.vue'
|
||||||
@ -43,6 +44,7 @@ import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
|
|||||||
import GmPanel from '@/components/utilities/GmPanel.vue'
|
import GmPanel from '@/components/utilities/GmPanel.vue'
|
||||||
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
|
const zoneStore = useZoneStore()
|
||||||
const zoneEditorStore = useZoneEditorStore()
|
const zoneEditorStore = useZoneEditorStore()
|
||||||
const assetStore = useAssetStore()
|
const assetStore = useAssetStore()
|
||||||
const isLoaded = ref(false)
|
const isLoaded = ref(false)
|
||||||
|
@ -52,7 +52,7 @@ onMounted(async () => {
|
|||||||
/**
|
/**
|
||||||
* Fetch assets from the server
|
* Fetch assets from the server
|
||||||
*/
|
*/
|
||||||
if (!await assetStore.fetchAssets()) {
|
if (!(await assetStore.fetchAssets())) {
|
||||||
notifications.addNotification({ message: 'Failed to fetch assets, the server may be offline or in maintenance. Please try again later.' })
|
notifications.addNotification({ message: 'Failed to fetch assets, the server may be offline or in maintenance. Please try again later.' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -18,7 +18,7 @@ export async function login(username: string, password: string, gameStore = useG
|
|||||||
const response = await axios.post(`${config.server_endpoint}/login`, { username, password })
|
const response = await axios.post(`${config.server_endpoint}/login`, { username, password })
|
||||||
useCookies().set('token', response.data.token as string, {
|
useCookies().set('token', response.data.token as string, {
|
||||||
// for whole domain
|
// for whole domain
|
||||||
domain: window.location.hostname.split('.').slice(-2).join('.'),
|
domain: window.location.hostname.split('.').slice(-2).join('.')
|
||||||
})
|
})
|
||||||
return { success: true, token: response.data.token }
|
return { success: true, token: response.data.token }
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
@ -18,13 +18,13 @@ export function tileToWorldXY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function tileToWorldX(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number, pos_y: number): number {
|
export function tileToWorldX(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number, pos_y: number): number {
|
||||||
const worldPoint = layer.tileToWorldXY(pos_x, pos_y);
|
const worldPoint = layer.tileToWorldXY(pos_x, pos_y)
|
||||||
return worldPoint.x + config.tile_size.x / 2;
|
return worldPoint.x + config.tile_size.x / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tileToWorldY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number, pos_y: number): number {
|
export function tileToWorldY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number, pos_y: number): number {
|
||||||
const worldPoint = layer.tileToWorldXY(pos_x, pos_y);
|
const worldPoint = layer.tileToWorldXY(pos_x, pos_y)
|
||||||
return worldPoint.y + config.tile_size.y * 1.5;
|
return worldPoint.y + config.tile_size.y * 1.5
|
||||||
}
|
}
|
||||||
|
|
||||||
export function placeTile(zone: Tilemap, layer: TilemapLayer, x: number, y: number, tileName: string) {
|
export function placeTile(zone: Tilemap, layer: TilemapLayer, x: number, y: number, tileName: string) {
|
||||||
|
@ -25,13 +25,13 @@ export const useAssetStore = defineStore('assets', {
|
|||||||
return fetch(config.server_endpoint + '/assets')
|
return fetch(config.server_endpoint + '/assets')
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((assets) => {
|
.then((assets) => {
|
||||||
this.setAssets(assets);
|
this.setAssets(assets)
|
||||||
return true;
|
return true
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Error fetching assets:', error);
|
console.error('Error fetching assets:', error)
|
||||||
return false;
|
return false
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import type { Character } from '@/types'
|
import type { Character, Zone } from '@/types'
|
||||||
|
|
||||||
export const useZoneStore = defineStore('zone', {
|
export const useZoneStore = defineStore('zone', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
tiles: [] as number[][],
|
zone: null as Zone | null,
|
||||||
characters: [] as Character[]
|
characters: [] as Character[]
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setTiles(tiles: number[][]) {
|
setZone(zone: Zone | null) {
|
||||||
this.tiles = tiles
|
this.zone = zone
|
||||||
},
|
},
|
||||||
setCharacters(characters: Character[]) {
|
setCharacters(characters: Character[]) {
|
||||||
this.characters = characters
|
this.characters = characters
|
||||||
@ -25,7 +25,7 @@ export const useZoneStore = defineStore('zone', {
|
|||||||
this.characters = this.characters.filter((c: Character) => c.id !== character.id)
|
this.characters = this.characters.filter((c: Character) => c.id !== character.id)
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
this.tiles = []
|
this.zone = null
|
||||||
this.characters = []
|
this.characters = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import type { Zone, Object, Tile } from '@/types'
|
|||||||
|
|
||||||
export const useZoneEditorStore = defineStore('zoneEditor', {
|
export const useZoneEditorStore = defineStore('zoneEditor', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
active: true,
|
active: false,
|
||||||
zone: null as Zone | null,
|
zone: null as Zone | null,
|
||||||
tool: 'move',
|
tool: 'move',
|
||||||
drawMode: 'tile',
|
drawMode: 'tile',
|
||||||
|
@ -102,7 +102,7 @@ export type ZoneEventTile = {
|
|||||||
id: string
|
id: string
|
||||||
zoneId: number
|
zoneId: number
|
||||||
zone: Zone
|
zone: Zone
|
||||||
type: "BLOCK" | "WARP" | "NPC" | "ITEM"
|
type: 'BLOCK' | 'WARP' | 'NPC' | 'ITEM'
|
||||||
position_x: number
|
position_x: number
|
||||||
position_y: number
|
position_y: number
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user