Exploring raycasting

  • Project file: dropbox.com/s/iwy8ckiozyp604z/Raycast.c3p

    Method 1: By Angle

    Store angle and position of each corner of each solid object in an array.

    Create a blue line from sprite, angled towards stored angle, width (length) of LOS.Range.

    Cast ray towards each angle by x=origin+LOS.Range*cos(angle), y=origin+LOS.Range*sin(angle)

    Subevent if ray intersected, set line width to LOS.HitDistance, change color to green (truncate the line if it hits a solid).

    Result/Issues:

    A and D - Rounding errors, line can either collide or not at corners. Expected behavior.

    B - Works as expected

    C - No collision/ray intersection detected (until trying to exit out the other edge). Can confirm when moving around the origin sprite, if the max range for that particular line terminates within the solid, the line stays blue. So the first corner does not trigger the ray intersected event at all (sometimes). Possible bug?

    Method 2: By coordinates

    Same as above, except casting the ray at each corner's stored coordinates. Normally I wouldn't do it this way, except by default there is no way to cast a ray by angle/range and I am experimenting anyways.

    Result/Issues:

    Some lines don't show up at all, some lines work, and some lines shoot all the way through the solid.

    For the lines that don't show up, debug shows that the line is spawned, but with width 0 and set to green. So the intersection event fires, but LOS.HitDistance returns 0. No idea what is going on here.

    For the lines that shoot through the solid, simply no collision was detected (I draw the lines at full length first, then resize if a collision occurs). Can be reasonable due to rounding errors. Either the ray doesn't completely reach the nearest corner to collided, or same as problem C above.

    Further testing reveals that when putting the solids out of LOS range (300), the cast ray action still works. The farthest corner will trigger the intersection event and extend the line as expected, but the nearer 3 corners either don't trigger the intersection event, or they trigger it and LOS.HitDistance is 0.

    There were a few issues and I wasn't sure if I was doing anything wrong/behaving as intended, so I figure I'd make a post and ask for input before making a bug report.

    Also feature request: cast ray by angle, to LOS range? Not a huge deal and I'm out of suggestion votes. Workaround is simple enough, but "x=origin+LOS.Range*cos(angle), y=origin+LOS.Range*sin(angle)" might not be immediately obvious to some people. Also I don't know if there might be a performance benefit to not using sin and cos to calculate out the coordinates when casting a significant amount of rays.

    PS: Thanks for developing this, it was a nice surprise! With canvas, all the tools are finally available to do visualizations for line of sight! redblobgames.com/articles/visibility (Edit: Also really fancy lights and shadows!)

  • Update: Debugger shows 0 collision and poly checks/sec?

  • Update 2: Applied for visual line of sight dropbox.com/s/m6x32uzqcjlf8sk/VisualLOS.c3p

    Canvas' poly outline looks good but the fill doesn't work half the time. Am I doing it wrong?

    Edit: Fixed, it had to do with the order of adding poly points and the resulting intersection of poly points.

  • Hey oosyrag thanks for your feedback. I fixed your GitHub bug this morning, and it should be resolved in today's beta release.

    When a ray passes directly through a corner it is touching the very end of the segment, which is quite improbable unless you actually point at that co-ordinate like you were trying! Due to floating point precision errors it was incorrectly testing as not intersecting, which is what I fixed. The rays C and A should behave correctly as collisions now.

    Looking at the redblob games article you probably wanted D and A to not count as collisions ( which they are ), but unfortunately that would make C always pass through the segment. I would advise checking the distance of the image point to the collision position, and if it's under a very small threshold then perform a second raycast from just past the hit position if you wanted to continue the ray past the corner.

    The 0 collision checks issue is because the raycast mechanism uses different ( new ) collision checks to the rest of the engine. We could add metrics for raycasting to the existing debug data, I will look into it.

    Looking at your example your probably having issues with self intersecting polygons, the polygon rendering algorithm doesn't support complex polygons like this as they are quite difficult and expensive to convert into triangles. You may find it easier to just draw a triangle per segment.

    We probably won't add another action for casting a ray at an angle, but we will consider it. Looking at your event sheet I wasn't sure why you were using angles and not the image points themselves? If you use the LOS between positions condition it will take into account the range, and will still give you the collision information like the RayCast action does. As you say it's easy enough to project the required vector anyway if you know the maths, and this is quite a math heavy behaviour anyway.

    Most of the expressions produce a default value of 0 if there was no hit, but for distance it could be because the ray was colliding with an object at it's origin position? More likely that there was no collision.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Regarding outside corners, I'm using a slightly modified method than from the article. Rather than just one ray at each corner, I'm using two instead, at 0.1 degrees offset at each one so I'll get one that collides and one that doesn't.

    For why I didn't cast at imagepoints, the second part of the example is where I experimented with that (Method 2: By coordinates). More issues popped up than via the first method, although they seem to be gone with the latest update.

    I'll probably end up drawing individual triangles instead of one big poly. Although I avoided the self intersecting problem, other visual glitches popped up, I had another github post on that one.

    Most of the expressions produce a default value of 0 if there was no hit, but for distance it could be because the ray was colliding with an object at it's origin position? More likely that there was no collision.

    The issue here was that I didn't set the line's width to HitDistance unless there was a hit detected as the condition. So there was a hit, and it returned 0. I don't see it occur in R144 at all though.

    With the update, both methods consistently behave as expected. So far so good, thanks!

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)