Collider并不总能检测到OnTriggerEnter

时间:2018-04-08 14:22:00

标签: c# unity3d mesh-collider

我在阅读“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;
 }
 }

但是我没有尝试理解为什么这种情况很少发生到目前为止是成功的,我希望有人可以帮助我,因为在我继续阅读本书之前,我觉得这对我的学习至关重要!提前致谢。如果需要进一步的信息,我很乐意提供。请参阅下图以更好地查看问题。 Six spheres on the wall, one fireball still in the air

编辑: 正如答案中所提到的,我相应地更换了火球脚本,但我不确定如何更改以下脚本。这个脚本在我的相机上,在我的播放器对象上。在更新功能中,Fireball被实例化并且还有一个移动,所以我猜这会导致问题?

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();
            } 
        }
    }
}
}

1 个答案:

答案 0 :(得分:3)

这不是如何移动Rigidbody对象并移动它可能会导致很多问题,包括问题中提到的问题。具有Rigidbody的对象应与Rigidbody组件一起移动,并使用Rigidbody.MovePositionRigidbody.AddForceRigidbody.velocity等函数移动transform或{ {1}}。

此外,您应该移动transform.Translate函数中的Rigidbody对象而不是FixedUpdate函数。 如果您要通过转换移动其他Update个对象,那么您也必须修复它们。以下示例将Rigidbody替换为transform.Translate Rigidbody.MovePosition } script:

Fireball

如果您仍遇到问题,请改用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

有时,根据对象的大小和移动速度,您需要将 Interpolate 从设置为 Interpolate < / em>和碰撞检测连续

不要忘记删除void FixedUpdate() { Vector3 pos = Vector3.zero; pos.z = speed * Time.deltaTime; rb.velocity = pos; } 功能中的代码。

修改

我查看了你的项目并发现了新的问题:

1 。您在“Fireball”GameObject上启用了IsTrigger。请取消选中对撞机上的Update

2 。你只想射击子弹。力量应该只添加一次IsTrigger。在FixedUpdate函数中添加强制而不是Start函数。使用FixedUpdate代替Rigidbody.velocity

删除Rigidbody.MovePosition函数及其中的代码。

这应该是你的新开始功能:

FixedUpdate