简体   繁体   English

团结光线投射,关于光线投射,如何? C#

[英]unity raycast , on raycast leave , how to ? c#

i have a problem understanding how to keep a reference to an object that has previously been hit by a raycast . 我有一个问题,了解如何保持对先前被光线投射命中的对象的引用。

for example i can have a raycast script put on the camera of my 1rst person controller going from the camera position to the forwad vector * some value 例如,我可以将一个光线投射脚本放在我的第一人称控制器的摄像头上,从摄像头位置到转向矢量*一些值

this script is attached to the camera 此脚本附加到相机

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

} }

it is working great , except if i try to access the GameObject Hitten outside my if condition (like the print print(hitten.name) ) 它工作得很好,除非我尝试在我的if条件之外访问GameObject Hitten(如print print(hitten.name)

i get this error before hitting an object from the right layer : 我在从右侧层击中一个对象之前得到此错误:

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

then when i hit the object it is ok 然后当我击中物体时它没问题

but the problem is , i dont understand how i can change back the object color to its original color (beforC) after turning it to Color.black when the ray exit the object 但问题是,我不明白当光线退出物体后,如何将物体颜色更改为原始颜色(beforC)后将其转换为Color.black

this is what i try to do in the commented line , but i just get the same error than with the print , and nothing is turning black . 这是我尝试在注释行中做的,但我得到的错误与打印相同,并且没有任何变黑。

i have tried this : 我试过这个:

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

but it is not working either 但它也没有用

can you help me understand the logic i should be using thanks in advance 你能帮我理解我应该提前使用的逻辑吗?

I had this same need, when I was trying to detect when a wall was obstructing the player. 当我试图检测墙壁何时阻碍玩家时,我有同样的需求。 I had never used a Raycast (or Linecast) before, and was surprised there wasn't a built in method to detect 'Enter', 'Stay', and 'Leave' events. 我以前从未使用过Raycast(或Linecast),并且很惊讶没有内置方法来检测'Enter','Stay'和'Leave'事件。

So I created this simple class to handle the details for me. 所以我创建了这个简单的类来处理我的细节。 I didn't bother creating any class constructors, and just exposed the properties as public. 我没有打扰创建任何类构造函数,只是将属性公开为public。 It handles both Raycasts and Linecasts. 它处理Raycast和Linecast。

This class tracks your objects each frame for you once you set it up using the properties. 一旦使用属性进行设置,此类将为您跟踪每个帧的对象。

Here's some sample code to demonstrate potential usage (the code I use for my wall detection): 这里有一些示例代码来演示潜在的用法(我用于墙壁检测的代码):

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

Here's the RayCaster class: 这是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);
    }

}

If your question is how to access the last object hit by your raycast then I suggest creating a global variable where you can store it. 如果您的问题是如何访问光线投射命中的最后一个对象,那么我建议您创建一个可以存储它的全局变量。

Instead of setting the local variable in your method you can then set the global variable when you raycast. 您可以在光线投射时设置全局变量,而不是在方法中设置局部变量。 This way you can always access the object until you hit a new one(because this one is now stored in your global variable) 这样你就可以随时访问该对象,直到找到一个新对象(因为这个对象现在存储在你的全局变量中)

EDIT: In the event that you want to be able to keep track of all the targets that you have ever raycast I suggest making an global array where you store each item, appending them as you hit a new target. 编辑:如果您希望能够跟踪您曾经进行过光线投射的所有目标,我建议您创建一个存储每个项目的全局数组,并在您点击新目标时附加它们。

so i did it with the mouse and it works you have to put your object on the right layer first (9th here) 所以我用鼠标做了它,你需要先将你的对象放在正确的层上(这里是第9个)

you middle mouse click on a object to change its color (here black), and right click anywhere (on the object or not) to change back its original color 你在鼠标中间单击一个对象来改变它的颜色(这里是黑色),然后右键单击任何地方(在对象上或不在对象上)以更改其原始颜色

only one object has its color changed at any moment , (lets call this state "selected") when you "select" the next object by middle mouse clicking on it wile one is already "selected", it'll change the first one to its original color , as it is now "unselected" 任何时刻只有一个对象的颜色发生了变化(让我们称这个状态为“已选”)当你通过鼠标中键点击它来“选择”下一个对象时,它已被“选中”,它会将第一个对象改为它的原始颜色,因为它现在“未被选中”

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

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

    if (Input.GetMouseButtonDown (2)) {
        isHitting = Physics.Raycast (originePos, dir, out hitinfo, lenthRay, selectionLayer);
        if(isHitting) {
            if(hitinfo.transform.gameObject == null){
                hitten= null;
            }
            if(hitten != null && hitinfo.transform.gameObject == hitten){
                alreadyHitten = true;
            }
            if(hitten != null && hitinfo.transform.gameObject != hitten){
                alreadyHitten = false;
                hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
                hitten = hitinfo.transform.gameObject;
            }
            hitten = hitinfo.transform.gameObject;
            if(hitten !=  null && !alreadyHitten){
                print (hitten.name);
                MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
                beforC = tmp.material.color;
                tmp.material.color = Color.black;
            }
        }
    }
    if (Input.GetMouseButtonDown (1)) {
        if(hitten != null){
            alreadyHitten = false;
            hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
            hitten = null;
        }
    }
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM