Gravity is just a constant acceleration over time. The physics engine’s “gravity” property is just a shortcut for applying a constant acceleration to each dynamic body in the simulation. If we wanted to effect different “gravities” on each body, we could turn off the physics engine’s application of gravity completely, and simply apply whatever force we want every frame to our bodies manually. Here is an example:
-- gravity demo
function setup()
-- some control variables
numBodies = 10
bodyRadius = 20
width = WIDTH
height = HEIGHT
-- turn of the physics engine's gravity altogether.
-- we're gonna do it ourself
physics.gravity(0, 0)
-- the "ground" body
ground = physics.body(CHAIN, true,
vec2(0, 0),
vec2(width, 0),
vec2(width, height),
vec2(0, height)
)
ground.type = STATIC
-- we'll keep all of our bodies in this table
bodies = {}
-- create the bodies and set them up
for i = 1, numBodies do
-- create, setup, and add the body to our bodies table
local body = physics.body(CIRCLE, bodyRadius)
body.type = DYNAMIC
body.x = math.random(bodyRadius, width - bodyRadius)
body.y = math.random(bodyRadius, height - bodyRadius)
body.restitution = 0.5
table.insert(bodies, body)
-- body.info can store a table of arbitrary values
body.info = {}
-- we'll create a random "gravity" for this body,
-- and add it to the body's info. we'll use this
-- again in draw()
local dir = math.random(1, 4)
if dir == 1 then
-- down
body.info.gravity = vec2(0, -10)
elseif dir == 2 then
-- right
body.info.gravity = vec2(10, 0)
elseif dir == 3 then
-- up
body.info.gravity = vec2(0, 10)
else
-- left
body.info.gravity = vec2(-10, 0)
end
end
end
function draw()
background(0)
-- draw the ground
strokeWidth(2)
stroke(255)
line(0, 0, width, 0)
line(width, 0, width, height)
line(width, height, 0, height)
line(0, height, 0, 0)
-- draw the bodies
for i, body in ipairs(bodies) do
-- draw the body
noStroke()
fill(255)
ellipse(body.x, body.y, bodyRadius*2)
-- draw the direction that it is "facing" in green
-- (so we can see it rolling)
local bodyDir = vec2(1, 0):rotate(math.rad(body.angle))
strokeWidth(2)
stroke(0, 255, 0)
line(body.x, body.y, body.x + bodyDir.x*10, body.y + bodyDir.y*10)
end
-- physics is updated before draw(), so let's
-- apply "gravity" after we've drawn our bodies,
-- since it won't be applied til next frame anyway
for i, body in ipairs(bodies) do
local grav = body.info.gravity
-- that's right. all "gravity" really is, is a constant acceleration.
-- i.e. a force applied constantly over time.
body:applyForce(grav)
-- draw the gravity's direction in red
stroke(255, 0, 0)
strokeWidth(2)
line(body.x, body.y, body.x + grav.x*2, body.y + grav.y*2)
end
end
Using this method opens up other possibilities too, for example radial gravity, or perhaps a simulation where every body asserts it’s gravity on every other body, or really whatever you want to do.