• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Major_Lag · Jan 19, 2020 at 06:21 AM · 2draycastraycastingraycasthit2dlaser

Is there a better way to find where to start my raycast?

I'm making a little game about lasers for fun and have run into an inconvenience with my splitters. The point of the splitter is to reflect the laser and also allow it to pass through it at the same time. But the way I have made it work makes it that it gets trapped if i start the raycast where i hit from the last. My solution was to start the raycast 1 unit in the previous direction past the splitter because the objects are movable & spinable by the player and is about 1 unit long. Here is a picture, the light blue rectangle s are my splitters. I use gizmos to help visualize my raycasting.alt text This isn't really optimal because what if the player wants to put a mirror, splitter, or other object near after it? Is there any way to find the exact opposite end of the sprite i hit? heres my code:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class Laser : MonoBehaviour
 {
     public int maxReflectionCount = 5;
     public int maxSplitCount = 5;
     public float maxStepDistance = 100;
 
     private void OnDrawGizmos()
     {
         if (!Application.isPlaying)
         {
             return;
         }
         DrawPredictedReflection(this.transform.position, this.transform.up, maxReflectionCount, maxSplitCount);
     }
 
     void DrawPredictedReflection(Vector2 position, Vector2 direction, int reflectionsRemaining, int splitsRemaining)
     {
         var gizmoHue = (reflectionsRemaining / (this.maxReflectionCount + 1f));
         Gizmos.color = Color.HSVToRGB(gizmoHue, 1, 1);
         RaycastHit2D hit2D = Physics2D.Raycast(position, direction, maxStepDistance);
 
         if (hit2D) //did we hit somthing?
         {
             Gizmos.DrawLine(position, hit2D.point);
             Gizmos.DrawWireSphere(hit2D.point, 0.25f);
 
             if (hit2D.transform.gameObject.tag == "Receiver")
             {
                 Debug.Log("Receiver hit");
             }
             if (hit2D.transform.gameObject.tag == "Mirror") //mirror hit. set new pos where hit. reflect angle and make that new direction
             {
                 Debug.Log("Mirror Hit");
                 direction = Vector2.Reflect(direction, hit2D.normal);
                 position = hit2D.point + direction * 0.01f;
 
                 if (reflectionsRemaining > 0)
                     DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
             }
             if (hit2D.transform.gameObject.tag == "Splitter") //reflect and go ahead
             {
 
                 Debug.Log("Splitter hit");
                 if (splitsRemaining > 0)//go ahead
                 {
                     Debug.Log("Splitting");
                     Vector2 splitPosition = hit2D.point + direction * 1f;
                     DrawPredictedReflection(splitPosition, direction, reflectionsRemaining, --splitsRemaining);
                 }
                     
                 
                 direction = Vector2.Reflect(direction, hit2D.normal);
                 position = hit2D.point + direction * 0.01f;
                 if (reflectionsRemaining > 0)//reflect too
                 {
                     DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
                 }
             }
         } 
     }
 }

I'll accept all help and/or if you spot a way to optimize my script please let me know! :)

splitters.jpg (86.4 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by jkpenner · Jan 19, 2020 at 06:59 AM

Instead of using just Raycast, try to use RaycastAll. RaycastAll will return all objects hit along the ray. You will need to just order all the objects hit by their distance from the origin since the order is not guaranteed. Then you can process each object in order.

Physics.RacastAll Reference

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Jan 19, 2020 at 10:59 AM 2
Share

Yes, that's probably the easiest solution if there's no "refraction" inside the splitter. i.e. the ray just passes through the splitter in a straight line.


If refraction is desired you would need to calculate the refraction angle inside the material and just cast a ray from the other side towards your first hit in the opposite refraction direction to determine the hit point where the ray should leave. There again you need to calculate the proper refraction angle to determine where the outgoing ray should go. Of course if you want internal reflection as well this can be done as well. For more information see Refraction (wikipedia) and / or one of those videos.


$$anonymous$$eep in mind that reflection / refraction does not always happen and not equally strong. Though since it's a game of course you can make up any kind of mechanic that suits your gameplay.

avatar image Major_Lag Bunny83 · Jan 19, 2020 at 06:13 PM 0
Share

I love this, this is great. Raycast all is a good short solution but casting a ray backwards to determine the point on the other side is what i need. I do want to add all i can like lenses, prisms and stuff so this sounds like the best solution.

avatar image
2

Answer by Major_Lag · Jan 19, 2020 at 08:16 PM

New working code from @Bunny83 solution:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class Laser : MonoBehaviour
 {
     public int maxReflectionCount = 5;
     public int maxSplitCount = 5;
     public float maxStepDistance = 100;
 
     private void OnDrawGizmos()
     {
         if (!Application.isPlaying)
         {
             return;
         }
         DrawPredictedReflection(this.transform.position, this.transform.up, maxReflectionCount, maxSplitCount);
     }
 
     void DrawPredictedReflection(Vector2 position, Vector2 direction, int reflectionsRemaining, int splitsRemaining)
     {
         var gizmoHue = (reflectionsRemaining / (this.maxReflectionCount + 1f));
         Gizmos.color = Color.HSVToRGB(gizmoHue, 1, 1);
         RaycastHit2D hit2D = Physics2D.Raycast(position, direction, maxStepDistance);
 
         if (hit2D) //did we hit somthing?
         {
             Gizmos.DrawLine(position, hit2D.point);
             Gizmos.DrawWireSphere(hit2D.point, 0.25f);
 
             if (hit2D.transform.gameObject.tag == "Receiver")
             {
                 Debug.Log("Receiver hit");
             }
             if (hit2D.transform.gameObject.tag == "Mirror") //mirror hit. set new pos where hit. reflect angle and make that new direction
             {
                 Debug.Log("Mirror Hit");
                 direction = Vector2.Reflect(direction, hit2D.normal);
                 position = hit2D.point + direction * 0.01f;
 
                 if (reflectionsRemaining > 0)
                     DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
             }
             if (hit2D.transform.gameObject.tag == "Splitter") //reflect and go ahead
             {
 
                 Debug.Log("Splitter hit");
                 if (splitsRemaining > 0)//go ahead
                 {
                     Debug.Log("Splitting");
                     Vector2 splitPosition = new Vector2();
                     Vector2 findOppBegin = hit2D.point + direction * 1f;
                     RaycastHit2D[] findOppHit = Physics2D.RaycastAll(findOppBegin, -direction);
                     for ( int i = 0;  i <= findOppHit.Length; i++) //findOppHit[i].transform.gameObject != hit2D.transform.gameObject
                     {
                         if (findOppHit[i].transform.gameObject == hit2D.transform.gameObject)
                         {
                             splitPosition = findOppHit[i].point + direction * 0.01f;
                             break;
                         }
                     }
 
                     DrawPredictedReflection(splitPosition, direction, reflectionsRemaining, --splitsRemaining);
                 }
                     
                 
                 direction = Vector2.Reflect(direction, hit2D.normal);
                 position = hit2D.point + direction * 0.01f;
                 if (reflectionsRemaining > 0)//reflect too
                 {
                     DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
                 }
             }
         } 
     }
 }

again any errors or optimizations let me know!

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image lgarczyn · Jan 20, 2020 at 01:20 PM 1
Share

I would be a bit careful with the code. First, if you still start the reverse raycasts from a unit away, if your reflective surface is somehow larger than a unit in any angle, your second raycasts could start inside.


Similarly, if another object is less than a unit away, it could get caught on the reverse raycasts.


This can be solved by checking colliders in RaycastHit2D against each other, and either increase or reduce the reverse raycasts offset, but there might be a better solution.


  1. Create an object of the exact same size as your mirrors, but inversed. The collider in the center is just empty space, and the space around it is filled with colliders.

  2. When a raycasts hits, convert the hit location into local space.

  3. Using that point, start a new raycasts in the inversed mirror, to see what it would hit. Possibly change the angle to account for refraction.

  4. Convert the result again into worldspace using the original mirror, you've got your new raycast origin.


This is a very theoretical idea, but it should work. Also do not that the transform of the inverse mirror must be completely neutral (0 pos, 0 rot, 1 scaling)

avatar image Major_Lag lgarczyn · Jan 20, 2020 at 07:32 PM 1
Share

if you still start the reverse raycasts from a unit away, if your reflective surface is somehow larger than a unit in any angle, your second raycasts could start inside.

I had made it 1 unit because i know i'm not going to be making any objects longer than 1 unit however if i ever decide against its a easy fix by multiplying the direction by a larger number in

 Vector2 findOppBegin = hit2D.point + direction * 1f;

if another object is less than a unit away, it could get caught on the reverse raycasts.

I have thought of this and decided to use RaycastAll in the opposite direction ins$$anonymous$$d so it gets all objects hit in that direction. Then use a forloop to go through the array of objects until i find a match of the object i last hit.

 RaycastHit2D[] findOppHit = Physics2D.RaycastAll(findOppBegin, -direction);
 for ( int i = 0;  i <= findOppHit.Length; i++) 
 {
         if (findOppHit[i].transform.gameObject == hit2D.transform.gameObject)
         {
                splitPosition = findOppHit[i].point + direction * 0.01f;
                break;
         }
 }

avatar image lgarczyn Major_Lag · Jan 21, 2020 at 10:14 PM 1
Share

Nice, then your solution is pretty much sound to the best of my knowledge.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

281 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

2D Raycast not working 1 Answer

2D click on object with a raycast not working 2 Answers

Raycast2D will point right, but won't point left when player turns. 1 Answer

Physics.Raycast doesn't hit anything even though Debug.DrawRay works 1 Answer

Raycast to ignore caster (Not by layer) 1 Answer

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges