Files
zp1/frontend/src/ui/hud.js
2026-04-25 22:09:27 +08:00

199 lines
6.1 KiB
JavaScript
Raw 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 { 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)
}
}
}