From a8dff683cc688c24b41f4df22ae71f9a60a77fd1 Mon Sep 17 00:00:00 2001 From: richarjiang Date: Tue, 21 Oct 2025 09:49:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(player):=20=E4=BC=98=E5=8C=96=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E7=A7=BB=E5=8A=A8=E6=96=B9=E5=90=91=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进了角色在寻路移动过程中的方向判断算法,通过聚合未来路径节点的方向信息来减少转向突变,提升移动动画的流畅性。同时调整了碰撞体参数和场景布局以优化游戏体验。 --- assets/scenes/main.scene | 20 ++++---- assets/scripts/PlayerController.ts | 80 ++++++++++++++++-------------- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/assets/scenes/main.scene b/assets/scenes/main.scene index 8ceb260..30e60f6 100644 --- a/assets/scenes/main.scene +++ b/assets/scenes/main.scene @@ -332,8 +332,8 @@ "_prefab": null, "_lpos": { "__type__": "cc.Vec3", - "x": -44.282, - "y": -755.631, + "x": -51.831, + "y": -759.406, "z": 0 }, "_lrot": { @@ -602,7 +602,7 @@ "a": 255 }, "_spriteFrame": { - "__uuid__": "1c7b5663-daeb-4a52-970f-2c530866798f@f9941", + "__uuid__": "9ff0a243-0244-4517-9cd3-b95fd18ce759@f9941", "__expectedType__": "cc.SpriteFrame" }, "_type": 0, @@ -1468,13 +1468,13 @@ "_restitution": 0, "_offset": { "__type__": "cc.Vec2", - "x": 0.5, + "x": -0.1, "y": 5 }, "_size": { "__type__": "cc.Size", - "width": 61.4, - "height": 129.1 + "width": 55.1, + "height": 114 }, "_id": "634GiEUhBB8Z1aGzkT6Zyd" }, @@ -3591,13 +3591,13 @@ "_restitution": 0, "_offset": { "__type__": "cc.Vec2", - "x": 6.4, - "y": 3.7 + "x": 1.7, + "y": -1.2 }, "_size": { "__type__": "cc.Size", - "width": 108, - "height": 175 + "width": 101, + "height": 147.1 }, "_id": "cdIXFZyqRL66Jq6KOCWAZ6" }, diff --git a/assets/scripts/PlayerController.ts b/assets/scripts/PlayerController.ts index 826e13a..aff2d93 100644 --- a/assets/scripts/PlayerController.ts +++ b/assets/scripts/PlayerController.ts @@ -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'; const { ccclass, property } = _decorator; @@ -63,6 +63,10 @@ export class PlayerController extends Component { // 道具列表 private props: Node[] = []; + // 行走方向相关参数 + private readonly directionLookAheadSteps = 2; // 更新方向时向前查看的路径节点数 + private readonly minDirectionUpdateDistance = 1; // 小于该距离时不刷新方向,避免抖动 + private guideNode: Node | null = null; private activePopup: Node | null = null; private activePopupName: string | null = null; @@ -422,8 +426,8 @@ export class PlayerController extends Component { deltaY: number, overrides?: { horizontal?: 'Left' | 'Right', vertical?: 'Up' | 'Down' } ): PlayerDirection { - const horizontalThreshold = 0.5; - const verticalThreshold = 0.5; + const horizontalThreshold = 0.1; + const verticalThreshold = 0.1; let horizontal: 'Left' | 'Right' = overrides?.horizontal ?? (this.isFacingLeft() ? 'Left' : 'Right'); if (!overrides?.horizontal && Math.abs(deltaX) > horizontalThreshold) { @@ -696,32 +700,51 @@ export class PlayerController extends Component { // 计算当前在路径中的大致位置 const pathLength = this.currentPath.length; - const currentPathIndex = Math.floor(ratio * (pathLength - 1)); - - // 确保不超出路径范围 - const nextIndex = Math.min(currentPathIndex + 1, pathLength - 1); - - // 如果已经到达最后一个路径点,不再更新方向 - if (currentPathIndex >= pathLength - 1) { + const approxIndex = Math.floor(ratio * (pathLength - 1)); + if (approxIndex >= pathLength - 1) { return; } - // 获取当前路径点和下一个路径点 - const currentPathPoint = this.currentPath[currentPathIndex]; - const nextPathPoint = this.currentPath[nextIndex]; + const currentPathIndex = Math.max(0, approxIndex); + const nextIndex = currentPathIndex + 1; + const maxIndex = Math.min(pathLength - 1, nextIndex + this.directionLookAheadSteps); - // 计算到下一个路径点的方向 - const deltaX = nextPathPoint.x - currentPos.x; - const deltaY = nextPathPoint.y - currentPos.y; + let weightedDirX = 0; + let weightedDirY = 0; + let totalWeight = 0; + let farthestDistance = 0; - // 如果移动距离很小,不更新动画 - const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); - if (distance < 1) { + // 聚合未来若干路径节点的方向信息,减缓转向突变 + for (let i = nextIndex; i <= maxIndex; i++) { + 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; } // 计算新的方向 - const newDirection = this.resolveDirectionFromDelta(deltaX, deltaY); + const newDirection = this.resolveDirectionFromDelta(averagedDirX, averagedDirY); // 只有当方向发生显著变化时才更新 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); - } - /** * 播放生命值标签强调动画(成功时) */