【问题标题】:Collider does not always detect OnTriggerEnterCollider 并不总是检测 OnTriggerEnter
【发布时间】:2018-04-08 14:21:59
【问题描述】:

我在阅读“Unity in Action”一书时偶然发现了一个问题。在第 3 章结束时,您将了解一个简单的 fps 游戏的基础知识。它基本上是一个简单的小关卡中的玩家(连接到它的相机),它只存在于形成墙壁和地板等的许多立方体中。这些立方体上都有盒子碰撞器。现在玩家还可以射击移动的敌人,这些敌人也可以射击。这是由 Raycast/RaycastHit 完成的。所有这一切都很完美,所以我想添加一些重新组装弹孔的东西,只需在火球(这是敌人和玩家射击的对象)击中它的墙上实例化一个黑色球体对象。这可行,但有时火球物体只是穿过墙壁。如果它后面还有另一面墙,火球对象会被第二面墙摧毁,并且在第二面墙上而不是在第一面墙上创建所需的球体。

我将火球中的速度从 20 改为 10,然后再改回 20,速度为 10 时,成功率约为 19/20,而速度为 20 时,成功率约为 6/10。

这是火球的代码,它应该检查它是否击中玩家(然后扣除生命值,可以正常工作)或击中敌人(然后敌人摔倒,也可以正常工作)或击中墙壁在这种情况下应该创建球体。

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

 public class Fireball : MonoBehaviour {

 public float speed = 10.0f;
 public int damage = 1;
 [SerializeField] private GameObject wallHit;
 private GameObject _wallHit;

 // Use this for initialization
 void Start () {

 }

 // Update is called once per frame
 void Update () {
     transform.Translate(0,0, speed * Time.deltaTime);
 }

 void OnTriggerEnter(Collider other){
     RaycastHit hit;
     PlayerCharacter player = other.GetComponent<PlayerCharacter>();
     ReactiveTarget target = other.GetComponent<ReactiveTarget>();
     WallBehavior wall = other.GetComponent<WallBehavior>();

     if(player != null){
         player.Hurt(damage);
     }
     if(target != null){
         target.ReactToHit();
     }
     if(wall != null){
         if(Physics.Raycast(transform.position, transform.forward, out hit)){
             wall.WallWasHit(hit);
         }
     }
     Destroy(this.gameObject);
 }
}

如您所见,我尝试的一件事是给每面墙一个 WallBehavior 脚本,如下所示:

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

 public class WallBehavior : MonoBehaviour {
 [SerializeField] private GameObject wallHit;
 private GameObject _wallHit;
 static int count = 0;

 // Use this for initialization
 void Start () {

 }

 // Update is called once per frame
 void Update () {

 }
 public void WallWasHit(RaycastHit hit){
             count++;
             Debug.Log("Wall was hit: " + count);

             _wallHit = Instantiate(wallHit) as GameObject;
             _wallHit.transform.position = hit.point;
 }
 }

但是到目前为止,我试图理解为什么这种情况很少发生的尝试都没有成功,我希望有人可以帮助我解决这个问题,因为在我继续阅读这本书之前,我觉得这可能对我的学习至关重要!提前致谢。如果需要更多信息,我很乐意提供。请参阅下图以更好地可视化该问题。

编辑: 如答案中所述,我相应地替换了火球脚本,但我不确定如何同样更改以下脚本。这个脚本在我的相机上,它在我的播放器对象上。在更新函数中,火球被实例化并被赋予了运动,所以我猜这会导致问题吗?

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

public class RayShooter : MonoBehaviour {
private Camera _camera;

[SerializeField] private GameObject fireballPrefab;
private GameObject _fireball;


void Start () {
    _camera = GetComponent<Camera>();

    Cursor.lockState = CursorLockMode.Locked;
    Cursor.visible = false;
}

void OnGUI(){
    int size = 12;
    float posX = _camera.pixelWidth/2 - size/4;
    float posY = _camera.pixelHeight/2 - size/2;
    GUI.Label(new Rect(posX, posY, size, size), "X");
}

// Update is called once per frame
void Update () {
    if(Input.GetMouseButtonDown(0)){
        Vector3 point = new Vector3(_camera.pixelWidth/2, _camera.pixelHeight/2, 0);
        _fireball = Instantiate(fireballPrefab) as GameObject;
        _fireball.transform.position = transform.TransformPoint(Vector3.forward * 1.5f);
        _fireball.transform.rotation = transform.rotation;

        Ray ray2 = _camera.ScreenPointToRay(point);
        RaycastHit hit;
        if(Physics.Raycast(ray2, out hit)){
            GameObject hitObject = hit.transform.gameObject;
            ReactiveTarget target = hitObject.GetComponent<ReactiveTarget>();
            if(target !=null){
                target.ReactToHit();
            } 
        }
    }
}
}

【问题讨论】:

    标签: c# unity3d mesh-collider


    【解决方案1】:

    这不是移动 Rigidbody 对象的方法,像这样移动它可能会导致很多问题,包括您的问题中提到的问题。带有Rigidbody 的对象应该使用Rigidbody 组件和Rigidbody.MovePosition、Rigidbody.AddForce 和Rigidbody.velocity 等函数而不是transform 或transform.Translate。

    另外,您应该在FixedUpdate 函数中移动Rigidbody 对象,而不是Update 函数。 如果您正在通过变换移动其他 Rigidbody 对象,那么您也必须修复它们。 下面的示例将 Fireball 脚本中的 transform.Translate 替换为 Rigidbody.MovePosition:

    public float speed = 10.0f;
    public int damage = 1;
    [SerializeField]
    private GameObject wallHit;
    private GameObject _wallHit;
    
    public Rigidbody rb;
    
    // Use this for initialization
    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }
    
    // Update is called once per frame
    void FixedUpdate()
    {
        //Move to towards Z-axis
        Vector3 pos = new Vector3(0, 0, 1);
        pos = pos.normalized * speed * Time.deltaTime;
    
        rb.MovePosition(rb.transform.position + pos);
    }
    
    void OnTriggerEnter(Collider other)
    {
        RaycastHit hit;
        PlayerCharacter player = other.GetComponent<PlayerCharacter>();
        ReactiveTarget target = other.GetComponent<ReactiveTarget>();
        WallBehavior wall = other.GetComponent<WallBehavior>();
    
        if (player != null)
        {
            player.Hurt(damage);
        }
        if (target != null)
        {
            target.ReactToHit();
        }
        if (wall != null)
        {
            if (Physics.Raycast(transform.position, transform.forward, out hit))
            {
                wall.WallWasHit(hit);
            }
        }
        Destroy(this.gameObject);
    }
    

    如果您仍然遇到问题,请改用Rigidbody.velocity:

    void FixedUpdate()
    {
        Vector3 pos = Vector3.zero;
        pos.z = speed * Time.deltaTime;
    
        rb.velocity = pos;
    }
    

    有时,根据对象的大小和移动速度,您需要将其刚体 Interpolate 从 None 设置为 Interpolate 和 碰撞检测 到 Continuous。

    不要忘记删除Update函数中的代码。


    编辑:

    我查看了您的项目,发现了新问题:

    1。您在“火球”游戏对象上启用了 IsTrigger。请取消选中对撞机上的IsTrigger。

    2。你只是想射一颗子弹。应该只添加一次力,而不是每个FixedUpdate。在Start 函数而不是FixedUpdate 函数中添加力。使用Rigidbody.velocity 而不是Rigidbody.MovePosition。

    删除FixedUpdate 函数和其中的代码。

    这应该是您的新 Start 函数:

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    
        Vector3 pos = transform.forward * speed * Time.deltaTime;
        rb.velocity = pos;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-05
      相关资源
      最近更新 更多