EnemyComponent.ts 10 KB

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