feat: 支持自动寻路算法

This commit is contained in:
2025-09-21 21:31:54 +08:00
parent 35cfabb66b
commit d6aa74cb9d
10 changed files with 1003 additions and 90 deletions

View File

@@ -1,4 +1,5 @@
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view } from 'cc';
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween } from 'cc';
import { TiledMapPathfinder } from './TiledMapPathfinder';
const { ccclass, property } = _decorator;
@ccclass('PlayerController')
@@ -10,8 +11,11 @@ export class PlayerController extends Component {
@property(Camera)
camera: Camera | null = null; // 主摄像机
@property({ range: [1, 20] })
moveSpeed: number = 5; // 移动速度
@property(TiledMapPathfinder)
pathfinder: TiledMapPathfinder | null = null; // 寻路组件
@property({ range: [1, 300] })
moveSpeed: number = 300; // 移动速度(像素/秒)
@property
mapWidth: number = 1080; // 地图宽度
@@ -20,7 +24,8 @@ export class PlayerController extends Component {
mapHeight: number = 2560; // 地图高度
private isMoving: boolean = false;
private targetPosition: Vec3 = new Vec3();
private currentPath: Vec3[] = [];
private currentPathIndex: number = 0;
private originalPosition: Vec3 = new Vec3();
onLoad() {
@@ -40,7 +45,7 @@ export class PlayerController extends Component {
}
private onTouchStart(event: EventTouch) {
if (!this.player || !this.camera) return;
if (!this.player || !this.camera || !this.pathfinder) return;
// 获取触摸点的UI坐标
const touchLocation = event.getUILocation();
@@ -51,7 +56,7 @@ export class PlayerController extends Component {
console.log(`触摸UI坐标: (${touchLocation.x}, ${touchLocation.y})`);
console.log(`转换后世界坐标: (${worldPos.x.toFixed(2)}, ${worldPos.y.toFixed(2)})`);
this.moveToPosition(worldPos);
this.moveToPositionWithPathfinding(worldPos);
}
private screenToWorldPoint(screenPos: { x: number, y: number }): Vec3 {
@@ -82,17 +87,41 @@ export class PlayerController extends Component {
}
private moveToPosition(worldPos: Vec3) {
if (!this.player) return;
private moveToPositionWithPathfinding(worldPos: Vec3) {
if (!this.player || !this.pathfinder) return;
// 停止当前移动
this.stopMovement();
// 限制目标位置在地图边界内
const clampedPos = this.clampPlayerPosition(worldPos);
// 设置目标位置保持Z轴不变
this.targetPosition.set(clampedPos.x, clampedPos.y, this.player.position.z);
this.isMoving = true;
// 检查目标位置是否可行走
if (!this.pathfinder.isWorldPositionWalkable(clampedPos)) {
console.log('目标位置不可行走,寻找最近的可行走位置');
const closestWalkable = this.pathfinder.getClosestWalkablePosition(clampedPos);
if (!closestWalkable) {
console.warn('找不到可行走的位置');
return;
}
clampedPos.set(closestWalkable);
}
console.log(`移动目标: (${clampedPos.x.toFixed(2)}, ${clampedPos.y.toFixed(2)})`);
// 使用寻路算法计算路径
const startPos = this.player.position;
this.currentPath = this.pathfinder.findPath(startPos, clampedPos);
if (this.currentPath.length === 0) {
console.warn('无法找到路径');
return;
}
console.log(`找到路径,包含${this.currentPath.length}个点`);
// 开始沿路径移动
this.currentPathIndex = 0;
this.isMoving = true;
this.moveToNextWaypoint();
}
// 限制玩家位置在地图边界内
@@ -109,41 +138,50 @@ export class PlayerController extends Component {
return clampedPosition;
}
update(deltaTime: number) {
if (!this.isMoving || !this.player) return;
const currentPos = this.player.position;
const distance = Vec3.distance(currentPos, this.targetPosition);
// 如果距离很小,直接到达目标位置
if (distance < 0.1) {
this.player.position = this.targetPosition.clone();
/**
* 移动到路径中的下一个路径点
*/
private moveToNextWaypoint() {
if (!this.player || this.currentPath.length === 0 || this.currentPathIndex >= this.currentPath.length) {
this.isMoving = false;
console.log('到达目标位置');
console.log('路径移动完成');
return;
}
// 计算移动方向
const direction = new Vec3();
Vec3.subtract(direction, this.targetPosition, currentPos);
direction.normalize();
const targetPos = this.currentPath[this.currentPathIndex];
const currentPos = this.player.position;
// 计算这一帧应该移动距离
const moveDistance = this.moveSpeed * deltaTime * 100; // 增加移动速度倍数
// 计算移动距离和时间
const distance = Vec3.distance(currentPos, targetPos);
const moveTime = distance / this.moveSpeed;
// 如果剩余距离小于这一帧要移动的距离,直接到达目标
if (distance <= moveDistance) {
this.player.position = this.targetPosition.clone();
this.isMoving = false;
console.log('到达目标位置');
} else {
// 正常移动
const newPosition = new Vec3();
Vec3.scaleAndAdd(newPosition, currentPos, direction, moveDistance);
console.log(`移动到路径点${this.currentPathIndex}: (${targetPos.x.toFixed(2)}, ${targetPos.y.toFixed(2)})`);
// 确保新位置在地图边界内
const clampedNewPosition = this.clampPlayerPosition(newPosition);
this.player.position = clampedNewPosition;
// 使用缓动移动到目标位置
tween(this.player)
.to(moveTime, { position: targetPos }, {
onComplete: () => {
this.currentPathIndex++;
this.moveToNextWaypoint();
}
})
.start();
}
/**
* 停止当前移动
*/
private stopMovement() {
if (this.player) {
tween(this.player).stop();
}
this.isMoving = false;
this.currentPath = [];
this.currentPathIndex = 0;
}
update(deltaTime: number) {
// 更新逻辑现在主要由缓动系统处理
// 这里可以添加其他需要每帧更新的逻辑
}
}