Search Unity

Raycast Help!

Discussion in 'Scripting' started by Tony_T, Aug 19, 2018.

  1. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    Hello everyone. Normally I would post on Unity answers but I can't log in for some reason (I have reported it). What I want to do is cast a ray against specific objects, ether with a tag or if the script is on the game object. I found a really helpful script that casts a ray like a field of view, so you can control the radius and the angle. My problem is that it requires you to add an origin which is okay but a target which is not okay because the target may be multiple objects. Is there a way i can cast the same ray but ether not input a target or input multiple targets? Here is a picture that may help you understand what i want and the code piece.

    Capture.PNG

    The white circle is the raycast which is set to 360 so its full and the distance is at 2.5 (ignore the white straight line, its just the end of the angle). The red line is the raycast which happens all around and inside the circle so it works as i want it but, i have to input the target, so if i have multiple targets it doesn't work. I've tried a few raycast types but none work as i want to, they have Vector3.forward, up, left, etc but those are specific vectors, i want all around it...

    void Update
    {
    Vector3 VisionDirection = (Player.transform.position - transform.position).normalized;
    RaycastHit hit;

    if (Vector3.Angle(transform.forward, VisionDirection) < VisionAngle / 2)
    if (Physics.Raycast(transform.position, VisionDirection, out hit, VisionRadius) && hit.collider.gameObject.GetComponent<Profile>() != null)
    Debug.DrawLine(transform.position, Player.transform.position, Color.red);
    }

    All i want to do is cast a simple ray around an object that affects only specific objects.
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,779
    Can you elaborate more, what you exactly mean?
     
  3. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    If i'm understanding you right, what you're trying to do is find all of your objects of a certain type in a circle around a point?

    In which case, rather than doing a tonne of raycasts out in 360 degrees, what you're looking for is this
    https://docs.unity3d.com/ScriptReference/Physics.OverlapSphere.html

    A raycast is a line, drawn from a point along a direction (or to another point). It returns whatever it hits first (there's also one that always continues to the end and returns a list of everything hit).
    If you want to check for objects within a volume, there are other functions for that
    https://docs.unity3d.com/ScriptReference/Physics.OverlapBox.html
    https://docs.unity3d.com/ScriptReference/Physics.OverlapCapsule.html
    https://docs.unity3d.com/ScriptReference/Physics.OverlapSphere.html
     
  4. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    Sorry if I confused you. Let me just tell you what I want to achieve with my script. I want to have an object that casts a ray around it and when specific objects come in range I want it to do something. Isn't there a way to cast a ray and if the tagged game objects hit the raycast do something.
     
  5. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    I had a look earlier of the overlap sphere but I wasn't sure if I can cast it all the time, like in the update void. I also had a look at vector3 distance but I'm not sure which one is correct for what I need. As I explained to someone above i just want to have a game object and when specific objects come in range I want it to do something. I don't really care if the objects is behind something. Just think of an door that has a sensor and it opens once a person is near it but in my case I want it to open for specific people.
     
  6. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    In that case you might try
    https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html
    You basically set up an object with a collider to be a trigger zone. When another collider enters that zone it calls this function and provides you a reference to the collider that entered. You can then use it to check the other object to see if it should be allowed to open the door and do what you want.
     
  7. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    I always had trouble with on trigger enter that's why I completely ignored it now. Sometimes it doesn't work, or if there are more trigger colliders or maybe raycasts it ignores them too. It will be very buggy!
     
  8. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    It works. If there was a bug, it was most-likely in your code.

    The script you found won't help alot, as you discovered, you'll need a target. The purpose of the script is to not send X raycasts, but one to the target and do calculations based on that.

    Without target(s), you'd have to blindy raycast lots of times in order to detect any objects that come closer.

    I recommend the same as @Mordus. Either us a different type of cast or simply add a trigger zone to your object.
     
  9. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    There have been times where on trigger enter/stay or exit were buggy, i will try to use that and ignore the raycast since I'm also using a raycast inside the sphere for something else but on the same script.
     
  10. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    What time was that? And which kind of bugs? Most of the time, when people ask for help or claim that basics stuff is buggy, it turns out there was a sneaky problem in their code. Everyone has these moments.

    If you provided an example of the thing you are/were trying to achieve and does/did not work, I'm sure someone will be able to solve the problem. :p
     
  11. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    So i tried using triggers but I run into a bug as it was expected. So I start coroutines whenever the players enter or exits the trigger but if you enter and exit very fast i guess the program doesn't respond fast enough. This is one of the coroutines to open the door. The other coroutine is similar only it closes the door so it's -=. If I enter and exit the trigger very fast the doors remain open, I've tried many different things from bools, to stop the coroutine on trigger exit but nothing even makes a small change to the doors behavior. You see this is the reason I said these are a bit buggy even when the code is correct. If it was a raycast it would be on Update and it would be very easy to check if the player is out of range. Any ideas of how I can fix this bug now?

    IEnumerator DoorOpen()
    {
    while (Door.transform.localPosition.x <= 1.35f)
    {
    Door.transform.localPosition += new Vector3(Time.deltaTime * 0.2f, 0, 0);

    yield return null;
    }

    StopCoroutine(DoorOpen());
    }
     
  12. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Well, if that's the code you run for both (as you said the other one uses substraction), and do not stop the active one when you start the other, they'll fight each other. One would say move 0.2f * Time.deltaTime up, the other one would do the exact opposite.

    This doesn't mean the engine or the physics system is buggy, it's the handling of the coroutines in your code.

    You wouldn't even need two routines if you keep track of the process in a field variable. You could also extend this and create fancy movement, for instance with animation curves.

    This being said, I hope you feel encouraged to solve it on your own.
     
  13. Tony_T

    Tony_T

    Joined:
    Jul 4, 2018
    Posts:
    13
    I did try to stop the opposite coroutine when i start another but no luck. If you are saying to put both coroutines in one i did try that as well with bools but no luck ether. If I knew how to solve it on my own I wouldn't be asking for help online so If you are not going to help me then please don't reply!
     
  14. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    This is an open community forum, if I feel like starting with hints instead of ready-to-use solutions, don't be ignorant about it. If that's not what you're looking for, simply ignore it. If that's no help for you, ignore it. Others would redirect you to the learning section.

    Since help does only mean to get some running code, here's a fairly simple (and very explicit) example:

    Code (CSharp):
    1. public class Example : MonoBehaviour
    2. {
    3.     [SerializeField]
    4.     private Transform _startMarker;
    5.     [SerializeField]
    6.     private Transform _endMarker;
    7.     [SerializeField]
    8.     private Transform _objectToMove;
    9.  
    10.     private float _progress;
    11.     private Coroutine _activeRoutine;
    12.  
    13.     private void OnTriggerEnter(Collider other)
    14.     {
    15.         if (_activeRoutine != null)
    16.         {
    17.             StopCoroutine(_activeRoutine);
    18.         }
    19.  
    20.         _activeRoutine = StartCoroutine(MoveToEnd());
    21.     }
    22.  
    23.     private void OnTriggerExit(Collider other)
    24.     {
    25.         if (_activeRoutine != null)
    26.         {
    27.             StopCoroutine(_activeRoutine);
    28.         }
    29.  
    30.         _activeRoutine = StartCoroutine(MoveToStart());
    31.     }
    32.  
    33.     private IEnumerator MoveToEnd()
    34.     {
    35.         while (_progress < 1f)
    36.         {
    37.             _objectToMove.position = Vector3.Lerp(_startMarker.position, _endMarker.position, _progress);
    38.             _progress += Time.deltaTime;
    39.             yield return null;
    40.         }
    41.  
    42.         _activeRoutine = null;
    43.     }
    44.  
    45.     private IEnumerator MoveToStart()
    46.     {
    47.         while (_progress > 0f)
    48.         {
    49.             _objectToMove.position = Vector3.Lerp(_startMarker.position, _endMarker.position, _progress);
    50.             _progress -= Time.deltaTime;
    51.             yield return null;
    52.         }
    53.  
    54.         _activeRoutine = null;
    55.     }
    56. }
    57.  
    Note that there's a lot potential to shorten the code. It's very explicit about what is happening, hence it is rather long and redundant.
    Anyway, before any of the routines is started, you'll check whether any is active and if so, stop it.
    Then, run the coroutine that is supposed to run. _process keeps track of how far the object has moved between the start and end so we can move it back from where we stopped, in case .it hasn't finished movement

    When the routine finished the movement completely and runs to its end, it'll assign null to the variable that's used for tracking the active one, since the coroutine will be de-registered by the engine if it finished the normal way. There's no need to stop it from within itself.

    Of course you can add parameters for speed or duration, use animation curves for special movements, or proceural movement. You can also force it to open completely before it closes, all that stuff ... But that's a different thing.