unity raycast , on raycast leave, 如何?C#

1 c# unity-game-engine raycasting

我在理解如何保留对先前被光线投射击中的对象的引用时遇到问题。

例如,我可以将光线投射脚本放在我的第一人称控制器的相机上,从相机位置到前向矢量 * 某个值

此脚本附加到相机

public class raycast : MonoBehaviour {
float lenthRay = 10.0f;
Vector3 originePos;
Vector3 dir;
RaycastHit hitinfo;
GameObject hitten;
bool isHitting;
Color beforC;
int selectionLayer = 9;

void Update () {
    originePos = Camera.main.transform.position;
    dir = Camera.main.transform.forward * lenthRay;
    Debug.DrawRay(originePos, dir, Color.blue);

    if (Physics.Raycast(originePos, dir, out hitinfo, lenthRay , selectionLayer)) {
        hitten = hitinfo.transform.gameObject;
        MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
        beforC = tmp.material.color;
        tmp.material.color = Color.black;
    } 
    //hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
    print(hitten.name);
}
Run Code Online (Sandbox Code Playgroud)

}

它工作得很好,除非我尝试在我的 if 条件之外访问 GameObject Hitten(如打印print(hitten.name)

在从正确的层击中对象之前,我收到此错误:

NullReferenceException: Object reference not set to an instance of an object
raycast.Update () (at Assets/raycast.cs:30)
Run Code Online (Sandbox Code Playgroud)

然后当我击中物体时就可以了

但问题是,我不明白我怎么可以变回对象的颜色其原来的颜色(beforC)也开始转向后Color.black当光线出口对象

这就是我在注释行中尝试做的事情,但我得到的错误与打印时相同,并且没有任何变黑。

我试过这个:

originePos = Camera.main.transform.position;
    dir = Camera.main.transform.forward * lenthRay;
    Debug.DrawRay(originePos, dir, Color.blue);
    isHitting = Physics.Raycast (originePos, dir, out hitinfo, lenthRay, selectionLayer);
    if (isHitting) {
        hitten = hitinfo.transform.gameObject;
        MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
        beforC = tmp.material.color;
        tmp.material.color = Color.black;

    } 
    if(!isHitting){
        hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
        print(hitten.name);
    }
Run Code Online (Sandbox Code Playgroud)

但它也不起作用

你能帮我理解我应该使用的逻辑吗 提前谢谢

Dou*_*ane 5

我也有同样的需求,当我试图检测墙壁何时挡住了玩家。我以前从未使用过 Raycast(或 Linecast),并且很惊讶没有内置方法来检测“进入”、“停留”和“离开”事件。

所以我创建了这个简单的类来为我处理细节。我没有费心创建任何类构造函数,只是将属性公开为公共。它处理光线投射和线投射。

一旦您使用属性进行设置,该类就会为您跟踪每一帧的对象。

下面是一些示例代码来演示潜在的用法(我用于墙壁检测的代码):

private RayCaster wallRay;

void Start() {
    wallRay = new RayCaster();
    wallRay.OnRayEnter += WallRay_OnEnter;
    wallRay.OnRayExit += WallRay_OnExit;
    wallRay.LayerMask = RayCaster.GetLayerMask("Wall");
    wallRay.StartTransform = camera.transform;
    wallRay.EndTransform = PlayerManager.Player.transform;
}

void Update() {
    wallRay.CastLine();
}

void WallRay_OnEnter(Collider collider) {
    // Fade OUT wall section       [Needs DOTween (free) installed]
    collider.gameObject.renderer.material.DOFade(0.65f, 0.2f);
}

void WallRay_OnExit(Collider collider) {
    // Fade IN wall section
    collider.gameObject.renderer.material.DOFade(1f, 0.2f);
}
Run Code Online (Sandbox Code Playgroud)

这是RayCaster类:

using System;
using System.Collections;
using UnityEngine;

public class RayCaster {

    public Transform StartTransform;
    public Transform EndTransform;
    public Vector3 Direction;
    public float RayLength;
    public int LayerMask = 0;

    public event Action<Collider> OnRayEnter;
    public event Action<Collider> OnRayStay;
    public event Action<Collider> OnRayExit;

    Collider previous;
    RaycastHit hit = new RaycastHit();

    public bool CastRay() {
        Physics.Raycast(StartTransform.position, Direction, out hit, RayLength, LayerMask);
        ProcessCollision(hit.collider);
        return hit.collider != null ? true : false;
    }

    public bool CastLine() {
        Physics.Linecast(StartTransform.position, EndTransform.position, out hit, LayerMask);
        ProcessCollision(hit.collider);
        return hit.collider != null ? true : false;
    }

    private void ProcessCollision(Collider current) {
        // No collision this frame.
        if (current == null) {
            // But there was an object hit last frame.
            if (previous != null) {
                DoEvent(OnRayExit, previous);
            }
        }

        // The object is the same as last frame.
        else if (previous == current) {
            DoEvent(OnRayStay, current);
        }

        // The object is different than last frame.
        else if (previous != null) {
            DoEvent(OnRayExit, previous);
            DoEvent(OnRayEnter, current);
        }

        // There was no object hit last frame.
        else {
            DoEvent(OnRayEnter, current);
        }

        // Remember this object for comparing with next frame.
        previous = current;
    }


    private void DoEvent(Action<Collider> action, Collider collider) {
        if (action != null) {
            action(collider);
        }
    }

    public static int GetLayerMask(string layerName, int existingMask=0) {
        int layer = LayerMask.NameToLayer(layerName);
        return existingMask | (1 << layer);
    }

}
Run Code Online (Sandbox Code Playgroud)