It looks like you're new here. If you want to get involved, click one of these buttons!
I'm thinking of starting an article series using Craft. I'd have kind of two angles. The first would be my usual learning by creating small programs that grow into larger programs. Some readers find those helpful in getting ideas of how to learn what the masses of code they are facing is all about.
The second notion would be to try to produce a sort of "linear" documentation of Craft, beginning at the beginning, and going as widely and as deeply as I can. Somewhere between a reference manual with examples, and a tutorial, I suppose.
Personally, I find the lack of any coherent narrative for Craft really irritating. There's all this power. There are all these very complicated examples, many of which just do things without really explaining how they do them. Somewhere in those examples, maybe, there's an example for what the reader might want to do, but it's embedded in a program that does something else almost entirely.
I'm hoping to help create something better, perhaps both in terms of example code, and written documentation. I'm sure that I'll need help finding examples, finding write ups, and so on. At this moment, I have no specific requests, but would appreciate questions and comments in this thread about whether this would be useful, what is needed, and most of all, how folks might help in small or large ways.
Thanks!
Comments
@RonJeffries Sounds good to me. I’d like to see something like that.
Do you think that would be a reasonable vehicle?
@RonJeffries it seems like you and me and a few others have come to the same conclusion about Craft—it’s got a ton of potential and a really opaque API.
My work with the Voxel Walker and the editor (and the texture pack fwiw) is motivated by the same awareness. It seems to me that we should have tons of cool Voxel worlds to walk around in by now. But we don’t. So I’m trying to make it easier for people to make cool things to walk around in.
That’s why I guess I’ve been focused on an example-by-example approach, and I think there’s possibly a salient perspective that’s come of it.
Basically, I think part of making Craft more accessible may be avoiding some of its systems altogether. Let me mention two examples,
entity:add()
and thetouchHandler
system.entity:add()
and the associated functions seem to be a somewhat confusing system for extending the abilities of Craft components, I think. In trying to simplify the camera setup in Voxel Walker, I’ve found that I don’t seem to need them. You can add properties and functions directly to entities, and thus extend their abilities withoutentity:add()
. It might not be possible to jettisonentity:add()
with all the builtin examples, but at least with the Camera examples, you can achieve all the same functionality without it, and it results in code that’s much clearer to me.The
touchHandler
system, too, I’ve come to regard suspiciously. It has some concerning pitfalls, not least of which that it seems to be completely incompatible with the defaulttouched(touch)
system. In short, as far as I can tell, usingtouchHandlers
breakstouched(touch)
. It’s got some good features, to be sure, mainly that you can define how an object reacts to touches all inside its own code without having to route everything through that one touch function on theMain
tab. But even so, it seems like it doesn’t add anything to Craft that can’t be done a simpler way, and it doesn’t play nice with the original Codea touch paradigm, which the vast majority of Codea projects rely on. And that makes a big hairy “gotcha” situation that newbie Craft users can get stuck in (like I did).Now, I’m not anywhere near familiar enough with the API to definitively assert that no one should ever use
entity:add()
ortouchHandlers
, but I think this brings up a point that deserves some thought: in addition to being confusing, some of the Craft API may be better avoided when possible.And if, for example, it would be better for people to ignore
touchHandlers
, it could actually be counter-productive to document it and create examples for it.I don’t have a tidy conclusion to offer but I think the matter may deserve some discussion.
yes. the doc repo @John mentions might help. but i'm finding it daunting, as today's slog of an article shows. i could learn faster by doing bigger things, but they'd be more cut paste, less real understanding.
but that article is so boring, maybe i need to learn a lot and only then write.
@Bri_G your pdf thing sounds good. maybe access to john's repo is better, i'll try to look at that. i suspect markdown format would be preferable to pdf, but don't know what they have now.
it would help if all the craft example code in the docs could run. maybe there needs to be a place to plug it in, to save duplication ...
at this point, i just don't know, still floundering.
What if the first aim of the articles was to make the very judgment call under discussion?
Like, the whole point could be playing with the systems presented to us, so as to gauge if they’re worth documenting in the first place?
I'm sorry, I don't grasp the idea ...
Your articles are like explorations, at least that’s how they read to me: you have a goal, you try some things, you see how those things work, and you watch your own thought process and report on it.
I was just wondering if, before creating an exhaustive documentation of any given Craft way of doing things, there might be a step exploring the question “is this a good way to do things in the first place?”
I found the Learn Craft project of little help, so to better understand it I tried to make a clearer version of it.
It’s rudimentary, but possibly worthwhile to examine in the context of the question “what do we want examples to do?”
TouchHandler and OrbitViewer are definitely not that great. They were just made for the examples and come with some annoying baggage. It's part of the issue with mixing declarative processing style code with OOP based design and is tricky to solve cleanly
@UberGoober Can you explain what the issue is with
entity:add(component)
?All
add()
does is add a component to an entity and feed it events about the lifecycle of the entity. The built-in components use this system automatically. Adding a script to your entity (i.e. a class) will callupdate(dt)
when the scene is updated. It's pretty similar to Unity'sgameObject.addComponent<Type>()
The advantage being that you can mix and match multiple re-useable component types on the same entity to avoid having big monolithic classes. You can also use
:has()
and:get()
to check if an entity has a component or:remove()
to get rid of it. Shortcuts likeentity.model
andentity.material
handle components for you (i.e. adding a renderer component for you)@RonJeffries if you want me to explain how anything works, let me know
@John I want to be clear that I really like Craft. If I’m questioning the value of sweating over making certain documentation, I know it comes from my limitations as much as or more than anything else.
Like you just said, the declarative style and OOP don’t always fit together cleanly, and tbh one of the advantages of Codea, and often part of the fun, is that you can achieve fairly complex things really easily, and that’s explicitly because you don’t have to worry about OOP. So the more OOP-style Craft paradigms sometimes make me feel a kind of torn loyalty.
The
entity:add()
system seems really elegant and powerful and clear when described, and in practice I just don’t seem to be able to get my head around it. This mostly comes up around trying to understand cameras.I made this little “rig” system that I’ve been using for cameras because, while working on the Voxel Editor, I kept trying to manually place the ‘player’ at a certain place, and I couldn’t seem to do it. There seemed to be multiple entities involved, and then the camera and the viewers each have some kind of associated entity, maybe, I think, I’m never totally sure, and I didn’t seem to be able to get anywhere by setting a simple “position” value on any of them.
So I just tried to make it simpler for myself. If you look at the code in my most recent Voxel Walker zip (also attached here), it should be pretty easy to see what I’ve done, because for the most part I’ve just snipped up your existing code and organized it all a very slightly different way. My overall goal, though, was to have the whole setup simple enough that if I wanted to place or rotate something I always knew exactly how to do it.
@UberGoober the rig concept you've got looks pretty interesting, it looks like you've focused on the idea of procedural setup functions, that apply a specific configuration to an entity
If I were to do a component based version of the same thing I would make it look something like this:
The
entity:add()
method returns the thing you created so you don't have to call get afterThe code would be almost exactly the same as yours, but use a class instead of functions, i.e.
I'm realising now, that there should probably be
component:added()
andcomponent:removed()
methods that would be called automatically when the component is added and removed. There is already acomponent:destroyed()
which is called when the entity is destroyed. This would let you automatically clean up your component like you have with theclearRig(camEntity)
method.I do like how you've used custom properties on entities to store extra information, which is a perfectly valid way of using them.
@John that seems like a good way to go about things, though the OOP pattern constrains rigs to being one-per-entity.
In the Player above, I found myself creating a rig for attaching a rigidbody to an entity, which has nothing to do with cameras, and in fact to compose the Player, I’m actually piling a few rigs on top of each other, in a way that could conceptually be chained together like this:
It seems to me that the main thing lost in my version of the rig pattern is the ability to remove a component from an entity, but when I think on it, I can’t recall anything I’ve come across in the examples or in my own usage where I absolutely needed the ability to remove a component.
Yeah, I hadn't considered your other rigs, but I feel like there is a way to combine these. Adding new methods to the entity also looks pretty interesting. Like your joystickPlayerRig jump function. My version only restricted it to one camera rig, since I don't see how you would need more than one thing controlling the camera at once
Codea 4 should be interesting since having a Library folder that works with require should make it pretty easy to add lots of extensions, even to the point where you could just have:
or something to that effect
interesting stuff above, @UberGoober and @John. I think, for now, I've just decided that a tutorial is a good idea and I'm going to try it until it isn't a good idea, or until I get tired of doing it. So ...
:has
and:get
? Is there code I should/could read as background info?added
andremoved
methods.Anyway I think I'll get down to writing the first tutorial bit and see what happens.
Thanks, folks! Let's see if we can build up some momentum and get some more good things happening.
@RonJeffries I think I can explain rigs simply.
Craft’s
camera:add()
is conceptually straightforward: to add features and controls to craft.camera, you don’t subclass it, you write a separate “helper” class, give it all the functions and properties it needs, and then “add” it to the camera.All rigs do is take an entity and add the camera, the properties, and the functions directly to it. No custom object necessary, you’re just “rigging up” a normal entity object. That’s it.
You can literally cut-and-paste the code from a helper class into a rig; the attached example project shows rigs that do just that with the OrbitViewer and the FirstPersonViewer.
I'll have to read it, I guess. My question was more "what are rigs, in general, in your mind? what do they mean to you, how are they different from other ways, what do they bring to the table for you?"
Here's today's article, a cut at a tutorial style.
@UberGoober do you know what the sensitivity, depth buffer clearing and color clearing are about? I see that you have setters and getters for them ...
This is a very early impression and I mean it to be helpful not irritating.
The rigs, especially the orbitviewer one seem very flat. I'd hope that there would be more depth to the tree of capability, which might be easier to obtain if the rigs used classes directly rather than just functions.
Does that make sense?
I think I may disagree with @John on the idea of tapping new custom properties into the existing entities. I have at least these concerns with it:
I think it would be better if Codea were to:
Failing that, it would be wise if folks adding properties to an entity were at least to give their properties names like
uberPropX
rather than justpropX
. But a good general rule, it seems to me, is not to extend system objects and classes.I’m not sure what you mean by “flat”. They’re plain and un-fancy and use a simple system instead of a cool one, but I suspect you’d find those things virtues, as I do.
As to what rigs mean to me, I made this system because I couldn’t figure out how to place the camera.
With the viewers, there’s a viewer object, a camera object, and there’s also an entity in there doing something, and I think there’s even a camera.entity that comes into play at times, and plus also the relationship between a component that’s been
add
-ed and the object it was added to is never super clear in the first place, and then when you get to the BasicPlayer it adds a second viewer component to an entity inside itself, which might mean there are two full sets of variables for accessing viewers, entities, cameras, camera.entities, and what have you—I’m not sure because my head’s already swimming by that point.I’m sure if I understood the
add()
system better it would have been easy for me to sort that out, but I found myself struggling like heck to just get the Walker in the place I wanted and rotated to face the direction I wanted. Who do I set the position on? Who do I rotate? Do I rotate with quats, Eulers, or the strangerx, ry
system introduced in the builtin viewers? I just couldn’t sort it out.So I said, heck with it, I need another way. I’m gonna start with something I know exactly how to place and rotate—a regular old entity—and then I’m gonna grab all this viewer code and do my best to just put the one single entity at the core of it. And then I’ll never have to struggle with how to place and rotate things again.
And so that’s what I did.
So fundamentally what a rig means to me is boiling the complex camera system down, as much as possible, to a plain old entity.
Like I said, the goal was to end up with something I could easily (and confidently) place and rotate, but that came with some unexpected bonuses.
One of which being that it’s super easy to change rigs. In the example project there’s a button that instantly switches between an OrbitViewer and a FirstPersonViewer, something I’ve struggled with, and never fully succeeded at, many times in other projects. Here it’s a function call.
The other bonus was that making a third-person camera effect was super easy. So much so that I basically did it by accident. The lack of a third-person view has always bugged me in the Craft Voxel Terrain example, and now, thanks to making rigs, I’m moderately excited to be able to integrate one soon.
So, you know, regarding overall design principles, I understand your objections, and I’m not sure I can say rigs are good code, but I can say that they’re obvious code. And I’m liking obvious, because I can work with it.
I like the
entity.properties
idea a lot, and Codea doesn’t need anything new to support it right now.Ironically the problem it solves is the same one that makes it possible to implement, lol.
Hm, ok, I think I get what you're trying to do. I've not worked enough with cameras to have a sense of what I'd do. I think we can be sure that I'd do it with classes, and probably more than one.
To be obvious to a reader, I think they'd have to be more modular. In particular, the touch stuff seems to me to be able to be separated out. As it is, it seems like one big thing that could be three or four smaller things. To me, small things working together is more obvious than one big thing. YMMV.
But, again, you've done it, and I haven't, so there;s that. On the other hand, I've read a lot of code ...
Did you see my question about sensitivity, etc.? Any idea what those are/
@RonJeffries I think setting properties on entity can be thought of as duck typing, which would require people to agree on common interfaces at some point, and as you said is easy for clobbering to occur
@UberGoober I think flat is meant in that there is no real class structure in the rigs concept, so it's more of a loose arrangement of parts, making it difficult to discern how it works
The components concept (i.e.
:add()
,:has()
,:remove()
is designed to completely sidestep all these issues. You can mix and match components, have their own local storage, and can be added or removed at will to change an entity's behavior. Me liking things likejump()
are, in my mind, handy shortcuts that could be exposed and mentioned in documentation. I think its best to only add a few "hero" methods and properties for commonly used things.You could also do something like this:
Could also have other convenience things like
Codea 4 is going to revamp the scene system, so this stuff will evolve, given that it's designed to work both in code and with an editor
@John the viewers have a method
scroll
that seems to be unused. Can you clue me in on what it's about?And where did that damping function come from? I'm curious.
Thanks!
@RonJeffries
scroll
works with scroll events created by trackpad devices, such as the iPad folio keyboard, external mouse or when running on ARM MacsThe damping function was probably something I found on StackOverlow or something similar to emulate the way Apple does their zooming (when going beyond min or max zoom levels). This is why it uses log, which starts off roughly linear and goes starts to become asymptotic
ty for those. here are a few more.
what's the relationship between models and blocks? does one use the other somehow?
is there a way to make a model cube show transparency like the glass block does?
Is there an example of adding cubes to build up a shape? (ah, found model:addElement in blocks.)
As I figure out what to write about, i'm finding I'd like to understand parallels like these. any help will be welcome.
Blocks and models are separate types of renderers. Blocks are treated differently because they are combined to create a single optimised mesh when rendering volumes and voxel chunks. This is why you can't just add a model directly to a block. You can do this with a dynamic block type because it implicitly creates and manages an entity on creation/destruction, which can have a model on itself. There is an example of this in Block Library:
For transparency you can use:
You can do this on any material, this will do it for the default material on a model. You can also do it directly on
entity.material
if the entity has oneI think, depending on context, extending
entity
is fair game.To me, the major strength of Codea—I’d go so far as to say the addictive part of Codea—is that it helps you do cool things fast.
I think @dave1707 regularly (and apparently effortlessly) spits out great examples of this. I just recently had a question about rotating entities. With under 60 lines of code @dave1707 made a demonstration that not only simulates flying over a scrolling landscape but also implements touch controls for changing direction.
That’s power. Codea power. I couldn’t do it. I hope one day I’ll be able to do it. And I think it’s good that Codea can do it. But trying to apply OOP everywhere is not gonna teach anyone how to do it.
I realize this is regurgitating an age-old argument over OOP, and I think that’s the point; Codea’s a living breathing embodiment of the argument itself. It can leverage the best of both worlds. It can also fall into the pitfalls of both. And I think maybe the takeaway is that the best Codea examples show off both.
[[ I will pick up the rig discussion in the editor thread where it’s more germane ]]
There are many ways to do things. Quick and dirty is sometimes OK. Objects aren't necessary for clarity, though they can be one good way to provide clear code. We need clear code for our future selves; we need it for teammates; and we need it for programs that grow over time, which most substantial programs do.
One thing that objects can provide is hierarchy. Instead of a program that goes on and on like a single long sentence, we can have the equivalent of paragraphs, sections, chapters, and so on. Objects are one way, but not the only way.
Lua uses grouping of functions under global names, like
math.sin
andstring.gsub
. Since functions can be local, we can build the hierarchy that way. CodeaUnit does some of that.There isn't really any difference with objects, because
class()
is just a function that builds a table, andthing:foo(x)
just meansthing.foo(thing,x)
, which meansthing["foo"](thing,x)
, no more and no less. There's just convenient notation. Their ability to have instances, all of that, is just tables, names, and functions.Me, I don't care how anyone codes, if I don't have to work with, or understand their code. If I do have to, I'd prefer to see them producing a suitable amount of hierarchy and modularity. In my own writing, which must be a hobby, since I don't get paid for it, I try to show what choices I make, why I make them, and what happens when I do what I do.
As should we all. Rock on!
@John asked us to work with him on improving the official Craft documentation, and here’s an example of something almost completely undocumented: setting Voxel block textures.
Apparently it has to start with this command:
… assetPackName being the string name of an asset pack in the root Codea directory. This seems to tell the Voxel system that all subsequent references to textures should be drawn from that pack. So for example this tells the Voxel system to use the built-in “Blocks” asset pack:
scene.voxels.blocks:addAssetPack("Blocks")
Then, to make a block use a given texture, you apparently have to first define a new type of block like this:
…which returns some kind of type definition object for the new block type. It seems important to capture that returned type object, because I’m not aware of any other way to get it later, and we need it for setting the texture of that block type.
So the initialization of a new block type would look something like this:
grass = scene.voxels.blocks:new("Grass")
And now that we have that type object, we can set its texture like this:
grass.setTexture(ALL, "Blocks:Dirt Grass")
A couple things to notice here:
…and having done all that, now any block that gets assigned the “Grass” type will use the defined textures.
so…
If we were to set about helping John add some official documentation for these functions, how would we do it?
I've bounced off Learn Craft several times ... would love a tutorial!
Thanks @UberGoober ... @BeeObLeo there's not much there yet, but there's some. Let me know here or on Twitter if you look and have issues, questions, suggestions ...
R