Moved game components into a new folder, working proof of concept hair customisation
This commit is contained in:
parent
ee3e1b55cb
commit
ab97e27f27
@ -67,7 +67,7 @@ input {
|
||||
}
|
||||
&[type='number']::-webkit-inner-spin-button,
|
||||
&[type='number']::-webkit-outer-spin-button,
|
||||
&[type='radio']{
|
||||
&[type='radio'] {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
</Container>
|
||||
<!-- Character sprite -->
|
||||
<Container ref="charContainer" :depth="isometricDepth" :x="currentX" :y="currentY">
|
||||
<!-- HAIR-->
|
||||
<Image :origin-y="4.2" :depth="1" :texture="props.zoneCharacter.character.hair?.spriteId + '-front'" />
|
||||
<Sprite ref="charSprite" :origin-y="1" :flipX="isFlippedX" :flipY="false" />
|
||||
</Container>
|
||||
</template>
|
||||
@ -22,7 +24,7 @@ import { type Sprite as SpriteT, type ZoneCharacter } from '@/types'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { useZoneStore } from '@/stores/zoneStore'
|
||||
import { watch, computed, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { Container, refObj, RoundRectangle, Sprite, Text, useGame, useScene } from 'phavuer'
|
||||
import { Container, Image, refObj, RoundRectangle, Sprite, Text, useGame, useScene } from 'phavuer'
|
||||
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
|
||||
import { loadSpriteTextures } from '@/composables/gameComposable'
|
||||
|
||||
@ -31,7 +33,6 @@ enum Direction {
|
||||
NEGATIVE,
|
||||
UNCHANGED
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
layer: Phaser.Tilemaps.TilemapLayer
|
||||
zoneCharacter: ZoneCharacter
|
||||
@ -181,6 +182,14 @@ watch(
|
||||
|
||||
watch(() => props.zoneCharacter, updateSprite)
|
||||
|
||||
|
||||
// Hair demo
|
||||
loadSpriteTextures(scene, props.zoneCharacter.character.hair?.sprite as SpriteT)
|
||||
.then(() => {})
|
||||
.catch((error) => {
|
||||
console.error('Error loading texture:', error)
|
||||
})
|
||||
|
||||
loadSpriteTextures(scene, props.zoneCharacter.character.characterType?.sprite as SpriteT)
|
||||
.then(() => {
|
||||
charSprite.value!.setTexture(charTexture.value)
|
@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Character from '@/components/sprites/Character.vue'
|
||||
import Character from '@/components/game/character/Character.vue'
|
||||
import { useZoneStore } from '@/stores/zoneStore'
|
||||
|
||||
const zoneStore = useZoneStore()
|
@ -11,9 +11,9 @@ import { useGameStore } from '@/stores/gameStore'
|
||||
import { useZoneStore } from '@/stores/zoneStore'
|
||||
import { loadZoneTilesIntoScene } from '@/composables/zoneComposable'
|
||||
import type { Zone as ZoneT, ZoneCharacter } from '@/types'
|
||||
import ZoneTiles from '@/components/zone/ZoneTiles.vue'
|
||||
import ZoneObjects from '@/components/zone/ZoneObjects.vue'
|
||||
import Characters from '@/components/zone/Characters.vue'
|
||||
import ZoneTiles from '@/components/game/zone/ZoneTiles.vue'
|
||||
import ZoneObjects from '@/components/game/zone/ZoneObjects.vue'
|
||||
import Characters from '@/components/game/zone/Characters.vue'
|
||||
|
||||
const scene = useScene()
|
||||
const gameStore = useGameStore()
|
@ -4,7 +4,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useZoneStore } from '@/stores/zoneStore'
|
||||
import ZoneObject from '@/components/zone/partials/ZoneObject.vue'
|
||||
import ZoneObject from '@/components/game/zone/partials/ZoneObject.vue'
|
||||
|
||||
const zoneStore = useZoneStore()
|
||||
|
@ -37,11 +37,11 @@ const chats = ref([] as Chat[])
|
||||
const chatWindow = ref<HTMLElement | null>(null)
|
||||
const chatInput = ref<HTMLElement | null>(null)
|
||||
|
||||
onClickOutside(chatInput, event => unfocusChat(event, chatInput.value as HTMLElement))
|
||||
onClickOutside(chatInput, (event) => unfocusChat(event, chatInput.value as HTMLElement))
|
||||
|
||||
function unfocusChat(event: Event, targetElement: HTMLElement) {
|
||||
if (!(event.target instanceof Node) || !targetElement.contains(event.target)) {
|
||||
targetElement.blur();
|
||||
targetElement.blur()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,12 @@
|
||||
<div class="flex w-full h-[400px] border border-solid border-gray-500 rounded-md rounded-tl-none bg-gray">
|
||||
<div class="w-1/3 h-full bg-[url('/assets/ui-texture.png')] bg-no-repeat bg-cover bg-center border-0 border-r border-solid border-gray-500 rounded-bl-md relative">
|
||||
<div class="absolute right-full -top-px flex gap-1 flex-col">
|
||||
<div v-for="character in characters" :key="character.id" class="character relative rounded-l border border-solid border-gray-500 w-9 h-[50px] bg-[url('/assets/ui-texture.png')] after:absolute after:w-full after:h-px after:bg-gray-500" :class="{ active: selected_character == character.id }">
|
||||
<div
|
||||
v-for="character in characters"
|
||||
:key="character.id"
|
||||
class="character relative rounded-l border border-solid border-gray-500 w-9 h-[50px] bg-[url('/assets/ui-texture.png')] after:absolute after:w-full after:h-px after:bg-gray-500"
|
||||
:class="{ active: selected_character == character.id }"
|
||||
>
|
||||
<img src="/assets/avatar/default/head.png" class="w-9 h-9 object-contain absolute top-1/2 -translate-y-1/2" alt="Player head" />
|
||||
<input class="h-full w-full absolute m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0" type="radio" name="character" :value="character.id" v-model="selected_character" />
|
||||
</div>
|
||||
@ -39,10 +44,10 @@
|
||||
<img src="/assets/icons/triangle-icon.svg" class="w-3 h-3.5 -scale-x-100" alt="Arrow right" />
|
||||
</button>
|
||||
</div>
|
||||
<!-- <div class="flex justify-between w-[190px]">-->
|
||||
<!-- <!– TODO: replace with color swatches –>-->
|
||||
<!-- <button v-for="n in 9" class="w-4 h-4 rounded-sm bg-white"></button>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="flex justify-between w-[190px]">-->
|
||||
<!-- <!– TODO: replace with color swatches –>-->
|
||||
<!-- <button v-for="n in 9" class="w-4 h-4 rounded-sm bg-white"></button>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- TODO: update gender on (selected) character -->
|
||||
<div class="flex justify-between w-[190px]">
|
||||
@ -66,8 +71,18 @@
|
||||
<button class="bg-gray border border-solid border-gray-500 min-w-9 max-w-9 min-h-9 max-h-9 p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-gray-300 focus-visible:bg-gray-500">
|
||||
<img src="/assets/icons/x-button-gray.svg" class="w-4 h-4 m-auto" alt="Male symbol" />
|
||||
</button>
|
||||
<!-- TODO: replace with hairstyles -->
|
||||
<button v-for="n in 30" class="bg-gray border border-solid border-gray-500 min-w-9 max-w-9 min-h-9 max-h-9 p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-gray-300 focus-visible:bg-gray-500"></button>
|
||||
<!-- TODO #255: make radio button so we can set a value, do the same with swatches -->
|
||||
<button
|
||||
v-for="hair in hairs"
|
||||
class="border border-solid border-gray-500 min-w-9 max-w-9 min-h-9 max-h-9 p-2 rounded-sm hover:border-gray-400 focus-visible:outline-none focus-visible:border-gray-300 focus-visible:bg-gray-500"
|
||||
@click="selectedHair = hair"
|
||||
:class="{
|
||||
'bg-cyan': hair.id === selectedHair?.id,
|
||||
'bg-gray-500 hover:bg-gray-500': hair.id !== selectedHair?.id
|
||||
}"
|
||||
>
|
||||
<img class="w-4 h-4 m-auto" :src="config.server_endpoint + '/assets/sprites/' + hair.spriteId + '/front.png'" alt="Male symbol" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 w-full">
|
||||
@ -103,7 +118,7 @@
|
||||
<form method="post" @submit.prevent="create" class="h-full flex flex-col justify-between">
|
||||
<div class="form-field-full">
|
||||
<label for="name" class="text-white">Nickname</label>
|
||||
<input class="input-field" v-model="name" name="name" id="name" placeholder="Enter a nickname.." />
|
||||
<input class="input-field" v-model="name" name="name" id="name" placeholder="Enter a nickname..." />
|
||||
</div>
|
||||
<div class="grid grid-flow-col justify-stretch gap-4">
|
||||
<button type="button" class="btn-empty py-1.5 px-4 inline-block" @click.prevent="isModalOpen = false">Cancel</button>
|
||||
@ -129,10 +144,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import config from '@/config'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { onBeforeUnmount, ref, watch } from 'vue'
|
||||
import Modal from '@/components/utilities/Modal.vue'
|
||||
import { type Character as CharacterT } from '@/types'
|
||||
import { type Character as CharacterT, type CharacterHair } from '@/types'
|
||||
import ConfirmationModal from '@/components/utilities/ConfirmationModal.vue'
|
||||
|
||||
const gameStore = useGameStore()
|
||||
@ -140,25 +156,39 @@ const isLoading = ref(true)
|
||||
const characters = ref([] as CharacterT[])
|
||||
const deletingCharacter = ref(null as CharacterT | null)
|
||||
|
||||
const hairs = ref([] as CharacterHair[])
|
||||
const selectedHair = ref(null as CharacterHair | null)
|
||||
|
||||
watch(selectedHair, (hair: CharacterHair | null) => {
|
||||
console.log(hair)
|
||||
})
|
||||
|
||||
// Fetch characters
|
||||
gameStore.connection?.on('character:list', (data: any) => {
|
||||
characters.value = data
|
||||
isLoading.value = false
|
||||
|
||||
// Fetch hairs
|
||||
// @TODO: This is hacky, we should have a better way to do this
|
||||
gameStore.connection?.emit('character:hair:list', {}, (data: CharacterHair[]) => {
|
||||
console.log(data)
|
||||
hairs.value = data
|
||||
})
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
// wait 0.75 sec
|
||||
setTimeout(() => {
|
||||
gameStore.connection?.emit('character:list')
|
||||
isLoading.value = false
|
||||
}, 750)
|
||||
})
|
||||
setTimeout(() => {
|
||||
gameStore.connection?.emit('character:list')
|
||||
}, 750)
|
||||
|
||||
// Select character logics
|
||||
const selected_character = ref(null)
|
||||
function select_character() {
|
||||
if (!selected_character.value) return
|
||||
deletingCharacter.value = null
|
||||
gameStore.connection?.emit('character:connect', { characterId: selected_character.value })
|
||||
gameStore.connection?.emit('character:connect', {
|
||||
characterId: selected_character.value,
|
||||
hairId: selectedHair.value?.id
|
||||
})
|
||||
gameStore.connection?.on('character:connect', (data: CharacterT) => gameStore.setCharacter(data))
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ import { useGameStore } from '@/stores/gameStore'
|
||||
import Menu from '@/components/gui/Menu.vue'
|
||||
import ExpBar from '@/components/gui/ExpBar.vue'
|
||||
import Hud from '@/components/gui/Hud.vue'
|
||||
import Zone from '@/components/zone/Zone.vue'
|
||||
import Zone from '@/components/game/zone/Zone.vue'
|
||||
import Hotkeys from '@/components/gui/Hotkeys.vue'
|
||||
import Chat from '@/components/gui/Chat.vue'
|
||||
import CharacterProfile from '@/components/gui/CharacterProfile.vue'
|
||||
|
Loading…
x
Reference in New Issue
Block a user