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

Unity蜘蛛侠游戏摆荡功能异常:玩家穿墙穿地求助

蜘蛛侠摆荡穿模问题解决思路

我正在制作一款蜘蛛侠游戏,已实现摆荡功能,但玩家在摆荡过程中会穿过墙体和地面。

摆荡功能实现代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]

public class Pendulum
{
public Transform bob_tr;

public Tether tether;

public Arm arm;

public Bob bob;

public bool Swinging;

Vector3 previousPosition;

public GameObject Player;


public void Initialize()
{
    bob_tr.transform.position = Player.transform.position;
    bob_tr.transform.parent = tether.tether_tr;
    Swinging = false;
}

public Vector3 MoveBob(Vector3 pos , float time)
{

    if (Input.GetMouseButtonDown(0))
    {
        Swinging = true;
    }
    else if (Input.GetMouseButtonUp(0))
    {
        Swinging = false;
    }

    if(Swinging == false)
    {
        arm.length = Vector3.Distance(bob_tr.transform.localPosition, tether.position);
    }
    
    bob.velocity += GetConstrainedVelocity(pos , previousPosition , time);
    bob.ApplyGravity();
    bob.ApplyDamping();
    bob.CapMaxSpeed();
    
    pos += bob.velocity * time;
    
    if(Vector3.Distance(pos , tether.position) < arm.length)
    {
        pos = Vector3.Normalize(pos - tether.position) * arm.length;
        return pos;
    }
    
    previousPosition = pos;
    
    return pos;
}

public Vector3 MoveBob(Vector3 pos , Vector3 prevPos , float time)
{

    if (Input.GetMouseButtonDown(0))
    {
        Swinging = true;
    }
    else if (Input.GetMouseButtonUp(0))
    {
        Swinging = false;
    }

    if(Swinging == false)
    {
        arm.length = Vector3.Distance(bob_tr.transform.localPosition, tether.position);
    }

    bob.velocity += GetConstrainedVelocity(pos , prevPos , time);
    bob.ApplyGravity();
    bob.ApplyDamping();
    bob.CapMaxSpeed();
    
    pos += bob.velocity * time;
    
    previousPosition = pos;
    
    return pos;
}

public Vector3 GetConstrainedVelocity(Vector3 currentPos, Vector3 previousPosition , float time)
{
    float distanceToTether;
    Vector3 constrainedPosition;
    Vector3 predictedPosition;
    
    
    distanceToTether = Vector3.Distance(currentPos , tether.position);
    
    if(distanceToTether > arm.length)
    {
        constrainedPosition = Vector3.Normalize(currentPos - tether.position) * arm.length;
        predictedPosition = (constrainedPosition - previousPosition) / time;
        return predictedPosition;
    }
    return Vector3.zero;
}


public Vector3 Fall(Vector3 pos , float time)
{
    arm.length = Vector3.Distance(bob_tr.transform.localPosition, tether.position);

    bob.ApplyGravity();
    bob.ApplyDamping();
    bob.CapMaxSpeed();
    
    pos += bob.velocity * time;
    return pos;
}

}

问题核心分析

当前代码仅处理了摆荡的绳索距离约束逻辑,完全未加入碰撞检测逻辑,玩家位置直接通过速度累加更新,导致穿透场景碰撞体。

解决方案

  1. 添加路径碰撞检测
    在更新玩家位置后,检测上一位置到目标位置的路径是否有障碍物,若有则修正位置并调整速度:
// 在pos += bob.velocity * time;之后插入
Vector3 direction = pos - previousPosition;
float distance = direction.magnitude;
// 用CapsuleCast更贴合角色碰撞体积,需传入角色胶囊体的上下点和半径
if (Physics.CapsuleCast(previousPosition + Vector3.up, previousPosition - Vector3.up, 0.5f, direction.normalized, out RaycastHit hit, distance))
{
    pos = hit.point;
    // 可选:添加碰撞反弹效果
    bob.velocity = Vector3.Reflect(bob.velocity, hit.normal) * 0.6f;
}
  1. 改用Unity物理组件处理碰撞
  • 若使用CharacterController:替换直接位置更新为controller.Move(bob.velocity * time),利用内置碰撞逻辑自动阻挡穿透。
  • 若使用Rigidbody:将摆荡计算的速度赋值给rigidbody.velocity,开启碰撞检测并冻结不必要的旋转轴,让物理引擎处理碰撞交互。
  1. 绳索路径碰撞检测
    在GetConstrainedVelocity方法中,添加Physics.Linecast检测锚点到玩家当前位置的连线是否被阻挡,若阻挡则终止摆荡,避免玩家被绳索拉进障碍物内部。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 11:36:06