|
@@ -1,41 +1,173 @@
|
|
|
-import { BoxCollider, Button, Collider, Component, ConeCollider, CylinderCollider, ITriggerEvent, Label, Node, NodeEventType, RigidBody, SphereCollider, Vec3, _decorator, find, game } from 'cc';
|
|
|
-import { StormSunderAudioMgr } from '../Manager/StormSunderAudioMgr';
|
|
|
-import { EventDispatcher } from 'db://assets/core_tgx/easy_ui_framework/EventDispatcher';
|
|
|
-import { GameEvent } from '../Enum/GameEvent';
|
|
|
-import { UIJoyStick } from '../UIJoyStick';
|
|
|
-import { GameMgr, GameStatus } from '../Manager/GameMgr';
|
|
|
-import { PropComponent, PropStatus } from './PropComponent';
|
|
|
-import { PlayerInfo } from './PlayerInfoComponent';
|
|
|
-import { Effect2DUIMgr } from '../Manager/Effect2DUIMgr';
|
|
|
+import { BoxCollider, Component, ITriggerEvent, Node, Vec3, _decorator, randomRange } from 'cc';
|
|
|
+import { PathfindingManager } from '../Manager/PathfindingManager';
|
|
|
import { PlayerStatus, TornadoComponent } from './TornadoComponent';
|
|
|
+import { PropStatus } from './PropComponent';
|
|
|
+import { GameUtil } from '../GameUtil';
|
|
|
+
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
+enum BehaviorType {
|
|
|
+ Move,
|
|
|
+ Collect //收集最近的道具
|
|
|
+}
|
|
|
|
|
|
-/** 龙卷风AI组件*/
|
|
|
+/** 龙卷风AI组件 */
|
|
|
@ccclass('TornadoAIComponent')
|
|
|
export class TornadoAIComponent extends TornadoComponent {
|
|
|
|
|
|
- attack_ai: number = 1;
|
|
|
- speed_ai: number = 1;
|
|
|
- expPower_ai: number = 1;
|
|
|
+ moveDuration: number = 3; //移动行为持续时间(秒)
|
|
|
+ escapeDuration: number = 5; //逃离行为持续时间(秒)
|
|
|
+ chaseDuration: number = 30; //追击行为持续时间(秒)
|
|
|
+ chaseAIProbability: number = 1; //是否追击 AI 的概率 1是100%
|
|
|
+ chasePlayerProbability: number = 1; //是否追击玩家的概率
|
|
|
+
|
|
|
+ isChasing: boolean = false; // 是否追击中
|
|
|
+ isEscaping: boolean = false; // 是否逃跑中
|
|
|
+ targetNode: Node | null = null; // 目标
|
|
|
+
|
|
|
+ behaviorType: BehaviorType = BehaviorType.Move; // 行为类型
|
|
|
|
|
|
- protected start(): void {
|
|
|
+ protected async start() {
|
|
|
super.start();
|
|
|
this.ai = true;
|
|
|
-
|
|
|
this.playerInfo.nickName = '阿西吧 ai';
|
|
|
- this.playerInfo.level = 1;
|
|
|
+ this.playerInfo.level = 2;
|
|
|
+ this.currentLv = this.playerInfo.level;
|
|
|
|
|
|
- console.log('playerInfo:', this.playerInfo);
|
|
|
this.onPlayerInfoHandler();
|
|
|
+ this.decideAction(); // 进入行为循环
|
|
|
+
|
|
|
+ this.radiusTigger.on('onTriggerEnter', this.onRadiusTriggerEnter, this);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 选择 AI 行为 */
|
|
|
+ private decideAction() {
|
|
|
+ if (this.playerStatus == PlayerStatus.DIE) return; // AI 死亡时不执行行为
|
|
|
+
|
|
|
+ // DOTO 目前固定 100% 选择移动行为(未来可修改概率)
|
|
|
+ const actionType = this.behaviorType;
|
|
|
+
|
|
|
+ if (actionType === BehaviorType.Move) {
|
|
|
+ this.randomMove();
|
|
|
+ } else {
|
|
|
+ const closestItem = this.findClosestItem();
|
|
|
+ if (closestItem) {
|
|
|
+ this.moveToTarget(closestItem, this.moveDuration);
|
|
|
+ } else {
|
|
|
+ this.randomMove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 随机移动 */
|
|
|
+ private randomMove() {
|
|
|
+ if (this.isChasing || this.isEscaping) return; // 如果正在追击或逃跑,则不进行随机移动
|
|
|
+
|
|
|
+ const randomDirection = new Vec3(randomRange(-50, 50), 0, randomRange(-50, 50));
|
|
|
+ const targetPosition = this.node.position.clone().add(randomDirection);
|
|
|
+ PathfindingManager.getInstance().moveTo(this.node, targetPosition, this.moveDuration);
|
|
|
+ console.log(`AI 触发随机移动行为!`);
|
|
|
+
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ if (!this.isChasing && !this.isEscaping) { // 再次检查状态,避免重复调用
|
|
|
+ this.decideAction();
|
|
|
+ }
|
|
|
+ }, this.moveDuration);
|
|
|
}
|
|
|
|
|
|
- protected onTriggerEnter(event: ITriggerEvent): void {
|
|
|
- super.onTriggerEnter(event)
|
|
|
+ /** 移动到目标 */
|
|
|
+ private moveToTarget(target: Node, duration: number) {
|
|
|
+ PathfindingManager.getInstance().moveTo(this.node, target.position, duration);
|
|
|
+
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ this.decideAction();
|
|
|
+ }, duration);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 触发器检测(过程中遇到其他龙卷风) */
|
|
|
+ protected onRadiusTriggerEnter(event: ITriggerEvent): void {
|
|
|
+ const otherCollider = event.otherCollider;
|
|
|
+ const otherNode = otherCollider.node;
|
|
|
+
|
|
|
+ if (event.otherCollider.getGroup() == 1 << 3) {
|
|
|
+ const targetTornado = otherNode.parent.getComponent(TornadoComponent);
|
|
|
+ if (!targetTornado) return;
|
|
|
+ console.log(`AI 触发器检测到其他龙卷风!`)
|
|
|
+ const isTargetAI = targetTornado instanceof TornadoAIComponent;
|
|
|
+ const targetLv = targetTornado.currentLv;
|
|
|
+
|
|
|
+ if (targetLv > this.currentLv) {
|
|
|
+ // 目标等级比自己高 → 逃跑
|
|
|
+ console.log(`AI 逃离行为!`)
|
|
|
+ this.escapeFrom(targetTornado.node);
|
|
|
+ } else if (targetLv < this.currentLv) {
|
|
|
+ // 目标等级比自己低 → 先判断是否追击
|
|
|
+ if (Math.random() < this.chaseAIProbability) {
|
|
|
+ if (isTargetAI) {
|
|
|
+ // 目标是 AI,直接追击
|
|
|
+ this.chaseTarget(targetTornado.node);
|
|
|
+ } else {
|
|
|
+ // 目标是玩家,进一步判断是否追击
|
|
|
+ if (Math.random() < this.chasePlayerProbability) {
|
|
|
+ this.chaseTarget(targetTornado.node);
|
|
|
+ } else {
|
|
|
+ // 不追击,则保持当前行为到持续时间结束
|
|
|
+ this.continueCurrentBehavior();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 不追击,持续当前行为直到时间结束
|
|
|
+ this.continueCurrentBehavior();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果等级相同,继续当前行为
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 继续当前行为直到时间结束 */
|
|
|
+ private continueCurrentBehavior() {
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ this.decideAction();
|
|
|
+ }, this.moveDuration);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 追击目标 */
|
|
|
+ private chaseTarget(target: Node) {
|
|
|
+ if (this.isChasing) return;
|
|
|
+ console.log(`AI 追击目标->>>>>>>>>>>>>`);
|
|
|
+
|
|
|
+ this.isChasing = true;
|
|
|
+ this.targetNode = target;
|
|
|
+
|
|
|
+ PathfindingManager.getInstance().followTarget(this, target, 20);
|
|
|
+
|
|
|
+ // 追击时间结束后恢复行为
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ this.isChasing = false;
|
|
|
+ this.targetNode = null;
|
|
|
+ this.decideAction();
|
|
|
+ }, this.chaseDuration);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /** 逃离目标 */
|
|
|
+ private escapeFrom(target: Node) {
|
|
|
+ this.isEscaping = true;
|
|
|
+ console.log(`AI 逃离行为->>>>>>>>>>>>>>`);
|
|
|
+ const direction = this.node.position.clone().subtract(target.position).normalize().multiplyScalar(20);
|
|
|
+ const escapePosition = this.node.position.clone().add(direction);
|
|
|
+
|
|
|
+ PathfindingManager.getInstance().moveTo(this.node, escapePosition, this.escapeDuration);
|
|
|
+
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ this.isEscaping = false;
|
|
|
+ this.decideAction();
|
|
|
+ }, this.escapeDuration);
|
|
|
}
|
|
|
|
|
|
- protected onTriggerStay(event: ITriggerEvent): void {
|
|
|
- super.onTriggerStay(event);
|
|
|
- console.log('阿西吧 干它!!!!!!!!!!!!!!!!!!');
|
|
|
+ /** 查找最近的道具 */
|
|
|
+ private findClosestItem(): Node | null {
|
|
|
+ // TODO: 实现查找最近的道具
|
|
|
+ return null;
|
|
|
}
|
|
|
}
|