1
0
forked from noxious/client

Moved map character network event logic into characters component, added playAnimation function to characterComposable, finished attack animation

This commit is contained in:
Dennis Postma 2025-02-05 18:27:33 +01:00
parent 0c9a41c286
commit 6c7864b4d4
5 changed files with 66 additions and 29 deletions

View File

@ -28,7 +28,7 @@ const gameStore = useGameStore()
const mapStore = useMapStore() const mapStore = useMapStore()
const scene = useScene() const scene = useScene()
const { characterContainer, characterSprite, currentPositionX, currentPositionY, isometricDepth, isFlippedX, updatePosition, calcDirection, updateSprite, initializeSprite, cleanup } = useCharacterSpriteComposable(scene, props.tileMap, props.mapCharacter) const { characterContainer, characterSprite, currentPositionX, currentPositionY, isometricDepth, isFlippedX, updatePosition, playAnimation, calcDirection, updateSprite, initializeSprite, cleanup } = useCharacterSpriteComposable(scene, props.tileMap, props.mapCharacter)
const handlePositionUpdate = (newValues: any, oldValues: any) => { const handlePositionUpdate = (newValues: any, oldValues: any) => {
if (!newValues) return if (!newValues) return
@ -51,7 +51,16 @@ watch(
rotation: props.mapCharacter.character.rotation, rotation: props.mapCharacter.character.rotation,
isAttacking: props.mapCharacter.isAttacking isAttacking: props.mapCharacter.isAttacking
}), }),
handlePositionUpdate (oldValues, newValues) => {
handlePositionUpdate(oldValues, newValues)
if (props.mapCharacter.isAttacking) {
// Play attack animation
playAnimation('attack')
// Disable attack immediately after playing the animation
mapStore.updateCharacterProperty(props.mapCharacter.character.id, 'isAttacking', false)
}
}
) )
onMounted(async () => { onMounted(async () => {

View File

@ -3,12 +3,44 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { MapCharacter, UUID } from '@/application/types'
import Character from '@/components/game/character/Character.vue' import Character from '@/components/game/character/Character.vue'
import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { onUnmounted } from 'vue'
const gameStore = useGameStore()
const mapStore = useMapStore() const mapStore = useMapStore()
const props = defineProps<{ const props = defineProps<{
tileMap: Phaser.Tilemaps.Tilemap tileMap: Phaser.Tilemaps.Tilemap
}>() }>()
gameStore.connection?.on('map:character:join', async (data: MapCharacter) => {
mapStore.addCharacter(data)
})
gameStore.connection?.on('map:character:leave', (characterId: UUID) => {
mapStore.removeCharacter(characterId)
})
gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
mapStore.updateCharacterPosition(data)
// @TODO: Replace with universal class, composable or store
if (data.characterId === gameStore.character?.id) {
gameStore.character!.positionX = data.positionX
gameStore.character!.positionY = data.positionY
gameStore.character!.rotation = data.rotation
}
})
gameStore.connection?.on('map:character:attack', (characterId: UUID) => {
mapStore.updateCharacterProperty(characterId, 'isAttacking', true)
})
onUnmounted(() => {
gameStore.connection?.off('map:character:join')
gameStore.connection?.off('map:character:leave')
gameStore.connection?.off('map:character:move')
})
</script> </script>

View File

@ -5,7 +5,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { MapCharacter, mapLoadData, UUID } from '@/application/types' import type { mapLoadData } from '@/application/types'
import { unduplicateArray } from '@/application/utilities' import { unduplicateArray } from '@/application/utilities'
import Characters from '@/components/game/map/Characters.vue' import Characters from '@/components/game/map/Characters.vue'
import MapTiles from '@/components/game/map/MapTiles.vue' import MapTiles from '@/components/game/map/MapTiles.vue'
@ -33,28 +33,6 @@ gameStore.connection?.on('map:character:teleport', async (data: mapLoadData) =>
mapStore.setCharacters(data.characters) mapStore.setCharacters(data.characters)
}) })
gameStore.connection?.on('map:character:join', async (data: MapCharacter) => {
mapStore.addCharacter(data)
})
gameStore.connection?.on('map:character:leave', (characterId: UUID) => {
mapStore.removeCharacter(characterId)
})
gameStore.connection?.on('map:character:attack', (characterId: UUID) => {
mapStore.updateCharacterProperty(characterId, 'isAttacking', true)
})
gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
mapStore.updateCharacterPosition(data)
// @TODO: Replace with universal class, composable or store
if (data.characterId === gameStore.character?.id) {
gameStore.character!.positionX = data.positionX
gameStore.character!.positionY = data.positionY
gameStore.character!.rotation = data.rotation
}
})
async function initialize() { async function initialize() {
if (!mapStore.mapId) return if (!mapStore.mapId) return
@ -87,8 +65,5 @@ onUnmounted(() => {
} }
gameStore.connection?.off('map:character:teleport') gameStore.connection?.off('map:character:teleport')
gameStore.connection?.off('map:character:join')
gameStore.connection?.off('map:character:leave')
gameStore.connection?.off('map:character:move')
}) })
</script> </script>

View File

@ -59,6 +59,26 @@ export function useCharacterSpriteComposable(scene: Phaser.Scene, tilemap: Phase
}) })
} }
const playAnimation = (animation: string, loop = false) => {
if (!characterSprite.value || !characterSpriteId.value) return
const fullAnimationName = `${characterSpriteId.value}-${animation}_${currentDirection.value}`
// Remove any existing animation complete listeners
characterSprite.value.off(Phaser.Animations.Events.ANIMATION_COMPLETE)
// Add new listener
characterSprite.value.on(Phaser.Animations.Events.ANIMATION_COMPLETE, () => {
characterSprite.value!.setFrame(0)
characterSprite.value!.setTexture(charTexture.value)
})
characterSprite.value.anims.play({
key: fullAnimationName,
repeat: loop ? -1 : 0
})
}
const calcDirection = (oldPositionX: number, oldPositionY: number, newPositionX: number, newPositionY: number): Direction => { const calcDirection = (oldPositionX: number, oldPositionY: number, newPositionX: number, newPositionY: number): Direction => {
if (newPositionY < oldPositionY || newPositionX < oldPositionX) return Direction.NEGATIVE if (newPositionY < oldPositionY || newPositionX < oldPositionX) return Direction.NEGATIVE
if (newPositionX > oldPositionX || newPositionY > oldPositionY) return Direction.POSITIVE if (newPositionX > oldPositionX || newPositionY > oldPositionY) return Direction.POSITIVE
@ -125,6 +145,7 @@ export function useCharacterSpriteComposable(scene: Phaser.Scene, tilemap: Phase
isometricDepth, isometricDepth,
isFlippedX, isFlippedX,
updatePosition, updatePosition,
playAnimation,
calcDirection, calcDirection,
updateSprite, updateSprite,
initializeSprite, initializeSprite,

View File

@ -27,7 +27,7 @@ export const useMapStore = defineStore('map', {
addCharacter(character: MapCharacter) { addCharacter(character: MapCharacter) {
this.characters.push(character) this.characters.push(character)
}, },
updateCharacterProperty<K extends keyof MapCharacter>(characterId: UUID, property: K, value: MapCharacter[K]) { updateCharacterProperty<K extends keyof MapCharacter>(characterId: string, property: K, value: MapCharacter[K]) {
const character = this.characters.find((char) => char.character.id === characterId) const character = this.characters.find((char) => char.character.id === characterId)
if (character) { if (character) {
character[property] = value character[property] = value