You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决顶视角游戏中玩家贴墙时坐标仍变动的问题?

解决顶视角游戏玩家贴墙移动坐标异常及碰撞检测失效问题

方案一:改用Rigidbody驱动移动(推荐)

Transform.Translate会直接修改物体位置,完全绕过Unity的物理碰撞系统,这就是贴墙时坐标异常、碰撞检测无效的核心原因。改用Rigidbody的物理移动方式,能让引擎自动处理碰撞约束:

  1. 给玩家对象添加Rigidbody组件,设置参数:

    • 勾选Freeze Rotation的X/Y/Z轴(顶视角不需要旋转)
    • 勾选Freeze Position的Y轴(保持平面移动)
    • 将Body Type设为Kinematic(仅靠代码控制移动,不受物理受力影响)或Dynamic(需要受其他物理影响时选择)
  2. 修改移动代码(以Kinematic为例):

private Rigidbody rb;

void Awake()
{
    rb = GetComponent<Rigidbody>();
}

void FixedUpdate()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(horizontal, 0, vertical).normalized;
    
    // 用MovePosition让物理引擎处理碰撞
    rb.MovePosition(rb.position + dir * speed * Time.fixedDeltaTime);
}

如果用Dynamic类型,可改用AddForce控制移动,同时调整Drag参数防止滑动过度:

void FixedUpdate()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(horizontal, 0, vertical).normalized;
    
    rb.AddForce(dir * speed * Time.fixedDeltaTime, ForceMode.Force);
}

方案二:手动射线检测实现碰撞约束

如果不想引入Rigidbody,可以在移动前向输入方向发射短射线,检测是否有墙体/静态物体,再决定是否允许该方向移动:

public float checkDistance = 0.1f; // 射线长度,略大于玩家Collider半径
public LayerMask obstacleLayer; // 指定墙体所在的Layer

void FixedUpdate()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(horizontal, 0, vertical);
    
    // 分别检测X和Z方向的障碍物
    bool canMoveX = !Physics.Raycast(transform.position, Vector3.right * horizontal, checkDistance, obstacleLayer);
    bool canMoveZ = !Physics.Raycast(transform.position, Vector3.forward * vertical, checkDistance, obstacleLayer);
    
    // 只保留可移动方向的输入
    Vector3 moveDir = new Vector3(canMoveX ? horizontal : 0, 0, canMoveZ ? vertical : 0).normalized;
    
    transform.Translate(moveDir * speed * Time.deltaTime);
}

注意:需要给墙体设置独立的Layer,并在obstacleLayer中选择该Layer,避免误检测其他物体。

方案三:修复现有碰撞检测逻辑

如果坚持用Transform.Translate,先排查碰撞检测失效的原因,再调整逻辑:

  • 确保玩家和墙体都添加了Collider组件,且未勾选IsTrigger(除非用触发检测)
  • 检查Edit > Project Settings > Physics中的Layer Collision Matrix,确保玩家所在Layer和墙体所在Layer的碰撞是开启状态
  • 使用OnCollisionStay记录接触方向,过滤输入:
private bool isCollidingLeft, isCollidingRight, isCollidingForward, isCollidingBackward;

void OnCollisionStay(Collision collision)
{
    // 遍历碰撞接触点,判断碰撞方向
    foreach (ContactPoint point in collision.contacts)
    {
        Vector3 normal = point.normal;
        if (normal.x > 0.7f) isCollidingLeft = true;
        if (normal.x < -0.7f) isCollidingRight = true;
        if (normal.z > 0.7f) isCollidingBackward = true;
        if (normal.z < -0.7f) isCollidingForward = true;
    }
}

void OnCollisionExit(Collision collision)
{
    isCollidingLeft = isCollidingRight = isCollidingForward = isCollidingBackward = false;
}

void FixedUpdate()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    
    // 根据碰撞状态过滤输入
    if ((horizontal < 0 && isCollidingLeft) || (horizontal > 0 && isCollidingRight))
        horizontal = 0;
    if ((vertical > 0 && isCollidingForward) || (vertical < 0 && isCollidingBackward))
        vertical = 0;
    
    Vector3 dir = new Vector3(horizontal, 0, vertical).normalized;
    transform.Translate(dir * speed * Time.deltaTime);
}

内容的提问来源于stack exchange,提问作者HarryMA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 08:35:21