import { _decorator, Component, Node, ProgressBar, Label, Vec3, find, UITransform, Collider2D, Contact2DType, IPhysics2DContact } 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 // 攻击中 } // 单个敌人实例的组件 @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; start() { // 计算游戏区域中心 this.calculateGameAreaCenter(); // 初始化攻击计时器 this.attackTimer = this.attackInterval; // 添加碰撞检测 this.setupCollider(); } // 设置碰撞检测 setupCollider() { // 获取或添加碰撞组件 let collider = this.node.getComponent(Collider2D); if (!collider) { console.warn('敌人节点没有碰撞组件,请确保已通过EnemyController添加'); } if (collider) { // 启用碰撞检测 collider.enabled = true; // 设置碰撞回调 collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); console.log('已设置敌人碰撞检测'); } } // 碰撞开始事件 onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { // 检查是否碰到墙体 const nodeName = otherCollider.node.name; const nodePath = this.getNodePath(otherCollider.node); // 检查是否是四个墙体之一 if (nodeName === 'TopFence' || nodeName === 'BottomFence' || nodeName === 'JiguangL' || nodeName === 'JiguangR' || nodePath.includes('GameArea/TopFence') || nodePath.includes('GameArea/BottomFence') || nodePath.includes('GameArea/JiguangL') || nodePath.includes('GameArea/JiguangR')) { console.log(`敌人碰到墙体 ${nodeName},停止移动,开始攻击`); // 记录碰撞的墙体 this.collidedWall = otherCollider.node; // 切换到攻击状态 this.state = EnemyState.ATTACKING; // 停止移动(速度设为零) this.speed = 0; } } // 获取节点路径 getNodePath(node: Node): string { let path = node.name; let current = node; while (current.parent) { current = current.parent; path = current.name + '/' + path; } return path; } // 计算游戏区域中心 calculateGameAreaCenter() { const gameArea = find('Canvas/GameLevelUI/GameArea'); if (gameArea) { this.gameAreaCenter = gameArea.worldPosition; console.log('游戏区域中心:', this.gameAreaCenter); } } // 更新血量显示 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(); } update(dt: number) { switch (this.state) { case EnemyState.MOVING: this.updateMovement(dt); break; case EnemyState.ATTACKING: this.updateAttack(dt); break; } } // 更新移动 updateMovement(dt: number) { // 更新改变方向的计时器 this.changeDirectionTime -= dt; // 随机改变水平方向 if (this.changeDirectionTime <= 0) { this.movingDirection = Math.random() > 0.5 ? 1 : -1; this.changeDirectionTime = 1 + Math.random() * 2; // 1-3秒后再次改变方向 } // 计算朝向游戏区域中心的方向 const directionToCenter = new Vec3( this.gameAreaCenter.x - this.node.worldPosition.x, this.gameAreaCenter.y - this.node.worldPosition.y, 0 ); directionToCenter.normalize(); // 检查是否即将进入游戏区域 if (this.isApproachingGameArea()) { // 如果即将进入游戏区域,停止移动并开始攻击 this.state = EnemyState.ATTACKING; this.speed = 0; console.log('敌人即将进入游戏区域,停止移动并开始攻击'); return; } // 水平移动(随机左右)+ 垂直移动(朝向中心) const newX = this.node.position.x + this.movingDirection * this.speed * 0.5 * dt; // 水平速度减半 const newY = this.node.position.y + directionToCenter.y * this.speed * dt; // 获取游戏区域边界 let leftBound = -500; let rightBound = 500; if (this.controller) { const bounds = this.controller.gameBounds; if (bounds) { const halfWidth = 20; // 估计敌人宽度的一半 leftBound = bounds.left - bounds.left + halfWidth; rightBound = bounds.right - bounds.left - halfWidth; } } // 检查是否超出边界 let finalX = newX; if (newX < leftBound) { finalX = leftBound; this.movingDirection *= -1; // 碰到左边界,改变方向 } else if (newX > rightBound) { finalX = rightBound; this.movingDirection *= -1; // 碰到右边界,改变方向 } // 更新敌人位置 this.node.position = new Vec3(finalX, newY, 0); // 手动检测是否接近墙体 this.checkWallProximity(); } // 检查是否即将进入游戏区域 isApproachingGameArea() { // 获取游戏区域节点 const gameArea = find('Canvas/GameLevelUI/GameArea'); if (!gameArea) return false; // 获取游戏区域的UITransform组件 const gameAreaTransform = gameArea.getComponent(UITransform); if (!gameAreaTransform) return false; // 获取游戏区域的世界坐标和尺寸 const gameAreaPos = gameArea.worldPosition; const gameAreaWidth = gameAreaTransform.width; const gameAreaHeight = gameAreaTransform.height; // 计算游戏区域的边界 const gameAreaLeft = gameAreaPos.x - gameAreaWidth / 2; const gameAreaRight = gameAreaPos.x + gameAreaWidth / 2; const gameAreaTop = gameAreaPos.y + gameAreaHeight / 2; const gameAreaBottom = gameAreaPos.y - gameAreaHeight / 2; // 获取敌人的世界坐标 const enemyPos = this.node.worldPosition; // 设置安全距离,防止敌人进入游戏区域 const safeDistance = 60; // 可以根据实际情况调整 // 检查敌人是否即将进入游戏区域 const isNearLeft = enemyPos.x > gameAreaLeft - safeDistance && enemyPos.x < gameAreaLeft; const isNearRight = enemyPos.x < gameAreaRight + safeDistance && enemyPos.x > gameAreaRight; const isNearTop = enemyPos.y < gameAreaTop + safeDistance && enemyPos.y > gameAreaTop; const isNearBottom = enemyPos.y > gameAreaBottom - safeDistance && enemyPos.y < gameAreaBottom; // 检查敌人是否在游戏区域内部 const isInside = enemyPos.x > gameAreaLeft && enemyPos.x < gameAreaRight && enemyPos.y < gameAreaTop && enemyPos.y > gameAreaBottom; // 如果敌人已经在游戏区域内部,立即停止 if (isInside) { console.log('敌人已进入游戏区域内部,立即停止'); return true; } // 如果敌人接近游戏区域的任一边界,返回true if (isNearLeft || isNearRight || isNearTop || isNearBottom) { // 记录接近的方向 let direction = ''; if (isNearLeft) direction += '左边界 '; if (isNearRight) direction += '右边界 '; if (isNearTop) direction += '上边界 '; if (isNearBottom) direction += '下边界 '; console.log(`敌人接近游戏区域${direction},距离小于${safeDistance}`); return true; } return false; } // 检测是否接近墙体 checkWallProximity() { // 查找四个墙体 const gameArea = find('Canvas/GameLevelUI/GameArea'); if (!gameArea) return; const walls = [ gameArea.getChildByName('TopFence'), gameArea.getChildByName('BottomFence'), gameArea.getChildByName('JiguangL'), gameArea.getChildByName('JiguangR') ]; // 检查与每个墙体的距离 for (const wall of walls) { if (!wall) continue; // 获取墙体的UITransform组件 const wallTransform = wall.getComponent(UITransform); if (!wallTransform) continue; // 计算敌人与墙体的距离 const distance = Vec3.distance(this.node.worldPosition, wall.worldPosition); // 根据墙体的尺寸调整阈值 let proximityThreshold = 100; // 默认阈值 // 如果是左右墙体,使用更大的阈值 if (wall.name === 'JiguangL' || wall.name === 'JiguangR') { proximityThreshold = 80; } // 如果距离小于阈值,认为已接近墙体 if (distance < proximityThreshold) { console.log(`敌人接近墙体 ${wall.name},距离: ${distance}`); // 记录接近的墙体 this.collidedWall = wall; // 切换到攻击状态 this.state = EnemyState.ATTACKING; // 停止移动(速度设为零) this.speed = 0; // 退出循环 break; } } } // 更新攻击 updateAttack(dt: number) { // 敌人在攻击状态下不移动 // 更新攻击计时器 this.attackTimer -= dt; // 攻击间隔到达,进行攻击 if (this.attackTimer <= 0) { this.attackTimer = this.attackInterval; this.attackWall(); } } // 攻击墙体 attackWall() { if (!this.controller) { console.warn('敌人没有controller引用,无法攻击墙体'); return; } // 对墙体造成伤害 this.controller.damageWall(this.attackPower); // 添加攻击动画效果(可选) this.playAttackAnimation(); console.log(`敌人攻击墙体,造成 ${this.attackPower} 点伤害`); } // 播放攻击动画 playAttackAnimation() { // 简单的缩放动画模拟攻击效果 const originalScale = this.node.scale.clone(); // 放大 this.node.setScale(originalScale.x * 1.2, originalScale.y * 1.2, originalScale.z); // 0.1秒后恢复原始大小 this.scheduleOnce(() => { this.node.setScale(originalScale.x, originalScale.y, originalScale.z); }, 0.1); } }