feat(game): 添加PUA激励台——AI评分打鸡血,触发攻击/攻速/HC/狂暴/翻车等游戏效果;移除静音按钮BGM默认开启
This commit is contained in:
@@ -117,34 +117,158 @@ export function createGameScene(PhaserLib: typeof Phaser): typeof Phaser.Scene {
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化音效引擎(首次点击后激活 AudioContext)
|
||||
// 初始化音效引擎(首次点击后激活 AudioContext,默认开启)
|
||||
const audio = AudioEngine.getInstance()
|
||||
this.input.once('pointerdown', () => {
|
||||
audio.init()
|
||||
audio.startBGM()
|
||||
})
|
||||
// 添加静音切换按钮(右上角)
|
||||
this.createMuteButton(audio)
|
||||
|
||||
// 注册 PUA buff 接口供 React 层调用
|
||||
if (typeof window !== 'undefined') {
|
||||
;(window as any).__gamePuaBuff = (
|
||||
effect: string, score: number, title: string
|
||||
) => {
|
||||
this.applyPuaBuff(effect, score, title)
|
||||
}
|
||||
}
|
||||
|
||||
this.setupInteraction()
|
||||
this.setupManagerCallbacks()
|
||||
if (typeof window !== 'undefined') { ;(window as any).__gameReady?.() }
|
||||
}
|
||||
|
||||
private createMuteButton(audio: AudioEngine): void {
|
||||
const btn = this.add.text(GAME_WIDTH - 10, 8, '🔊', {
|
||||
fontSize: '16px', backgroundColor: 'rgba(0,0,0,0.35)',
|
||||
padding: { x: 6, y: 3 },
|
||||
}).setOrigin(1, 0).setDepth(50).setInteractive({ useHandCursor: true })
|
||||
btn.on('pointerdown', () => {
|
||||
const nowMuted = !audio.isMuted()
|
||||
audio.setMuted(nowMuted)
|
||||
btn.setText(nowMuted ? '🔇' : '🔊')
|
||||
if (!nowMuted) audio.startBGM()
|
||||
else audio.stopBGM()
|
||||
private createMuteButton(_audio: AudioEngine): void {
|
||||
// 静音按钮已移除,音乐默认开启
|
||||
void _audio
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用 PUA buff 效果到游戏
|
||||
* effect: attack_boost | speed_boost | money_rain | rage_mode | backfire
|
||||
*/
|
||||
private applyPuaBuff(effect: string, score: number, title: string): void {
|
||||
const towers = this.towerManager.getAllTowers()
|
||||
const audio = AudioEngine.getInstance()
|
||||
|
||||
// 全屏效果提示横幅
|
||||
const colors: Record<string, string> = {
|
||||
rage_mode: '#FF4E00',
|
||||
speed_boost: '#FBBF24',
|
||||
attack_boost: '#22C55E',
|
||||
money_rain: '#A78BFA',
|
||||
backfire: '#6B7280',
|
||||
}
|
||||
const color = colors[effect] ?? '#E2E8F0'
|
||||
this.showPuaBanner(title, score, color)
|
||||
|
||||
const dur = Math.max(8000, score * 1500) // buff 持续时间(ms)
|
||||
|
||||
switch (effect) {
|
||||
case 'rage_mode': {
|
||||
// 9-10分:全场狂暴 — 攻速×2,全图红色相机震动
|
||||
audio.playBossAppear()
|
||||
this.cameras.main.flash(600, 255, 60, 0, false)
|
||||
this.cameras.main.shake(400, 0.008)
|
||||
towers.forEach(t => { t['_puaSpeedMult'] = 2.0 })
|
||||
this.manager.addHC(score * 15)
|
||||
this.time.delayedCall(dur, () => {
|
||||
towers.forEach(t => { t['_puaSpeedMult'] = 1.0 })
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'speed_boost': {
|
||||
// 7-8分:攻速 ×1.5
|
||||
audio.playWaveStart()
|
||||
towers.forEach(t => { t['_puaSpeedMult'] = 1.5 })
|
||||
this.time.delayedCall(dur, () => {
|
||||
towers.forEach(t => { t['_puaSpeedMult'] = 1.0 })
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'attack_boost': {
|
||||
// 4-6分:伤害 ×(1 + score*0.08)
|
||||
audio.playDingTalk()
|
||||
const mult = 1 + score * 0.08
|
||||
towers.forEach(t => { t['_puaDmgMult'] = mult })
|
||||
this.time.delayedCall(dur, () => {
|
||||
towers.forEach(t => { t['_puaDmgMult'] = 1.0 })
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'money_rain': {
|
||||
// 5-7分:立即获得 HC,屏幕绿色雨
|
||||
const hcBonus = score * 20
|
||||
this.manager.addHC(hcBonus)
|
||||
audio.playOpsAttack()
|
||||
this.showMoneyRain(hcBonus)
|
||||
break
|
||||
}
|
||||
case 'backfire': {
|
||||
// 1-2分:废话反效果 — 全场塔禁锢 2 秒
|
||||
audio.playEnemyDeath()
|
||||
this.cameras.main.shake(300, 0.005)
|
||||
this.freezeAllTowers(2000)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 显示 PUA buff 横幅 */
|
||||
private showPuaBanner(title: string, score: number, color: string): void {
|
||||
const stars = '★'.repeat(Math.min(score, 10))
|
||||
const banner = this.add.text(
|
||||
GAME_WIDTH / 2, HUD_HEIGHT + 80,
|
||||
`${title} ${stars}`,
|
||||
{
|
||||
fontFamily: 'VT323, monospace',
|
||||
fontSize: '28px',
|
||||
color,
|
||||
stroke: '#000000',
|
||||
strokeThickness: 4,
|
||||
shadow: { offsetX: 0, offsetY: 0, color, blur: 16, stroke: true, fill: true },
|
||||
}
|
||||
).setOrigin(0.5, 0.5).setDepth(60).setAlpha(0)
|
||||
|
||||
this.tweens.add({
|
||||
targets: banner,
|
||||
alpha: 1,
|
||||
y: HUD_HEIGHT + 60,
|
||||
duration: 300,
|
||||
yoyo: false,
|
||||
onComplete: () => {
|
||||
this.time.delayedCall(2000, () => {
|
||||
this.tweens.add({
|
||||
targets: banner, alpha: 0, y: HUD_HEIGHT + 40,
|
||||
duration: 400, onComplete: () => banner.destroy(),
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/** 金币雨效果(money_rain) */
|
||||
private showMoneyRain(amount: number): void {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const x = Math.random() * GAME_WIDTH
|
||||
const coin = this.add.text(x, HUD_HEIGHT + 20, `+${Math.floor(amount / 12)}HC`, {
|
||||
fontFamily: 'VT323, monospace',
|
||||
fontSize: '16px',
|
||||
color: '#A78BFA',
|
||||
stroke: '#000',
|
||||
strokeThickness: 2,
|
||||
}).setOrigin(0.5, 0).setDepth(55).setAlpha(0.9)
|
||||
this.tweens.add({
|
||||
targets: coin,
|
||||
y: coin.y + 120 + Math.random() * 80,
|
||||
alpha: 0,
|
||||
delay: i * 80,
|
||||
duration: 900,
|
||||
onComplete: () => coin.destroy(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private setupManagerCallbacks(): void {
|
||||
this.manager.onHCChange.push((hc: number) => {
|
||||
this.hcText.setText(`HC: ${hc}`)
|
||||
|
||||
@@ -16,11 +16,18 @@ export abstract class TowerBase {
|
||||
|
||||
public readonly cost: number
|
||||
public readonly attackRange: number
|
||||
public readonly attackDamage: number
|
||||
private readonly _attackDamage: number
|
||||
// 实际伤害 = 基础伤害 × PUA倍率
|
||||
get attackDamage(): number {
|
||||
return this._attackDamage * this._puaDmgMult
|
||||
}
|
||||
public readonly attackSpeed: number
|
||||
public readonly maxStamina: number = STAMINA_MAX
|
||||
public stamina: number = STAMINA_MAX
|
||||
public isFrozen: boolean = false
|
||||
// PUA buff 动态倍率(由 GameScene.applyPuaBuff 设置)
|
||||
public _puaSpeedMult: number = 1.0 // 攻速倍率
|
||||
public _puaDmgMult: number = 1.0 // 伤害倍率
|
||||
|
||||
protected attackCooldown: number = 0
|
||||
protected staminaRegen: number = STAMINA_REGEN
|
||||
@@ -47,7 +54,7 @@ export abstract class TowerBase {
|
||||
this.gridY = gridY
|
||||
this.cost = cost
|
||||
this.attackRange = attackRange
|
||||
this.attackDamage = attackDamage
|
||||
this._attackDamage = attackDamage
|
||||
this.attackSpeed = attackSpeed
|
||||
this.spriteKey = spriteKey
|
||||
|
||||
@@ -92,7 +99,8 @@ export abstract class TowerBase {
|
||||
if (target && this.attackCooldown <= 0) {
|
||||
this.attack(target)
|
||||
this.stamina -= 5
|
||||
this.attackCooldown = 1000 / this.attackSpeed
|
||||
// 应用 PUA 攻速倍率(倍率越高冷却越短)
|
||||
this.attackCooldown = 1000 / (this.attackSpeed * this._puaSpeedMult)
|
||||
this.updateStaminaBar()
|
||||
} else if (!target) {
|
||||
this.stamina = Math.min(this.maxStamina, this.stamina + (this.staminaRegen * delta) / 1000)
|
||||
|
||||
Reference in New Issue
Block a user