【问题标题】:Character is not colliding with other other objects in Unity3D角色没有与 Unity3D 中的其他其他对象发生碰撞
【发布时间】:2015-09-30 00:55:51
【问题描述】:

我现在正在开发一款游戏(第一个 3D 风格的游戏),但我遇到了我的角色碰撞问题。我有一个 Player 对象,它有另一个对象作为真正的可移动角色(现在我只有一个)。我的角色也有刚体和盒子对撞机。我已经制作了一个关卡(带有手动放置的平台),并且我想避免我的平台掉落,而用户控制它。我试图在平台的一侧放置一个立方体,并附有盒子碰撞器,但由于某些原因角色没有检测到碰撞。我希望我的角色被对撞机“立方体”阻止,但它没有发生。

我使用这个脚本来移动我的对象(附加到我的角色 Player 对象):

public class Bounce : MonoBehaviour {


float lerpTime;
float currentLerpTime;
float perc = 1;

Vector3 startPos;
Vector3 endPos;

bool firstInput;
public bool justJump;

public GameObject player;


// Update is called once per frame
void Update () {
    if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
        if (perc == 1) {
            lerpTime = 1;
            currentLerpTime = 0;
            firstInput = true;
            justJump = true;
        }
    }
    startPos = gameObject.transform.position;


    if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
        endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));

    }
    if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
        endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f));
    }

    if (firstInput == true) {
        currentLerpTime += Time.deltaTime * 5;
        perc = currentLerpTime / lerpTime;
        gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
        if (perc > 0.8f)  {
            perc = 1;
        }

        if (Mathf.Round(perc) == 1) {
            justJump = false;
        }
    }


}

void OnCollisionEnter(Collision collision) {
    Debug.Log("!!!!!!!");
}
}

我在角色本身上使用了这个脚本:(旋转和动画)

代码(csharp):

public class AnimationController : MonoBehaviour {

Animator anim;
public GameObject thePlayer;

// Use this for initialization
void Start () {
    anim = gameObject.GetComponent<Animator>();
}

// Update is called once per frame
void Update () {
    Bounce bounceScript = thePlayer.GetComponent<Bounce>();
    if (bounceScript.justJump == true) {
        anim.SetBool("Jump", true);
    }
    else {
        anim.SetBool("Jump", false);
    }

    if (Input.GetButtonDown("right")) {
        //transform.rotation *= Quaternion.Euler(0,30,0);
        transform.RotateAround(transform.position, Vector3.up, 90);
    }
    if (Input.GetButtonDown("left")) {
        transform.Rotate (0, -90, 0, 0);
    }
}
}

只有当立方体不是 isKinematic 时才会发生碰撞,但它不会因为某种原因阻止我的玩家穿过立方体。

我已经阅读了一些有关此类问题的网站,但还没有任何帮助。

如果您能给我任何代码改进,那就太好了:)

编辑1:

抱歉,这么晚才回复,这几天我的游戏什么也做不了。今天我尝试用光线投射做一些事情,你可以看到我的代码,我第一次尝试只是在更新方法中:

void Update () {
        if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
            if (perc == 1) {
                lerpTime = 1;
                currentLerpTime = 0;
                firstInput = true;
                justJump = true;
            }
        }
        startPos = gameObject.transform.position;

    /*  if (Input.GetButtonDown("right") && gameObject.transform.position == endPos) {
            //endPos = new Vector3(transform.position.x + 0.5f, transform.position.y, transform.position.z);

        }
        if (Input.GetButtonDown("left") && gameObject.transform.position == endPos) {
            endPos = new Vector3(transform.position.x - 0.5f, transform.position.y, transform.position.z);
        }*/


        Vector3 fwd = player.transform.TransformDirection(Vector3.forward);
        RaycastHit objectHit;

        if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
            if (objectHit.collider.tag == "Wall") {
                Debug.Log("WALL RAYCAST HIT!");
            }
        }


        if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
            endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));

        }
        if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
            //endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f)); 
        }


        if (firstInput == true) {
                currentLerpTime += Time.deltaTime * 5;
                perc = currentLerpTime / lerpTime;
                gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
                if (perc > 0.8f)  {
                    perc = 1;
                }

                if (Mathf.Round(perc) == 1) {
                    justJump = false;
                }
            }
    }

有了这个,我可以一次获得 2-3 次调试日志 WALL RAYCAST HIT,但只能获得一次。当我移动角色时,它不会再次出现,出于某种原因(我认为应该是因为在每一帧中都会调用更新方法)。

虽然当我将它放在 Input.GetButtonDown("up") 方法中时,它不会记录任何内容:

if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
             fwd = player.transform.TransformDirection(Vector3.forward);


            if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
                if (objectHit.collider.tag == "Wall") {
                    Debug.Log("WALL RAYCAST HIT!");
                }
            }
            endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));

        }

【问题讨论】:

    标签: unity3d


    【解决方案1】:

    当您更新 transform.position 时,您实际上将您的对象“传送”到新位置。即使您使用 Lerp 函数之类的功能顺利完成此操作,就像您在移动脚本中所做的那样,Unity 也知道您正在将对象传送到新坐标。

    这没有错,所有游戏都是这样工作的。像 Lerp 这样的函数只是制造了运动的错觉,所以玩家跌倒就像角色实际上从一个点移动到另一个点一样。

    发生的情况是你的脚本不断告诉角色移动到一个新位置,尽管它的路径上有任何物体。发生了碰撞,但您的 Update 函数仍将字符置于 ints 新位置。

    我可以想到两种可能的方法来解决这个问题:

    1. 为您的移动脚本创建一个 OnCollisionEnter() 函数,以某种方式停止您的移动。通过像使用 firstInput 一样创建标志,您可以实现此目的。

    2. 您可以使用刚体来处理您的移动和碰撞,而不是更新您的 transform.position。这样,每次您需要移动角色时,您都需要为角色刚体添加一些速度,而不是直接更新 transform.position。

    由于您的角色不会以固定的方式移动,而是以“一次一步”的方式移动,我认为第一个解决方案更适合您。

    代码会是这样的

    void OnCollisionenter(Collision collision)
    {
        collided = true;
    }
    

    你的移动脚本的结尾应该更新为

    if(!collided)
    {
        if (firstInput == true) {
            currentLerpTime += Time.deltaTime * 5;
            perc = currentLerpTime / lerpTime;
            transform.position = Vector3.Lerp(startPos, endPos, perc);
            if (perc > 0.8f)  {
                perc = 1;
            }
    
            if (Mathf.Round(perc) == 1) {
                justJump = false;
            }
        }
    }
    else
    {
        // Remember to reset this when you stop your character
        endPos = transform.position;
        collided = false;
    }
    

    这次我无法在写到这里之前测试代码,所以你可能需要在它工作之前做一些更改。

    ps:我认为您不需要 firstInput 变量。一旦设置为 true,您就再也不会将其设置为 false。此外,Input.GetButtonDown() 函数只会在按下按钮的第一帧返回 true,这就是我猜你在创建 firstInput 时的意图。

    ps2:我的解决方案为您的类添加了一个 collided 布尔属性,所以不要忘记添加一行 private bool collided; 与您的其他类属性。另外,请阅读关于我在其他问题上向您推荐的状态机模式的那一章。创建这种类型的控制属性如 collided 布尔值不是一个好习惯,如果您已经实现了状态机,则可以避免这种情况。

    【讨论】:

    • 感谢您的帮助!我已经尝试过您的解决方案,但由于某种原因,它穿过了立方体/墙壁,并且不会停在需要的地方。我将对刚体速度进行一些搜索。
    • 在您的第一个代码中,您是否在控制台上收到"!!!!!!!" 消息?如果你没有,你可能在你的盒子或角色中错过了一个对撞机。无论如何,我在这里构建一个原型来检查代码,你很快就会写给你
    • 看来你需要给玩家添加一个刚体。我在这里做了一些测试,但在我的广告可用时无法找到任何好的解决方案。我可能会尝试更晚一点。关于如何做到这一点的一个建议是保持领先于玩家,在他开始任何移动之前,您可以使用光线投射来验证其前进方向是否有障碍物,这样您就可以在移动开始之前停止移动。我认为这对于您所拥有的运动是有意义的,并且易于编码,因为在您的情况下,您只需要检查四个方向。
    【解决方案2】:

    嘿,我有一个类似的问题,我正在使用来自 Mixamo.com 的动画模型,我注意到由于某种奇怪的原因,尽管有碰撞器,但角色并没有与边界发生碰撞,由于某种原因,直到我添加它才起作用CharacterController 到我的模型而不是碰撞器只需搜索 CharacterController 并添加它,就像您将任何脚本或刚体添加到游戏对象一样。

    希望它有效 XD 问候

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多