feat(ui): 将召唤下一波按钮移至右侧面板HC下方,改为React DOM渲染,移除Phaser Canvas内按钮

This commit is contained in:
Cloud Bot
2026-03-24 08:36:38 +00:00
parent 653c54c06f
commit 1473542f65
2 changed files with 131 additions and 57 deletions

View File

@@ -116,15 +116,12 @@ function PuaPanel({ gameReady, hc, waveStarted }: { gameReady: boolean; hc: numb
return (
<div style={{
width: '240px',
flexShrink: 0,
backgroundColor: 'rgba(10,18,40,0.97)',
borderLeft: '2px solid #1e3a5f',
display: 'flex',
flexDirection: 'column',
padding: '12px 10px',
gap: '10px',
overflow: 'hidden',
padding: '10px 10px 6px',
gap: '8px',
overflow: 'hidden auto',
flex: 1,
}}>
{/* 标题 */}
<div style={{ textAlign: 'center' }}>
@@ -397,7 +394,12 @@ export default function GamePage() {
const [hc, setHc] = useState(200)
const [selectedTower, setSelectedTower] = useState<TowerType | null>(null)
const [gameReady, setGameReady] = useState(false)
const [waveStarted, setWaveStarted] = useState(false) // 第一波开始后才允许激励
const [waveStarted, setWaveStarted] = useState(false)
// 召唤按钮状态(由 HUD 通过 window.__gameSetWaveBtn 驱动)
const [waveBtn, setWaveBtn] = useState<{ text: string; disabled: boolean }>({
text: '▶ 召唤下一波',
disabled: false,
})
const selectedTowerRef = useRef<TowerType | null>(null)
const handleSelectTower = useCallback((type: TowerType) => {
@@ -439,6 +441,11 @@ export default function GamePage() {
if (mounted) { selectedTowerRef.current = null; setSelectedTower(null) }
}
;(window as any).__gameReady = () => { if (mounted) setGameReady(true) }
// HUD 通过此回调更新召唤按钮状态
;(window as any).__gameSetWaveBtn = (s: { text: string; disabled: boolean }) => {
;(window as any).__gameWaveBtnState = s
if (mounted) setWaveBtn({ ...s })
}
// 轮询 __gameWaveStartedPhaser 设置后通知 React
const checkWaveStarted = setInterval(() => {
if ((window as any).__gameWaveStarted) {
@@ -458,7 +465,8 @@ export default function GamePage() {
if (typeof window !== 'undefined') {
;['__gameOnHCChange','__gameOnTowerDeselect','__gameSelectTower',
'__gameReady','__gameDifficulty','__gamePuaBuff',
'__gameGetHC','__gameSpendHC','__gameWaveStarted'].forEach(k => {
'__gameGetHC','__gameSpendHC','__gameWaveStarted',
'__gameSetWaveBtn','__gameWaveBtnState','__gameOnWaveClick'].forEach(k => {
delete (window as any)[k]
})
}
@@ -469,7 +477,7 @@ export default function GamePage() {
<div className="w-full h-screen flex flex-col overflow-hidden"
style={{ backgroundColor: '#0A1628' }}>
{/* 中间行:游戏画布 + PUA面板 */}
{/* 中间行:游戏画布 + 右侧控制面板 */}
<div className="flex-1 min-h-0 flex flex-row overflow-hidden">
{/* 游戏画布 */}
<div
@@ -477,8 +485,81 @@ export default function GamePage() {
className="flex-1 min-w-0 min-h-0"
style={{ backgroundColor: '#0A1628' }}
/>
{/* PUA 激励台(右侧) */}
<PuaPanel gameReady={gameReady} hc={hc} waveStarted={waveStarted} />
{/* 右侧面板HC + 召唤按钮 + PUA激励台 */}
<div style={{
width: '240px',
flexShrink: 0,
backgroundColor: 'rgba(10,18,40,0.97)',
borderLeft: '2px solid #1e3a5f',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
}}>
{/* HC 数量显示 */}
<div style={{
padding: '10px 12px 8px',
borderBottom: '1px solid #1e3a5f',
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<span style={{ fontFamily: 'VT323, monospace', fontSize: '13px', color: '#64748B' }}>
</span>
<span style={{
fontFamily: "'Press Start 2P', monospace",
fontSize: '12px',
color: '#A78BFA',
letterSpacing: '1px',
}}>
{hc} HC
</span>
</div>
</div>
{/* 召唤下一波按钮 */}
<div style={{ padding: '10px 12px', borderBottom: '2px solid #1e3a5f' }}>
<button
onClick={() => {
if (typeof window !== 'undefined') {
(window as any).__gameOnWaveClick?.()
}
}}
disabled={waveBtn.disabled || !gameReady}
style={{
width: '100%',
padding: '10px 8px',
backgroundColor: waveBtn.disabled || !gameReady ? '#0F172A' : '#1e3a5f',
border: `2px solid ${waveBtn.disabled || !gameReady ? '#1e293b' : '#7C3AED'}`,
borderRadius: '8px',
color: waveBtn.disabled || !gameReady ? '#4B5563' : '#C4B5FD',
fontFamily: 'VT323, monospace',
fontSize: '20px',
cursor: waveBtn.disabled || !gameReady ? 'not-allowed' : 'pointer',
transition: 'all 0.15s ease',
letterSpacing: '1px',
lineHeight: 1.2,
boxShadow: waveBtn.disabled || !gameReady ? 'none' : '0 0 12px rgba(124,58,237,0.3)',
}}
onMouseEnter={e => {
if (!waveBtn.disabled && gameReady) {
(e.currentTarget as HTMLButtonElement).style.backgroundColor = '#2d3a5e'
;(e.currentTarget as HTMLButtonElement).style.boxShadow = '0 0 18px rgba(124,58,237,0.5)'
}
}}
onMouseLeave={e => {
if (!waveBtn.disabled && gameReady) {
(e.currentTarget as HTMLButtonElement).style.backgroundColor = '#1e3a5f'
;(e.currentTarget as HTMLButtonElement).style.boxShadow = '0 0 12px rgba(124,58,237,0.3)'
}
}}
>
{waveBtn.text}
</button>
</div>
{/* PUA 激励台 */}
<PuaPanel gameReady={gameReady} hc={hc} waveStarted={waveStarted} />
</div>
</div>
{/* 底部塔选择面板 */}