import { _decorator, Component, Node, ProgressBar, Label, Vec3, find, UITransform, Collider2D, Contact2DType, IPhysics2DContact } from 'cc'; import { sp } from 'cc'; const { ccclass, property } = _decorator; // 前向声明EnemyController接口,避免循环引用 interface EnemyControllerType { gameBounds: { left: number; right: number; top: number; bottom: number; }; damageWall: (damage: number) => void; } // 敌人状态枚举 enum EnemyState { MOVING, // 移动中 ATTACKING, // 攻击中 DEAD // 死亡 } // 单个敌人实例的组件 @ccclass('EnemyInstance') export class EnemyInstance extends Component { // 敌人属性 public health: number = 30; public maxHealth: number = 30; public speed: number = 50; public attackPower: number = 10; // 移动属性 public movingDirection: number = 1; // 1: 向右, -1: 向左 public targetY: number = 0; // 目标Y位置 public changeDirectionTime: number = 0; // 下次改变方向的时间 // 攻击属性 public attackInterval: number = 2; // 攻击间隔(秒) private attackTimer: number = 0; // 对控制器的引用 public controller: EnemyControllerType = null; // 敌人当前状态 private state: EnemyState = EnemyState.MOVING; // 游戏区域中心 private gameAreaCenter: Vec3 = new Vec3(); // 碰撞的墙体 private collidedWall: Node = null; // 骨骼动画组件 private skeleton: sp.Skeleton | null = null; // 调试标记,避免重复输出日志 private _debugFlag: boolean = false; start() { // 初始化敌人 this.initializeEnemy(); } // 初始化敌人 private initializeEnemy() { this.health = this.maxHealth; this.state = EnemyState.MOVING; if (this.speed === 0) this.speed = 50; if (this.attackPower === 0) this.attackPower = 10; this.attackInterval = 2.0; // 默认攻击间隔 this.attackTimer = 0; // 获取骨骼动画组件 this.skeleton = this.getComponent(sp.Skeleton); this.playWalkAnimation(); // 计算游戏区域中心 this.calculateGameAreaCenter(); // 初始化碰撞检测 this.setupCollider(); } // 设置碰撞器 setupCollider() { // 检查节点是否有碰撞器 let collider = this.node.getComponent(Collider2D); if (!collider) { return; } // 设置碰撞事件监听 collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); } // 碰撞开始事件 onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { const nodeName = otherCollider.node.name; // 如果碰到墙体,停止移动并开始攻击 if (nodeName.includes('Wall') || nodeName.includes('wall') || nodeName.includes('Fence') || nodeName.includes('Jiguang')) { this.state = EnemyState.ATTACKING; this.attackTimer = 0; // 立即开始攻击 // 切换攻击动画 this.playAttackAnimation(); } } // 获取节点路径 getNodePath(node: Node): string { let path = node.name; let current = node; while (current.parent) { current = current.parent; path = current.name + '/' + path; } return path; } // 计算游戏区域中心 private calculateGameAreaCenter() { const gameArea = find('Canvas/GameLevelUI/GameArea'); if (gameArea) { this.gameAreaCenter = gameArea.worldPosition; } } // 更新血量显示 updateHealthDisplay() { // 更新血条 const hpBar = this.node.getChildByName('HPBar'); if (hpBar) { const progressBar = hpBar.getComponent(ProgressBar); if (progressBar) { progressBar.progress = this.health / this.maxHealth; } } // 更新血量数字 const hpLabel = this.node.getChildByName('HPLabel'); if (hpLabel) { const label = hpLabel.getComponent(Label); if (label) { label.string = this.health.toString(); } } } // 受到伤害 takeDamage(damage: number) { this.health -= damage; // 更新血量显示 this.updateHealthDisplay(); // 如果血量低于等于0,销毁敌人 if (this.health <= 0 && this.state !== EnemyState.DEAD) { this.state = EnemyState.DEAD; // 进入死亡流程,禁用碰撞避免重复命中 const col = this.getComponent(Collider2D); if (col) col.enabled = false; this.playDeathAnimationAndDestroy(); } } onDestroy() { // 通知控制器 & GameManager if (this.controller && typeof (this.controller as any).notifyEnemyDead === 'function') { (this.controller as any).notifyEnemyDead(this.node); } } update(deltaTime: number) { if (this.state === EnemyState.MOVING) { this.updateMovement(deltaTime); } else if (this.state === EnemyState.ATTACKING) { this.updateAttack(deltaTime); } // 不再每帧播放攻击动画,避免日志刷屏 } // 更新移动逻辑 private updateMovement(deltaTime: number) { // 检查是否接近游戏区域边界 if (this.checkNearGameArea()) { this.state = EnemyState.ATTACKING; this.attackTimer = 0; this.playAttackAnimation(); return; } // 继续移动 this.moveTowardsTarget(deltaTime); } // 检查是否接近游戏区域 private checkNearGameArea(): boolean { const currentPos = this.node.worldPosition; // 获取游戏区域边界 const gameArea = find('Canvas/GameLevelUI/GameArea'); if (!gameArea) return false; const uiTransform = gameArea.getComponent(UITransform); if (!uiTransform) return false; const gameAreaPos = gameArea.worldPosition; const halfWidth = uiTransform.width / 2; const halfHeight = uiTransform.height / 2; const bounds = { left: gameAreaPos.x - halfWidth, right: gameAreaPos.x + halfWidth, top: gameAreaPos.y + halfHeight, bottom: gameAreaPos.y - halfHeight }; // 检查是否在游戏区域内或非常接近 const safeDistance = 50; // 安全距离 const isInside = currentPos.x >= bounds.left - safeDistance && currentPos.x <= bounds.right + safeDistance && currentPos.y >= bounds.bottom - safeDistance && currentPos.y <= bounds.top + safeDistance; if (isInside) { return true; } return false; } // 移动到目标位置 private moveTowardsTarget(deltaTime: number) { const currentPos = this.node.position; // 简单的向中心移动 const targetPos = new Vec3(0, 0, 0); // 移动到中心 const direction = targetPos.subtract(currentPos).normalize(); // 应用移动 const moveDistance = this.speed * deltaTime; const newPos = currentPos.add(direction.multiplyScalar(moveDistance)); this.node.position = newPos; } // 更新攻击逻辑 private updateAttack(deltaTime: number) { this.attackTimer -= deltaTime; if (this.attackTimer <= 0) { // 执行攻击 this.performAttack(); // 重置攻击计时器 this.attackTimer = this.attackInterval; } } // 执行攻击 private performAttack() { if (!this.controller) { return; } // 对墙体造成伤害 this.controller.damageWall(this.attackPower); } // 播放行走动画 private playWalkAnimation() { if (!this.skeleton) return; const enemyComp = this.getComponent('EnemyComponent') as any; const anims = enemyComp?.getAnimations ? enemyComp.getAnimations() : {}; const walkName = anims.walk ?? 'walk'; const idleName = anims.idle ?? 'idle'; if (this.skeleton.findAnimation(walkName)) { this.skeleton.setAnimation(0, walkName, true); } else if (this.skeleton.findAnimation(idleName)) { this.skeleton.setAnimation(0, idleName, true); } } // 播放攻击动画 private playAttackAnimation() { if (!this.skeleton) return; const enemyComp2 = this.getComponent('EnemyComponent') as any; const anims2 = enemyComp2?.getAnimations ? enemyComp2.getAnimations() : {}; const attackName = anims2.attack ?? 'attack'; // 移除频繁打印 if (this.skeleton.findAnimation(attackName)) { this.skeleton.setAnimation(0, attackName, true); } } private playDeathAnimationAndDestroy() { if (this.skeleton) { const enemyComp = this.getComponent('EnemyComponent') as any; const anims = enemyComp?.getAnimations ? enemyComp.getAnimations() : {}; const deathName = anims.dead ?? 'dead'; if (this.skeleton.findAnimation(deathName)) { this.skeleton.setAnimation(0, deathName, false); // 销毁节点在动画完毕后 this.skeleton.setCompleteListener(() => { this.node.destroy(); }); return; } } // 若无动画直接销毁 this.node.destroy(); } }