feat: 添加游戏内动画特效,优化玩家卡片UI并调整布局。
This commit is contained in:
parent
191895567c
commit
58d9edc766
@ -447,10 +447,172 @@
|
|||||||
color: $accent-cyan;
|
color: $accent-cyan;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-effect .log-content {
|
// =====================================
|
||||||
color: $brand-primary;
|
// 动画特效库
|
||||||
|
// =====================================
|
||||||
|
|
||||||
|
// 飘字上浮动画
|
||||||
|
@keyframes floatUp {
|
||||||
|
0% {
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(-50%, -60rpx);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-label {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 36rpx;
|
||||||
|
z-index: 100;
|
||||||
|
animation: floatUp 1s ease-out forwards;
|
||||||
|
text-shadow: 0 0 10rpx rgba(0, 0, 0, 0.8), 2rpx 2rpx 0 #000;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.text-heal {
|
||||||
|
color: $color-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-damage {
|
||||||
|
color: $color-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-item {
|
||||||
|
color: $color-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.global {
|
||||||
|
position: fixed;
|
||||||
|
font-size: 48rpx;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 屏幕震动
|
||||||
|
@keyframes screenShake {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
transform: translate(-8rpx, 6rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
transform: translate(8rpx, -6rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
30% {
|
||||||
|
transform: translate(-6rpx, -6rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: translate(6rpx, 6rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(-6rpx, 4rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: translate(6rpx, -4rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
transform: translate(-4rpx, 6rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
transform: translate(4rpx, -6rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
90% {
|
||||||
|
transform: translate(-2rpx, 2rpx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-shake {
|
||||||
|
animation: screenShake 0.4s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 玩家受伤红闪
|
||||||
|
@keyframes damageFlash {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: none;
|
||||||
|
background: $bg-dark-card;
|
||||||
|
}
|
||||||
|
|
||||||
|
25%,
|
||||||
|
75% {
|
||||||
|
background: rgba($color-error, 0.2);
|
||||||
|
box-shadow: 0 0 20rpx rgba($color-error, 0.4), inset 0 0 15rpx rgba($color-error, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
background: rgba($color-error, 0.4);
|
||||||
|
box-shadow: 0 0 30rpx rgba($color-error, 0.6), inset 0 0 20rpx rgba($color-error, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-damaged {
|
||||||
|
animation: damageFlash 0.6s ease-in-out, shake 0.4s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 玩家治疗绿闪
|
||||||
|
@keyframes healGlow {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20rpx rgba($color-success, 0.6), inset 0 0 10rpx rgba($color-success, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-healed {
|
||||||
|
animation: healGlow 0.6s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 倒计时紧急脉冲
|
||||||
|
@keyframes urgentPulse {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.urgent {
|
||||||
|
animation: urgentPulse 0.5s ease-in-out infinite;
|
||||||
|
color: $color-error !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.log-empty {
|
.log-empty {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -526,7 +688,7 @@
|
|||||||
// 对手栏
|
// 对手栏
|
||||||
// =====================================
|
// =====================================
|
||||||
.opponents-bar {
|
.opponents-bar {
|
||||||
height: 180rpx;
|
height: 150rpx;
|
||||||
background: rgba(0, 0, 0, 0.2);
|
background: rgba(0, 0, 0, 0.2);
|
||||||
border-bottom: 1px solid $border-dark;
|
border-bottom: 1px solid $border-dark;
|
||||||
}
|
}
|
||||||
@ -538,20 +700,79 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.player-card {
|
.player-card {
|
||||||
min-width: 260rpx;
|
// 默认样式 (通用)
|
||||||
height: 140rpx;
|
|
||||||
background: $bg-dark-card;
|
background: $bg-dark-card;
|
||||||
border: 1px solid $border-dark;
|
border: 1px solid $border-dark;
|
||||||
border-radius: $radius-lg;
|
border-radius: $radius-lg;
|
||||||
padding: $spacing-md;
|
padding: $spacing-sm;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all $transition-normal;
|
transition: all $transition-normal;
|
||||||
|
|
||||||
|
// 对手样式 (紧凑纵向)
|
||||||
|
&.opponent {
|
||||||
|
min-width: 140rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6rpx;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-right: 0;
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
margin-bottom: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-info {
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-size: 20rpx; // 更小的字体
|
||||||
|
max-width: 120rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icons {
|
||||||
|
position: absolute;
|
||||||
|
top: 6rpx;
|
||||||
|
right: 6rpx;
|
||||||
|
flex-direction: column; // 图标纵向排列以节省横向空间
|
||||||
|
gap: 2rpx;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 18rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 2rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "我"的样式 (保持横向,但更精致)
|
||||||
&.me {
|
&.me {
|
||||||
background: rgba($brand-primary, 0.1);
|
background: rgba($brand-primary, 0.1);
|
||||||
border-color: rgba($brand-primary, 0.3);
|
border-color: rgba($brand-primary, 0.3);
|
||||||
|
min-width: 280rpx;
|
||||||
|
height: 140rpx;
|
||||||
|
padding: $spacing-md;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
font-size: 44rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-size: $font-sm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active-turn {
|
&.active-turn {
|
||||||
@ -560,8 +781,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.damaged {
|
&.damaged {
|
||||||
animation: shake 0.5s ease-in-out;
|
animation: damageFlash 0.6s ease-in-out, shake 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.healed {
|
||||||
|
animation: healGlow 0.6s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes shake {
|
@keyframes shake {
|
||||||
@ -627,6 +851,7 @@
|
|||||||
font-size: 16rpx;
|
font-size: 16rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================
|
// =====================================
|
||||||
// 棋盘区域
|
// 棋盘区域
|
||||||
@ -637,7 +862,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: $spacing-lg;
|
padding: $spacing-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
.turn-indicator {
|
.turn-indicator {
|
||||||
@ -744,6 +969,180 @@
|
|||||||
&.has-magnifier {
|
&.has-magnifier {
|
||||||
border: 2rpx dashed rgba($accent-cyan, 0.5);
|
border: 2rpx dashed rgba($accent-cyan, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 新增特效样式 ---
|
||||||
|
&.explosion {
|
||||||
|
animation: explode 0.5s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 道具特效 - 移植自 Explosion.css
|
||||||
|
&.item-medkit {
|
||||||
|
animation: itemReveal 0.5s ease-out, pulseGlowGreen 2s infinite;
|
||||||
|
background-color: rgba(16, 185, 129, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-revive {
|
||||||
|
animation: itemReveal 0.5s ease-out, pulseGlowGreen 1.5s infinite;
|
||||||
|
background-color: rgba(16, 185, 129, 0.3) !important;
|
||||||
|
border: 1px solid #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-knife {
|
||||||
|
animation: itemReveal 0.5s ease-out, glint 1s infinite;
|
||||||
|
background-color: rgba(239, 68, 68, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-lightning {
|
||||||
|
animation: itemReveal 0.4s ease-out, glint 0.5s infinite;
|
||||||
|
background-color: rgba(239, 68, 68, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-poison {
|
||||||
|
animation: itemReveal 0.6s ease-out, pulseGlowPurple 3s infinite;
|
||||||
|
background-color: rgba(139, 92, 246, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-shield {
|
||||||
|
animation: itemReveal 0.5s ease-out, pulseGlowBlue 2s infinite;
|
||||||
|
background-color: rgba(59, 130, 246, 0.2) !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-skip {
|
||||||
|
animation: itemReveal 0.5s ease-out, pulseGlowGold 2s infinite;
|
||||||
|
background-color: rgba(245, 158, 11, 0.2) !important;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-magnifier {
|
||||||
|
animation: itemReveal 0.5s ease-out, float 2s ease-in-out infinite;
|
||||||
|
background-color: rgba(59, 130, 246, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-bomb_timer {
|
||||||
|
animation: itemReveal 0.5s ease-out, pulseGlowRed 0.5s infinite, shake 0.2s infinite;
|
||||||
|
background-color: rgba(239, 68, 68, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-curse {
|
||||||
|
animation: itemReveal 0.7s ease-out, pulseGlowPurple 1s infinite;
|
||||||
|
background-color: rgba(139, 92, 246, 0.3) !important;
|
||||||
|
filter: grayscale(0.5) contrast(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.item-chest {
|
||||||
|
animation: itemReveal 0.5s ease-out, pulseGlowGold 3s infinite;
|
||||||
|
background-color: rgba(245, 158, 11, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 补充缺失的动画 Keyframes
|
||||||
|
@keyframes explode {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.5);
|
||||||
|
opacity: 0.8;
|
||||||
|
box-shadow: 0 0 20rpx #ef4444, 0 0 40rpx #fb923c;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
box-shadow: 0 0 10rpx rgba(239, 68, 68, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes itemReveal {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.5) rotate(-20deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: scale(1.2) rotate(10deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1) rotate(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulseGlowGreen {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 5rpx #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20rpx #10b981, 0 0 30rpx #34d399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulseGlowBlue {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 5rpx #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20rpx #3b82f6, 0 0 30rpx #60a5fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulseGlowPurple {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 5rpx #8b5cf6;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20rpx #8b5cf6, 0 0 30rpx #a78bfa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulseGlowRed {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 5rpx #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20rpx #ef4444, 0 0 30rpx #f87171;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulseGlowGold {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 5rpx #f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 20rpx #f59e0b, 0 0 30rpx #fbbf24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes glint {
|
||||||
|
0% {
|
||||||
|
filter: brightness(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
filter: brightness(1.8) contrast(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
filter: brightness(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-icon {
|
.cell-icon {
|
||||||
@ -778,13 +1177,13 @@
|
|||||||
// 底部面板
|
// 底部面板
|
||||||
// =====================================
|
// =====================================
|
||||||
.bottom-panel {
|
.bottom-panel {
|
||||||
padding: $spacing-md;
|
padding: $spacing-sm;
|
||||||
padding-bottom: calc($spacing-md + env(safe-area-inset-bottom));
|
padding-bottom: calc($spacing-sm + env(safe-area-inset-bottom));
|
||||||
background: rgba(0, 0, 0, 0.4);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: $spacing-md;
|
gap: $spacing-md;
|
||||||
border-top: 1px solid $border-dark;
|
border-top: 1px solid $border-dark;
|
||||||
height: 240rpx; // 增加底部面板高度以容纳更大的卡片
|
height: 180rpx; // 减小高度
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-logs {
|
.game-logs {
|
||||||
@ -1038,3 +1437,4 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@ -156,12 +156,13 @@
|
|||||||
v-for="(cell, i) in gameState.grid"
|
v-for="(cell, i) in gameState.grid"
|
||||||
:key="i"
|
:key="i"
|
||||||
class="grid-cell"
|
class="grid-cell"
|
||||||
:class="{
|
:class="[
|
||||||
|
cell.revealed ? (cell.type === 'bomb' ? 'type-bomb explosion' : (cell.type === 'item' ? 'type-item item-' + (cell.itemId || 'generic') : 'type-empty')) : 'bg-slate-800',
|
||||||
|
{
|
||||||
'revealed': cell.revealed,
|
'revealed': cell.revealed,
|
||||||
'type-bomb': cell.revealed && cell.type === 'bomb',
|
|
||||||
'bg-slate-800': !cell.revealed,
|
|
||||||
'has-magnifier': myPlayer && myPlayer.revealedCells && myPlayer.revealedCells[i]
|
'has-magnifier': myPlayer && myPlayer.revealedCells && myPlayer.revealedCells[i]
|
||||||
}"
|
}
|
||||||
|
]"
|
||||||
@tap="handleCellClick(i)"
|
@tap="handleCellClick(i)"
|
||||||
>
|
>
|
||||||
<view v-if="cell.revealed">
|
<view v-if="cell.revealed">
|
||||||
@ -555,6 +556,11 @@ export default {
|
|||||||
console.log('[我的位置]', data.turnOrder?.indexOf(this.myUserId));
|
console.log('[我的位置]', data.turnOrder?.indexOf(this.myUserId));
|
||||||
console.log('[网格大小]', data.gridSize);
|
console.log('[网格大小]', data.gridSize);
|
||||||
console.log('[游戏状态]', data);
|
console.log('[游戏状态]', data);
|
||||||
|
console.log('[DEBUG] myUserId:', this.myUserId);
|
||||||
|
console.log('[DEBUG] turnOrder:', data.turnOrder);
|
||||||
|
console.log('[DEBUG] currentTurnIndex:', data.currentTurnIndex);
|
||||||
|
console.log('[DEBUG] 当前回合玩家:', data.turnOrder?.[data.currentTurnIndex]);
|
||||||
|
console.log('[DEBUG] isMyTurn?', data.turnOrder?.[data.currentTurnIndex] === this.myUserId);
|
||||||
console.log('================================');
|
console.log('================================');
|
||||||
} else if (opCode === 6) {
|
} else if (opCode === 6) {
|
||||||
// ========== 控制台日志 - 游戏结束 ==========
|
// ========== 控制台日志 - 游戏结束 ==========
|
||||||
@ -565,13 +571,42 @@ export default {
|
|||||||
console.log('================================');
|
console.log('================================');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opCode === 1 || opCode === 2) {
|
if (opCode === 1) {
|
||||||
|
this.gameState = data;
|
||||||
|
this.addLog('system', '战局开始,准备翻格!');
|
||||||
|
} else if (opCode === 2) {
|
||||||
|
// 状态更新 - 检测 HP 变化触发特效
|
||||||
|
const prevState = this.gameState;
|
||||||
|
if (prevState && prevState.players) {
|
||||||
|
Object.keys(data.players || {}).forEach(uid => {
|
||||||
|
const prevP = prevState.players[uid];
|
||||||
|
const newP = data.players[uid];
|
||||||
|
if (!prevP || !newP) return;
|
||||||
|
|
||||||
|
const hpDiff = newP.hp - prevP.hp;
|
||||||
|
if (hpDiff < 0) {
|
||||||
|
// 受伤
|
||||||
|
const dmg = Math.abs(hpDiff);
|
||||||
|
this.spawnLabel(0, 0, `-${dmg}`, 'damage', undefined, uid);
|
||||||
|
this.triggerDamageEffect(uid, dmg);
|
||||||
|
} else if (hpDiff > 0) {
|
||||||
|
// 治疗
|
||||||
|
const heal = Math.abs(hpDiff);
|
||||||
|
this.spawnLabel(0, 0, `+${heal}`, 'heal', undefined, uid);
|
||||||
|
this.healedPlayers.push(uid);
|
||||||
|
setTimeout(() => this.healedPlayers = this.healedPlayers.filter(id => id !== uid), 600);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
this.gameState = data;
|
this.gameState = data;
|
||||||
if (opCode === 1) this.addLog('system', '战局开始,准备翻格!');
|
|
||||||
} else if (opCode === 5) {
|
} else if (opCode === 5) {
|
||||||
this.handleEvent(data);
|
this.handleEvent(data);
|
||||||
} else if (opCode === 6) {
|
} else if (opCode === 6) {
|
||||||
|
if (data.gameState) {
|
||||||
|
this.gameState = data.gameState;
|
||||||
|
} else {
|
||||||
this.gameState = data;
|
this.gameState = data;
|
||||||
|
}
|
||||||
this.addLog('system', `战局结束:${data.winnerId === this.myUserId ? '您获得了胜利!' : '很遗憾失败了'}`);
|
this.addLog('system', `战局结束:${data.winnerId === this.myUserId ? '您获得了胜利!' : '很遗憾失败了'}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -593,6 +628,7 @@ export default {
|
|||||||
if (event.type === 'damage' || event.type === 'item') {
|
if (event.type === 'damage' || event.type === 'item') {
|
||||||
if (iAmTarget && event.value) this.spawnLabel(0, 0, `-${event.value}`, 'damage', undefined, this.myUserId);
|
if (iAmTarget && event.value) this.spawnLabel(0, 0, `-${event.value}`, 'damage', undefined, this.myUserId);
|
||||||
}
|
}
|
||||||
|
// 对于 opCode 5 的 damage 事件,也触发特效(通常 opCode 2 会覆盖,但多触发一次无妨,作为保险)
|
||||||
if (event.type === 'damage' && iAmTarget) this.triggerDamageEffect(this.myUserId, event.value);
|
if (event.type === 'damage' && iAmTarget) this.triggerDamageEffect(this.myUserId, event.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -661,22 +697,32 @@ export default {
|
|||||||
return this.getItemIcon(content);
|
return this.getItemIcon(content);
|
||||||
},
|
},
|
||||||
getPlayerAvatar(player) {
|
getPlayerAvatar(player) {
|
||||||
// 如果服务器已经发送了avatar字段,直接使用
|
// 优先从 character 字段获取 emoji
|
||||||
if (player.avatar) {
|
const charAvatars = {
|
||||||
return player.avatar;
|
dog: '🐶',
|
||||||
|
elephant: '🐘',
|
||||||
|
tiger: '🐯',
|
||||||
|
monkey: '🐵',
|
||||||
|
sloth: '🦥',
|
||||||
|
hippo: '🦛',
|
||||||
|
cat: '🐱',
|
||||||
|
chicken: '🐔'
|
||||||
|
};
|
||||||
|
if (player.character && charAvatars[player.character]) {
|
||||||
|
return charAvatars[player.character];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 否则,根据userId或username确定性分配一个动物头像
|
// 如果服务器直接发送了 avatar 字段
|
||||||
const avatars = ['🐶', '🐘', '🐯', '🐵', '🦥', '🦛'];
|
if (player.avatar) return player.avatar;
|
||||||
|
|
||||||
// 使用userId或username作为哈希种子,确保同一玩家总是获得相同的头像
|
// 降级:根据 userId 确定性分配
|
||||||
|
const avatars = ['🐶', '🐘', '🐯', '🐵', '🦥', '🦛'];
|
||||||
const seed = player.userId || player.username || player.id || '';
|
const seed = player.userId || player.username || player.id || '';
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
for (let i = 0; i < seed.length; i++) {
|
for (let i = 0; i < seed.length; i++) {
|
||||||
hash = ((hash << 5) - hash) + seed.charCodeAt(i);
|
hash = ((hash << 5) - hash) + seed.charCodeAt(i);
|
||||||
hash = hash & hash; // 转换为32位整数
|
hash = hash & hash; // 转换为32位整数
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = Math.abs(hash) % avatars.length;
|
const index = Math.abs(hash) % avatars.length;
|
||||||
return avatars[index];
|
return avatars[index];
|
||||||
},
|
},
|
||||||
|
|||||||
@ -340,7 +340,8 @@ class NakamaManager {
|
|||||||
}
|
}
|
||||||
this.isConnected = false;
|
this.isConnected = false;
|
||||||
this.session = null;
|
this.session = null;
|
||||||
this.gameToken = null;
|
// 注意:不要清空 gameToken,以便重连时仍然可以使用
|
||||||
|
// this.gameToken 只在 logout 或新 authenticate 时才会被更新
|
||||||
console.log('[Nakama] Disconnected');
|
console.log('[Nakama] Disconnected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user