Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • 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 deter$$anonymous$$e the hit point where the ray should leave. There again you need to calculate the proper refraction angle to deter$$anonymous$$e 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 $$anonymous$$d 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 deter$$anonymous$$e 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.

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 click on object with a raycast not working 2 Answers

2D Raycast not working 1 Answer

My Raycasts seem to sometimes miss 0 Answers

onGround raycasts return onGround is true while colliding with platform sides 0 Answers

how to drag an object using 2d raycasts 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges