|
|
@@ -1,4 +1,5 @@
|
|
|
-import { _decorator, Component } from 'cc';
|
|
|
+import { _decorator, Component, Node, Color, UIOpacity } from 'cc';
|
|
|
+import { sp } from 'cc';
|
|
|
import { ConfigManager, EnemyConfig } from '../Core/ConfigManager';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
@@ -12,6 +13,33 @@ export class EnemyComponent extends Component {
|
|
|
public spawner: any = null; // 对生成器的引用
|
|
|
private rageActive: boolean = false;
|
|
|
private rageStartTime: number = 0;
|
|
|
+ // 隐身状态
|
|
|
+ private stealthActive: boolean = false;
|
|
|
+
|
|
|
+ start() {
|
|
|
+ // 如果具备隐身能力,则初始化隐身循环
|
|
|
+ const ability = this.getSpecialAbility();
|
|
|
+ if (ability === 'stealth') {
|
|
|
+ const cooldown = this.getSpecialAbilityCooldown();
|
|
|
+ // 初始进入隐身
|
|
|
+ this.applyStealthOpacity(100);
|
|
|
+ this.stealthActive = true;
|
|
|
+ // 按冷却时间循环切换显隐
|
|
|
+ this.schedule(() => {
|
|
|
+ if (this.stealthActive) {
|
|
|
+ this.applyStealthOpacity(255);
|
|
|
+ } else {
|
|
|
+ this.applyStealthOpacity(100);
|
|
|
+ }
|
|
|
+ this.stealthActive = !this.stealthActive;
|
|
|
+ }, Math.max(0.1, cooldown));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onDisable() {
|
|
|
+ // 组件禁用时取消调度,避免泄漏
|
|
|
+ this.unscheduleAllCallbacks();
|
|
|
+ }
|
|
|
|
|
|
// 获取敌人生命值
|
|
|
public getHealth(): number {
|
|
|
@@ -160,20 +188,68 @@ export class EnemyComponent extends Component {
|
|
|
// === 特殊能力 ===
|
|
|
// 获取特殊能力类型
|
|
|
public getSpecialAbility(): string {
|
|
|
- if (this.enemyConfig?.special_abilities && this.enemyConfig.special_abilities.length > 0) {
|
|
|
- return this.enemyConfig.special_abilities[0].type || 'none';
|
|
|
+ const abilities = this.enemyConfig?.special_abilities;
|
|
|
+ if (Array.isArray(abilities) && abilities.length > 0) {
|
|
|
+ return abilities[0]?.type || 'none';
|
|
|
}
|
|
|
return 'none';
|
|
|
}
|
|
|
|
|
|
// 获取特殊能力冷却时间
|
|
|
public getSpecialAbilityCooldown(): number {
|
|
|
- if (this.enemyConfig?.special_abilities && this.enemyConfig.special_abilities.length > 0) {
|
|
|
- return this.enemyConfig.special_abilities[0].cooldown || 5.0;
|
|
|
+ const abilities = this.enemyConfig?.special_abilities;
|
|
|
+ if (Array.isArray(abilities) && abilities.length > 0) {
|
|
|
+ const cooldown = abilities[0]?.cooldown;
|
|
|
+ return typeof cooldown === 'number' ? cooldown : 5.0;
|
|
|
}
|
|
|
return 5.0;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 应用隐身透明度到 EnemySprite 的 Skeleton
|
|
|
+ * @param opacity 透明度(0-255),示例:50 表示半透明
|
|
|
+ */
|
|
|
+ private applyStealthOpacity(opacity: number): void {
|
|
|
+ const enemySprite = this.findEnemySpriteNode();
|
|
|
+ if (!enemySprite) {
|
|
|
+ console.warn('[EnemyComponent] 未找到 EnemySprite 节点,无法应用隐身透明度');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置 UIOpacity 以保证整节点透明度生效
|
|
|
+ let uiOpacity = enemySprite.getComponent(UIOpacity);
|
|
|
+ if (!uiOpacity) {
|
|
|
+ uiOpacity = enemySprite.addComponent(UIOpacity);
|
|
|
+ }
|
|
|
+ uiOpacity.opacity = Math.max(0, Math.min(255, opacity));
|
|
|
+
|
|
|
+ // 同时设置 Skeleton 的颜色 alpha(与编辑器表现一致)
|
|
|
+ const skeleton = enemySprite.getComponent(sp.Skeleton);
|
|
|
+ if (skeleton) {
|
|
|
+ const current = skeleton.color ?? new Color(255, 255, 255, 255);
|
|
|
+ const next = new Color(current.r, current.g, current.b, Math.max(0, Math.min(255, opacity)));
|
|
|
+ skeleton.color = next;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 在当前节点层级下查找 EnemySprite 节点(兼容不同层级路径)
|
|
|
+ */
|
|
|
+ private findEnemySpriteNode(): Node | null {
|
|
|
+ // 直接子节点命中
|
|
|
+ const direct = this.node.getChildByName('EnemySprite');
|
|
|
+ if (direct) return direct;
|
|
|
+
|
|
|
+ // 深度遍历查找
|
|
|
+ const stack: Node[] = [...this.node.children];
|
|
|
+ while (stack.length > 0) {
|
|
|
+ const cur = stack.pop()!;
|
|
|
+ if (cur.name === 'EnemySprite') return cur;
|
|
|
+ stack.push(...cur.children);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
// === 狂暴状态管理 ===
|
|
|
// 检查是否处于狂暴状态
|
|
|
public isInRage(): boolean {
|