Files
test1/game/ui/MapTransitionModal.ts

184 lines
5.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { MapConfig } from '../data/mapConfigs'
import { ALL_MAPS } from '../data/mapConfigs'
import { GameManager } from '../GameManager'
/**
* 地图切换过渡弹窗DOM 层,覆盖 canvas
* 显示当前地图通关信息3秒后自动关闭并触发下一张地图加载
*/
export class MapTransitionModal {
private container: HTMLElement | null = null
private autoCloseTimer: ReturnType<typeof setTimeout> | null = null
/**
* 显示地图过关弹窗
* @param clearedMap 刚通关的地图配置
* @param onNext 3秒后自动触发的回调加载下一张地图
*/
show(clearedMap: MapConfig, onNext: () => void): void {
this.cleanup()
const manager = GameManager.getInstance()
const nextMapIndex = manager.currentMapIndex + 1
const nextMap = ALL_MAPS[nextMapIndex]
const isFinalMap = !nextMap
this.createDOM(clearedMap, nextMap ?? null, isFinalMap, onNext)
}
private createDOM(
clearedMap: MapConfig,
nextMap: MapConfig | null,
isFinalMap: boolean,
onNext: () => void
): void {
const manager = GameManager.getInstance()
const kpi = manager.kpi
const overlay = document.createElement('div')
overlay.id = 'map-transition-overlay'
overlay.style.cssText = `
position: fixed;
inset: 0;
background: rgba(0,0,0,0.85);
z-index: 9998;
display: flex;
align-items: center;
justify-content: center;
font-family: 'VT323', monospace;
animation: mtFadeIn 0.4s ease;
`
const card = document.createElement('div')
card.style.cssText = `
background: #0f1b2d;
border: 2px solid #7c3aed;
border-radius: 16px;
padding: 36px 48px;
max-width: 520px;
width: 90%;
box-shadow: 0 0 60px rgba(124,58,237,0.6);
text-align: center;
animation: mtSlideIn 0.4s ease;
`
// 过关标题
const titleEl = document.createElement('div')
titleEl.textContent = isFinalMap ? '全部通关!最终胜利!' : `过关!`
titleEl.style.cssText = `
font-size: 36px;
color: #fbbf24;
margin-bottom: 8px;
letter-spacing: 3px;
`
card.appendChild(titleEl)
// 地图名称
const mapNameEl = document.createElement('div')
mapNameEl.textContent = `${clearedMap.name}」已清场`
mapNameEl.style.cssText = `
font-size: 22px;
color: #a78bfa;
margin-bottom: 20px;
`
card.appendChild(mapNameEl)
// 分割线
const hr = document.createElement('div')
hr.style.cssText = `
height: 1px;
background: linear-gradient(90deg, transparent, #7c3aed, transparent);
margin-bottom: 16px;
`
card.appendChild(hr)
// KPI & 说明
const statsEl = document.createElement('div')
statsEl.innerHTML = `最终KPI: <span style="color:#34d399">${kpi}%</span> &nbsp;|&nbsp; <span style="color:#94a3b8">HC 将重置为 170</span>`
statsEl.style.cssText = `
font-size: 20px;
color: #e2e8f0;
margin-bottom: 24px;
`
card.appendChild(statsEl)
// 下一关提示 / 最终胜利提示
const nextEl = document.createElement('div')
if (isFinalMap) {
nextEl.textContent = '恭喜完成全部关卡!你是真正的打工人传奇!'
nextEl.style.cssText = `
font-size: 18px;
color: #fbbf24;
background: rgba(251,191,36,0.1);
border: 1px solid #fbbf24;
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 20px;
`
} else {
nextEl.innerHTML = `<span style="color:#9ca3af">下一关:</span> <span style="color:#60a5fa">${nextMap!.name}</span>`
nextEl.style.cssText = `
font-size: 20px;
color: #e2e8f0;
background: rgba(96,165,250,0.1);
border: 1px solid #3b82f6;
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 20px;
`
}
card.appendChild(nextEl)
// 倒计时提示HC 重置提醒)
const countdownEl = document.createElement('div')
countdownEl.id = 'mt-countdown'
countdownEl.textContent = isFinalMap ? '3秒后返回主菜单...' : '3秒后进入下一关HC重置为170...'
countdownEl.style.cssText = `
font-size: 16px;
color: #6b7280;
`
card.appendChild(countdownEl)
// 注入动画
const style = document.createElement('style')
style.textContent = `
@keyframes mtFadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes mtSlideIn { from { transform: scale(0.85); opacity: 0 } to { transform: scale(1); opacity: 1 } }
`
document.head.appendChild(style)
overlay.appendChild(card)
document.body.appendChild(overlay)
this.container = overlay
// 3秒自动触发
let remaining = 3
const tick = () => {
remaining--
const el = document.getElementById('mt-countdown')
if (el) el.textContent = isFinalMap
? `${remaining}秒后返回主菜单...`
: `${remaining}秒后进入下一关HC重置为170...`
}
const interval = setInterval(tick, 1000)
this.autoCloseTimer = setTimeout(() => {
clearInterval(interval)
this.cleanup()
onNext()
}, 3000)
}
cleanup(): void {
if (this.autoCloseTimer !== null) {
clearTimeout(this.autoCloseTimer)
this.autoCloseTimer = null
}
const el = document.getElementById('map-transition-overlay')
if (el) el.remove()
this.container = null
}
destroy(): void {
this.cleanup()
}
}