perf(player): 优化移动方向计算和道具飞行动画
- 改进移动方向计算逻辑,从移动过程中持续更新改为移动开始前计算一次,提升性能 - 优化道具飞向玩家的动画,使用世界坐标和正确的坐标转换 - 移除触摸开始时自动隐藏弹窗的逻辑 - 调整方向判断算法,优先判断水平方向,更符合梦幻西游风格
This commit is contained in:
@@ -152,7 +152,6 @@ export class PlayerController extends Component {
|
||||
|
||||
private onTouchStart(event: EventTouch) {
|
||||
if (this.activePopup) {
|
||||
this.hideActivePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -422,14 +421,13 @@ export class PlayerController extends Component {
|
||||
this.lastTargetPosition.set(targetPos);
|
||||
this.lastPosition.set(currentPos);
|
||||
|
||||
// 在移动前计算并设置方向(只计算一次)
|
||||
this.updateMovementDirectionOnce(currentPos, targetPos);
|
||||
|
||||
// 使用缓动移动到目标位置
|
||||
this.moveTween = tween(this.player)
|
||||
.to(moveTime, { position: targetPos }, {
|
||||
easing: 'linear', // 使用线性插值,保持匀速移动
|
||||
onUpdate: (target: Node) => {
|
||||
// 在移动过程中更新动画方向
|
||||
this.updateMovementDirection(target.position);
|
||||
},
|
||||
onComplete: () => {
|
||||
this.currentPathIndex++;
|
||||
this.moveToNextWaypoint();
|
||||
@@ -465,6 +463,11 @@ export class PlayerController extends Component {
|
||||
|
||||
console.log(`开始平滑路径移动,总距离: ${totalDistance.toFixed(2)}, 总时间: ${totalTime.toFixed(2)}秒`);
|
||||
|
||||
// 在移动前计算并设置方向(只计算一次)
|
||||
const startPos = this.player.position.clone();
|
||||
const finalTargetPos = this.currentPath[this.currentPath.length - 1];
|
||||
this.updateMovementDirectionOnce(startPos, finalTargetPos);
|
||||
|
||||
// 创建连续的路径移动
|
||||
this.moveTween = tween(this.player)
|
||||
.to(totalTime, { position: this.currentPath[this.currentPath.length - 1] }, {
|
||||
@@ -474,7 +477,6 @@ export class PlayerController extends Component {
|
||||
const currentPos = this.getPositionOnPath(ratio);
|
||||
if (currentPos) {
|
||||
target.position = currentPos;
|
||||
this.updateMovementDirection(currentPos);
|
||||
}
|
||||
},
|
||||
onComplete: () => {
|
||||
@@ -531,23 +533,17 @@ export class PlayerController extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* 在移动过程中更新动画方向
|
||||
* 在移动开始前计算一次方向(梦幻西游风格:点击一次屏幕只计算一次方向)
|
||||
* 算法:优先判断水平方向(左/右),只有当水平方向不明显时才判断垂直方向
|
||||
*/
|
||||
private updateMovementDirection(currentPos: Vec3) {
|
||||
if (!this.player || this.currentPath.length === 0) {
|
||||
private updateMovementDirectionOnce(startPos: Vec3, targetPos: Vec3) {
|
||||
if (!this.player) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算移动方向(基于下一路径点)
|
||||
let targetPos: Vec3;
|
||||
if (this.currentPathIndex < this.currentPath.length - 1) {
|
||||
targetPos = this.currentPath[this.currentPathIndex + 1];
|
||||
} else {
|
||||
targetPos = this.currentPath[this.currentPath.length - 1];
|
||||
}
|
||||
|
||||
const deltaX = targetPos.x - currentPos.x;
|
||||
const deltaY = targetPos.y - currentPos.y;
|
||||
// 计算移动方向(基于起始位置和目标位置)
|
||||
const deltaX = targetPos.x - startPos.x;
|
||||
const deltaY = targetPos.y - startPos.y;
|
||||
|
||||
// 如果移动距离很小,不更新动画
|
||||
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
@@ -555,17 +551,19 @@ export class PlayerController extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算主要移动方向
|
||||
const absX = Math.abs(deltaX);
|
||||
const absY = Math.abs(deltaY);
|
||||
// 梦幻西游方向判断逻辑:
|
||||
// 1. 优先判断水平方向:左上、左下、左都算左边;右上、右下、右都算右边
|
||||
// 2. 只有当水平方向不明显时(接近垂直),才判断垂直方向
|
||||
|
||||
// 更新当前方向
|
||||
if (absX > absY) {
|
||||
// 水平移动为主
|
||||
this.currentDirection = deltaX < 0 ? 3 : 5;
|
||||
// 设置一个阈值,当水平方向的绝对值大于这个阈值时,优先判断水平方向
|
||||
const horizontalThreshold = 0.5; // 可以根据需要调整这个值
|
||||
|
||||
if (Math.abs(deltaX) > horizontalThreshold) {
|
||||
// 水平方向明显,优先判断左右
|
||||
this.currentDirection = deltaX < 0 ? 3 : 5; // 3表示左,5表示右
|
||||
} else {
|
||||
// 垂直移动为主
|
||||
this.currentDirection = deltaY < 0 ? 3 : 5;
|
||||
// 水平方向不明显,判断垂直方向
|
||||
this.currentDirection = deltaY < 0 ? 3 : 5; // 3表示上,5表示下
|
||||
}
|
||||
|
||||
// 切换到对应的动画(只传递基础动画名称)
|
||||
@@ -1067,8 +1065,8 @@ export class PlayerController extends Component {
|
||||
|
||||
console.log('创建道具飞向玩家的动画');
|
||||
|
||||
// 获取玩家位置
|
||||
const playerPos = this.player.position.clone();
|
||||
// 获取玩家节点的世界坐标(中心位置)
|
||||
const playerWorldPos = this.player.worldPosition.clone();
|
||||
|
||||
// 创建所有道具的飞行动画承诺
|
||||
const flyPromises: Promise<void>[] = [];
|
||||
@@ -1081,7 +1079,7 @@ export class PlayerController extends Component {
|
||||
const originalPos = prop.position.clone();
|
||||
|
||||
// 计算飞行时间(根据距离调整)
|
||||
const distance = Vec3.distance(originalPos, playerPos);
|
||||
const distance = Vec3.distance(originalPos, playerWorldPos);
|
||||
const flyDuration = Math.max(0.5, distance / 500); // 最少0.5秒,速度500像素/秒
|
||||
|
||||
// 添加延迟,让道具依次飞向玩家
|
||||
@@ -1093,9 +1091,30 @@ export class PlayerController extends Component {
|
||||
// 创建飞行动画的承诺
|
||||
const flyPromise = new Promise<void>((resolve) => {
|
||||
this.scheduleOnce(() => {
|
||||
// 将玩家的世界坐标转换为道具父节点的本地坐标
|
||||
const propParent = prop.parent;
|
||||
let targetPos: Vec3;
|
||||
|
||||
if (propParent) {
|
||||
const parentTransform = propParent.getComponent(UITransform);
|
||||
if (parentTransform) {
|
||||
targetPos = parentTransform.convertToNodeSpaceAR(playerWorldPos);
|
||||
} else {
|
||||
// 如果没有UITransform组件,使用简单的坐标转换
|
||||
targetPos = new Vec3(
|
||||
playerWorldPos.x - propParent.worldPosition.x,
|
||||
playerWorldPos.y - propParent.worldPosition.y,
|
||||
playerWorldPos.z - propParent.worldPosition.z
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 如果道具没有父节点,直接使用世界坐标
|
||||
targetPos = playerWorldPos.clone();
|
||||
}
|
||||
|
||||
tween(prop)
|
||||
.to(flyDuration, {
|
||||
position: new Vec3(playerPos.x, playerPos.y, playerPos.z)
|
||||
position: targetPos
|
||||
}, {
|
||||
easing: 'quadOut',
|
||||
onComplete: () => {
|
||||
|
||||
Reference in New Issue
Block a user