import { _decorator, Component, Node, Vec3, Quat, RigidBody, Collider, ICollisionEvent, PhysicsSystem, geometry, Layers } from 'cc';
const { ccclass, property } = _decorator;
declare const YUKA: any;
@ccclass
export class MonkeyAI extends Component {
@property(Node)
public player: Node = null!;
public groundLayerValue: number = 1; // 地面层级值
public obstacleLayerValue: number = 1; // 障碍物层级值
public bulletLayerValue: number = 1; // 子弹层级值
public wanderSpeed: number = 2; // 随机漫步速度
public fleeSpeed: number = 5; // 逃跑速度
public sightRange: number = 10; // 触发逃跑距离
public fleeDelay: number = 3.0; // 逃跑延迟时间
private _state: string = 'WANDER'; // 当前状态
private _fleeTimer: number = 0; // 逃跑计时器
private _vehicle: any; // 实体
private _entityManager: any; // 实体管理器
private _rb: RigidBody = null!; //刚体
onLoad() {
this._rb = this.getComponent(RigidBody)!;
if (typeof YUKA === 'undefined') return;
this._vehicle = new YUKA.Vehicle();
this._vehicle.maxSpeed = this.wanderSpeed;
this._vehicle.position.set(this.node.worldPosition.x, this.node.worldPosition.y, this.node.worldPosition.z);
this._entityManager = new YUKA.EntityManager();
this._entityManager.add(this._vehicle);
this.switchToWander();
const collider = this.getComponent(Collider);
if (collider) {
collider.on('onCollisionEnter', this.onCollision, this);
}
}
private onCollision(event: ICollisionEvent) {
const otherNode = event.otherCollider.node;
// 检查是否被子弹击中
if (otherNode.name.includes("Bullet") || otherNode.getComponent('BulletLogic')) {
console.log("猴子被捕获!");
// 销毁子弹和猴子
otherNode.destroy();
this.node.destroy();
}
}
update(dt: number) {
if (!this.player || typeof YUKA === 'undefined') return;
const currentPos = this.node.worldPosition;
this._vehicle.position.set(currentPos.x, currentPos.y, currentPos.z);
// 1. 状态逻辑
const distToPlayer = Vec3.distance(currentPos, this.player.worldPosition);
if (distToPlayer < this.sightRange) {
this.switchToFlee(this.player.worldPosition);
this._fleeTimer = this.fleeDelay;
} else if (this._state === 'FLEE') {
this._fleeTimer -= dt;
if (this._fleeTimer <= 0) this.switchToWander();
}
this._entityManager.update(dt);
// 2. 障碍物检测
const velocity = this._vehicle.velocity;
const moveDir = new Vec3(velocity.x, 0, velocity.z).normalize();
const forwardRay = new geometry.Ray(currentPos.x, currentPos.y + 0.5, currentPos.z, moveDir.x, 0, moveDir.z);
let isBlocked = false;
if (PhysicsSystem.instance.raycast(forwardRay)) {
const results = PhysicsSystem.instance.raycastResults;
for (let res of results) {
// 检查是否碰撞到障碍物(例如岩石)
if (res.collider.node.layer === this.obstacleLayerValue && res.distance < 1.2) {
isBlocked = true;
console.log("地形检测");
break;
}
}
}
// 3. 位移和基于层级的地面贴合
if (!isBlocked) {
const nextX = currentPos.x + (velocity.x * dt);
const nextZ = currentPos.z + (velocity.z * dt);
const groundY = this.getGroundHeight(new Vec3(nextX, currentPos.y, nextZ));
this.node.setWorldPosition(new Vec3(nextX, groundY, nextZ));
} else {
this._vehicle.velocity.set(0, 0, 0);
}
// 4. 平滑旋转
if (velocity.length() > 0.1) {
const targetQuat = new Quat();
Quat.fromViewUp(targetQuat, moveDir, Vec3.UP);
const finalQuat = new Quat();
Quat.slerp(finalQuat, this.node.worldRotation, targetQuat, 0.1);
this.node.setWorldRotation(finalQuat);
}
this._rb.setLinearVelocity(Vec3.ZERO);
this._rb.setAngularVelocity(Vec3.ZERO);
}
private getGroundHeight(pos: Vec3): number {
const ray = new geometry.Ray(pos.x, pos.y + 10, pos.z, 0, -1, 0);
if (PhysicsSystem.instance.raycast(ray)) {
const results = PhysicsSystem.instance.raycastResults;
for (let res of results) {
// 使用层级检测地面
if (res.collider.node.layer === this.groundLayerValue) {
return res.hitPoint.y;
console.log("地形检测");
}
}
}
return pos.y;
}
private switchToFlee(targetPos: Vec3) {
if (this._state === 'FLEE') {
if (this._vehicle.steering.behaviors.length > 0) {
this._vehicle.steering.behaviors[0].target.set(targetPos.x, targetPos.y, targetPos.z);
}
return;
}
this._state = 'FLEE';
console.log("逃跑模式");
this._vehicle.maxSpeed = this.fleeSpeed;
this._vehicle.steering.clear();
this._vehicle.steering.add(new YUKA.FleeBehavior(new YUKA.Vector3(targetPos.x, targetPos.y, targetPos.z)));
}
private switchToWander() {
this._state = 'WANDER';
this._vehicle.maxSpeed = this.wanderSpeed;
this._vehicle.steering.clear();
this._vehicle.steering.add(new YUKA.WanderBehavior(3, 2, 10));
console.log("随机漫步模式");
}
}
注:此翻译结果仅提供基本转换功能,可能存在一些错误或不完全准确的翻译。
评论 (0)