Unity 中的光线投射和计时器问题

Posted

技术标签:

【中文标题】Unity 中的光线投射和计时器问题【英文标题】:Issue with Ray casting and timers in Unity 【发布时间】:2013-10-30 06:12:36 【问题描述】:

这是follow on from my last question 现在我正在寻找扩展它的功能,但我遇到了一些主要障碍。

我的目标如下:

我有一台相机,它正在投射光线以击中带有特定标签的对象。当光线在一段时间内击中标签时,我正在寻找发生的事情,现在我正在寻找的只是调试消息或简单的东西。当射线没有击中带有标签的任何对象时,我希望我的计时器不更新。如果用户将视线从对象上移开并返回,我希望计时器从 0 重新开始,并且如果用户查看另一个标签,即计时器再次启动,我想要类似的功能。

但是,我的计时器没有按预期工作,而且无论我在看什么,它都在不停地计数。我在这上面花了 3 个小时,我得到了隧道视野,在那里我不断尝试相同的代码行。

有一双双眼睛的人可以看看我到目前为止所做的事情并向我指出我错过了什么/做错了什么吗?

public float end_time;
public float start_time;
private float running_time;

public Texture2D progress_bar_empty;
public Texture2D progress_bar_full;
public Material highlight_material;
public float progress = 0;
public bool hited = false;


public List<string> _tags = new List<string>();

private GameObject hit_object;
private Material oldMat;


RaycastHit hit;
// Use this for initialization
void Start () 

    start_time = Time.deltaTime;
    running_time = 0;   


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

    EyeTarget();
    Check(hited);


void EyeTarget()

    try
    
        Vector3 fwd = transform.TransformDirection(Vector3.forward);
        if (Physics.Raycast(transform.position, fwd, out hit))
        
            foreach(string t in _tags)
            
                if(hit.collider.gameObject.tag == t)
                
                    HighLight();

                                   
            
        
        Debug.DrawRay(transform.position, fwd, Color.red);
    
    catch(Exception e)
    
        Debug.Log(e.Message);
    


void ResetTimer()

    start_time = Time.time;
    running_time = 0f;
    //Debug.Log("resetting timer");



void HighLight()

    if(hit_object == null)
    
        ResetTime();
        oldMat = hit.transform.renderer.material;
        hit.collider.gameObject.renderer.material = highlight_material;
        hit_object = hit.collider.gameObject;
        hited = true;
           
    else if( hit.transform.tag != hit_object.tag)
    
        //hit.collider.gameObject.renderer.material = oldMat;
        hit_object = null;
        hit_object.renderer.material = oldMat;
        progress = 0;
        Debug.Log("hi");
        hited = false;
    

// see if ray has hit object
void Check(bool hit)


    if(hit)
    
        start_time = Time.time - end_time;
        running_time += Time.deltaTime;
        if ( running_time >= end_time )
        

            hited = false;
        
    
    else if( hited == false)
        ResetTime();



void ResetTime()

      start_time = Time.time;
    running_time = 0f;
    Debug.Log("restting timer");

【问题讨论】:

有一些问题,但你遇到的主要问题是没有任何东西会调用Highlight,除非你的光线投射击中带有正确标签的对象。您在 else if 中的 Highlight 中也有错误,您首先设置 hit_object = null 然后尝试设置其材质。 【参考方案1】:

我尽量不考虑您的版本。此版本将在光标离开标记对象时停止计时器,并在另一个标记对象位于raycast 下时从 0 重新开始。

我的代码有点冗长,但更容易看到发生了什么。

    public float end_time;
public float start_time;
public float running_time;

public Texture2D progress_bar_empty;
public Texture2D progress_bar_full;
public Material highlight_material;
public float progress = 0;

public bool trackTimer = false;

public List<string> _tags = new List<string>();

public GameObject lastHitObject = null;
private Material oldMat;

// Use this for initialization
void Start () 

    ResetTimer();


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

    EyeTarget();

    // Update the timer if and only if we are tracking time AND
    // the last ray cast hit something.
    bool updateTimer = (trackTimer && lastHitObject != null);  
    Check(updateTimer);


void EyeTarget()

    RaycastHit hit;
    bool hitTaggedObject = false;

    Vector3 fwd = transform.TransformDirection(Vector3.forward);
    if (Physics.Raycast(transform.position, fwd, out hit))
    
        foreach(string t in _tags)
        
            if(hit.collider.gameObject.tag == t)
            
                HighLight(hit.collider.gameObject);
                hitTaggedObject = true;
                               
        
     

    // ** Make sure to clean up highlighting if nothing new was hit
    if (!hitTaggedObject)
        HighLight(null);
    


void ResetTimer()

    start_time = Time.time;
    running_time = 0f;



void HighLight(GameObject nextHitObject)

    // Case1: Last ray and new ray both hit objects
    if(lastHitObject != null && nextHitObject != null)

        //1a: same objects, do nothing
        if(lastHitObject.tag == nextHitObject.tag)return;   

           //1b: different objects, swap highlight texture
            lastHitObject.renderer.material = oldMat;
            lastHitObject = nextHitObject;
            oldMat = lastHitObject.renderer.material;
            lastHitObject.renderer.material = highlight_material;
            trackTimer = true;
            return;
        
    

    // Case2: Last ray hit nothing, new ray hit object.
    if(lastHitObject == null && nextHitObject != null)
        ResetTimer();
        lastHitObject = nextHitObject;
        oldMat = lastHitObject.renderer.material;
        lastHitObject.renderer.material = highlight_material;
        trackTimer = true;
        return;
    

    // Case3: Last ray hit something, new ray hit nothing
    if(lastHitObject != null && nextHitObject == null)
        lastHitObject.renderer.material = oldMat;
        lastHitObject = null;
        trackTimer = false;
        return;
    

// see if ray has hit object
void Check(bool updateTimer)

    if(updateTimer)
    
        start_time = Time.time - end_time;
        running_time += Time.deltaTime;
        if ( running_time >= end_time )
        
            trackTimer = false;
        
       

trackTimer 是一个状态标志,与所选对象的状态分开,用于跟踪 running_time 何时达到 end_time。一旦这 2 个相等,trackTimer 将变为 false,您需要在计时器重新开始之前突出显示一个新对象或重新突出显示当前对象。

【讨论】:

以上是关于Unity 中的光线投射和计时器问题的主要内容,如果未能解决你的问题,请参考以下文章

Hololens 2 的光线投射问题

Unity3D:弹跳/反射光线投射

Unity3D 5.x 交互功能 - 光线投射碰撞设置

在 Unity 中沿光线投射实例化预定义数量的对象

2-6 光线投射

使用光线投射和实例化对象问题检查与多边形碰撞器的碰撞(统一)