From ffc7efb17c44b1b7c6b5e3deb2fb757686f0fce1 Mon Sep 17 00:00:00 2001
From: Dennis Postma <dennis@directonline.io>
Date: Wed, 19 Feb 2025 11:21:46 +0100
Subject: [PATCH] Improve hair positioning

---
 src/components/game/character/Character.vue   |  4 +--
 .../game/character/partials/CharacterHair.vue | 34 ++++++++++++-------
 .../useCharacterSpriteComposable.ts           |  1 +
 3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/src/components/game/character/Character.vue b/src/components/game/character/Character.vue
index 126ad53..62bd819 100644
--- a/src/components/game/character/Character.vue
+++ b/src/components/game/character/Character.vue
@@ -3,7 +3,7 @@
     <ChatBubble :mapCharacter="props.mapCharacter" />
     <HealthBar :mapCharacter="props.mapCharacter" />
     <CharacterHair :mapCharacter="props.mapCharacter" />
-    <Sprite ref="characterSprite" :origin-y="1" :flipX="isFlippedX" />
+    <Sprite ref="characterSprite" :flipX="isFlippedX" />
   </Container>
 </template>
 
@@ -17,7 +17,7 @@ import { useSoundComposable } from '@/composables/useSoundComposable'
 import { useGameStore } from '@/stores/gameStore'
 import { useMapStore } from '@/stores/mapStore'
 import { Container, Sprite, useScene } from 'phavuer'
-import { onMounted, onUnmounted, ref, watch } from 'vue'
+import { onMounted, onUnmounted, watch } from 'vue'
 
 const props = defineProps<{
   tileMap: Phaser.Tilemaps.Tilemap
diff --git a/src/components/game/character/partials/CharacterHair.vue b/src/components/game/character/partials/CharacterHair.vue
index 2e4de3f..12f6dfd 100644
--- a/src/components/game/character/partials/CharacterHair.vue
+++ b/src/components/game/character/partials/CharacterHair.vue
@@ -5,7 +5,7 @@
 <script lang="ts" setup>
 import type { MapCharacter, Sprite as SpriteT } from '@/application/types'
 import { loadSpriteTextures } from '@/services/textureService'
-import { CharacterHairStorage, SpriteStorage } from '@/storage/storages'
+import { CharacterHairStorage, CharacterTypeStorage, SpriteStorage } from '@/storage/storages'
 import { useGameStore } from '@/stores/gameStore'
 import { Image, useScene } from 'phavuer'
 import { computed, onMounted, ref } from 'vue'
@@ -17,7 +17,8 @@ const props = defineProps<{
 const gameStore = useGameStore()
 const scene = useScene()
 const hairSpriteId = ref('')
-const sprite = ref<SpriteT | null>(null)
+const hairSprite = ref<SpriteT | null>(null)
+const characterSpriteHeight = ref(0)
 
 const texture = computed(() => {
   const { rotation } = props.mapCharacter.character
@@ -30,28 +31,37 @@ const isFlippedX = computed(() => [6, 4].includes(props.mapCharacter.character.r
 
 const imageProps = computed(() => {
   const direction = [0, 6].includes(props.mapCharacter.character.rotation ?? 0) ? 'back' : 'front'
-  const spriteAction = sprite.value?.spriteActions?.find((spriteAction) => spriteAction.action === direction)
+  const spriteAction = hairSprite.value?.spriteActions?.find((spriteAction) => spriteAction.action === direction)
+
+  const hairHeight = (spriteAction?.frameHeight ?? 0) + (spriteAction?.originY ?? 0)
+  const originY = characterSpriteHeight.value / hairHeight
 
   return {
     depth: 9999,
-    originX: Number(spriteAction?.originX) ?? 0,
-    originY: Number(spriteAction?.originY) ?? 0,
+    originX: 0.5, // This is always center
+    originY: originY, // @TODO #376: See if we can fully calculate this
     flipX: isFlippedX.value,
     texture: texture.value
   }
 })
 
 onMounted(async () => {
-  if (!props.mapCharacter.character.characterHair) return
+  if (!props.mapCharacter.character.characterType || !props.mapCharacter.character.characterHair) return
 
+  const characterTypeStorage = new CharacterTypeStorage()
   const characterHairStorage = new CharacterHairStorage()
-  const _hairSpriteId = await characterHairStorage.getSpriteId(props.mapCharacter.character.characterHair)
-  if (!_hairSpriteId) return
-
-  hairSpriteId.value = _hairSpriteId
   const spriteStorage = new SpriteStorage()
-  sprite.value = await spriteStorage.getById(_hairSpriteId)
 
-  await loadSpriteTextures(scene, _hairSpriteId)
+  const characterType = await characterTypeStorage.getById(props.mapCharacter.character.characterType!)
+  if (!characterType) return
+  characterSpriteHeight.value = 100
+
+  hairSpriteId.value = await characterHairStorage.getSpriteId(props.mapCharacter.character.characterHair)
+  if (!hairSpriteId.value) return
+
+  hairSprite.value = await spriteStorage.getById(hairSpriteId.value)
+  if (!hairSprite.value) return
+
+  await loadSpriteTextures(scene, hairSpriteId.value)
 })
 </script>
diff --git a/src/composables/useCharacterSpriteComposable.ts b/src/composables/useCharacterSpriteComposable.ts
index 1d59fdb..ee88add 100644
--- a/src/composables/useCharacterSpriteComposable.ts
+++ b/src/composables/useCharacterSpriteComposable.ts
@@ -142,6 +142,7 @@ export function useCharacterSpriteComposable(scene: Phaser.Scene, tilemap: Phase
     }
 
     if (characterSprite.value) {
+      characterSprite!.value?.setOrigin(0.5, 1)
       characterSprite.value.setTexture(spriteSpriteActionId.value)
       characterSprite.value.setFlipX(isFlippedX.value)
     }