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