import { type MapCharacter } from '@/application/types' import { loadSpriteTextures } from '@/composables/gameComposable' import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/mapComposable' import { CharacterTypeStorage } from '@/storage/storages' import { refObj } from 'phavuer' import { computed, ref } from 'vue' import { Direction } from '@/application/enums' export function useCharacterSprite(scene: Phaser.Scene, tilemap: Phaser.Tilemaps.Tilemap, mapCharacter: MapCharacter) { const charSprite = refObj() const charSpriteId = ref('') const currentPositionX = ref(0) const currentPositionY = ref(0) const isometricDepth = ref(1) const isInitialPosition = ref(true) const tween = ref(null) const updateIsometricDepth = (positionX: number, positionY: number) => { isometricDepth.value = calculateIsometricDepth(positionX, positionY, 28, 94, true) } const updatePosition = (positionX: number, positionY: number, direction: Direction) => { const newPositionX = tileToWorldX(tilemap, positionX, positionY) const newPositionY = tileToWorldY(tilemap, positionX, positionY) if (isInitialPosition.value) { currentPositionX.value = newPositionX currentPositionY.value = newPositionY isInitialPosition.value = false return } if (tween.value?.isPlaying()) { tween.value.stop() } const distance = Math.sqrt(Math.pow(newPositionX - currentPositionX.value, 2) + Math.pow(newPositionY - currentPositionY.value, 2)) const baseSpeed = 150 // pixels per second const duration = (distance / baseSpeed) * 1000 // Convert to milliseconds tween.value = tilemap.scene.tweens.add({ targets: charSprite.value, x: newPositionX, y: newPositionY, duration, ease: 'Linear', onStart: () => { if (direction === Direction.POSITIVE) { updateIsometricDepth(positionX, positionY) } }, onUpdate: () => { currentPositionX.value = charSprite.value?.x ?? currentPositionX.value currentPositionY.value = charSprite.value?.y ?? currentPositionY.value }, onComplete: () => { if (direction === Direction.NEGATIVE) { updateIsometricDepth(positionX, positionY) } } }) } const calcDirection = (oldPositionX: number, oldPositionY: number, newPositionX: number, newPositionY: number): Direction => { if (newPositionY < oldPositionY || newPositionX < oldPositionX) return Direction.NEGATIVE if (newPositionX > oldPositionX || newPositionY > oldPositionY) return Direction.POSITIVE return Direction.UNCHANGED } const isFlippedX = computed(() => [6, 4].includes(mapCharacter.character.rotation ?? 0)) const currentDirection = computed(() => { return [0, 6].includes(mapCharacter.character.rotation ?? 0) ? 'left_up' : 'right_down' }) const currentAction = computed(() => { return mapCharacter.isMoving ? 'walk' : 'idle' }) const charTexture = computed(() => { const spriteId = charSpriteId.value ?? 'idle_right_down' return `${spriteId}-${currentAction.value}_${currentDirection.value}` }) const updateSprite = () => { if (!charSprite.value) return if (mapCharacter.isMoving) { charSprite.value.anims.play(charTexture.value, true) } else { charSprite.value.anims.stop() charSprite.value.setFrame(0) charSprite.value.setTexture(charTexture.value) } } const initializeSprite = async () => { const characterTypeStorage = new CharacterTypeStorage() const spriteId = await characterTypeStorage.getSpriteId(mapCharacter.character.characterType!) if (!spriteId) return charSpriteId.value = spriteId await loadSpriteTextures(scene, spriteId) if (charSprite.value) { charSprite.value.setTexture(charTexture.value) charSprite.value.setFlipX(isFlippedX.value) charSprite.value.setName(mapCharacter.character.name) } updatePosition(mapCharacter.character.positionX, mapCharacter.character.positionY, mapCharacter.character.rotation) } const cleanup = () => { tween.value?.stop() } return { charSprite, charSpriteId, currentPositionX, currentPositionY, isometricDepth, isFlippedX, updatePosition, calcDirection, updateSprite, initializeSprite, cleanup } }