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
0
Question by ZacGarby · Sep 05, 2015 at 10:45 PM · c#2draycastshooter

How to make a simple line of sight in a 2D top down shooter.

I'm making a top down shooter game, and I need to check if the player can see an enemy. At the moment, I'm using a raycast from the player to the enemy, and detecting if it hits the enemy or something else. But, for some reason, it doesn't do anything. I'm using it in a function which returns my custom type 'EnemyUnit', but, even it the recast should hit something in the way, it just returns itself, but which it can't actually see. Here's the block which has my raycast in it:

 RaycastHit2D sightTest = Physics2D.Raycast(transform.position, transform.position - finalDetected.transform.position, detectionOptions.detectionRange);
         if (sightTest.collider != null) {
             if (sightTest.collider.gameObject != gameObject) {
                 finalDetected = null;
                 Debug.Log ("Rigidbody collider is: " + sightTest.collider);
             }
         }
         return finalDetected;

This isn't the whole function, but it's the part with the raycast in it.

finalDetected is a variable with type of EnemyUnit, you can - probably - guess what the rest are.

EDIT: I've just changed it a bit to make it not return anything, but now the problem is it just detects the map...

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

3 Replies

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

Answer by wibble82 · Sep 06, 2015 at 09:18 AM

Hi Zac

A few bits here. First up,, as pointed out by pako, if what you want is a ray from the transform.position to finalDetected.transform.position, you have the maths the wrong way round. To calculate a vector that goes from A to B, the calculation is OFFSET = B - A.

A side note is that directions are typically normalized (i.e. of unit length), though its possible the raycast function does this for you internally.

First thing I would do here is use the debug utilities to draw your ray in the editor and make sure it is correct. See here: http://docs.unity3d.com/ScriptReference/Debug.DrawRay.html

A quick blast at the code (without testing) would be something like:

 //precompute our ray settings
 Vector3 start = transform.position;
 Vector3 direction = (finalDetected.transform.position - transform.position).normalized;
 float distance = detectionOptions.detectionRange;
 
 //draw the ray in the editor
 Debug.DrawRay(start,direction*distance,Colors.Red);
 
 //do the ray test
 RaycastHit2D sightTest = Physics2D.Raycast(start,  direction, distance);
 if (sightTest.collider != null) 
 {
   if (sightTest.collider.gameObject != gameObject) 
   {
       finalDetected = null;
       Debug.Log ("Rigidbody collider is: " + sightTest.collider);
   }
 }
 

With it drawn on screen you should know for certain if the ray is doing what you think it should be doing.

Following that, you might be seeing an issue as you are only asking the ray for the first object it hits (thats what Physics2D.Raycast does). So if it hits something else you won't get your enemy. That's fine if you definitely want the first object hit, but if there's stuff you want to ignore and you aren't using layer masks, you'll need to handle manually.

You can limit this problem by filtering based on layer (see Cam's answer), but if you still need to check all objects along the ray, use the raycastall function, and iterate over the results:

 //precompute our ray settings
 Vector3 start = transform.position;
 Vector3 direction = (finalDetected.transform.position - transform.position).normalized;
 float distance = detectionOptions.detectionRange;
 
 //draw the ray in the editor
 Debug.DrawRay(start,direction*distance,Colors.Red);
 
 //do the ray test
 RaycastHit2D[] sightTestResults = Physics2D.RaycastAll(start,  direction, distance);
 
 //now iterate over all results to work out what has happened
 for(int i = 0; i < sightTestResults.Length; i++)
 {
     RaycastHit2D sightTest = sightTestResults[i];
     
     //do stuff with this result? not sure exactly what your function needs though :)
 }

The results come out sorted (closest first), so you could identify:

  • stuff you wanted to 'block' the line of sight - break out of loop with 'false'

  • stuff you don't care about - just continue looping

  • stuff you want to detect hitting - break out of loop with 'true'

You could even use more debug draw functions to show where the ray cast hit to help you work out what is happening.

Hope that helps!

-Chris

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 ZacGarby · Sep 06, 2015 at 10:03 AM 0
Share

It worked, thx!

avatar image wibble82 · Sep 06, 2015 at 10:13 AM 0
Share

No prob - though if the fix was flipping round that maths, credit goes to @pako - he/she spotted that before me :)

avatar image
1

Answer by pako · Sep 06, 2015 at 07:59 AM

It seems you are casting the ray backwards. I think that if you want to cast the ray towards the enemy you should use for the end point:

 finalDetected.transform.position - transform.position

...not the other way around. So, try:

  RaycastHit2D sightTest = Physics2D.Raycast(transform.position,  finalDetected.transform.position - transform.position, detectionOptions.detectionRange);
          if (sightTest.collider != null) {
              if (sightTest.collider.gameObject != gameObject) {
                  finalDetected = null;
                  Debug.Log ("Rigidbody collider is: " + sightTest.collider);
              }
          }
          return finalDetected;

I haven't tested this myself, but this is something that "stands out". Just try and see if it makes a difference.

Comment
Add comment · 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
0

Answer by Cam Edwards · Sep 05, 2015 at 11:42 PM

Rather than checking to see if the raycast hits the GameObject performing the cast, you could assign all objects you want to check to a certain layer and cast against that.

To make that a bit clearer you could define two layers, one for enemies that you want to check line of sight against, and one for things that get in the way of line of sight like walls or obstacles. Then, when you do your raycast, you can pass it a layer mask to only check for collisions of objects on your "enemy" or "obstacle" layer. See here for how to set up and use layers.

The LayerMask parameter to Raycast is a bit weird if you don't understand bitshifting (and I don't, completely). It goes -something- like this:

-EDIT- I just tried to explain bitmasks, but it proved too long to write up in an answer. You can google it for a good explanation. Put REALLY shortly, if you want to mask against a single layer, you can use this as your LayerMask parameter:

1 << N

Where N is the layer you want to include.

For this example, if you set your "enemy" layer as layer 8 and your "obstacle" layer as layer 9 (the first 2 user-definable layers), I'm fairly sure that the LayerMask to include JUST layers 8 and 9 is:

11 << 8

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 getyour411 · Sep 06, 2015 at 03:08 AM 0
Share

It can be simplified by declaring

public Layer$$anonymous$$ask layersIWant;

which will open a dropdown/selection box in the Inspector, tick the ones you want.

avatar image ZacGarby · Sep 06, 2015 at 09:56 AM 0
Share

I think that the problem is actually the direction of the raycast rather than the layers.

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

30 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

Related Questions

Upon shooting, Raycast target moves infinitely 1 Answer

Button blocking raycast 3 Answers

2D sidescroller shooting 1 Answer

Getting a Raycast rope to follow its object 0 Answers

Physics2D.Raycasting questions 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