EnemyComponent.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. import { _decorator, Component, Node, Color, UIOpacity } from 'cc';
  2. import { sp } from 'cc';
  3. import { ConfigManager, EnemyConfig } from '../Core/ConfigManager';
  4. import EventBus, { GameEvents } from '../Core/EventBus';
  5. const { ccclass, property } = _decorator;
  6. /**
  7. * 敌人组件
  8. * 用于存储敌人的配置信息和基础属性
  9. */
  10. @ccclass('EnemyComponent')
  11. export class EnemyComponent extends Component {
  12. public enemyConfig: EnemyConfig = null;
  13. public spawner: any = null; // 对生成器的引用
  14. private rageActive: boolean = false;
  15. private rageStartTime: number = 0;
  16. // 隐身状态
  17. private stealthActive: boolean = false;
  18. start() {
  19. // 统一由 EnemyInstance 发出隐身事件并驱动 AttackStateManager。
  20. // 此组件仅响应事件并更新视觉透明度,不再主动调度隐身。
  21. }
  22. onEnable() {
  23. const eventBus = EventBus.getInstance();
  24. eventBus.on(GameEvents.ENEMY_STEALTH_START, this.onStealthStart, this);
  25. eventBus.on(GameEvents.ENEMY_STEALTH_END, this.onStealthEnd, this);
  26. }
  27. onDisable() {
  28. // 组件禁用时取消调度,避免泄漏
  29. this.unscheduleAllCallbacks();
  30. const eventBus = EventBus.getInstance();
  31. eventBus.off(GameEvents.ENEMY_STEALTH_START, this.onStealthStart, this);
  32. eventBus.off(GameEvents.ENEMY_STEALTH_END, this.onStealthEnd, this);
  33. }
  34. // 获取敌人生命值
  35. public getHealth(): number {
  36. return this.enemyConfig?.stats?.health || 100;
  37. }
  38. // 获取敌人速度
  39. public getSpeed(): number {
  40. return this.enemyConfig?.stats?.speed || 50;
  41. }
  42. // 获取敌人伤害
  43. public getDamage(): number {
  44. return this.enemyConfig?.combat?.attackDamage || 20;
  45. }
  46. // 获取敌人攻击范围
  47. public getAttackRange(): number {
  48. return this.enemyConfig?.combat?.attackRange || 30;
  49. }
  50. // 获取敌人攻击速度
  51. public getAttackSpeed(): number {
  52. return this.enemyConfig?.combat?.attackSpeed || 1.0;
  53. }
  54. // 获取敌人防御力
  55. public getDefense(): number {
  56. return this.enemyConfig?.stats?.defense || 0;
  57. }
  58. // 获取击杀奖励
  59. public getCoinReward(): number {
  60. return this.enemyConfig?.stats?.dropEnergy || 1;
  61. }
  62. // === 移动相关配置 ===
  63. // 获取移动类型
  64. public getMovementType(): string {
  65. return this.enemyConfig?.movement?.moveType || 'straight';
  66. }
  67. // 获取移动模式
  68. public getMovementPattern(): string {
  69. return this.enemyConfig?.movement?.pattern || 'direct';
  70. }
  71. // 获取摆动幅度
  72. public getSwingAmplitude(): number {
  73. return this.enemyConfig?.movement?.swingAmplitude || 0.0;
  74. }
  75. // 获取摆动频率
  76. public getSwingFrequency(): number {
  77. return this.enemyConfig?.movement?.swingFrequency || 0.0;
  78. }
  79. // 获取速度变化
  80. public getSpeedVariation(): number {
  81. return this.enemyConfig?.movement?.speedVariation || 0.1;
  82. }
  83. // 获取旋转速度
  84. public getRotationSpeed(): number {
  85. return this.enemyConfig?.movement?.rotationSpeed || 180.0;
  86. }
  87. // === 战斗相关配置 ===
  88. // 获取攻击类型
  89. public getAttackType(): string {
  90. return this.enemyConfig?.combat?.attackType || 'melee';
  91. }
  92. // 获取攻击冷却时间
  93. public getAttackCooldown(): number {
  94. return this.enemyConfig?.combat?.attackCooldown || 2.0;
  95. }
  96. // 获取攻击延迟
  97. public getAttackDelay(): number {
  98. return this.enemyConfig?.combat?.attackDelay || 1.0;
  99. }
  100. // 获取武器类型
  101. public getWeaponType(): string {
  102. return this.enemyConfig?.combat?.weaponType || 'none';
  103. }
  104. // 获取投掷物类型
  105. public getProjectileType(): string {
  106. return this.enemyConfig?.combat?.projectileType || 'none';
  107. }
  108. // 获取投掷物速度
  109. public getProjectileSpeed(): number {
  110. return this.enemyConfig?.combat?.projectileSpeed || 100.0;
  111. }
  112. // 是否造成墙体震动
  113. public getCausesWallShake(): boolean {
  114. return this.enemyConfig?.combat?.causesWallShake || false;
  115. }
  116. // === 格挡系统 ===
  117. // 是否可以格挡
  118. public canBlock(): boolean {
  119. return this.enemyConfig?.combat?.canBlock || false;
  120. }
  121. // 获取格挡几率
  122. public getBlockChance(): number {
  123. return this.enemyConfig?.combat?.blockChance || 0.0;
  124. }
  125. // 获取格挡伤害减免
  126. public getBlockDamageReduction(): number {
  127. return this.enemyConfig?.combat?.blockDamageReduction || 0.5;
  128. }
  129. // === 狂暴系统 ===
  130. // 是否有狂暴能力
  131. public hasRage(): boolean {
  132. return this.enemyConfig?.boss?.rage_threshold > 0 || false;
  133. }
  134. // 获取狂暴触发血量阈值
  135. public getRageThreshold(): number {
  136. return this.enemyConfig?.boss?.rage_threshold || 0.3;
  137. }
  138. // 获取狂暴触发血量阈值(别名方法)
  139. public getRageTriggerThreshold(): number {
  140. return this.getRageThreshold();
  141. }
  142. // 获取狂暴伤害倍率
  143. public getRageDamageMultiplier(): number {
  144. return this.enemyConfig?.boss?.rage_damage_multiplier || 1.5;
  145. }
  146. // 获取狂暴速度倍率
  147. public getRageSpeedMultiplier(): number {
  148. return this.enemyConfig?.boss?.rage_speed_multiplier || 1.3;
  149. }
  150. // 获取狂暴持续时间
  151. public getRageDuration(): number {
  152. return 10.0; // 固定持续时间
  153. }
  154. // === 特殊能力 ===
  155. // 获取特殊能力类型
  156. public getSpecialAbility(): string {
  157. const abilities = this.enemyConfig?.special_abilities;
  158. if (Array.isArray(abilities) && abilities.length > 0) {
  159. return abilities[0]?.type || 'none';
  160. }
  161. return 'none';
  162. }
  163. // 获取特殊能力冷却时间
  164. public getSpecialAbilityCooldown(): number {
  165. const abilities = this.enemyConfig?.special_abilities;
  166. if (Array.isArray(abilities) && abilities.length > 0) {
  167. const cooldown = abilities[0]?.cooldown;
  168. return typeof cooldown === 'number' ? cooldown : 5.0;
  169. }
  170. return 5.0;
  171. }
  172. /**
  173. * 应用隐身透明度到 EnemySprite 的 Skeleton
  174. * @param opacity 透明度(0-255),示例:50 表示半透明
  175. */
  176. private applyStealthOpacity(opacity: number): void {
  177. const enemySprite = this.findEnemySpriteNode();
  178. if (!enemySprite) {
  179. console.warn('[EnemyComponent] 未找到 EnemySprite 节点,无法应用隐身透明度');
  180. return;
  181. }
  182. // 设置 UIOpacity 以保证整节点透明度生效
  183. let uiOpacity = enemySprite.getComponent(UIOpacity);
  184. if (!uiOpacity) {
  185. uiOpacity = enemySprite.addComponent(UIOpacity);
  186. }
  187. uiOpacity.opacity = Math.max(0, Math.min(255, opacity));
  188. // 同时设置 Skeleton 的颜色 alpha(与编辑器表现一致)
  189. const skeleton = enemySprite.getComponent(sp.Skeleton);
  190. if (skeleton) {
  191. const current = skeleton.color ?? new Color(255, 255, 255, 255);
  192. const next = new Color(current.r, current.g, current.b, Math.max(0, Math.min(255, opacity)));
  193. skeleton.color = next;
  194. }
  195. }
  196. /**
  197. * 在当前节点层级下查找 EnemySprite 节点(兼容不同层级路径)
  198. */
  199. private findEnemySpriteNode(): Node | null {
  200. // 直接子节点命中
  201. const direct = this.node.getChildByName('EnemySprite');
  202. if (direct) return direct;
  203. // 深度遍历查找
  204. const stack: Node[] = [...this.node.children];
  205. while (stack.length > 0) {
  206. const cur = stack.pop()!;
  207. if (cur.name === 'EnemySprite') return cur;
  208. stack.push(...cur.children);
  209. }
  210. return null;
  211. }
  212. // === 隐身事件响应 ===
  213. private onStealthStart(data: { enemy: any, duration?: number }) {
  214. if (!data || !data.enemy || !data.enemy.node) return;
  215. if (data.enemy.node !== this.node) return;
  216. this.stealthActive = true;
  217. this.applyStealthOpacity(100);
  218. console.log(`[EnemyComponent] 接收隐身开始事件: ${this.node.name}, 持续: ${data.duration ?? '-'} 秒`);
  219. }
  220. private onStealthEnd(data: { enemy: any }) {
  221. if (!data || !data.enemy || !data.enemy.node) return;
  222. if (data.enemy.node !== this.node) return;
  223. this.stealthActive = false;
  224. this.applyStealthOpacity(255);
  225. console.log(`[EnemyComponent] 接收隐身结束事件: ${this.node.name}`);
  226. }
  227. // === 狂暴状态管理 ===
  228. // 检查是否处于狂暴状态
  229. public isInRage(): boolean {
  230. if (!this.rageActive) return false;
  231. // 检查狂暴是否过期
  232. const currentTime = Date.now();
  233. const rageDuration = this.getRageDuration() * 1000; // 转换为毫秒
  234. if (currentTime - this.rageStartTime > rageDuration) {
  235. this.endRage();
  236. return false;
  237. }
  238. return true;
  239. }
  240. // 触发狂暴状态
  241. public triggerRage(): void {
  242. if (!this.hasRage()) return;
  243. this.rageActive = true;
  244. this.rageStartTime = Date.now();
  245. console.log(`[EnemyComponent] 狂暴状态激活,持续时间: ${this.getRageDuration()}秒`);
  246. }
  247. // 结束狂暴状态
  248. public endRage(): void {
  249. this.rageActive = false;
  250. this.rageStartTime = 0;
  251. console.log(`[EnemyComponent] 狂暴状态结束`);
  252. }
  253. // 获取当前攻击力(考虑狂暴加成)
  254. public getCurrentAttackPower(): number {
  255. const baseDamage = this.getDamage();
  256. if (this.isInRage()) {
  257. return baseDamage * this.getRageDamageMultiplier();
  258. }
  259. return baseDamage;
  260. }
  261. // 获取当前移动速度(考虑狂暴加成)
  262. public getCurrentSpeed(): number {
  263. const baseSpeed = this.getSpeed();
  264. if (this.isInRage()) {
  265. return baseSpeed * this.getRageSpeedMultiplier();
  266. }
  267. return baseSpeed;
  268. }
  269. // 获取动画配置
  270. public getAnimations(): any {
  271. return this.enemyConfig?.visualConfig?.animations || {};
  272. }
  273. // 获取音频配置
  274. public getAudioConfig(): any {
  275. return this.enemyConfig?.audioConfig || {};
  276. }
  277. // 检查是否有特殊能力
  278. public hasSpecialAbility(abilityType: string): boolean {
  279. if (!this.enemyConfig || !this.enemyConfig.special_abilities) return false;
  280. return this.enemyConfig.special_abilities.some(ability => ability.type === abilityType);
  281. }
  282. // 获取特殊配置
  283. public getBossConfig(): any {
  284. return this.enemyConfig?.boss || null;
  285. }
  286. // 获取敌人信息文本
  287. public getEnemyInfo(): string {
  288. if (!this.enemyConfig) return '未知敌人';
  289. return `${this.enemyConfig.name}\n` +
  290. `类型: ${this.enemyConfig.type}\n` +
  291. `生命值: ${this.enemyConfig.stats?.health || 0}\n` +
  292. `速度: ${this.enemyConfig.stats?.speed || 0}\n` +
  293. `伤害: ${this.enemyConfig.combat?.attackDamage || 0}\n` +
  294. `攻击范围: ${this.enemyConfig.combat?.attackRange || 0}`;
  295. }
  296. // 死亡时调用
  297. public onDeath() {
  298. if (this.spawner && this.spawner.onEnemyDeath) {
  299. this.spawner.onEnemyDeath(this.node);
  300. }
  301. }
  302. }