Today’s tutorial introduces the Corona physics contact which, generally speaking, is a reference to a specific collision which is about to occur.

Pre-collision event

The physics contact will, in almost every case, be used during a pre-collision event, so you can handle the result of the collision before it actually occurs. In any collision event between two objects, Corona allows you to access each object by its Lua object ID. With those references, you might decide to perform an action on one (or both) objects. For example, you might change one object to a sensor, destroy one of the objects, animate it, apply a specific force upon it, etc. While these examples are all possible via a normal collision handler, the pre-collision event, along with the physics contact, can overcome certain unique scenarios.

One-sided platforms

A common requirement in 2D side-view games is the “one-sided platform” such as those in Super Mario Brothers and hundreds of other 2D platform games. The character can jump from beneath a platform, pass through the platform, and land nicely atop it.

One “solution” to this might be to change the character into a sensor at the beginning of a jump, such that it passes through the platform. Then, upon “exit” from the platform, the character is reverted back to a normal object. While this is an acceptable solution in some cases, it presents at least two obvious problems:

  1. What if an enemy “goomba” is walking atop the platform? In this case, the character will still be a sensor when it collides with the enemy’s feet, and the character will pass directly through both the platform and the enemy.
  2. What if the character collides with some other non-platform object during its upward trajectory toward the platform? In this case, normal collision forces such as “bounce” would be lost.

Introducing the physics contact

The solution to the above dilemma can be solved with a physics contact and a pre-collision handler. As stated at the beginning of this tutorial, you can consider the physics contact as a specific reference to a collision that is about to occur. Using this contact reference, you can access four properties that aren’t typically accessible.

Let’s consider the one-sided platform example again. When the character jumps and collides with the platform from below, Corona understands that a collision is about to occur between the character’s head and the bottom of the platform. Using a physics contact, you can gain temporary “access” to this upcoming collision and tell Corona how you’d like to handle it. You can even tell Corona to ignore it completely — and that is exactly what we need for the one-sided platform scenario.

Here’s how to access the physics contact in code, using a pre-collision event listener:

local function onPreCollision( self, event )
    print( )  -- the first object in the collision
    print( event.other )   -- the second object in the collision

    print( )             -- the physics contact reference
    print( )  -- read-only: are the two objects touching?
    print( )   -- true or false; will the collision occur?
    print( )      -- get/set the collision bounce factor
    print( )    -- get/set the collision friction factor

object.preCollision = onPreCollision
object:addEventListener( "preCollision", object )

Notice that the physics contact ( provides you with collision-specific properties that you cannot access in a traditional listener events. Using basic conditional logic, you can then opt to ignore a collision entirely, or even change the bounce or friction factor(s) for that specific collision, overriding the standard bounce/friction that you declared for the object(s).

For a one-sided platform, this physics contact method is ideal. You can initially set a property of the platform as “pass through” (or any other term), and then, using conditional logic, tell Corona to ignore the collision entirely if the the platform is a "passthru" type, as in this example:

local character = display.newImage( "character.png" )
physics.addBody( character, "dynamic", { bounce=0.3, friction=0.3 } )

local platform = display.newImage( "platform.png" )
platform.collType = "passthru"
physics.addBody( platform, "static", { bounce=0.0, friction=0.3 } )

local function onPreCollision( self, event )

   local collideObject = event.other
   if ( collideObject.collType == "passthru" ) then = false  -- disable this specific collision!

character.preCollision = onPreCollision
character:addEventListener( "preCollision", character )

It’s important to note that the physics contact ( is not a reference to either object involved in the collision, but rather a reference to the collision itself. With that reference, you can opt to override the collision entirely — or just tweak a few optional properties of it — before it actually occurs. Also note that setting the physics contact properties does not permanently set those properties on either object involved — Corona only uses the properties for that specific collision, then it discards them. For example, if you change the bounce factor of the physics contact, it will not set/reset the core bounce factor on either object involved, but simply the bounce for that specific collision event.

Other possibilities

While the one-sided platform case is fairly common, there are other potential applications of the physics contact. For example, in a “pinball” game, you could use conditional logic (and physics contacts) to achieve the following:

  • Silver balls collide with red bumpers for extreme bounce (set contact bounce to 1)
  • Silver balls collide with blue bumpers for no bounce (set contact bounce to 0)
  • Gold balls collide with red bumpers for no bounce (opposite of the first case)
  • Gold balls collide with blue bumpers for medium bounce

Sample project

Check out the Corona PhysicsContact sample to see physics contacts and “one-sided platforms” in action.

In summary

The new physics contact provides four new properties that can be accessed on a specific collision basis:

In special circumstances, these properties allow a level of fine-tuned control that is not possible using basic collision events and collision filters.

  1. This is great news and will make our testing much easier.

    But how do you use this with a spawn + table function?

    balls = { }
    function spawnBall ()
    local ball etc
    –add to balls table etc

    ball:addEventListener( “preCollision” ) — throws the expected assertion error


    function ball:preCollision( event )

    • Brent Sorrentino says:

      You can achieve this by using “local” pre-collisions. Replace the global function “char:preCollision” in the demo project with this local function (internal contents remain the same):

      local function preCollision( self, event )


      And then add a local collision listener to each ball in your scenario:

      ball.preCollision = preCollision
      ball:addEventListener( “preCollision”, ball )

      That should work. And thanks for bringing this topic to my attention; certainly its a useful method if there are many objects following this preCollision behavior.

      • Thanks for the reply. Don’t why I thought it required something other than the usual approach.

        Anyhow, this:

        function onLocalPreCollision( self, event ) — can’t use local on this function

        print( “enabled ” .. )

        Throws this error
        Build: 2012.971
        Runtime error
        d:\coronasdk\game\main.lua:616: attempt to concatenate field ‘isEnabled’ (a boolean value)

        Also, imho, adding the four new properties to ‘self’ would easily be as useful as your adding them to ‘event’

        • Brent Sorrentino says:

          Your error is a concatenation error, not an error with the For some reason (I have never determined why), Lua occasionally gripes when you try to concatenate two items. Instead of concatenating them, just type it like:

          print( “enabled”, )

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>