CoCraTu 5: Physics
We’ve learned how to move things using code. It turns out that Codea can handle moving them for us, for fun and profit.
Codea has “physics”, the ability for our programs to simulate real-world physics, more or less accurately. In fact, Codea has two kinds of physics, 2D and 3D. 3D, naturally, is part of Craft, and that’s our subject for today, and probably for a few more sections.
We have seen how to create “entities”, and how to give them visible shapes. It turns out that entities can have physical shapes as well, but just a few such shapes. An entity that responds to physics must have an element called rigidbody
, which can take on three values:
- DYNAMIC - subject to physics including forces, gravity and collisions;
- STATIC - Not affected by forces. Can collide with DYNAMIC;
- KINEMATIC - Can be given velocity. Can collide with DYNAMIC.
Physical entities also have “shape”, which can be any of:
- box - a rectangular box of any dimensions;
- sphere - a sphere of any radius;
- capsule - a sort of pill-shaped thing of any radius;
- model - any model.
Using a model allows for physical objects of arbitrary shape.
Our First Physics Example
Our first example is a simple cube that starts up in the “air”, and falls to the floor under the influence of gravity. We begin with this program:
-- CoCraTu-005
function setup()
scene = craft.scene()
createFloor()
createBox()
scene.camera:add(OrbitViewer, vec3(0,0,0), 20, 1, 20)
angle = 0
end
function update(dt)
scene:update(dt)
end
-- Called automatically by codea
function draw()
update(DeltaTime)
scene:draw()
end
function createBox()
local box = scene:entity()
local body = 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
function createFloor()
local floor = scene:entity()
local body = 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
Let’s consider the floor first:
function createFloor()
local floor = scene:entity()
local body = 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
This is a standard floor, like in our previous examples, but we’ve added these two lines:
local body = floor:add(craft.rigidbody, STATIC)
floor:add(craft.shape.box, vec3(25, 0.01, 25))
This informs Codea that our floor is subject to physics, that it does not move, and that its shape is a box. I’ve given the box the same shape as the visible dimensions. That’s what we’ll usually do.
The box is similar, given a box-shaped rigidbody
, but it’s DYNAMIC. The third parameter there is the mass of the object, which of course plays into how it behaves under physics.
Since this object is DYNAMIC, and since we start it at a y coordinate of 5, we expect to see it start high up and fall to the floor. And it does:
We can make this a bit more interesting if we rez our cube at a somewhat random angle. Add this line:
function createBox()
local box = scene:entity()
local body = 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)
-- add line below
box.eulerAngles = vec3(math.random(10), math.random(10), math.random(10))
box.y = 5
return box
end
Now the box doesn’t fall squarely onto the floor and gravity will pull it down until it finally lands flat.
There isn’t much bouncing, because neither the floor nor the cube are bouncy. The technical term for bounciness is “coefficient of restitution”. If restitution is zero, the object is not bouncy. If restitution is one, it is perfectly bouncy. For numbers between zero and one, it’s somewhat bouncy.
I’ll leave it to you to find out what happens if it’s larger than one.
Let’s give the floor and box restitution of 0.9:
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)
-- add line below
box.eulerAngles = vec3(math.random(10), math.random(10), math.random(10))
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
Now our cube bounces around quite nicely. You’ll also note that it can fall off the edge and drop, presumably forever. When we write physics programs we need to be careful not to lose objects, unless we want to. We would generally do this by providing walls, which may or may not be visible. We’ll explore a walled space in a subsequent example.
Summary
We’ve seen that Codea Craft provides a notion of physics, which includes gravity and coefficient of restitution. We’ll see in future sections that we can apply a velocity to our objects, or linear or rotational forces. Using these facilities can allow us to create interesting simulations of physical systems, or games involving vehicles and missiles. The limit is our own imagination.
In upcoming sections, we’ll experiment with multiple collisions, and we’ll explore some of the other capabilities of the Craft physics model.
Challenge
Here are a few things you might want to try before we move on:
- Walls
- Can you build some walls around our floor, so that the cube can’t escape?
- Velocity
- What happens if you set
body.linearVelocity
to a small vector? - Multiple Objects
- Can you create a number of objects inside your walls and get them to interact?
Reading
Try exploring the Codea docs around craft.rigidbody
and related topics. See if you can discover anything useful. And if you do, please let me know!