feat(player): 优化角色移动方向更新机制

改进了角色在寻路移动过程中的方向判断算法,通过聚合未来路径节点的方向信息来减少转向突变,提升移动动画的流畅性。同时调整了碰撞体参数和场景布局以优化游戏体验。
This commit is contained in:
richarjiang
2025-10-21 09:49:40 +08:00
parent f70bf7ba14
commit a8dff683cc
2 changed files with 53 additions and 47 deletions

View File

@@ -332,8 +332,8 @@
"_prefab": null, "_prefab": null,
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": -44.282, "x": -51.831,
"y": -755.631, "y": -759.406,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -602,7 +602,7 @@
"a": 255 "a": 255
}, },
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "1c7b5663-daeb-4a52-970f-2c530866798f@f9941", "__uuid__": "9ff0a243-0244-4517-9cd3-b95fd18ce759@f9941",
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
}, },
"_type": 0, "_type": 0,
@@ -1468,13 +1468,13 @@
"_restitution": 0, "_restitution": 0,
"_offset": { "_offset": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": -0.1,
"y": 5 "y": 5
}, },
"_size": { "_size": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 61.4, "width": 55.1,
"height": 129.1 "height": 114
}, },
"_id": "634GiEUhBB8Z1aGzkT6Zyd" "_id": "634GiEUhBB8Z1aGzkT6Zyd"
}, },
@@ -3591,13 +3591,13 @@
"_restitution": 0, "_restitution": 0,
"_offset": { "_offset": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 6.4, "x": 1.7,
"y": 3.7 "y": -1.2
}, },
"_size": { "_size": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 108, "width": 101,
"height": 175 "height": 147.1
}, },
"_id": "cdIXFZyqRL66Jq6KOCWAZ6" "_id": "cdIXFZyqRL66Jq6KOCWAZ6"
}, },

View File

@@ -1,4 +1,4 @@
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, BoxCollider2D, Contact2DType, Label, Color, Canvas, UITransform, AudioSource, director } from 'cc'; import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, BoxCollider2D, Contact2DType, Label, Color, Canvas, UITransform, AudioSource, director, PhysicsSystem2D, EPhysics2DDrawFlags } from 'cc';
import { TiledMapPathfinder } from './TiledMapPathfinder'; import { TiledMapPathfinder } from './TiledMapPathfinder';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -63,6 +63,10 @@ export class PlayerController extends Component {
// 道具列表 // 道具列表
private props: Node[] = []; private props: Node[] = [];
// 行走方向相关参数
private readonly directionLookAheadSteps = 2; // 更新方向时向前查看的路径节点数
private readonly minDirectionUpdateDistance = 1; // 小于该距离时不刷新方向,避免抖动
private guideNode: Node | null = null; private guideNode: Node | null = null;
private activePopup: Node | null = null; private activePopup: Node | null = null;
private activePopupName: string | null = null; private activePopupName: string | null = null;
@@ -422,8 +426,8 @@ export class PlayerController extends Component {
deltaY: number, deltaY: number,
overrides?: { horizontal?: 'Left' | 'Right', vertical?: 'Up' | 'Down' } overrides?: { horizontal?: 'Left' | 'Right', vertical?: 'Up' | 'Down' }
): PlayerDirection { ): PlayerDirection {
const horizontalThreshold = 0.5; const horizontalThreshold = 0.1;
const verticalThreshold = 0.5; const verticalThreshold = 0.1;
let horizontal: 'Left' | 'Right' = overrides?.horizontal ?? (this.isFacingLeft() ? 'Left' : 'Right'); let horizontal: 'Left' | 'Right' = overrides?.horizontal ?? (this.isFacingLeft() ? 'Left' : 'Right');
if (!overrides?.horizontal && Math.abs(deltaX) > horizontalThreshold) { if (!overrides?.horizontal && Math.abs(deltaX) > horizontalThreshold) {
@@ -696,32 +700,51 @@ export class PlayerController extends Component {
// 计算当前在路径中的大致位置 // 计算当前在路径中的大致位置
const pathLength = this.currentPath.length; const pathLength = this.currentPath.length;
const currentPathIndex = Math.floor(ratio * (pathLength - 1)); const approxIndex = Math.floor(ratio * (pathLength - 1));
if (approxIndex >= pathLength - 1) {
// 确保不超出路径范围
const nextIndex = Math.min(currentPathIndex + 1, pathLength - 1);
// 如果已经到达最后一个路径点,不再更新方向
if (currentPathIndex >= pathLength - 1) {
return; return;
} }
// 获取当前路径点和下一个路径点 const currentPathIndex = Math.max(0, approxIndex);
const currentPathPoint = this.currentPath[currentPathIndex]; const nextIndex = currentPathIndex + 1;
const nextPathPoint = this.currentPath[nextIndex]; const maxIndex = Math.min(pathLength - 1, nextIndex + this.directionLookAheadSteps);
// 计算到下一个路径点的方向 let weightedDirX = 0;
const deltaX = nextPathPoint.x - currentPos.x; let weightedDirY = 0;
const deltaY = nextPathPoint.y - currentPos.y; let totalWeight = 0;
let farthestDistance = 0;
// 如果移动距离很小,不更新动画 // 聚合未来若干路径节点的方向信息,减缓转向突变
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); for (let i = nextIndex; i <= maxIndex; i++) {
if (distance < 1) { const samplePoint = this.currentPath[i];
const deltaX = samplePoint.x - currentPos.x;
const deltaY = samplePoint.y - currentPos.y;
const distanceToPoint = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
farthestDistance = Math.max(farthestDistance, distanceToPoint);
if (distanceToPoint < 0.0001) {
continue;
}
const weight = i - currentPathIndex;
weightedDirX += (deltaX / distanceToPoint) * weight;
weightedDirY += (deltaY / distanceToPoint) * weight;
totalWeight += weight;
}
if (totalWeight === 0 || farthestDistance < this.minDirectionUpdateDistance) {
return;
}
const averagedDirX = weightedDirX / totalWeight;
const averagedDirY = weightedDirY / totalWeight;
const averagedMagnitude = Math.sqrt(averagedDirX * averagedDirX + averagedDirY * averagedDirY);
if (averagedMagnitude < 0.1) {
return; return;
} }
// 计算新的方向 // 计算新的方向
const newDirection = this.resolveDirectionFromDelta(deltaX, deltaY); const newDirection = this.resolveDirectionFromDelta(averagedDirX, averagedDirY);
// 只有当方向发生显著变化时才更新 // 只有当方向发生显著变化时才更新
if (newDirection !== this.currentDirection) { if (newDirection !== this.currentDirection) {
@@ -1346,23 +1369,6 @@ export class PlayerController extends Component {
} }
private setNodeWorldPosition(node: Node, worldPos: Vec3) {
const parent = node.parent;
if (!parent) {
node.setWorldPosition(worldPos);
return;
}
const parentTransform = parent.getComponent(UITransform);
if (parentTransform) {
const localResult = parentTransform.convertToNodeSpaceAR(new Vec3(worldPos.x, worldPos.y, worldPos.z));
node.setPosition(localResult);
return;
}
node.setWorldPosition(worldPos);
}
/** /**
* 播放生命值标签强调动画(成功时) * 播放生命值标签强调动画(成功时)
*/ */