# Boa: a Physics Lab experiment with linearDamping

The code below is intended to be added as a new tab to a copy of the Physics Lab example project and `TestBoa()` as the first test in the list of tests in the `Main` tab’s `setup()` function. It makes use of the `linearDamping` property of a `physics.body`, that is not currently documented in the in-app reference. As the test ‘turns off defaultGravity’, it is important that it is the first test.

An example of the test running is below:

``````
--
-- Boa, a Physics Lab test
-- Add TestBoa() to tests = {TestBoa(), ...} list in Main setup()
--
TestBoa = class()

local HEAD, BODY, TAIL = 1, 2, 3
local size = 10 -- Sets the scale of the snake

function TestBoa:init()
self.title="Boa - Touch and drag head to move"
vec2(1, 2),
vec2(0.5, 4),
vec2(-0.5, 4),
vec2(-1, 2),
vec2(-1, -3),
vec2(0, -4),
vec2(1, -3)}
vec2(1, 3),
vec2(0, 4),
vec2(-1, 3),
vec2(-1, -3),
vec2(0, -4),
vec2(1, -3)}
vec2(1, 3),
vec2(0, 4),
vec2(-1, 3),
vec2(-1, 2),
vec2(0, -4),
vec2(1, 2)}
for k, v in ipairs(linkPoints) do
for i = 1, #v do
v[i] = v[i] * size
end
end
end
end

function TestBoa:setup()
self.joints = {}
local nLinks = 10 -- Sets the length of the snake
for i = 2, nLinks do
local type = BODY
if i == nLinks then type = TAIL end
local oc = ol.position
local nc = oc + vec2(0, -6 * size)
local joint = physics.joint(REVOLUTE, nl, ol, (oc + nc) / 2)
end
-- Turn off defaultGravity (if first test setup by Physics Lab)
physics.gravity(0, 0)
end

function TestBoa:cleanup()
self.joints = nil
end

function TestBoa:draw()
pushStyle()
pushMatrix()
translate(hPos.x, hPos.y)
rotate(hAng)
-- Draw a forked tongue
lineCapMode(ROUND)
stroke(255, 0, 0)
strokeWidth(10)
line(0, 4 * size, 0, 5 * size)
strokeWidth(7)
line(0, 5 * size, -0.3 * size, 5.5 * size)
line(0, 5 * size, 0.3 * size, 5.5 * size)
-- Draw two eyes
noStroke()
fill(255)
ellipse(-0.7 * size, 2 * size, 0.8 * size)
ellipse(0.7 * size, 2 * size, 0.8 * size)
popMatrix()
popStyle()
end

function TestBoa:touched(touch)
end

``````

I get error on line 77.

Show me your main and I’ll try it.

Nice one @mpilgrem.

@wrmichael - you add it as a new class, TestBoa ,to the physics lab example then modify line 11 in Main to include the new class. It should now read

``````    tests = {Test1(), Test2(), Test3(), Test4(), Test5(), Test6(), Test7(), Test8(), TestBoa()}
``````

Cool. But my Bo just drops and falls off the screen.

@wrmichael You might want to try turning off gravity ;).

I see the problem @wrmichael. It lies in `setup()` in `Main`, which preserves `defaultGravity` only after having initialised all the tests and having setup the first test. It also lies in `draw()`, that repeatedly resets gravity to `defaultGravity`.

The quick fix is to make sure that `TestBoa()` is the first test listed in `tests = {TestBoa(), ... }`.

Hello @John. I have added the following suggested changes, to the Physics Lab example project, to the Issue Tracker:

A. Preserve `defaultGravity` before the tests are initialised and, importantly, before `tests[1]` is set up through `setTest(currentTestIndex)`. That is, move the following line in the existing `setup()` function immediately after creating `debugDraw = PhysicsDebugDraw()`:

`defaultGravity = physics.gravity()`

B. Allow a test to override the default `defaultGravity` by changing the logic at the end of the existing `draw()` function as follows:

``````
if use_accelerometer == 1 then
physics.gravity(Gravity)
else
physics.gravity(currentTest.defaultGravity or defaultGravity) -- Changed
end

``````

If I make the changes above to a copy of the Physics Lab example project, in the `TestBoa:setup()` function I need to replace the final line:

`physics.gravity(0, 0)`

with

`self.defaultGravity = vec2()`

The position that `TestBoa()` appears in `tests = {...}` then does not matter.

The following replacement for `TestBoa:draw()` colours in the snake’s body. The helper function is required because `triangulate()` requires points to be in the opposite order (clockwise) to that required by `physics.body(POLYGON, ...)` (anti-clockwise).

``````
function TestBoa:draw()
pushStyle()
pushMatrix()
-- Colour in the body yellow-green
for i = 1, #self.links do
local m = mesh()
m:setColors(196, 255, 0)
resetMatrix()
m:draw()
end
resetMatrix()
-- Draw a forked red tongue
lineCapMode(SQUARE)
stroke(255, 0, 0)
strokeWidth(10)
line(0, 4 * size, 0, 5 * size)
lineCapMode(ROUND)
strokeWidth(7)
line(0, 5 * size, -0.3 * size, 5.5 * size)
line(0, 5 * size, 0.3 * size, 5.5 * size)
-- Draw two black eyes
noStroke()
fill(0)
ellipse(-0.7 * size, 2 * size, 0.8 * size)
ellipse(0.7 * size, 2 * size, 0.8 * size)
popMatrix()
popStyle()
end

-- Helper function
function reverse(p)
local n = #p
local rp = {}
for i = 1, n do
rp[i] = p[n - i + 1]
end
return rp
end

``````

The code below is a variation on the same theme, showing how one snake can interact with another. It assumes the changes to a copy of the Physics Lab example project in my post above.

``````
--
-- Box of Boas, a Physics Lab test
-- Add TestBoa() to tests = {TestBoa(), ...} list in Main setup()
--
TestBoa = class()

local HEAD, BODY, TAIL = 1, 2, 3

Boa = class()

if type == BODY then link.linearDamping = 3 end
end

function Boa:init(hPos, length, size, colour)
self.size = size
self.colour = colour
vec2(1, 2),
vec2(0.5, 4),
vec2(-0.5, 4),
vec2(-1, 2),
vec2(-1, -3),
vec2(0, -4),
vec2(1, -3)}
vec2(1, 3),
vec2(0, 4),
vec2(-1, 3),
vec2(-1, -3),
vec2(0, -4),
vec2(1, -3)}
vec2(1, 3),
vec2(0, 4),
vec2(-1, 3),
vec2(-1, 2),
vec2(0, -4),
vec2(1, 2)}
for k, v in ipairs(self.linkPoints) do
for i = 1, #v do
v[i] = v[i] * size
end
end
self.joints = {}
self.meshes = {}
for i = 2, length do
local type = BODY
if i == length then type = TAIL end
local oc = ol.position
local nc = oc + vec2(0, -6 * size)
local joint = physics.joint(REVOLUTE, nl, ol, (oc + nc) / 2)
end
for i = 1, length do
local m = mesh()
m:setColors(colour)
self.meshes[i] = m
end
end

function Boa:draw()
local size = self.size
local colour = self.colour
pushStyle()
pushMatrix()
-- Colour in body of snake
for i = 1, #self.links do
resetMatrix()
self.meshes[i]:draw()
end
resetMatrix()
-- Draw red forked tongue
lineCapMode(SQUARE)
stroke(255, 0, 0)
strokeWidth(10)
line(0, 4 * size, 0, 5 * size)
lineCapMode(ROUND)
strokeWidth(7)
line(0, 5 * size, -0.3 * size, 5.5 * size)
line(0, 5 * size, 0.3 * size, 5.5 * size)
-- Draw two black eyes
noStroke()
fill(0)
ellipse(-0.7 * size, 2 * size, 0.8 * size)
ellipse(0.7 * size, 2 * size, 0.8 * size)
popMatrix()
popStyle()
end

function TestBoa:init()
self.title="Box of Boas - Touch and drag heads to move"
end

function TestBoa:setup()
self.defaultGravity = vec2()
local n = 5
self.snakes = {}
for i = 1, n do
local l = math.random(8, 12)
local s = math.random(20 - l, 22 - l)
local c = color(math.random(128, 255), math.random(128, 255),
math.random(64))
self.snakes[i] =
Boa(vec2(WIDTH/(n + 1) * i, HEIGHT * 4/5), l, s, c)
end
end

function TestBoa:cleanup()
self.snakes = nil
end

function TestBoa:draw()
for i = 1, #self.snakes do
self.snakes[i]:draw()
end
end

function TestBoa:touched(touch)
end

-- Helper function
function reverse(p)
local n = #p
local rp = {}
for i = 1, n do
rp[i] = p[n - i + 1]
end
return rp
end

``````

Hello @John. My experiments with `linearDamping` and `angularDamping` have identified a minor bug in their implementation, which I have added to the Issue Tracker and the wiki.

Setting is fine but, when getting,`myBody.linearDamping` and `myBody.angularDamping` return booleans, rather than the numerical value set for the property of the body. This is because, in `Lget` in `body.mm`, `lua_pushboolean` has been used instead of `lua_pushnumber`.

Cheers, I’ll fix those right away