199 lines
6.1 KiB
JavaScript
199 lines
6.1 KiB
JavaScript
import { WEAPONS, WEAPON_CONFIG } from '../utils/constants.js'
|
||
|
||
/**
|
||
* HUD界面类
|
||
* 显示游戏中的血量、武器、弹药等信息
|
||
*/
|
||
export class HUD {
|
||
constructor(container) {
|
||
this.container = container
|
||
this.container.className = 'hud-container'
|
||
this.container.innerHTML = ''
|
||
this.visible = false
|
||
this._build()
|
||
}
|
||
|
||
/**
|
||
* 构建HUD界面元素
|
||
*/
|
||
_build() {
|
||
// 血量条
|
||
this.healthBar = document.createElement('div')
|
||
this.healthBar.className = 'hud-health-bar'
|
||
this.healthBar.innerHTML = '<div class="hud-health-fill"></div><span class="hud-health-text">100</span>'
|
||
this.container.appendChild(this.healthBar)
|
||
|
||
// 武器面板
|
||
this.weaponPanel = document.createElement('div')
|
||
this.weaponPanel.className = 'hud-weapon-panel'
|
||
|
||
// 武器列表
|
||
const weaponList = [WEAPONS.PISTOL, WEAPONS.MACHINE_GUN, WEAPONS.SHOTGUN, WEAPONS.GRENADE]
|
||
this.weaponSlots = []
|
||
for (let i = 0; i < weaponList.length; i++) {
|
||
const slot = document.createElement('div')
|
||
slot.className = 'hud-weapon-slot'
|
||
slot.dataset.index = i
|
||
|
||
// 按键提示(1-4)
|
||
const keyLabel = document.createElement('span')
|
||
keyLabel.className = 'hud-weapon-key'
|
||
keyLabel.textContent = (i + 1).toString()
|
||
|
||
// 武器名称
|
||
const weaponName = document.createElement('span')
|
||
weaponName.className = 'hud-weapon-name'
|
||
weaponName.textContent = WEAPON_CONFIG[weaponList[i]].name
|
||
|
||
// 弹药数量
|
||
const ammoText = document.createElement('span')
|
||
ammoText.className = 'hud-weapon-ammo'
|
||
|
||
slot.appendChild(keyLabel)
|
||
slot.appendChild(weaponName)
|
||
slot.appendChild(ammoText)
|
||
this.weaponSlots.push({ slot, ammoText })
|
||
this.weaponPanel.appendChild(slot)
|
||
}
|
||
|
||
this.container.appendChild(this.weaponPanel)
|
||
|
||
// 手雷蓄力条(默认隐藏)
|
||
this.grenadeChargeBar = document.createElement('div')
|
||
this.grenadeChargeBar.className = 'hud-grenade-charge'
|
||
this.grenadeChargeBar.innerHTML = '<div class="hud-grenade-charge-fill"></div>'
|
||
this.grenadeChargeBar.style.display = 'none'
|
||
this.container.appendChild(this.grenadeChargeBar)
|
||
|
||
// 信息面板(波次、分数、时间)
|
||
this.infoPanel = document.createElement('div')
|
||
this.infoPanel.className = 'hud-info-panel'
|
||
|
||
this.waveText = document.createElement('span')
|
||
this.waveText.className = 'hud-info-item'
|
||
this.waveText.textContent = 'Wave: 0'
|
||
|
||
this.scoreText = document.createElement('span')
|
||
this.scoreText.className = 'hud-info-item'
|
||
this.scoreText.textContent = 'Score: 0'
|
||
|
||
this.timeText = document.createElement('span')
|
||
this.timeText.className = 'hud-info-item'
|
||
this.timeText.textContent = 'Time: 0:00'
|
||
|
||
this.infoPanel.appendChild(this.waveText)
|
||
this.infoPanel.appendChild(this.scoreText)
|
||
this.infoPanel.appendChild(this.timeText)
|
||
this.container.appendChild(this.infoPanel)
|
||
|
||
// 准星
|
||
this.crosshair = document.createElement('div')
|
||
this.crosshair.className = 'hud-crosshair'
|
||
this.container.appendChild(this.crosshair)
|
||
|
||
// 击杀信息(最近5条)
|
||
this.killFeed = document.createElement('div')
|
||
this.killFeed.className = 'hud-kill-feed'
|
||
this.container.appendChild(this.killFeed)
|
||
}
|
||
|
||
/**
|
||
* 显示HUD
|
||
*/
|
||
show() {
|
||
this.visible = true
|
||
this.container.style.display = 'flex'
|
||
}
|
||
|
||
/**
|
||
* 隐藏HUD
|
||
*/
|
||
hide() {
|
||
this.visible = false
|
||
this.container.style.display = 'none'
|
||
}
|
||
|
||
/**
|
||
* 更新血量显示
|
||
* @param {number} health 血量值 0-100
|
||
*/
|
||
updateHealth(health) {
|
||
const fill = this.healthBar.querySelector('.hud-health-fill')
|
||
const text = this.healthBar.querySelector('.hud-health-text')
|
||
const pct = Math.max(0, Math.min(100, health))
|
||
fill.style.width = pct + '%'
|
||
// 颜色根据血量变化:绿色>60,橙色>30,红色<=30
|
||
if (pct > 60) fill.style.backgroundColor = '#44ff44'
|
||
else if (pct > 30) fill.style.backgroundColor = '#ffaa00'
|
||
else fill.style.backgroundColor = '#ff4444'
|
||
text.textContent = Math.ceil(pct)
|
||
}
|
||
|
||
/**
|
||
* 更新武器显示
|
||
* @param {number} currentIndex 当前武器索引
|
||
* @param {Object} ammo 各武器弹药数
|
||
*/
|
||
updateWeapons(currentIndex, ammo) {
|
||
const weaponList = [WEAPONS.PISTOL, WEAPONS.MACHINE_GUN, WEAPONS.SHOTGUN, WEAPONS.GRENADE]
|
||
for (let i = 0; i < this.weaponSlots.length; i++) {
|
||
const slot = this.weaponSlots[i]
|
||
// 高亮当前武器
|
||
slot.slot.classList.toggle('hud-weapon-active', i === currentIndex)
|
||
const weaponKey = weaponList[i]
|
||
const currentAmmo = ammo[weaponKey]
|
||
if (currentAmmo === Infinity) {
|
||
slot.ammoText.textContent = '∞'
|
||
} else {
|
||
slot.ammoText.textContent = currentAmmo + '/' + WEAPON_CONFIG[weaponKey].maxAmmo
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新手雷蓄力显示
|
||
* @param {number} percent 蓄力百分比 0-1
|
||
*/
|
||
updateGrenadeCharge(percent) {
|
||
if (percent > 0) {
|
||
this.grenadeChargeBar.style.display = 'block'
|
||
const fill = this.grenadeChargeBar.querySelector('.hud-grenade-charge-fill')
|
||
fill.style.width = (percent * 100) + '%'
|
||
} else {
|
||
this.grenadeChargeBar.style.display = 'none'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新游戏信息
|
||
* @param {number} wave 当前波次
|
||
* @param {number} score 分数
|
||
* @param {number} time 游戏时间(秒)
|
||
*/
|
||
updateInfo(wave, score, time) {
|
||
this.waveText.textContent = 'Wave: ' + wave
|
||
this.scoreText.textContent = 'Score: ' + score
|
||
const mins = Math.floor(time / 60)
|
||
const secs = Math.floor(time % 60)
|
||
this.timeText.textContent = `Time: ${mins}:${secs.toString().padStart(2, '0')}`
|
||
}
|
||
|
||
/**
|
||
* 添加击杀信息条目
|
||
* @param {string} message 击杀信息文本
|
||
*/
|
||
addKillFeed(message) {
|
||
const entry = document.createElement('div')
|
||
entry.className = 'hud-kill-entry'
|
||
entry.textContent = message
|
||
this.killFeed.appendChild(entry)
|
||
// 4秒后自动移除
|
||
setTimeout(() => {
|
||
if (entry.parentNode) entry.parentNode.removeChild(entry)
|
||
}, 4000)
|
||
// 最多保留5条
|
||
while (this.killFeed.children.length > 5) {
|
||
this.killFeed.removeChild(this.killFeed.firstChild)
|
||
}
|
||
}
|
||
} |