Codea Craft - 2
Note: I had this marked private. Perhaps it’s really even more ignorant than most of my work. Anyway, here it is now.
Here we are again. It’s Tuesday and let’s see what more we can learn about Codea Craft today.
We work working with the Learn Craft example, and learned a bit about the scene and putting objects into it. I can already see some prospects for my little vehicles (which I am really thinking of as bugs, because they’re already smarter than most vehicles). I think I could almost build a floor and put them down on it and move them about. They expect a space that’s 1000 by 1000, and we could either build that large a floor and back the camera way away, or build a smaller floor and scale the bugs into it. Either seems straightforward.
A Design Digression
There’s a lot of chatter on my Twitter feed lately, people whining because so-called Agile teams wind up with bad designs. The people then conclude things like “they should do more up front design” or “the Agile leadership should talk more about design up front”. Yes, well. If Alice and Bob and Carlos and Dave and Eve are working on a program, and the design isn’t very good, it certainly makes sense to blame 17 old white guys who wrote two web pages two decades ago. Ignore the best designs coming from self-organizing teams bit, or the individuals and interactions bit and all that. Ignore the hundreds of pages, thousands of pages, written on how to build good software, before the Agile guys, by them, and after them.
Sorry. I got carried away. However …
Much of what I write about when I write about programming, my friend Bill Tozier calls “Programming in Public”. He thinks I coined the phrase, and if it’s a good phrase, I’m happy to take the credit. It certainly describes what I do. I take some problem, usually start from scratch, and try to write down my every thought as I work on the problem. If I think design thoughts, I talk about them. If I draw a diagram, I put it in the article. It’s all right there on the page.
I certainly do have an agenda, and it is to explore the “emergence” of good design in an incremental fashion. That doesn’t mean the design “just happens”, although sometimes it feels like that. What it means is that with attention to good naming, to removal of duplication, to making things simpler, to putting similar things together and breaking different things apart, one can grow the program in capability, and the quality of the design, together. It becomes less clear whether today’s design thoughts are prior to today’s work, or subsequent to yesterday’s. It’s like designing all the time.
If — and only if, in my view — we pay attention to design all the time, then, if you just watch the evolution of the system’s design, it seems to emerge. The design goes in a series of small phases, getting a bit worse as the program does more, then getting better as we refactor. If we just look at the end points after refactoring, the design just gets better and better.
I don’t imagine, and neither should you, that the design gets better all by itself. Nor do Design Elves come in at night and clean up the cruft and make the design better. No! The programmer, me in this case, causes the design to grow and improve, through continuous attention to the design.
Now, I think that if someone had actually paid attention to what I’ve written and said in these past two decades, they’d know that the design of their program is up to them. Neither the Manifesto Authors, nor the Design Elves, are going to come in and fix it. It’s you, folks. It’s you.
Anyway, I was thinking …
As I mentioned last time, one of the concerns one would rightly have about incremental design is “what if an unexpected requirement comes along?” (Of course, if the requirement is unexpected, the same concern should be had about an up front design as well, but it seems no one draws that parallel.) Anyway, I like to “surprise” myself with off the wall requirements sometimes, and it suddenly came to me that Codea has this 3D stuff, and what if we had to take our two-dimensional bugs and transplant them into 3D?
The first step I’d take, faced with this requirement, would be to get familiar with the 3D stuff. That’s what we’re doing now. But I’m also already thinking about how I might fit our bugs into the 3D and surely, I’ll guide my learning in directions that seem to me to be most applicable to our problem, not so much into parts of the framework that don’t seem needed. Clearly there is risk to this, but there’s risk to everything. I suppose one possibility is that the framework is somehow terribly ill-suited to our bugs and we don’t find that out until too late. It could happen. One just pays attention and does one’s best. That’s pretty much all there is in life, isn’t it?
What does that have to do with today?
Well, two things. First, the above thoughts were on my mind, so I wrote them and tweeted them as well. Second, I know that our Learn Craft example is going to take us into the Camera section today, and I am at least a bit concerned that I don’t know enough about scenes, models, materials, and all that. It feels too soon to go to cameras. Kind of a breadth-first versus depth-first question, and I’m wanting a bit more depth. I’ll make one note here and then move along in this example.
The note is this. In the Craft documentation I linked to, there is this example:
This reads as an example of how to connect a scripted object into Craft so that it can move. I tried that code, however, and it doesn’t seem to do anything. I’m not sure why, and it might even have to do with the camera settings, but whatever it is, I feel it’s important and I want to chase it down. For now, though, let’s plug forward with the camera page.
Back to work …
The camera example draws a picture and gives us two parameters that rotate the view around the scene. CameraX rotates the view right around the center of the floor, even if you’re looking down on it. CameraY seems to be always tilting forward in the current view. It’s a bit odd but you’d get used to it. It also turns out that if you drag your finger on the screen, you can rotate the view, and the parameters update (usually) as you do it
There are some other parameters provided by the program as well, and I know there are some more sophisticated camera examples coming up soon. For now, thinking primarily about the rotation, let’s see what the code says:
— Craft Camera
function setup()
— Create a new craft scene
scene = craft.scene()
scene.sky.active = false
createGround(-1.125)
— The scene.camera entity only lets you control the camera postion / rotation
— The camera component has settings for things like the field of view and helper methods
cameraSettings = scene.camera:get(craft.camera)
myEntity = scene:entity()
myEntity.model = craft.model("Blocky Characters:Orc")
myEntity.y = -1
myEntity.z = 0
myEntity.scale = vec3(1,1,1) / 8
myEntity.eulerAngles = vec3(0, 180, 0)
scene.camera.z = -4
parameter.number("CameraX", 0, 360, 0)
parameter.number("CameraY", 0, 360, 0)
parameter.number("FieldOfView", 45, 90, 60)
parameter.boolean("Ortho", false)
parameter.number("OrthoSize", 1,10,5)
end
function update(dt)
if CurrentTouch.state == MOVING then
CameraX = CameraX - CurrentTouch.deltaX * 0.25
CameraY = CameraY - CurrentTouch.deltaY * 0.25
end
cameraSettings.fieldOfView = FieldOfView
— Orthographic mode
cameraSettings.ortho = Ortho
cameraSettings.orthoSize = OrthoSize
—Set the camera rotation to look at the center of the scene
scene.camera.eulerAngles = vec3(CameraY, CameraX, 0)
scene.camera.position = -scene.camera.forward * 5
— Update the scene (physics, transforms etc)
scene:update(dt)
end
— Called automatically by codea
function draw()
update(DeltaTime)
— Draw the scene
scene:draw()
— 2D drawing goes here
drawStepName()
end
function PrintExplanation()
output.clear()
print("The scene contains a built-in camera entity that you can move around")
print("Since the camera is an entity you can use all the same properties to move it as the previous example")
end
This bit seems cryptic:
— The scene.camera entity only lets you control the camera postion / rotation
— The camera component has settings for things like the field of view and helper methods
cameraSettings = scene.camera:get(craft.camera)
Reading this carefully, what I’m gleaning is that if we were to talk to scene.camera
, we could only set position and rotation, but that this get
operation is returning the inner camera component, which may have more capability. Let me see if I can find anything in the documentation.
OK, this doesn’t tell us much but it does show things like field of view which is more than just position and rotation. Maybe that’s what’s up. But what is this get
operation? OK. The get
operation fetches a component (the component?) of a particular type from the entity in hand. We asked scene.camera
for it, so I guess there’s always a camera in there somewhere. I don’t see us creating one, anyway.
My tentative reading is that we’re going to do some rad things to this camera, so we had to get ahold of the real thing, not just use scene.camera
. What are those rad things?
function update(dt)
if CurrentTouch.state == MOVING then
CameraX = CameraX - CurrentTouch.deltaX * 0.25
CameraY = CameraY - CurrentTouch.deltaY * 0.25
end
cameraSettings.fieldOfView = FieldOfView
— Orthographic mode
cameraSettings.ortho = Ortho
cameraSettings.orthoSize = OrthoSize
—Set the camera rotation to look at the center of the scene
scene.camera.eulerAngles = vec3(CameraY, CameraX, 0)
scene.camera.position = -scene.camera.forward * 5
— Update the scene (physics, transforms etc)
scene:update(dt)
end
Ah! During update, if our finger is moving on the screen, we update the CameraX and CameraY parameters. (Otherwise, they’ll stay wherever they currently are, either from previous finger movement, or from directly moving the sliders.) Then …
- We set the field of view from that slider. It appears to be an angle.
- We set ortho mode. Based on toggling it, this turns perspective on and off.
- We set ortho size. Based on moving it, this seems to move the view in and out.
- We then set the camera’s “Euler angles” from the sliders. We’ll look that up but clearly they rotate the view.
- We then set the camera position to
-scene.camera.forward*5
, whatever that means.
Here’s what ortho does:
I’ve gleaned one thing already, which is that we generally set the camera z to a negative value, backing away from the screen in the z direction. I guess otherwise we’d be looking at the back of the picture. I’ve just decided to try that out …
Setting it positive gives me a black screen. I think the camera is behind the dude, but looking away. Rotating the X and Y doesn’t bring the dude into view, which confuses me a bit. I’d have thought it would. Changing the multiplier moves the camera closer and further away, which at least makes some sense to me.
The docs do not mention camera.forward
. Shall I print it to see what it is? I guess so … and it’s vec3(0,0,1) when we start, and as we rotate the camera, it changes. This is making me think that camera.eulerAngles
is actually moving the camera to new positions, by rotating it, or, if not moving it exactly, setting its angular position in the world. Most confusing. Must read more …
Hmm. eulerAngles
sets the “rotation of the entity in local space”. As a rotation, I’d expect it to be a normalized vector, of size one, so that moving the actual position in or out would be a matter of scaling the vector, as our code here does. I wonder, though, if we set the position somewhere other than by scaling the rotation, would the rotation then move? My guess is yes, and that this particular style of moving the camera is used because we’re adjusting rotational values. If we wanted to set a particular camera position we might do it differently. This is one of those ideas you hope you’ll remember when the time comes. For now, what I’ve got is, roughly, this:
A camera has a rotation, expresses as
eulerAngles
, that represents the angles from (0,0,0) to point to the camera. (Or, possibly, the angles from the camera to (0,0,0). Should experiment and figure that out.) Anyway, we can position the camera inward or outward along that line by scaling the angles.
This would be quite frustrating were I not such a calm person. It’s like looking through a very dirty window and scrubbing a few small spots clear, so that you can see part of the picture and not all of it. I’m not remotely ready to start writing the manual, but I definite am learning. And for this example, I think we’ve learned all that we can for now. It’s nearing lunch time, but I think I’ll take a quick look at the next example.
Viewers
The next example is called “Viewers” and it shows a picture of a trebuchet. You can pinch and drag to change the view:
The text refers to “OrbitViewer” which is surely the camera we’re using. It’s referenced in from the Cameras example. I’ve looked briefly at that but not in this article series. We’ll surely go there soon. But let’s look at what we find in this code first. It’s quite enlightening in its fashion:
— Craft Camera
function setup()
— Create a new craft scene
scene = craft.scene()
scene.sky.active = false
myEntity = scene:entity()
myEntity.model = craft.model("CastleKit:siegeTrebuchet")
myEntity.eulerAngles = vec3(0, 180, 0)
— From the Cameras library project (added as dependency - see the + button)
— parameters are (target position, initial distance, min dist, max dist)
viewer = scene.camera:add(OrbitViewer, myEntity.model.bounds.center, 30, 20, 100)
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()
— 2D drawing goes here
drawStepName()
end
function PrintExplanation()
output.clear()
print("To simplify camera setup, you can use the Cameras library which contains same viewer classes")
print("OrbitViewer is useful for controlling the camera via simple gestures")
print("OrbitViewer supports rotating, zooming and panning (via one and two fingers)")
end
So this is nice. We learn, mostly, that we can just include in OrthoViewer tab from the other example, and voila! we have a very nice ability to swoop around our view. We’ll remember this for when we put our bugs into the scene, we’ll be able to zoom around and watch our favorites.
Nothing else to see here, though we now put understanding OrthoViewer on our agenda. Let’s peek at the last tab, “TheSky”. I happen to know it’s not terribly interesting but it may be important. Here’s what it looks like:
LOTS OF PICTURES GO HERE
We’ll look further at this in due time. It’s clear from the pictures that we can paint a sky, or a sort of gradient background, or a flat one. All very interesting, and it feels pretty independent of the other things we’ve learned so far. I hope so, anyway.
See you next time!