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

Unity 3D FPS跑酷游戏:墙跑问题及玩家到碰撞墙向量获取

解决方案:墙跑优化与碰撞向量获取

嘿,很高兴看到你在做校园FPS跑酷项目,已经搞定大部分功能超棒的!针对你遇到的两个核心问题,我给你一些实用的落地建议:

一、解决墙跑时易脱离墙面的问题

墙跑和空中移动的逻辑冲突,本质是两种状态的移动优先级没理清,试试这几个调整方向:

  • 拆分状态逻辑:明确区分「墙跑状态」和「普通空中状态」,当检测到玩家处于墙跑时,暂时禁用或弱化普通空中移动的代码逻辑。比如只允许玩家沿墙面的切线方向移动,而非自由的3D空间移动。
  • 添加操作容错阈值:不要一检测到玩家输入远离墙面就立刻触发掉落。可以设置一个角度阈值(比如15°),当玩家输入方向与墙面法线的夹角在阈值内时,依然保持墙跑状态,给玩家操作的缓冲空间。
  • 强制贴墙的物理修正:在墙跑时给玩家施加一个指向墙面的小力,确保玩家不会因为轻微的移动输入就脱离墙面。同时把玩家的移动向量投影到墙面的切线平面上,让移动始终贴合墙面。

举个简单的代码示例(假设你用Rigidbody控制玩家):

public bool isWallRunning;
public Vector3 currentWallNormal; // 记录当前墙面的法线
public float wallRunSpeed = 8f;
public float wallStickForce = 5f;
public Rigidbody playerRB;

void Update()
{
    if (isWallRunning)
    {
        // 获取玩家输入
        Vector3 inputDir = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        // 将输入向量投影到墙面切线平面,限制移动方向
        Vector3 moveDir = Vector3.ProjectOnPlane(inputDir, currentWallNormal).normalized;
        // 应用墙跑移动
        playerRB.velocity = new Vector3(moveDir.x * wallRunSpeed, playerRB.velocity.y, moveDir.z * wallRunSpeed);
        // 添加贴墙力,防止脱离
        playerRB.AddForce(-currentWallNormal * wallStickForce, ForceMode.Force);
    }
    else
    {
        // 你的普通空中移动逻辑
        ApplyAirMovement();
    }
}

二、获取玩家原点到碰撞墙壁的向量

这个需求可以通过碰撞检测的两种方式实现,根据你的墙跑检测逻辑选择:

方式1:用Raycast检测时获取

如果你的墙跑是通过射线检测周围墙面触发的,可以在射线命中时直接计算向量:

public Transform playerTransform;
public float wallCheckDistance = 1.5f;

void CheckForWall()
{
    RaycastHit hit;
    // 检测玩家左右两侧的墙面(可根据需求调整射线方向)
    bool hitLeft = Physics.Raycast(playerTransform.position, -playerTransform.right, out hit, wallCheckDistance);
    bool hitRight = Physics.Raycast(playerTransform.position, playerTransform.right, out hit, wallCheckDistance);

    if (hitLeft || hitRight)
    {
        isWallRunning = true;
        currentWallNormal = hit.normal;
        // 玩家原点到碰撞墙壁的向量(碰撞点 - 玩家位置)
        Vector3 playerToWall = hit.point - playerTransform.position;
        // 如果你需要的是墙面指向玩家的向量,反过来就行:playerTransform.position - hit.point
    }
    else
    {
        isWallRunning = false;
    }
}

方式2:用OnCollisionStay回调获取

如果你的墙跑是通过碰撞接触触发的,可以在碰撞回调里遍历接触点计算:

private void OnCollisionStay(Collision collision)
{
    if (collision.gameObject.CompareTag("Wall") && /* 其他墙跑触发条件 */)
    {
        isWallRunning = true;
        foreach (ContactPoint contact in collision.contacts)
        {
            currentWallNormal = contact.normal;
            // 玩家原点到碰撞点的向量
            Vector3 playerToWall = contact.point - transform.position;
            // 这里可以根据需要存储或使用这个向量
        }
    }
}

注意:如果玩家用的是胶囊体,玩家原点如果在胶囊中心,你可以根据需求调整计算起点(比如胶囊底部位置),让向量更贴合实际需求。

这些方法应该能帮你解决当前的问题,要是有具体的代码细节或者场景特殊情况,还可以再调整优化哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:42:28