I think we need to learn about Craft physics so that we can tutorialize something about it. This turns out to be a bit of fun.

My programing history has put me in a place where, when what I’m working on has to move something, I move it to the place where it should go. Even if I need gravity, I still calculate everything and then plunk the object where the net forces say it should go.

This is no longer the way, at least sometimes. Systems these days include “physics”, embedded simulators for forces, gravity, friction, and all that jazz. Codea, not to be outdone, has physics for its 2D graphics, and physics for Craft, the 3D graphics subsystem. I figure that if we’re doing a Craft tutorial thing, we’ve got to include physics.

I plan to start small.

First, I think I would like to have a floor, so I’m starting with this program.

-- CoCraTu-005

function setup()
    scene = craft.scene()
    createFloor()
    scene.camera:add(OrbitViewer, vec3(0,0,0), 5, 10, 20)
    angle = 0
end

function update(dt)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)
    scene:draw()	
end

function createFloor()
    local floor = scene:entity()
    floor.model = craft.model.cube(vec3(25, 0.1, 25))
    floor.y = -1.05
    floor.material = craft.material(asset.builtin.Materials.Specular)
    floor.material.map = readImage(asset.builtin.Blocks.Brick_Grey)
    floor.material.offsetRepeat = vec4(0,0,25,25)
    return floor
end

That gives me a large floor:

floor

I think that I have to make the floor physical, and static (because it doesn’t move). Copying from the documentation I try this:

function createFloor()
    local floor = scene:entity()
    floor:add(craft.rigidbody, STATIC)
    floor:add(craft.shape.box, vec3(25, 0.01, 25))
    floor.model = craft.model.cube(vec3(25, 0.1, 25))
    floor.y = -1.05
    floor.material = craft.material(asset.builtin.Materials.Specular)
    floor.material.map = readImage(asset.builtin.Blocks.Brick_Grey)
    floor.material.offsetRepeat = vec4(0,0,25,25)
    return floor
end

I’ve added a “rigidbody” to the floor entity, and given the floor a “shape” consisting of a box the same dimensions as the visible floor.

Now my plan is to rez a cube in mid-air and see if it falls to the floor. So I need to create a box:

function setup()
    scene = craft.scene()
    createFloor()
    createBox()
    scene.camera:add(OrbitViewer, vec3(0,0,0), 15, 1, 20)
    angle = 0
end

function createBox()
    local box = scene:entity()
    box:add(craft.rigidbody, DYNAMIC, 1) -- mass
    box:add(craft.shape.box, vec3(1,1,1))
    box.model = craft. model.cube(vec3(1,1,1))
    box.material = craft.material(asset.builtin.Materials.Specular)
    box.material.map = readImage(asset.builtin.Blocks.Missing)
    box.y = 5
    return box
end

Note that I’ve changed the camera to be zoomed out to 15. I did this by trial and error to get what I hope will be an adequate view of the proceedings.

My fond hope at this point is that when the program runs, a box will appear about 5 units up and plunge to the floor, and then stop. Let’s find out.

Amazing! It worked as anticipated. The cube fell. Better yet, it stopped.

it falls

Let’s see if we can make the cube bounce. It turns out that a rigidbody has an attribute restitution, which doesn’t mean it’ll pay you back a loan, but that it is bouncy. 1.0 is 100 percent bounce. We’ll need to make both our floor and cube bouncy:

function createBox()
    local box = scene:entity()
    local body = box:add(craft.rigidbody, DYNAMIC, 1) -- mass
    body.restitution = 0.9
    box:add(craft.shape.box, vec3(1,1,1))
    box.model = craft. model.cube(vec3(1,1,1))
    box.material = craft.material(asset.builtin.Materials.Specular)
    box.material.map = readImage(asset.builtin.Blocks.Missing)
    box.y = 5
    return box
end

function createFloor()
    local floor = scene:entity()
    local body = floor:add(craft.rigidbody, STATIC)
    body.restitution = 0.9
    floor:add(craft.shape.box, vec3(25, 0.01, 25))
    floor.model = craft.model.cube(vec3(25, 0.1, 25))
    floor.y = -1.05
    floor.material = craft.material(asset.builtin.Materials.Specular)
    floor.material.map = readImage(asset.builtin.Blocks.Brick_Grey)
    floor.material.offsetRepeat = vec4(0,0,25,25)
    return floor
end

The result is that the cube bounces nicely. After a while, it doesn’t come down quite square and starts to tumble. Probably that’s roundoff.

bouncing cube

Summary

This went quite smoothly. I did find an example for restitution but I was already on the right track.

I don’t think I know enough about Craft physics yet to write the tutorial, but I’ve got a good start. Not bad for a Saturday morning.