add emoji to frontend
This commit is contained in:
@@ -55,8 +55,15 @@ useSharedTicker((delta) => {
|
||||
} else {
|
||||
currentY.value = destY
|
||||
}
|
||||
|
||||
// Emoji bobbing animation
|
||||
emojiTime += delta * 0.05
|
||||
emojiBob.value = Math.sin(emojiTime) * 5
|
||||
})
|
||||
|
||||
let emojiTime = 0
|
||||
const emojiBob = ref(0)
|
||||
|
||||
function getTexture() {
|
||||
const gender = (props.avatar.gender || 'male').toLowerCase()
|
||||
let pid = props.avatar.pic_id
|
||||
@@ -117,6 +124,57 @@ function handlePointerTap() {
|
||||
name: props.avatar.name
|
||||
})
|
||||
}
|
||||
|
||||
const emojiStyle = {
|
||||
fontFamily: '"Segoe UI Emoji", "Apple Color Emoji", "Noto Color Emoji", sans-serif',
|
||||
fontSize: 70,
|
||||
align: 'center',
|
||||
} as any
|
||||
|
||||
const drawEmojiBg = (g: Graphics) => {
|
||||
g.clear()
|
||||
|
||||
const w = 80
|
||||
const h = 80
|
||||
const r = 16
|
||||
const halfW = w / 2
|
||||
const halfH = h / 2
|
||||
|
||||
// 1. Draw all fills first (to cover background)
|
||||
g.beginPath()
|
||||
g.roundRect(-halfW, -halfH, w, h, r)
|
||||
g.fill({ color: 0xffffff, alpha: 1.0 })
|
||||
|
||||
// Tail fill
|
||||
g.beginPath()
|
||||
g.moveTo(-halfW + 10, halfH) // Start at bottom-left area of body
|
||||
g.lineTo(-halfW - 10, halfH + 20) // Point pointing down-left
|
||||
g.lineTo(-halfW, halfH - 10) // Back to left edge of body
|
||||
g.closePath()
|
||||
g.fill({ color: 0xffffff, alpha: 1.0 })
|
||||
|
||||
// 2. Draw Strokes (Outlines)
|
||||
// We draw the bubble body stroke
|
||||
g.roundRect(-halfW, -halfH, w, h, r)
|
||||
g.stroke({ width: 3, color: 0x000000, alpha: 1.0 })
|
||||
|
||||
// We draw the tail stroke
|
||||
g.beginPath()
|
||||
g.moveTo(-halfW + 10, halfH)
|
||||
g.lineTo(-halfW - 10, halfH + 20)
|
||||
g.lineTo(-halfW, halfH - 10)
|
||||
g.stroke({ width: 3, color: 0x000000, alpha: 1.0 })
|
||||
|
||||
// 3. Clean up the intersection with a white patch
|
||||
// We fill a small polygon over the line where tail meets body
|
||||
g.beginPath()
|
||||
g.moveTo(-halfW + 8, halfH - 2) // Inside body, near bottom
|
||||
g.lineTo(-halfW - 2, halfH - 12) // Inside body, near left
|
||||
g.lineTo(-halfW - 8, halfH + 16) // Towards tail tip (but not all the way)
|
||||
g.lineTo(-halfW + 8, halfH + 2) // Towards tail base
|
||||
g.closePath()
|
||||
g.fill({ color: 0xffffff, alpha: 1.0 })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -141,6 +199,22 @@ function handlePointerTap() {
|
||||
@render="drawFallback"
|
||||
/>
|
||||
|
||||
<!-- Emoji Bubble -->
|
||||
<container
|
||||
v-if="avatar.action_emoji"
|
||||
:x="tileSize * 0.6"
|
||||
:y="(getTexture() ? -tileSize * 3.5 : -tileSize * 1.2) + emojiBob"
|
||||
:z-index="100"
|
||||
>
|
||||
<graphics @render="drawEmojiBg" />
|
||||
<text
|
||||
:text="avatar.action_emoji"
|
||||
:style="emojiStyle"
|
||||
:anchor="0.5"
|
||||
:scale="1.0"
|
||||
/>
|
||||
</container>
|
||||
|
||||
<text
|
||||
:text="avatar.name"
|
||||
:style="nameStyle"
|
||||
|
||||
@@ -76,6 +76,11 @@ async function handleClearObjective() {
|
||||
</div>
|
||||
|
||||
<div class="content-scroll">
|
||||
<!-- Action State Banner -->
|
||||
<div v-if="!data.is_dead && data.action_state" class="action-banner">
|
||||
{{ data.action_state }}
|
||||
</div>
|
||||
|
||||
<!-- Stats Grid -->
|
||||
<div class="stats-grid">
|
||||
<StatItem label="境界" :value="data.realm" :sub-value="data.level" />
|
||||
@@ -226,6 +231,17 @@ async function handleClearObjective() {
|
||||
border: 1px solid #7a2a2a;
|
||||
}
|
||||
|
||||
.action-banner {
|
||||
background: rgba(23, 125, 220, 0.15);
|
||||
color: #aaddff;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
margin-bottom: 8px;
|
||||
border: 1px solid rgba(23, 125, 220, 0.3);
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface Item extends EffectEntity {
|
||||
|
||||
export interface AvatarSummary extends EntityBase, Coordinates {
|
||||
action?: string;
|
||||
action_emoji?: string;
|
||||
gender?: string;
|
||||
pic_id?: number;
|
||||
is_dead?: boolean;
|
||||
@@ -49,6 +50,7 @@ export interface AvatarDetail extends EntityBase {
|
||||
nickname?: string;
|
||||
appearance: string; // 外貌描述
|
||||
is_dead?: boolean;
|
||||
action_state?: string; // 当前正在进行的动作描述
|
||||
death_info?: {
|
||||
time: number;
|
||||
reason: string;
|
||||
|
||||
Reference in New Issue
Block a user