2014-11-16 4 views
0

У меня проблема с пониманием того, как сохранить ссылку на объект, который ранее был поражен raycast.Единство raycast, на raycast оставить, как? C#

, например, я могу иметь raycast сценарий положить на камеру моего 1rst контроллера человека, идущего от положения камеры к forwad вектора * некоторые значения

этот сценарий присоединен к камере

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

}

это работает прекрасно, за исключением случаев, когда я пытаюсь получить доступ к геймобжекты вне моего подводные камни и течения, если условие (например, печать print(hitten.name))

я получаю эту ошибку прежде, чем поразить объект из правого слоя:

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

тогда, когда я ударил объект это нормально

но проблема в том, что я не понимаю, как я могу изменить обратно объект цвет до его первоначального цвета (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); 
    } 

, но он не работает либо

вы можете мне помочь понять логику, я должен использовать заранее спасибо

+0

Я считаю, что проблема заключается в том, что ваш хостинг GameObject не инициализирован, чтобы проверить, если это так, инициализируйте его значением по умолчанию и посмотрите, что произойдет. – MSB

+0

@MSB да, это не было инициализировано, поэтому я добавил 'void Start() { \t \t hitten = null; \t} 'но я не вижу никаких изменений –

+0

извините, мой вопрос на самом деле не ясен, это не значит, что у вас больше нет ошибки, речь идет о том, как получить доступ к последнему объекту raycasthit, когда он больше не попадает –

ответ

0

Если ваш вопрос заключается в том для доступа к последнему удару объекта с помощью raycast, я предлагаю создать глобальную переменную, в которой вы можете ее сохранить.

Вместо настройки локальной переменной в вашем методе вы можете установить глобальную переменную, когда вы выполняете raycast. Таким образом, вы всегда можете получить доступ к объекту до тех пор, пока не нажмете новый (потому что он теперь хранится в вашей глобальной переменной).

EDIT: Если вы хотите отслеживать все цели, когда-либо raycast, я предлагаю создать глобальный массив, в котором вы храните каждый элемент, добавляя их при попадании в новую цель.

+0

вещь мне нужна что-то эквивалентное onMouseExit в обработке, поэтому я могу превратить (здесь я прототип с цветовой переменной) обратно в предыдущее состояние. Здесь у нас есть только что-то, что эквивалентно onMouseOver, и как только я что-то делаю, я не могу вернуть его обратно в рамку, в которой raycast покидает объект. Я пытаюсь сделать это со списком сейчас, но пока нет положительного результата –

+0

, можете ли вы попытаться подробнее рассказать о том, что вы хотите? Если вы хотите изменить цвет объекта, который вы нажали с помощью raycast, а затем немного изменить его назад, это кажется вполне возможным с помощью предписанного метода. – MSB

+0

Меня поразило, что эффект, который вы могли бы сделать, - это изменить графику объекта во время мышки над ним? подтвердите пожалуйста, если это так. – MSB

0

так я сделал это с помощью мыши, и она работает вы должны поместить ваш объект на праве слоя первым (девятым здесь)

вам среднюю кнопки мыши на объект, чтобы изменить его цвета (здесь черным), и щелкните правой кнопкой мыши в любом месте (на объекте или нет), чтобы изменить его исходный цвет.

только один объект имеет свой цвет, измененный в любой момент (позволяет вызывать это состояние «выбрано») , когда вы «выбираете» следующий объект щелкнув по средней клике мыши, он уже «выбран», он изменит первый на свой первоначальный цвет, так как теперь он «не выбран»

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

}

2

У меня была эта же потребность, когда я пытался определить, когда стена была затрудняя игрока. Раньше я никогда раньше не использовал Raycast (или Linecast), и был удивлен, что не было встроенного метода для обнаружения событий «Enter», «Stay» и «Leave».

Итак, я создал этот простой класс для обработки деталей для меня. Я не стал создавать конструкторы классов и просто публиковал свойства. Он обрабатывает как Raycasts, так и 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); 
} 

Вот 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); 
    } 

} 
Смежные вопросы