Casting a 2D ray for LOS detection

Topics: Developer Forum
Nov 25, 2008 at 11:45 PM
I am trying to figure out the best way to cast a 2D ray using the simulator and determine if and where the nearest point is that ray intersects in the physical world. The first way that comes to mind with the new version of the framework is to create an object as a sensor and add it to the simulator to detect collisions but this seems a bit clunk to me. The perfect solution would be a method that returned bool and had an out Vector2 (only used when it collided) to tell you if the ray collided with anything and if so where the nearest point it collided with.

If anyone has suggestions I would love to hear them. I am running the newest release of the engine.
Coordinator
Nov 26, 2008 at 12:28 PM
@shaku:
The OnCollision delegate from a geometry gives you a contact list. Each of the contacts are where the 2 geometries collided. They have a Position property that tells you where it is.
Another way of checking for collisions (also covered by our manual) is the Collide method that returns a bool. You give it a position (vector2) or a geometry, and it will check collision against those 2 geometries.

Here is an example.

1. Create a long geometry. Set it as a sensor
2. Register the OnCollision event (it only fires when collision occurs. The same as check if a collision is true or false)
3. When a collision occurs, you loop the contact list and find the collision position that is the closest to the player.

@sensorium7: If you have any questions regarding the collision system, please consult the manual (it explains the most of it) or ask on the forums. I will be ready to answer any questions you might have.
Nov 26, 2008 at 3:16 PM
Edited Nov 26, 2008 at 3:18 PM
@genbox

Thank you for the quick reply. I am sorry if my post seemed like I was posting before reading your manual and viewing your samples; I assure you I have looked over both very thoroughly and I have also created a system similar to what you described. Here is how my system works currently:

  1. I have a helper class called LOSChecker whom has a method "CheckLOS" which takes the following parameters.
    1. Start Point (Near Point)
    2. End Point (Far Point)
    3. Response Delegate
  2. It creates a "LOSRequestClass" from this and stores it in an array for later; it then creates geometry to represent this check and implements it in the physics system with a call back to LOSDidCollide on that geometry's OnCollision call back.
  3. It waits 1 full update cycle and if there is no collision call back for that specific LOS request then it responds to the Response Delegate with false and Vector2.Zero. If there is a collision before the next update cycle it responds with a true and the closest contact found to the start point.

The method works ok but there are a few things that makes it a pain:
  1. In some cases you are getting back a TON of contact points because of how much geometry it crosses so you could be calculating distance from near point on thousands of points to ensure you find the nearest one since they are not returned in any paticular order.
  2. This call must be done Asynchronously in the current implementation (I could do the same thing and just call the Intersect method on each geometry but it appears this only returns one contact point so this would not give me the ability to find the nearest point of contact?)
Let me know if you see anything obviously wrong with my implementation; again thank you for taking the time to respond to my post.
Coordinator
Nov 26, 2008 at 4:17 PM
Edited Nov 26, 2008 at 4:18 PM
1. You can adjust the amount of contacts detected and resolved by using the MaxContactsToDetect and MaxContactsToResolve.

2. Indeed. The intersect only returns one feature.

I've been giving this some thought, and I'm still not sure, but it might help you:

1. Maintain a list of geoms in sight.
2. (optional) Check each polygon (vertex) of geometries if they are contained inside your LOS sensor. Make a list of those who are.
3. Create a list of vertices from geometries in the LOS list (only if you did not do step 2), and sort them by the position (Side scroller: sort by X axis)
4. The top (first) vertex in the list is the closest point to the character.

1 - notes: You can do this by using the broad phase collider collision event (OnBroadPhaseCollision). It's the same as if you checked every AABB against each other, but we have some slick algorithms to speed things up, if you use this one.

2 - notes: This step is only to speed things up a little. But then again, it might not.

3 - notes: The sorting can be tricky and you might need to create a comparer your self. .NET is a godsend when it comes to sorting.

4 - notes: The top is the closest, the bottom is the one farthest away.

I'm sorry if this is nonsense, the upper floor (my brains) does not work correctly without sleep. :)
Nov 26, 2008 at 4:25 PM
@genbox

lol at your last comment; I understand how that is.

The problem with maintaining a list of geometries in site is that this los check could be coming from a 100% random location each time because this is a global system used to detect ray intersects with the terrain. I use this for generating dynamic geometry which connects to the terrain as well as weapon effects. This LOS check could be called every frame by multiple players from multiple locations at the same time.

I have not finalized my LOS System yet so I will just try to clean it up a bit and see what the performance is like when it gets into full swing. Thanks a lot for the help and if anything pops into your head about a better way to do simple 2D ray collision please be sure to let me know!