A few weeks ago, a useful new daily build feature was added to Corona’s physics system: raycasting. The physics.rayCast() API is an easy-to-use function for casting a “sensor ray” into the physics world — and we didn’t stop with that. Soon after, reflection was added to the raycasting system via the physics.reflectRay() API. Today’s tutorial discusses both of these and includes a “real world” demo project which you should download so you can follow along.

What is Raycasting?

raycast-screenAt the most basic level, raycasting involves transmitting a ray — a straight line — from one point to another point, and using it to detect if one or more physics bodies resides in that path. Among other things, this can be used to detect if an object resides in the firing path of a gun, “the line-of-sight” of an NPC, etc. Essentially, it’s a quick and efficient way to query the physics world for the presence of other physics objects.

Corona also features a convenient API for reflecting a ray from any object it strikes. From any raycast with a registered hit, physics.reflectRay() returns a vector representing the direction of the reflection, with a magnitude (length) of 1. Today’s demo shows this API in practice.

Room of Mirrors

If you haven’t downloaded the demo project, please do so and follow along with the code.

The first step in the demo is to configure the world, in this case a room of mirrors with a laser turret in the center. You can set up your physics world however you wish, of course. This example just loops through a series of tables containing x, y, and rotation values for each mirror and places them on the screen. The turret itself is a standard display object with a radial physics body — yes, raycasting reflection works on radial bodies too!

Next, we’ll add a tap listener to the stage with an event listener targeting the screenTap function. In addition, a canFire boolean flag controls if the user can fire a laser. The castRay function called on a screen tap event is explained in the next section.

Casting the Ray

Casting the actual ray is simple. Just provide an x and y starting position, an x and y destination, and the total number of “hits” you wish to detect.

The physics.rayCast() API returns an array of tables describing each hit, but since we’re only interested in the first hit that the raycast registers, we’ll only deal with the first table in the array.

From the table representing the specific hit, we get the following details:

  • object — The display object colliding with the ray.
  • position.x — The x collision position of “object”, in content space.
  • position.y — The y collision position of “object”, in content space.
  • normal.x — The x component of the normal of the surface hit in “object”, in local space.
  • normal.y — The y component of the normal of the surface hit in “object”, in local space.

If we register at least one hit — as in, physics.rayCast() doesn’t return nil — we can use the hit information to draw a line from the starting point to the hit point:

Reflecting the Ray

If you wish to reflect the ray off a surface it hits, Corona provides the convenient physics.reflectRay() API. As stated above, this returns a vector representing the direction of the reflection, with a magnitude (length) of 1.

Calling this function requires three arguments.

  • from_x — the starting x position of the cast ray.
  • from_y — the starting y position of the cast ray.
  • hit — an entry in the “hits” array, as returned by the cast ray.

Notice that the from arguments are based on the core raycast starting position, not the hit position x and y.

To extrude the reflected ray and set a destination point for it, just factor in a vector length of your choosing, sum it to the hit point, and then draw a new line from the hit point to the next destination point. In this example, we use 1600 for the vector length, but it can be set to whatever you need for the reflected vector.

In the demo project, the castRay() function repeats until there are no more hits or when the maxBeams value is exceeded. This is useful when a particular beam begins to bounce directly back and forth between two surfaces in such a similar pattern that the process would repeat almost indefinitely. When either condition is satisfied and the process is terminated, we call a basic transition to fade out the parent display group, and then clear/reset the group when the transition completes.

In Summary…

This essentially completes the demo walkthrough. If you tap on the screen, a laser beam is fired from the turret to the point where you tapped. A raycast is done upon that line, and if it hits another object in the physics world, the ray reflection is calculated and extruded to another point. Based on that data, another raycast is performed and the process continues until there are either no more hits or the beam threshold is exceeded.

As you can see, raycasting can be a useful addition to your physics toolset. From querying the physics world to calculating a potential path of a moving object, raycasting is fast, simple, and can be accomplished in just a few lines of code.

Questions or comments? Please post below — and if you haven’t yet downloaded the demo project, please do so here.

Original article:  

Physics Raycasting and Reflection