forked from noxious/client
Map editor fixes (select & move), character sprites are now dynamically loaded and cached, moved repeated code into a composable, updated types
This commit is contained in:
parent
39b65b3884
commit
d402744955
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" @move="moveZoneObject" @rotate="rotateZoneObject" @delete="deleteZoneObject" />
|
<SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" :movingZoneObject="movingZoneObject" @move="moveZoneObject" @rotate="rotateZoneObject" @delete="deleteZoneObject" />
|
||||||
<ZoneObject v-for="zoneObject in zoneEditorStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject @pointerup="() => (selectedZoneObject = zoneObject)" />
|
<ZoneObject v-for="zoneObject in zoneEditorStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject :selectedZoneObject :movingZoneObject @pointerup="() => (selectedZoneObject = zoneObject)" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -5,18 +5,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { Image, useScene } from 'phavuer'
|
import { Image, useScene } from 'phavuer'
|
||||||
import { calculateIsometricDepth, loadTexture, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
||||||
|
import { loadTexture } from '@/composables/gameComposable'
|
||||||
import type { AssetDataT, ZoneObject } from '@/types'
|
import type { AssetDataT, ZoneObject } from '@/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
tilemap: Phaser.Tilemaps.Tilemap
|
tilemap: Phaser.Tilemaps.Tilemap
|
||||||
zoneObject: ZoneObject
|
zoneObject: ZoneObject
|
||||||
|
selectedZoneObject: ZoneObject | null
|
||||||
|
movingZoneObject: ZoneObject | null
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const scene = useScene()
|
const scene = useScene()
|
||||||
const isTextureLoaded = ref(false)
|
const isTextureLoaded = ref(false)
|
||||||
|
|
||||||
const imageProps = computed(() => ({
|
const imageProps = computed(() => ({
|
||||||
|
alpha: props.movingZoneObject?.id === props.zoneObject.id ? 0.5 : 1,
|
||||||
|
tint: props.selectedZoneObject?.id === props.zoneObject.id ? 0x00ff00 : 0xffffff,
|
||||||
depth: calculateIsometricDepth(props.zoneObject.positionX, props.zoneObject.positionY, props.zoneObject.object.frameWidth, props.zoneObject.object.frameHeight),
|
depth: calculateIsometricDepth(props.zoneObject.positionX, props.zoneObject.positionY, props.zoneObject.object.frameWidth, props.zoneObject.object.frameHeight),
|
||||||
x: tileToWorldX(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
|
x: tileToWorldX(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
|
||||||
y: tileToWorldY(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
|
y: tileToWorldY(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
|
||||||
@ -40,4 +45,4 @@ loadTexture(scene, {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Error loading texture:', error)
|
console.error('Error loading texture:', error)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
@ -18,12 +18,13 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
import { type ExtendedCharacter } from '@/types'
|
import { type ExtendedCharacter, type Sprite as SpriteT } from '@/types'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useZoneStore } from '@/stores/zoneStore'
|
import { useZoneStore } from '@/stores/zoneStore'
|
||||||
import { watch, computed, ref, onMounted, onUnmounted } from 'vue'
|
import { watch, computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
import { Container, refObj, RoundRectangle, Sprite, Text, useGame, useScene } from 'phavuer'
|
import { Container, refObj, RoundRectangle, Sprite, Text, useGame, useScene } from 'phavuer'
|
||||||
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
||||||
|
import { loadSpriteTextures } from '@/composables/gameComposable'
|
||||||
|
|
||||||
enum Direction {
|
enum Direction {
|
||||||
POSITIVE,
|
POSITIVE,
|
||||||
@ -36,6 +37,7 @@ const props = defineProps<{
|
|||||||
character: ExtendedCharacter
|
character: ExtendedCharacter
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const isTextureLoaded = ref(false)
|
||||||
const charChatContainer = refObj<Phaser.GameObjects.Container>()
|
const charChatContainer = refObj<Phaser.GameObjects.Container>()
|
||||||
const charContainer = refObj<Phaser.GameObjects.Container>()
|
const charContainer = refObj<Phaser.GameObjects.Container>()
|
||||||
const charSprite = refObj<Phaser.GameObjects.Sprite>()
|
const charSprite = refObj<Phaser.GameObjects.Sprite>()
|
||||||
@ -181,6 +183,14 @@ watch(
|
|||||||
watch(() => props.character.isMoving, updateSprite)
|
watch(() => props.character.isMoving, updateSprite)
|
||||||
watch(() => props.character.rotation, updateSprite)
|
watch(() => props.character.rotation, updateSprite)
|
||||||
|
|
||||||
|
loadSpriteTextures(scene, props.character.characterType?.sprite as SpriteT).then((loaded) => {
|
||||||
|
isTextureLoaded.value = loaded
|
||||||
|
charSprite.value!.setTexture(charTexture.value)
|
||||||
|
charSprite.value!.setFlipX(isFlippedX.value)
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('Error loading texture:', error)
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
charChatContainer.value!.setName(`${props.character!.name}_chatContainer`)
|
charChatContainer.value!.setName(`${props.character!.name}_chatContainer`)
|
||||||
charChatContainer.value!.setVisible(false)
|
charChatContainer.value!.setVisible(false)
|
||||||
@ -194,10 +204,6 @@ onMounted(() => {
|
|||||||
scene.cameras.main.stopFollow()
|
scene.cameras.main.stopFollow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sprite
|
|
||||||
charSprite.value!.setTexture(charTexture.value)
|
|
||||||
charSprite.value!.setFlipX(isFlippedX.value)
|
|
||||||
|
|
||||||
updatePosition(props.character.positionX, props.character.positionY, props.character.rotation)
|
updatePosition(props.character.positionX, props.character.positionY, props.character.rotation)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { Image, useScene } from 'phavuer'
|
import { Image, useScene } from 'phavuer'
|
||||||
import { calculateIsometricDepth, loadTexture, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
||||||
|
import { loadTexture } from '@/composables/gameComposable'
|
||||||
import type { AssetDataT, ZoneObject } from '@/types'
|
import type { AssetDataT, ZoneObject } from '@/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
import type { AssetDataT, Sprite } from '@/types'
|
||||||
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
|
import { AssetStorage } from '@/storage/assetStorage'
|
||||||
|
import config from '@/config'
|
||||||
|
|
||||||
|
export async function loadTexture(scene: Phaser.Scene, assetData: AssetDataT): Promise<boolean> {
|
||||||
|
const gameStore = useGameStore()
|
||||||
|
const assetStorage = new AssetStorage()
|
||||||
|
|
||||||
|
// Check if the texture is already loaded in Phaser
|
||||||
|
if (scene.textures.exists(assetData.key)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the asset is already cached
|
||||||
|
let asset = await assetStorage.get(assetData.key)
|
||||||
|
|
||||||
|
// If asset is not found, download it
|
||||||
|
if (!asset) {
|
||||||
|
await assetStorage.download(assetData)
|
||||||
|
asset = await assetStorage.get(assetData.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If asset is found, add it to the scene
|
||||||
|
if (asset) {
|
||||||
|
return new Promise<boolean>((resolve) => {
|
||||||
|
console.log(asset.data)
|
||||||
|
scene.textures.addBase64(asset.key, asset.data)
|
||||||
|
scene.textures.once(`addtexture-${asset.key}`, () => {
|
||||||
|
gameStore.game.loadedAssets.push(asset)
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadSpriteTextures(scene: Phaser.Scene, sprite: Sprite) {
|
||||||
|
const sprite_actions = await fetch(config.server_endpoint + '/assets/list_sprite_actions/' + sprite?.id).then((response) => response.json())
|
||||||
|
for await (const sprite_action of sprite_actions) {
|
||||||
|
await loadTexture(scene, {
|
||||||
|
key: sprite_action.key,
|
||||||
|
data: sprite_action.data,
|
||||||
|
group: sprite_action.isAnimated ? 'sprite_animations' : 'sprites',
|
||||||
|
updatedAt: sprite_action.updatedAt,
|
||||||
|
frameCount: sprite_action.frameCount,
|
||||||
|
frameWidth: sprite_action.frameWidth,
|
||||||
|
frameHeight: sprite_action.frameHeight
|
||||||
|
} as AssetDataT)
|
||||||
|
|
||||||
|
if (sprite_action.isAnimated) {
|
||||||
|
scene.anims.create({
|
||||||
|
key: sprite_action.key,
|
||||||
|
frameRate: 7,
|
||||||
|
frames: scene.anims.generateFrameNumbers(sprite_action.key, { start: 0, end: sprite_action.frameCount! - 1 }),
|
||||||
|
repeat: -1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -4,8 +4,7 @@ import TilemapLayer = Phaser.Tilemaps.TilemapLayer
|
|||||||
import Tileset = Phaser.Tilemaps.Tileset
|
import Tileset = Phaser.Tilemaps.Tileset
|
||||||
import Tile = Phaser.Tilemaps.Tile
|
import Tile = Phaser.Tilemaps.Tile
|
||||||
import type { AssetDataT, Zone as ZoneT } from '@/types'
|
import type { AssetDataT, Zone as ZoneT } from '@/types'
|
||||||
import { AssetStorage } from '@/storage/assetStorage'
|
import { loadTexture } from '@/composables/gameComposable'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
|
||||||
|
|
||||||
export function getTile(layer: TilemapLayer | Tilemap, x: number, y: number): Tile | undefined {
|
export function getTile(layer: TilemapLayer | Tilemap, x: number, y: number): Tile | undefined {
|
||||||
const tile = layer.getTileAtWorldXY(x, y)
|
const tile = layer.getTileAtWorldXY(x, y)
|
||||||
@ -95,36 +94,3 @@ export async function loadZoneTilesIntoScene(zone: ZoneT, scene: Phaser.Scene) {
|
|||||||
await loadTexture(scene, tile)
|
await loadTexture(scene, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadTexture(scene: Phaser.Scene, assetData: AssetDataT): Promise<boolean> {
|
|
||||||
const gameStore = useGameStore()
|
|
||||||
const assetStorage = new AssetStorage()
|
|
||||||
|
|
||||||
// Check if the texture is already loaded in Phaser
|
|
||||||
if (scene.textures.exists(assetData.key)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the asset is already cached
|
|
||||||
let asset = await assetStorage.get(assetData.key)
|
|
||||||
|
|
||||||
// If asset is not found, download it
|
|
||||||
if (!asset) {
|
|
||||||
await assetStorage.download(assetData)
|
|
||||||
asset = await assetStorage.get(assetData.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If asset is found, add it to the scene
|
|
||||||
if (asset) {
|
|
||||||
return new Promise<boolean>((resolve) => {
|
|
||||||
console.log(asset.data)
|
|
||||||
scene.textures.addBase64(asset.key, asset.data)
|
|
||||||
scene.textures.once(`addtexture-${asset.key}`, () => {
|
|
||||||
gameStore.game.loadedAssets.push(asset)
|
|
||||||
resolve(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -76,45 +76,7 @@ function preloadScene(scene: Phaser.Scene) {
|
|||||||
*/
|
*/
|
||||||
scene.load.image('blank_tile', '/assets/zone/blank_tile.png')
|
scene.load.image('blank_tile', '/assets/zone/blank_tile.png')
|
||||||
scene.load.image('waypoint', '/assets/waypoint.png')
|
scene.load.image('waypoint', '/assets/waypoint.png')
|
||||||
|
|
||||||
/**
|
|
||||||
* We're using rex-await-loader to load assets asynchronously
|
|
||||||
* Phaser does not support this out of the box, so we're using this plugin
|
|
||||||
*/
|
|
||||||
// scene.load.rexAwait(async function (successCallback) {
|
|
||||||
// await assetManager.getAssetsByGroup('tiles').then((assets) => {
|
|
||||||
// assets.forEach((asset) => {
|
|
||||||
// if (scene.load.textureManager.exists(asset.key)) return
|
|
||||||
// scene.textures.addBase64(asset.key, asset.data)
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// // Load objects
|
|
||||||
// await assetManager.getAssetsByGroup('objects').then((assets) => {
|
|
||||||
// assets.forEach((asset) => {
|
|
||||||
// if (scene.load.textureManager.exists(asset.key)) return
|
|
||||||
// scene.textures.addBase64(asset.key, asset.data)
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// successCallback()
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createScene(scene: Phaser.Scene) {
|
function createScene(scene: Phaser.Scene) {}
|
||||||
/**
|
|
||||||
* Create sprite animations
|
|
||||||
* This is done here because phaser forces us to
|
|
||||||
*/
|
|
||||||
// assetManager.getAssetsByGroup('sprite_animations').then((assets) => {
|
|
||||||
// assets.forEach((asset) => {
|
|
||||||
// scene.anims.create({
|
|
||||||
// key: asset.key,
|
|
||||||
// frameRate: 7,
|
|
||||||
// frames: scene.anims.generateFrameNumbers(asset.key, { start: 0, end: asset.frameCount! - 1 }),
|
|
||||||
// repeat: -1
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -16,7 +16,7 @@ import { useGameStore } from '@/stores/gameStore'
|
|||||||
import { useZoneEditorStore } from '@/stores/zoneEditorStore'
|
import { useZoneEditorStore } from '@/stores/zoneEditorStore'
|
||||||
import ZoneEditor from '@/components/gameMaster/zoneEditor/ZoneEditor.vue'
|
import ZoneEditor from '@/components/gameMaster/zoneEditor/ZoneEditor.vue'
|
||||||
import AwaitLoaderPlugin from 'phaser3-rex-plugins/plugins/awaitloader-plugin'
|
import AwaitLoaderPlugin from 'phaser3-rex-plugins/plugins/awaitloader-plugin'
|
||||||
import { loadTexture } from '@/composables/zoneComposable'
|
import { loadTexture } from '@/composables/gameComposable'
|
||||||
import type { AssetDataT } from '@/types'
|
import type { AssetDataT } from '@/types'
|
||||||
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
|
@ -9,6 +9,7 @@ export type AssetDataT = {
|
|||||||
data: string
|
data: string
|
||||||
group: 'tiles' | 'objects' | 'sprites' | 'sprite_animations' | 'sound' | 'music' | 'ui' | 'font' | 'other'
|
group: 'tiles' | 'objects' | 'sprites' | 'sprite_animations' | 'sound' | 'music' | 'ui' | 'font' | 'other'
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
|
isAnimated?: boolean
|
||||||
frameCount?: number
|
frameCount?: number
|
||||||
frameWidth?: number
|
frameWidth?: number
|
||||||
frameHeight?: number
|
frameHeight?: number
|
||||||
|
Loading…
x
Reference in New Issue
Block a user