Archive for the ‘Notes’ Category

IceJunk

Saturday, January 1st, 2000

I did this code for some allegro.cc competition called “Screen hack” (I think). A complete game, and the code fits in one 80×25 chars screen.
[[Include(icejunk.c)]]

Options_are_Good

Saturday, January 1st, 2000

”Options are bad.” I’ve seen that claim too many times now. Like often, the intention of such phrases is good, but is easy to mis-interpret. This is very similiar to ”KISS”: Of course it is important to keep things simple, and often even force yourself to keep your project simpler than it could be - since else you will need to spend increasinly more time. But the things which you want need to be there nevertheless - the most simple program always is no program at all, and that is not the goal of KISS. Also, projects do evolve over time, and so a feature which initially would have violated KISS might very well be possible a year later.

With options, more options not only violate the KISS principle, but also the amount of testing increases. Still, options are not bad. That is - if you allow adjusting any small setting, then yes, this may be bad - many combinations might not make sense, and things get complicated, if not in code then for the user who can not know which settings make sense and which not.

But, if you have no options, you actually do have options - they simply are fixed and forced on the user, without the possibility to choose what they like. Which is very bad.

And, the claim that testing increases much is false, if you do options right. The example that may be given is, if you have 4 boolean options A, B, C and D, then you need to test your program with ABCD first, then ABC[D], AB[C]D, AB[C][D] and so on, 16 possible combinations in total. But that assumes that each option depends on all the other ones. If your options behave like that, they probably are done in a bad way. Good option are done so they automatically work together with any other options.

This is not always simple to achieve of course. So yes, no options is simpler than options. Such as no program is simpler than a program. But a program with good options is much better than a program with no options. Since, at least for part of the users, the hardcoded defaults will be bad defaults.

Optimization

Saturday, January 1st, 2000

Optimization is good. The hardware I own usually is some years behind the newest one available at the time, so that alone makes me appreciate when something has as much raw performance as possible. There just is no good reason to make something use up more resources than it needs. Why waste CPU cycles to make it run 10 times slower, if you can optimize to make it run twice as fast? Why use twice as much memory as needed, when you can optimize to use only half as much?

Optimization is bad. It takes a lot of time better spent on implementing and improving the rest of your program, and the result is code which is hard or impossible to understand or modify, which is less robust, and maybe even has some subtle bugs. Why do something in a convoluted and complicated way, just to save some extra checks or a few bytes of memory here and there?

So, there, that’s my opinion on optimization.

Put in a different way, there is no clear yes or no answer. There’s always trade offs. The first one, it simple takes time to optimize working code. But of course, if you can make the code work better, and maybe even easier to understand, then it’s good to take the time to optimize it. Another trade off maybe, you can either optimize for size or speed, or something else. Such other thing may be robustness, correctness, or code readability. E.g. you could write something in C/C++ instead of Python - but is it really worth transfering your working code to something unmaintanable? In many cases, it is - there simply is no way around it. E.g. you can’t expect to make a graphics application by maintaining your framebuffer as a python list of lists, and then have it update more than one frame / second.

ObjectOrientedC

Saturday, January 1st, 2000

This is just an example how to get object oriented C. There are many more ways to do it, some much more advanced. This is the one used throughout Land.

About the used terms, just always assume what makes sense. Everything listed in the same line below means the same to me. Especially note terms in bold who appear more than once:

* base object, super class, parent class, base class
* sub object, derived object, sub class, derived class
* object instance, instance, class instance, ”’object”’
* ”’object”’, class, type
* object method, method, function, class method
* object property, property, variable, class variable, class property
* abstract object, abstract class

Assume, we have an object called Animal, with two methods “eat” and “go”.

{{{#!cplusplus
void animal_eat(Animal *self, char const *what, int howmuch);
int animal_go(Animal *self, int direction, int howfar);
}}}

And, we also have a derived object called Bird.

This is how we could use it:
{{{#!cplusplus
Bird *bird = bird_new(”Sparrow”);
animal_eat(bird, “Apple”, 1);
animal_go(bird, 0, 1);
bird_del(bird);
}}}

Let’s define all the structs, and also add four properties to Animal, “name”, “hungry”, “x”, and “y”, and an extra property “z” to Bird.

{{{#!cplusplus
typedef struct AnimalInterface AnimalInterface;
typedef struct Animal Animal;

struct AnimalInterface
{
void (*eat)(Animal *self, char const *what, int howmuch);
int (*go)(Animal *self, int direction, int howfar);
};

struct Animal
{
AnimalInterface *vt;
char *name;
int hungry;
int x, y;
};

struct Bird
{
Animal super;
int z;
};

}}}

As you can see, this is defined using two C structs, one for the Interface, and one for the object itself. The interface simply is implemented as a vtable pointed to by the object.

Next, we define some housekeeping stuff.

{{{#!cplusplus

AnimalInterface *animal_interface;
void animal_init(void)
{
animal_interface = calloc(1, sizeof *animal_interface);
animal_interface->eat = NULL;
animal_interface->go = NULL;
}
}}}

This is an initialization function for the module. It defines an interface - but since our Animal is sort of an abstract base class, the methods are filled in as NULL.

{{{#!cplusplus

void animal_initialize(Animal *self, char const *name)
{
memset(self, sizeof *self, 0);
self->vt = animal_interface;
self->name = name;
}

Animal *animal_new(char const *name)
{
Animal *self = malloc(sizeof *self);
animal_initialize(self, name);
return self;
}

void animal_del(Animal *self)
{
free(self);
}
}}}

We defined a constructor, and a destructor. The constructor can have parameters, and we have a version of it which will not allocate, but just initialize.

{{{#!cplusplus

#define BIRD(_base_) ((Bird *)_base_)

void bird_eat(Animal *super, char const *what, int howmuch)
{
Bird *self = BIRD(super);
super->hungry -= howmuch * get_nutrition(what);
}

int bird_go(Animal *super, int direction, int howfar)
{
Bird *self = BIRD(super);
if (collision()) return 0;

super->x += cos(direction) * howfar;
super->y += sin(direction) * howfar;
super->hungry += howfar;

return 1;
}

int bird_fly(Bird *self, int howfar)
{
if (collision()) return 0;
self->z += howfar;
return 1;
}

void bird_initialize(Animal *super, char const *name)
{
animal_initialize(super, name);
super->vt = bird_interface;
Bird *self = BIRD(super);
self->z = 0;
}

Animal *bird_new(char const *name)
{
Bird *self = calloc(1, sizeof *self);
bird_initialize(&self->super, name);
return &self->super;
}

void bird_del(Animal *self)
{
animal_del(self);
}

AnimalInterface *bird_interface;
void bird_init(void)
{
bird_interface = calloc(1, sizeof *bird_interface);
bird_interface->eat = bird_eat;
bird_interface->go = bird_go;
}
}}}

Here, we actually define the methods of the Bird object. The last function is the module init function again, which creates an interface, and this time, with both methods filled in.

We also have a constructor, again with a separate intialization function, and a destructor. The instance of the object always is passed as the type of the base object, Animal, and we use a macro BIRD if we need to access it as the derived object.

If you remember the initial example:
{{{#!cplusplus
Bird *bird = bird_new(”Sparrow”);
animal_eat(bird, “Apple”, 1);
animal_go(bird, 0, 1);
bird_del(bird);
}}}

Then this could of course be written as:
{{{#!cplusplus
Bird *bird = bird_new(”Sparrow”);
bird_eat(bird, “Apple”, 1);
bird_go(bird, 0, 1);
bird_del(bird);
}}}

And then maybe also:

{{{#!cplusplus
bird_fly(bird, 1);
}}}

But, the advantage of the former simply is that we might now know what types of animal it is, like, assume, this is a game involving 100 different animals, who can eat things and go around. Then our main program can be written without needing to know the type of the current animal.

There are also various possible variations, e.g. instead of the “super/self” and so on parameters we could have used “super/sub” or “animal/bird”. It is also possible to have deeper sub classing, e.g. a class Sparrow derived from Bird. And object may be created in a different way than the constructor function, for example there could be a mapping of strings to classes, then a function “Animal *animal_create(char const *name) could create the appropriate one. Classes who don’t need any own variables don’t actually need their own struct, but just a new vtable.

LudumDare/8

Saturday, January 1st, 2000

This was one of the best LDs for me. I for sure coded more than in any other (or not less) :) And I went completely crazy, and decided to write a 3D engine. I always wanted to write one, and this now finally was the perfect chance. Next time I want to do a 3D game, I will use premade a 3D engine probably. Mine here is very simple, it takes a set of meshes out of triangles, arranges each mesh into an octree, and all meshes are spheres in the world by their bounding sphere.

This is nothing advanced of course. But, it’s more than just throwing triangles at OpenGL, so I declare it as a 3D engine. And I’m quite proud for sure, even if there’s not much gameplay. Besides the code, I also wrote a Blender export script in python, which directly translates Blender meshes into C code. It would be really easy to create extra levels or monsters that way. Maybe I will even do that.

* ”’Monday 00:26”’

It is done. A lot of things is still missing which I would like to have, but for now, this is the final LD48 submission.

* ”’Sunday 19:54”’

There’s a swarm of critters flying around, and you can shoot ‘em down. That’s as much gameplay as there will be.

* ”’Sunday 18:07”’

Balls have now eyes and the whole swarm is chasing the player.

* ”’Sunday 14:28”’

Ok, finally, a swarm. Well, or at least, some balls.. they will get proper flocking behavior next.

* ”’Sunday 13:35”’

Breakthrough. I did it. Yes, I’m good. My octree works. Of course, half of my code now is octree-debugging code. So the next step will be, remove all the debugging code, then finally start with the game.

* ”’Sunday 2:48”’

Well, this definitly was lots of fun. I don’t know when I was coding like this, if at all :) Anyway, right now, I can’t code anymore, my brain somehow all but stopped working. Sleeeeeeep…

* ”’Sunday 00:59”’

Ok, found a nasty bug in the octree generation - when deciding which faces to include in a cell, face culling was on, so triangles randomly did not go into their cells. Hopefully that was the last bug with the octree.

* ”’Sunday 00:36”’

Blahrg. Octree is not working properly :(

* ”’Saturday 23:16”’

I don’t think I ever coded so much in a previous LD. Seems my octree implemented from scratch actually is working. So now I can throw around lots of ray<->landscape collisions. Probably I could have gotten away with a simple 2D grid as well :P As for rendering, I think I’ll have to leave it at a throwing every single polygon at OpenGL for now. Next is the spheres moving in swarms.

* ”’Saturday 19:54”’

Oh well, took me quite some time to get ray-triangle intersection working. Now I somehow need a better data structure than a huge list of triangles I think - both to speed up collision and rendering. But first, I’ll try to implement basic gameplay.

* ”’Saturday 17:34”’

After 7-8 hours of messing around, the above is all I got. I wrote everything from scratch: A blender export script in python, and code to display the data with OpenGL, using an OpenGL light. It’s not a lot - with a proper 3D module, the same could have been done in just a few minutes. Anyway, now I can start thinking about gameplay relevant things I hope.

LudumDare

Saturday, January 1st, 2000

LudumDare is a competition similar to SpeedHack, see the links:

* http://ludumdare.com
* http://www.freelunchdesign.com/cgi-bin/codwiki.pl?LudumDare

Land/Compiling

Saturday, January 1st, 2000

You need some prerequisites to compile Land.

Build tools

* Compiler
* Under Linux, gcc.
* Under Windows, mingw + msys.
* Under OSX, don’t know yet.

* scramble - a tool to create .c and .h files out of the Land sources
* scons - a tool to build the project under all supported platforms
* python - required to run the above

Libraries

* Allegro
* OpenGL, with GLU (optional)
* AllegroGL (optional)
* loadpng (optional)
* libpng (optional)
* zlib (optional)
* algif (optional)
* freetype (optional)
* fudgefont (optional)
* glyphkeeper (optional)
* dumb (optional)

Land

Saturday, January 1st, 2000

http://allefant.sf.net/pics/land/logo.png

Progress

/!\ Broken Needs work (./) Useable {*} Finished

{1} Immediate priority {2} Normal priority {3} Low priority >:> problematic

|| State/Priority || Module || Notes ||
||<=> (./) || [:Land/Base:Base] || ||
||<=> (./) || [:Land/Widgets:Widgets] || ||
|| {*} || base widgets || ||
|| {*} || reference counting || ||
|| {*} || properties || ||
|| (./) || menus || ||
|| (./) || lists || ||
|| (./) || scrolling || ||
|| (./) || sliders || ||
|| (./) || buttons || ||
|| (./) || text || ||
|| /!\ || edit || ||
|| /!\ || options || ||
|| /!\ || checkboxes || ||
||<=> (./) || Themeing || ||
|| (./) || Borders|| ||
||<=> || Fonts / Text output|| ||
|| (./) || Truetype|| ||
|| (./) || Bitmapped|| ||
|| /!\ || Glyph pair kerning || ||
||<=> (./) || Display || ||
|| (./) || Drawing primitives|| ||
|| (./) || OpenGL integration || ||
|| (./) || Destination clipping|| ||
|| /!\ || Palette support|| ||
|| /!\ || Non- 32bit support || Currently, some places just assume 32-bit RGBA textures ||
|| (./) || Views || ||
||<=> (./) || [:Land/Images:Images] || ||
|| (./) || Loading|| ||
|| (./) || Source clipping|| ||
|| || Drawing into images|| ||
||<=> (./) || Tile engine || ||
|| {*} || Rectangular grid || ||
|| {*} || Isometric grid || ||
|| (./) || Hexagon grid || ||
||<=> (./) {1} || Sprites || ||
|| /!\ || Bounding box collision || ||
|| (./) || Grid hash || ||
|| /!\ || Quadtree || Saves memory for sparse maps ||
|| (./) || Pixel perfect || ||
||<=> (./) || Containers || ||
|| (./) || Dynamic arrays || ||
|| (./) || Linked lists || ||
|| (./) || Hash maps || ||
|| (./) || Queues || ||
||<=> || [:Land/Documentation:Documentation] || ||
|| (./) || Source format.|| Python docstrings ||
||<=> (./) || Input || ||
|| (./) || Keyboard || ||
|| (./) || Mouse || ||
|| /!\ || Joystick || ||
||<=> (./) || Sound || ||
|| (./) || Mix single samples || ||
|| /!\ || Stream wave data || ||
||<=> (./) || Network || ||
|| (./) || Send packets || ||
|| || Automatic connection handling || ||
||<=> (./) || File formats || ||
|| {*} || png || ||
|| {*} || jpg || ||
|| {*} || gif || ||
|| {*} || bmp/tga/pcx || ||
|| {*} || mpg || ||
|| {*} || ogg || ||
|| {*} || ttf || ||
|| {*} || it/xm/s3m || ||
|| || mid || ||

Templates

Saturday, January 1st, 2000

One feature of C++ are templates. Most notable is the STL, but templates also have many other uses. In fact, they are nothing more than better macros. Anything you can do with templates in C++, you also could manage in plain C, using those ugly #define or #include tricks. You write code once, but some details of it, like certain data types or operations, can be replaced. The code is just a template, and each actual instantiation of the code will then have different things filled in.

This has a big advantage: You only need to write the code once, so if something changes, then you do not have to adjust multiple versions, with the big risk of doing it wrong in one or forgetting one. Of course, the same could also be done without templates or macros, by using some runtime mechanisms to choose the right version, but that involves conditionals or lookups, and will be much slower. With templates or macros, the compiler will be able to run all of its optimizations ”after” the code was instantiated. So in the end, there indeed will be multiple versions, but you as programmer only have to maintain one.

Still, the solution is flawed. In C, writing ‘macroed’ code is not nice, you probably will end up with lots of \ characters after each line, put stuff into #include files, and generally your algorithm will be much harder to read than the specialized version. Often it will be easier to e.g. maintain three separate functions stuck together in some file than having a single function using macros for the three different possibilities.

The same, unfortunately, is true for C++. No doubt, for many things, it usually is nicer to have a templated C++ version than using C macros. But it still makes the code more unreadable than using a fixed version.

This is what I solve with my approach. The idea is simply to use a meta language. So sort of a very powerful #define. I simply write my algorithm in Python, writing out the C code for the compiler to use. That way, I can do it in a way like with #defines or templates, but in many case, can do much better. That’s the main idea behind scramble. Keep the simplicity of C, and get all the more powerful features by having the whole Python interpreter as preprocessor.

TODO

Saturday, January 1st, 2000

infinite.. all the projects i’m contributing to.. all the games i started.. all the things i wanted to try out.. oh, and also all the other things i’m supposed to do.. can’t really even start to make an actual list, without cutting off stuff that is really important to me and therefore cutting off the list would defeat the purpose of the list. What a dilemma.