WIP chat bubble
This commit is contained in:
parent
4a410b375f
commit
4eea9d1f2c
@ -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')
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
*/
|
@ -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) => {
|
||||||
|
@ -198,3 +198,8 @@ export type Chat = {
|
|||||||
message: string
|
message: string
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ChatMessage = {
|
||||||
|
character: Character
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user