Converging on a plan, I decide to do a series of tutorials. Herein, an explanation of what I mean and intend, and the first one.

Introduction

The exploration mode in something like Codea Craft is just too painful to write about, and must surely be painful to read. So I’ve decided to try writing a series of tutorials about Codea Craft. They will consist of examples that work, without the innumerable mistakes and false paths that I actually take to get there.

These tutorials will start out very basic and get more advanced as time goes on. If you’re already pretty good with Codea Craft, this and other early articles may be too basic for you. However, if you check them out, please provide feedback on how they could be improved, or on any errors I may make.

To the extent that I show the exploration process, which may sometimes be valuable, I’ll do it in sidebars to the tutorial, so that they’ll be easier to skip for those who want to know one way to do something, rather than several ways not to.

Over time, I’m sure I’ll be building CodeaUnit tests into the process, and of course there will be a certain amount of refactoring. However, at this writing, I do not intend to be doing one growing application, but instead, a series of small complete programs. I’m sure that quite often, a given program will start out based on one from before, but we’ll be creating a series of separate programs.

Feedback via Twitter (@RonJeffries) or email (ronjeffries at acm dot org) are always welcome. Or suggestions, ideas, corrections, questions. Whatever.

I think the short name for the series will be CoCraTu, or, very likely cocratu1.

Let’s get to it.

In the Beginning, There Was the Cube

In this first tutorial, we’ll display a cube on the Codea Craft screen, and give it a bit of behavior.

We will get our first introduction to Codea Craft’s scene, entity, material, and map, as well as a glance at the eulerAngles of the entity. And we’ll just barely touch the camera.

At the end of this chapter, I’ll link to some reading that relates to what we’ve seen here. And I’ll issue a small challenge.

Create a New Project

Use Codea’s + button to create a new project. Be sure to use the Craft template:

create

The editor will open on a screen that looks like this:

-- CoCraTu-001

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    local e = scene:entity()
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
end

I’ll leave the irritating comments in the template for a while, but my own practice is to work without them once I get the picture of what’s happening.

What’s This Code Doing?

Scene
Every Codea Craft program has at least one scene, and there is, as far as I know, only one scene at a time.
Entity
A scene has one or more entities, that is, “things” that are managed and displayed by Craft.
Draw
Codea calls the function draw() frequently, at the fastest speed it can manage, choosing speeds 1/120 sec, 1/60, 1/30. The frequency of its calls depends on the speed of your device and how complex the scene is.
Update
Our responsibility is to call the function scene:update(deltaTime) on every draw cycle. By convention, as we see here, we write an update function in Main and call it. Inside that function we can make any changes we want to the situation, and then call scene:update.

The changes we might make, as we’ll see below, might move objects, rotate them, or change our view of them.

It’s easy to make mistakes when programming, and very easy to make mistakes with Codea Craft. Therefore, we run our programs very often, and when we add tests to them, we run those often as well. When we run now, we get an entirely blank screen, showing the Codea console on the left.

blanks

Now let’s do the least we can to draw our first Craft object, a cube.

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    local e = scene:entity()
    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    scene.camera.z = -4
end

This give us this picture:

the cube

Lets look at the three new lines we wrote:

    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    scene.camera.z = -4

The model is the shape of the entity. Craft has a few built-in models, including the cube and the “isosphere”. Our first line above says that our cube should have dimensions 1x1x1. What are the units? For now, let’s not worry about that. The question’s time will come, I’m sure. They’re just the units of things on the display.

Where is it? Our cube defaults to location (0,0,0). That will be important below.

The material is analogous to the notion of material in Blender or other 3D drawing applications. I think of it as a kind of canvas wrapped around the shape, on which we can paint, with the capability Codea calls map. We’ll see that soon. Here, we used the built in asset Basic.

In Codea, if we touch that line, we get this picture:

assets

We can scroll to find Materials:

materials

And touching that, we get a selection of materials:

selection

I touched Basic, which was how that line got filled in.

Without a material, the object won’t be visible at all. You can test that by commenting out the material line.

The final line is

    scene.camera.z = -4

We’ll see more about cameras later on. Here, we’re using the default camera, which starts out at location (0,0,0). But our cube also sits at 0,0,0, which means the default camera is inside the cube, which means that we can’t see the cube. (It has no paint on the inside.)

So we move the camera toward ourselves. Yes, that’s right, the z axis is “out to in” on the screen. Negative z is toward you, positive is away from you.

So this program:

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    local e = scene:entity()
    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    scene.camera.z = -4
end

Creates a unit cube at (0,0,0), gives it a basic material, and looks at it from four units out. No surprise, it looks like a square, since we’re looking at it straight on.

Let’s spiff this up a bit. In addition to its position, an entity has a rotation, which can be set by setting its eulerAngles property. The rotation is a quaternion. No one wants to create quaternions directly, so eulerAngles is a blessing.

Let’s rotate our cube by 45 degrees and see what we get.

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    local e = scene:entity()
    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    e.eulerAngles = vec3(0,45,0) 
    scene.camera.z = -4
end

We get this picture:

cube at 45

It’s fairly easy to see that this is a view of our plain cube at 45 degrees. Yes. eulerAngles is in degrees, not radians.

Paint the Cube

The cube is so plain, however, that it is quite difficult to make out where its edges are. We can improve that.

Add this line after the e.material line:

    e.material.map = readImage()

Then touch the parens, and you should see the asset browser again:

assets2

This time select Blocks, which are convenient textures for the blocks we’ll be using in later tutorials. I selected the Missing one:

missing

The code is now this:

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    local e = scene:entity()
    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    e.material.map = readImage(asset.builtin.Blocks.Missing)
    e.eulerAngles = vec3(0,45,0) 
    scene.camera.z = -4
end

And the picture is this:

cube with question mark

Now we can see that we really have a cube. You should wonder why our map has appeared on more than one face of the cube. That will be because of how the material is defined, with each face of the cube using the whole material. Materials and the textures they contain are an entire topic. We may touch on them in future chapters, but they are more the domain of your favorite 3D object making program.

Rotate the Cube

But let’s go a bit further with our cube. We now know how to set the rotation of the cube. Let’s set it dynamically!

We’ll need access to our entity e, in update, so we remove the local in setup, we add an angle to update, and we do the update:

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    e = scene:entity()
    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    e.material.map = readImage(asset.builtin.Blocks.Missing)
    e.eulerAngles = vec3(0,0,0) 
    scene.camera.z = -4
    angle = 0
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    angle = angle + 1
    e.eulerAngles = vec3(0, angle, 0)
    scene:update(dt)
end

In update, we increment the angle and set the entity’s eulerAngles` to cause it to rotate around its y (vertical) axis.

The result is this:

cube rotates

Perfect! As our final trick, let’s make it tumble:

function update(dt)
    -- Update the scene (physics, transforms etc)
    angle = angle + 1
    e.eulerAngles = vec3(angle/10, angle, angle/5)
    scene:update(dt)
end

cube tumbles

Let’s view the entire program and review:

-- CoCraTu-001

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    e = scene:entity()
    e.model = craft.model.cube(vec3(1,1,1))
    e.material = craft.material(asset.builtin.Materials.Basic)
    e.material.map = readImage(asset.builtin.Blocks.Missing)
    e.eulerAngles = vec3(0,0,0) 
    scene.camera.z = -4
    angle = 0
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    angle = angle + 1
    e.eulerAngles = vec3(angle/10, angle, angle/5)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
end

I want to emphasize this line:

    scene.camera.z = -4

This line was critical to seeing anything on the screen. Since we were drawing our cube at (0,0,0), the default camera position, which is also (0,0,0), was inside the cube and couldn’t see it. Do not forget this. If your Craft program shows nothing, or something strange, it’s likely that you need to adjust the camera. We’ll do more about that soon.

What we’ve learned today is that a Codea Craft program has a scene, and the scene can have an entity. (It can actually have any number.)

The entity has a model, which can be a cube. (It can actually be a very complex shape.)

The model has a material, a canvas on which we can place colors and textures (pictures).

The model material has a map, a picture that appears on the canvas. The material defines how that picture paints the model. In our case, the single picture paints all the cube faces. We’ll see that there are many other possibilities.

The entity has a location in 3D space. We have only used a single location, (0,0,0). The entity also has a rotation in 3D space. We set that at first to 45 degrees around the Y (vertical) axis. Then we rotated it around that axis as the program ran. Finally we rotated our cube around all three axes.

The scene, containing all the entities, needs to be updated every time Codea draws the screen, which it does many times per second. By convention, we provide a function update, which receives the time since the last update as a parameter, and we call update from the draw function, which Codea calls automatically.

In our program, we keep track of an angle, which we just increment on each call. We use it to set the euler angles of our cube, which makes it tumble on the screen.

Refactoring

Even as simple an example as this could be improved. I would propose that we rename our entity from e to cube. In my personal conventions, I make global variables begin with upper case, but the Codea Craft convention would have us name scene in lower case. That notwithstanding, I propose that we should name our own things with upper case names:

-- CoCraTu-001

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    Cube = scene:entity()
    Cube.model = craft.model.cube(vec3(1,1,1))
    Cube.material = craft.material(asset.builtin.Materials.Basic)
    Cube.material.map = readImage(asset.builtin.Blocks.Missing)
    Cube.eulerAngles = vec3(0,0,0) 
    scene.camera.z = -4
    angle = 0
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    angle = angle + 1
    Cube.eulerAngles = vec3(angle/10, angle, angle/5)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
end

Reading

In the Codea Craft documentation I’d recommend now reviewing the descriptions of scene, entity, and material. You can find those on line, or inside Codea’s built-in reference.

And, of course, feel free to study more and to experiment.

Challenge

Can you make our cube move around a bit, back and forth or side to side? Hint: entity has x, y, and z coordinates, just like the camera. Be careful!

Feedback

Feedback on this tutorial is welcome. I’ll use it to improve this one, and subsequent chapters in the series.


  1. CoCraTu is pronounced in the Scottish fashion, Co-Cra-Tu. Hi, Alistair!