1
0
forked from noxious/client

WIP chat bubble

This commit is contained in:
Dennis Postma 2024-09-25 01:41:03 +02:00
parent 4a410b375f
commit 4eea9d1f2c
6 changed files with 62 additions and 27 deletions

View File

@ -21,9 +21,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, nextTick } from 'vue' import { onBeforeUnmount, onMounted, ref, nextTick } from 'vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import type { Character } from '@/types' import type { Character, ChatMessage } from '@/types'
import { useZoneStore } from '@/stores/zoneStore'
import { useScene } from 'phavuer'
const scene = useScene()
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneStore = useZoneStore()
const message = ref('') const message = ref('')
const chats = ref([] as ChatMessage[]) const chats = ref([] as ChatMessage[])
@ -55,18 +59,33 @@ const scrollToBottom = () => {
}) })
} }
type ChatMessage = {
character: Character
message: string
}
onMounted(() => {
gameStore.connection?.on('chat:message', (data: ChatMessage) => { gameStore.connection?.on('chat:message', (data: ChatMessage) => {
chats.value.push(data) chats.value.push(data)
scrollToBottom() scrollToBottom()
if (zoneStore.characterLoaded) {
const charChatContainer = scene.children.getByName(data.character.name + '_chatContainer') as Phaser.GameObjects.Container
if (charChatContainer) {
const text = charChatContainer.getByName(data.character.name + '_text') as Phaser.GameObjects.Text
if (text) {
text.setText(data.message)
} else {
return
}
charChatContainer.setVisible(true)
// Hide chat bubble after a few seconds
setTimeout(() => {
const charChatContainer = scene.children.getByName(data.character.name + '_chatContainer') as Phaser.GameObjects.Container
if (charChatContainer) {
charChatContainer.setVisible(false)
}
}, 3000)
}
}
}) })
scrollToBottom() scrollToBottom()
})
onBeforeUnmount(() => { onBeforeUnmount(() => {
gameStore.connection?.off('chat:message') gameStore.connection?.off('chat:message')

View File

@ -1,9 +1,9 @@
<template> <template>
<Container ref="charChatContainer" :depth="999" v-if="props.character" :x="currentX" :y="currentY">>
<RoundRectangle @create="createChatBubble" :origin-x="0.5" :origin-y="7.5" :fillColor="0xffffff" :width="194" :height="21" :radius="5" />
<Text @create="createChatText" :text="`This is a chat message 🤯👋`" :origin-x="0.5" :origin-y="10.9" :style="{ fontSize: 13, fontFamily: 'Arial', color: '#000' }" />
</Container>
<Container :depth="999" v-if="props.character" :x="currentX" :y="currentY"> <Container :depth="999" v-if="props.character" :x="currentX" :y="currentY">
<!-- Start chat bubble -->
<!-- <RoundRectangle :origin-x="0.5" :origin-y="7.5" :fillColor="0xffffff" :width="194" :height="21" :radius="5" />-->
<!-- <Text @create="createText" :text="`This is a chat message 🤯👋`" :origin-x="0.5" :origin-y="10.9" :style="{ fontSize: 13, fontFamily: 'Arial', color: '#000' }" />-->
<!-- End chat bubble -->
<Text @create="createText" :text="props.character.name" :origin-x="0.5" :origin-y="9" /> <Text @create="createText" :text="props.character.name" :origin-x="0.5" :origin-y="9" />
<RoundRectangle :origin-x="0.5" :origin-y="18.5" :fillColor="0xffffff" :width="74" :height="6" :radius="5" /> <RoundRectangle :origin-x="0.5" :origin-y="18.5" :fillColor="0xffffff" :width="74" :height="6" :radius="5" />
<RoundRectangle :origin-x="0.5" :origin-y="36.4" :fillColor="0x00b3b3" :width="70" :height="3" :radius="5" /> <RoundRectangle :origin-x="0.5" :origin-y="36.4" :fillColor="0x00b3b3" :width="70" :height="3" :radius="5" />
@ -15,10 +15,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Container, Image, refObj, refTo, RoundRectangle, Sprite, Text, useScene } from 'phavuer' import { Container, Image, refObj, RoundRectangle, Sprite, Text, useScene } from 'phavuer'
import { type ExtendedCharacter as CharacterT } from '@/types' import { type ExtendedCharacter as CharacterT } from '@/types'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
import { watch, computed, ref, onMounted, onUnmounted } from 'vue' import { watch, computed, ref, onMounted, onUnmounted, type Ref } from 'vue'
import config from '@/config' import config from '@/config'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore' import { useZoneStore } from '@/stores/zoneStore'
@ -29,7 +29,8 @@ enum Direction {
NOCHANGE NOCHANGE
} }
const charContainer = refObj(); const charChatContainer = refObj() as Ref<Phaser.GameObjects.Container>;
const charContainer = refObj() as Ref<Phaser.GameObjects.Container>;
interface Props { interface Props {
layer: Phaser.Tilemaps.TilemapLayer layer: Phaser.Tilemaps.TilemapLayer
@ -158,20 +159,32 @@ const charTexture = computed(() => {
return `${spriteId}-${action}_left_up` return `${spriteId}-${action}_left_up`
}) })
const createChatBubble = (container: Phaser.GameObjects.Container) => {
container.setName(props.character?.name + '_chatBubble')
}
const createChatText = (text: Phaser.GameObjects.Text) => {
text.setName(props.character?.name + '_chatText')
text.setFontSize(13)
text.setFontFamily('Arial')
}
const createText = (text: Phaser.GameObjects.Text) => { const createText = (text: Phaser.GameObjects.Text) => {
text.setFontSize(13) text.setFontSize(13)
text.setFontFamily('Arial') text.setFontFamily('Arial')
} }
onMounted(() => { onMounted(() => {
/**
* @TODO: Put this at an appropriate place not in this component
*/
// Check if player is this character, then lock with camera // Check if player is this character, then lock with camera
if (props.character && props.character.id === gameStore.character?.id) { if (props.character && props.character.id === gameStore.character?.id) {
charChatContainer.value?.setName(props.character.name + '_chatContainer')
charChatContainer.value?.setVisible(false)
charContainer.value?.setName(props.character.name) charContainer.value?.setName(props.character.name)
zoneStore.characterLoaded = true; zoneStore.characterLoaded = true;
} }
if (props.character) { if (props.character) {
updatePosition(props.character.positionX, props.character.positionY, Direction.POSITIVE) updatePosition(props.character.positionX, props.character.positionY, Direction.POSITIVE)
} }

View File

@ -22,7 +22,7 @@ export function useCameraControls(scene: Phaser.Scene): any {
() => zoneStore.characterLoaded, () => zoneStore.characterLoaded,
(characterLoaded) => { (characterLoaded) => {
if(characterLoaded) { if(characterLoaded) {
scene.cameras.main.startFollow(scene.children.getByName(gameStore.character.name)); scene.cameras.main.startFollow(scene.children.getByName(gameStore.character!.name) as Phaser.GameObjects.Container);
} }
} }
) )

View File

@ -1,4 +1,4 @@
const dev: boolean = false const dev: boolean = true
export default { export default {
name: 'New Quest', name: 'New Quest',
@ -6,3 +6,7 @@ export default {
server_endpoint: dev ? 'http://localhost:4000' : 'https://nq-server.cr-a.directonline.io', server_endpoint: dev ? 'http://localhost:4000' : 'https://nq-server.cr-a.directonline.io',
tile_size: { x: 64, y: 32, z: 1 } tile_size: { x: 64, y: 32, z: 1 }
} }
/**
* @TODO: Implement .env like server has
*/

View File

@ -59,13 +59,7 @@ const gameConfig = {
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight, height: window.innerHeight,
type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS
render: { render: { resolution: 10 },
pixelArt: true,
antialias: true,
roundPixels: true
},
resolution: 10,
pixelArt: true
} }
const createGame = (game: Phaser.Game) => { const createGame = (game: Phaser.Game) => {

View File

@ -198,3 +198,8 @@ export type Chat = {
message: string message: string
createdAt: Date createdAt: Date
} }
export type ChatMessage = {
character: Character
message: string
}