| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- 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);
- }
- }
|