/
RaskolnickOFF
/
3D
Обзор
Документация
Войти
/
RaskolnickOFF
/
3D
Код
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
js/source/systems/enemy/EnemyHealthBarSystem.js
134 строки
5 KB
RaskolnickOFF
Structure update
06 июн 2026, 03:18
06 июн 2026, 03:18
9bc1c25
Код
Авторство
О чём код?
// js/source/systems/enemy/EnemyHealthBarSystem.js — HP-бары над врагами (рендер-слой) import { Components } from '../../core/Components.js'; import * as THREE from 'three'; export class EnemyHealthBarSystem { /** * @param {import('../core/RenderContext.js').RenderContext} ctx */ constructor(ctx) { this.scene = ctx.scene; this.camera = ctx.camera; this._bars = new Map(); this._tempPos = new THREE.Vector3(); } _createBarShape(w, h, curve) { const shape = new THREE.Shape(); shape.moveTo(0, 0); shape.lineTo(w, 0); shape.lineTo(w, -h); shape.lineTo(0, -h); shape.closePath(); return shape; } update(engine) { const enemies = engine.with(Components.ENEMY); const barWidth = 0.8; const barHeight = 0.08; const curveAmount = 0; for (const enemy of enemies) { const id = enemy.id; const group = enemy.get(Components.MESH); const health = enemy.get(Components.HEALTH); if (!group || health === undefined) continue; let barData = this._bars.get(id); if (!barData) { const healthBarGroup = group.getObjectByName('healthBar'); if (!healthBarGroup) continue; const bgShape = this._createBarShape(barWidth, barHeight, curveAmount); const bgGeo = new THREE.ShapeGeometry(bgShape); const bgMat = new THREE.MeshBasicMaterial({ color: '#333333', transparent: true, opacity: 0.5, depthWrite: false, side: THREE.DoubleSide }); const bgBar = new THREE.Mesh(bgGeo, bgMat); bgBar.name = 'healthBg'; const fillShape = this._createBarShape(barWidth, barHeight, curveAmount); const fillGeo = new THREE.ShapeGeometry(fillShape); const fillMat = new THREE.MeshBasicMaterial({ color: '#00ff00', transparent: true, opacity: 0.8, depthWrite: false, side: THREE.DoubleSide }); const fillBar = new THREE.Mesh(fillGeo, fillMat); fillBar.name = 'healthFill'; this.scene.add(bgBar); this.scene.add(fillBar); group.remove(healthBarGroup); barData = { bgBar, fillBar }; this._bars.set(id, barData); } const { bgBar, fillBar } = barData; if (!bgBar || !fillBar) continue; group.getWorldPosition(this._tempPos); const y = this._tempPos.y + 1.0; bgBar.position.set(this._tempPos.x, y, this._tempPos.z); fillBar.position.set(this._tempPos.x, y + 0.005, this._tempPos.z); bgBar.quaternion.copy(this.camera.quaternion); fillBar.quaternion.copy(this.camera.quaternion); const maxHP = 100; const ratio = Math.max(0, Math.min(1, health / maxHP)); if (ratio > 0.5) { const t = (ratio - 0.5) * 2; fillBar.material.color.setRGB(1 - t, 1, 0); } else { const t = ratio * 2; fillBar.material.color.setRGB(1, t, 0); } fillBar.material.opacity = 0.5 + ratio * 0.4; const newWidth = barWidth * ratio; if (newWidth > 0.01) { const newShape = this._createBarShape(newWidth, barHeight, curveAmount); const newGeo = new THREE.ShapeGeometry(newShape); fillBar.geometry.dispose(); fillBar.geometry = newGeo; } } for (const [id, barData] of this._bars) { if (!engine.getEntity(id)) { this.scene.remove(barData.bgBar); this.scene.remove(barData.fillBar); barData.bgBar.geometry.dispose(); barData.fillBar.geometry.dispose(); this._bars.delete(id); } } } reset() { for (const [id, barData] of this._bars) { if (barData.bgBar) { this.scene.remove(barData.bgBar); barData.bgBar.geometry?.dispose(); } if (barData.fillBar) { this.scene.remove(barData.fillBar); barData.fillBar.geometry?.dispose(); } } this._bars.clear(); } }