EnemyInstance.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { _decorator, Component, Node, ProgressBar, Label, Vec3, find, UITransform, Collider2D, Contact2DType, IPhysics2DContact } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. // 前向声明EnemyController接口,避免循环引用
  4. interface EnemyControllerType {
  5. gameBounds: {
  6. left: number;
  7. right: number;
  8. top: number;
  9. bottom: number;
  10. };
  11. damageWall: (damage: number) => void;
  12. }
  13. // 敌人状态枚举
  14. enum EnemyState {
  15. MOVING, // 移动中
  16. ATTACKING // 攻击中
  17. }
  18. // 单个敌人实例的组件
  19. @ccclass('EnemyInstance')
  20. export class EnemyInstance extends Component {
  21. // 敌人属性
  22. public health: number = 30;
  23. public maxHealth: number = 30;
  24. public speed: number = 50;
  25. public attackPower: number = 10;
  26. // 移动属性
  27. public movingDirection: number = 1; // 1: 向右, -1: 向左
  28. public targetY: number = 0; // 目标Y位置
  29. public changeDirectionTime: number = 0; // 下次改变方向的时间
  30. // 攻击属性
  31. public attackInterval: number = 2; // 攻击间隔(秒)
  32. private attackTimer: number = 0;
  33. // 对控制器的引用
  34. public controller: EnemyControllerType = null;
  35. // 敌人当前状态
  36. private state: EnemyState = EnemyState.MOVING;
  37. // 游戏区域中心
  38. private gameAreaCenter: Vec3 = new Vec3();
  39. // 碰撞的墙体
  40. private collidedWall: Node = null;
  41. start() {
  42. // 初始化敌人
  43. this.initializeEnemy();
  44. }
  45. // 初始化敌人
  46. private initializeEnemy() {
  47. this.health = this.maxHealth;
  48. this.state = EnemyState.MOVING;
  49. this.speed = 50; // 默认速度
  50. this.attackPower = 10; // 默认攻击力
  51. this.attackInterval = 2.0; // 默认攻击间隔
  52. this.attackTimer = 0;
  53. // 计算游戏区域中心
  54. this.calculateGameAreaCenter();
  55. // 初始化碰撞检测
  56. this.setupCollider();
  57. }
  58. // 设置碰撞器
  59. setupCollider() {
  60. // 检查节点是否有碰撞器
  61. let collider = this.node.getComponent(Collider2D);
  62. if (!collider) {
  63. return;
  64. }
  65. // 设置碰撞事件监听
  66. collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
  67. }
  68. // 碰撞开始事件
  69. onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
  70. const nodeName = otherCollider.node.name;
  71. // 如果碰到墙体,停止移动并开始攻击
  72. if (nodeName.includes('Wall') || nodeName.includes('wall') || nodeName.includes('Fence') || nodeName.includes('Jiguang')) {
  73. this.state = EnemyState.ATTACKING;
  74. this.attackTimer = 0; // 立即开始攻击
  75. }
  76. }
  77. // 获取节点路径
  78. getNodePath(node: Node): string {
  79. let path = node.name;
  80. let current = node;
  81. while (current.parent) {
  82. current = current.parent;
  83. path = current.name + '/' + path;
  84. }
  85. return path;
  86. }
  87. // 计算游戏区域中心
  88. private calculateGameAreaCenter() {
  89. const gameArea = find('Canvas/GameLevelUI/GameArea');
  90. if (gameArea) {
  91. this.gameAreaCenter = gameArea.worldPosition;
  92. }
  93. }
  94. // 更新血量显示
  95. updateHealthDisplay() {
  96. // 更新血条
  97. const hpBar = this.node.getChildByName('HPBar');
  98. if (hpBar) {
  99. const progressBar = hpBar.getComponent(ProgressBar);
  100. if (progressBar) {
  101. progressBar.progress = this.health / this.maxHealth;
  102. }
  103. }
  104. // 更新血量数字
  105. const hpLabel = this.node.getChildByName('HPLabel');
  106. if (hpLabel) {
  107. const label = hpLabel.getComponent(Label);
  108. if (label) {
  109. label.string = this.health.toString();
  110. }
  111. }
  112. }
  113. // 受到伤害
  114. takeDamage(damage: number) {
  115. this.health -= damage;
  116. // 更新血量显示
  117. this.updateHealthDisplay();
  118. }
  119. update(deltaTime: number) {
  120. if (this.state === EnemyState.MOVING) {
  121. this.updateMovement(deltaTime);
  122. } else if (this.state === EnemyState.ATTACKING) {
  123. this.updateAttack(deltaTime);
  124. }
  125. }
  126. // 更新移动逻辑
  127. private updateMovement(deltaTime: number) {
  128. // 检查是否接近游戏区域边界
  129. if (this.checkNearGameArea()) {
  130. // 如果接近游戏区域,停止移动并开始攻击
  131. this.state = EnemyState.ATTACKING;
  132. this.attackTimer = 0; // 立即开始攻击
  133. return;
  134. }
  135. // 继续移动
  136. this.moveTowardsTarget(deltaTime);
  137. }
  138. // 检查是否接近游戏区域
  139. private checkNearGameArea(): boolean {
  140. const currentPos = this.node.worldPosition;
  141. // 获取游戏区域边界
  142. const gameArea = find('Canvas/GameLevelUI/GameArea');
  143. if (!gameArea) return false;
  144. const uiTransform = gameArea.getComponent(UITransform);
  145. if (!uiTransform) return false;
  146. const gameAreaPos = gameArea.worldPosition;
  147. const halfWidth = uiTransform.width / 2;
  148. const halfHeight = uiTransform.height / 2;
  149. const bounds = {
  150. left: gameAreaPos.x - halfWidth,
  151. right: gameAreaPos.x + halfWidth,
  152. top: gameAreaPos.y + halfHeight,
  153. bottom: gameAreaPos.y - halfHeight
  154. };
  155. // 检查是否在游戏区域内或非常接近
  156. const safeDistance = 50; // 安全距离
  157. const isInside = currentPos.x >= bounds.left - safeDistance &&
  158. currentPos.x <= bounds.right + safeDistance &&
  159. currentPos.y >= bounds.bottom - safeDistance &&
  160. currentPos.y <= bounds.top + safeDistance;
  161. if (isInside) {
  162. return true;
  163. }
  164. return false;
  165. }
  166. // 移动到目标位置
  167. private moveTowardsTarget(deltaTime: number) {
  168. const currentPos = this.node.position;
  169. // 简单的向中心移动
  170. const targetPos = new Vec3(0, 0, 0); // 移动到中心
  171. const direction = targetPos.subtract(currentPos).normalize();
  172. // 应用移动
  173. const moveDistance = this.speed * deltaTime;
  174. const newPos = currentPos.add(direction.multiplyScalar(moveDistance));
  175. this.node.position = newPos;
  176. }
  177. // 更新攻击逻辑
  178. private updateAttack(deltaTime: number) {
  179. this.attackTimer -= deltaTime;
  180. if (this.attackTimer <= 0) {
  181. // 执行攻击
  182. this.performAttack();
  183. // 重置攻击计时器
  184. this.attackTimer = this.attackInterval;
  185. }
  186. }
  187. // 执行攻击
  188. private performAttack() {
  189. if (!this.controller) {
  190. return;
  191. }
  192. // 对墙体造成伤害
  193. this.controller.damageWall(this.attackPower);
  194. }
  195. }