Corona SDK – Physics – chains

Playing with physics joints today. A common physics effect is to create chain. A chain in Corona SDK is a group of physics objects joined together with a Pivot joint. Create a chain by creating a series of display objects, use physics.addBody() to turn them into physics bodies, and last create a joint between each object connecting them in series.

A chain will often contain many links. This means that you will end up creating many physics bodies, and a joint a between pair. This is a lot of objects. Best to use a Loop here.

Create a joint between two physics objects with physics.newJoint(). The method takes 5 parameters:

physics.newJoint( "pivot", object1, object2, anchorX, anchorY )
  •  “pivot” – Sets the type of joint to pivot. 
  • object1 – first object in the joint.
  • object2 – second object in the joint.
  • anchorX – X position of of the joint between the two objects.
  • anchorY – Y position of the joint between the to objects.

The anchorX and anchorY set a common point where object1 and object2 are connected.

Here’s a simple function that makes a chain made of any number of rectangular links.

local function make_chain( x, y, w, h, c )
	local prev_link
	for i = 1, c do 
		local link = display.newRect( x, y+(i*(h+1)), w, h )
		if i == 1 then 
			physics.addBody( link, "static" )	
		else 
			physics.addBody( link, "dynamic" )	
			link.linearDamping = 1
			link.angularDamping = 11
		end 
		if i > 1 then 
			print( i )
			physics.newJoint( "pivot", prev_link, link, x, prev_link.y + (h*0.5) )
		end 
		prev_link = link
	end 
end 

This function takes 5 parameters

  • x – The x position of the first link.
  • y – The y position of the first link.
  • w – Width of each link.
  • h – Height of each link.
  • c – (Count) the number of links in the chain.

The first chain link is a static and so supports the chain.

For testing try the code below. Make a new default project in Corona and paste the following into main.lua. This example creates a chain, and a circle. Swipe to shoot the ball. The ball helps give you an idea how the chain reacts. 

local physics = require( "physics" )
physics.start()
physics.setDrawMode("hybrid")
-- physics.setContinuous( false )
physics.setVelocityIterations( 16 )

local function make_chain( x, y, w, h, c )
	local prev_link
	for i = 1, c do 
		local link = display.newRect( x, y+(i*(h+1)), w, h )
		if i == 1 then 
			physics.addBody( link, "static" )	
		else 
			physics.addBody( link, "dynamic" )	
			link.linearDamping = 1
			link.angularDamping = 11
		end 
		if i > 1 then 
			print( i )
			physics.newJoint( "pivot", prev_link, link, x, prev_link.y + (h*0.5) )
		end 
		prev_link = link
	end 
end 

make_chain( 160, 10, 20, 20, 10 )
-- make_chain( 160, 10, 20, 100, 3 )
-- make_chain( 160, 10, 10, 30, 5 )
-- make_chain( 160, 10, 5, 10, 20 )
-- make_chain( 80, 10, 5, 10, 20 )
-- make_chain( 240, 10, 5, 10, 20 )


local floor = display.newRect( 160, 480, 320, 10 )
physics.addBody( floor, "static" )
local left = display.newRect( 0, 240, 10, 480 )
physics.addBody( left, "static" )
local right = display.newRect( 320, 240, 10, 480 )
physics.addBody( right, "static" )
local top = display.newRect( 160, 0, 320, 10 )
physics.addBody( top, "static" )

local ball = display.newCircle( 160, 300, 30 )
physics.addBody( ball, "dynamic", {radius=30} )

local function shoot( event ) 
	if event.phase == "ended" then 
		local dx = event.x - event.xStart
		local dy = event.y - event.yStart
		ball:applyLinearImpulse( -dx * 0.01, -dy * 0.01, ball.x, ball.y )
	end 
end 

Runtime:addEventListener( "touch", shoot )

 

FOAM

And another, physics engine. this one looks pretty good.

http://blog.generalrelativity.org/actionscript-30/foam-rigid-body-physics-engine-alpha-release-01/

After playing with FOAM for an evening, I found this engine to be a fairly easy to work with. I did run into a problem where the FOAM Vector class conflicted with the built in Flash Vector class. The Flash Vector class was added in CS4, FOAM obviously was written before this.

The problem could have been circumvented by carefully qualifying package names. This would have been an elegant and intelligent solution. In stead I decided for the more ham fisted approach of changing all instances of the name Vector to VectorPoint.

I just opened all of the files in the org.generalrelativity.foam and subpackages and did a find and replace on each file, replacing Vector for VectorPoint. Don’t forget to change the file name of Vector.as to VectorPoint.as. Compiler errors will often point out any spots where you missed an instance of the name.

The generalrelativity blog posts some FOAM renderers. This are useful files. I packaged them in the org.generalrealtivity.foam.view package. It seemed like a logical place to store them. Don’t forget to change the package declaration at the top of each of these files.

FOAM seems pretty easy to use. Unlike Box2d it uses pixels and stage coordinates to position elements on the stage which made it more intuitive to use. The property names seem very intuitive also. Moving objects look to all be built off the SimpleParticle class. Which has obvious properties like x and y to work with. So, creating any Object that inherits from SimpleParticle, you can position it by setting it’s x and y to stage coordinates. Pretty simple. Almost like working with regular MovieClips.

I did notice that fast moving objects could pass through another object. I assume this is caused when the velocity is great enough that the object moves past the interposing object without intersecting.