Sprite animation, part 0.5: blender!

Laziness is what drives progress.  You’d think that with all the technology we have around we would all be enjoying endless holidays.  Nope.

So, in order to save a few hours of difficult pixel-arting, I am spending a few hours learning how to use Blender to make my sprites.  And strangely it’s not going that bad !  I already have a Minecraft creeper that works pretty well, with a cartoony rendering and all.  Could 3D be easier than 2D ?  Maybe…  Probably.  Certainly.

3D creeper by me!

Look at the mini green thing above!  It doesn’t look like it, but it’s full 3D ; only, it’s rendered with an orthographic camera in order to avoid any persperctive. I like the black outline, but I’m looking for something a bit less dark, more alpha-blended. Proof it’s 3D:

My creeper in real 3D.

Before trying Blender, I tried the only 3D-designing software I knew: Minecraft.  Here, have some screenshots:

16x16 sprite build in Minecraft. Voxels are good and bad. They're so hard to animate!

Modeling my sprites in minecraft was cool, but animating then was a pain, that’s why I installed Blender.

And, to end the post, here’s the first sprite sheet I drew by hand in 2D myself:

Sprite sheet I created for Infiniworld.

It’s not bad, but it takes WAY too long to draw.

So… I’m going to have fun with Blender a bit more!

Sprite animation, part 0.

Hello hello!

Damn, art sucks. I meant to write something about sprite animation for the past few months, and I obviously didn’t.

The good thing is that I already have the code running ! Mostly: still some pbs with frame interpolation.

My problem is that I have to spend hours on Gimp to draw some sprites that are decent enough to make the game appealing. This is killing me…

So, if I feel like it, I’ll try to finish up a sprite sheet this week-end. Baby steps. I’ll do that while everybody else in the Universe is at Minecon.

I live in the Netherlands, but my job sent me to Los Angeles this month. I get to visit Caltech and JPL which is cool. Also, Minecon happens in Las Vegas, and that’s not that far!  Problem: I got confirmation for my plane ticket to the US the very day Minecon was sold out. I didn’t want to buy a ticket before being sure I would travel. So here I am, bored to death under the Californian palmtrees, drawing with pixels.

So, next updates, sprites !

Apocalypse Bunny on Open Pandora.

If you don’t know the Open Pandora, then here’s a link:

http://www.openpandora.org/

I just received mine yesterday, and so far it seems to work which makes me quite happy. Now, it’s not a plug and play console, and I have a lot to learn in order to make things work.

However, I could easily install Apocalypse Bunny! The Pandora comes with python 2.6. Installing pygame was a one-liner:

sudo opkg install python-pygame

Then I just downloaded a tar.gz of apocalypse bunny and ran it.  It runs out of the box ! Of course, the controls aren’t optimized, and it should be toggled to full screen. But it works.

Apocalypse Bunny running on an OpenPandora, at less than 10 FPS.

The frame rate makes me a bit sad.

With one drawback: it starts at 10–6 frames per seconds, and after about 20 seconds in the game (when foxes have appeared), it runs at 1 frame per second.  This is way, waaaay below the interactivity threshold.

So… I should forget python when developing for the Pandora I think, or at least the way SDL is implemented/bound to python on Pandora. It’s way too slow. Now, what are the alternatives? Java or C#/mono? Sure they’re going to be faster than python but they still run the code in a virtual machine so I’ll run into the same performance problems later. I really, really, really don’t want to bother with C++. What do you guys think?

Apocalypse Bunny, lessons learned.

Working on Apocalypse Bunny was quite fun.  The ambition was low, which makes the goal reachable and the progress quick.  Also I got to touch many pieces of the software so there was no time to be bored.  I even had to do some pixel art \o/.

Sure there’s no sound, and yes the world map doesn’t make sense, and of course the gameplay is limited.  Don’t care.

It’s time to go back to Infiniworld, the big project.  I learned some valuable lessons thanks to Apocalypse Bunny.

Let’s split our code in packages and modules as early as we can.

I know the zen of Python: “Flat is better than nested”, and I agree.  Python is not java, and theses periods don’t come for free.  The thing is that we do not need to have a flat code to have a flat interface.  To the user, it does not matter that the constant infiniworld.NATURE_GRASS is actually a shortcut for infiniworld.models.tiles.NATURE_GRASS.

The more files we have, the less code they contain.  The less code they contain, the less reasons we have to modify them.  The less we modify, the less we break.  It also helps us keeping our list of import statements short, which helps keeping track of dependencies.

I started by keeping all my modules in the root package but they grew very big.  I got entangled in that mess and had to reorganize all the code in smaller pieces.  That’s not a problem at all for Python, and not a problem for the user either if we make our __init__.py files properly, but that’s a problem for git or every version control system: I lost all my history.  Git accepts that we move or rename a file, but it cannot handle the fact that one file became five or ten.  There’s a big discontinuity in the tree now :(.

So if you know in advance that you will have to split your module, don’t write a module but write a package instead.

We need to make room for the special effects.

Until Apocalypse Bunny, all the EntityViews used to corresponding to an EntityModel.  Apocalypse Bunny changed that with what I called “special effects”.  The expanding circle drawn when we blast a psy-wave does NOT exist in the model, this is a purely visual artifact created only by the view.  Same goes for the blood left on the floor when a creature dies, it’s only visual special effects.

A special effect has a position, a rendering method, a sprite, and listens to events like any other EntityView, but it does not have any corresponding entity in the model.  It is so similar to an EntityView that I actually inherited the special effect classes from EntityView.  I will reconsider the names here because that’s going to be confusing.

Because of the similarities, we want to process special effects like we process the views corresponding to real entities.  So we want to put them in the same list/dictionary/set/group than the ‘real’ ones.  But because of the difference, we need a special identifier that no real entity is using.  I decided that since the entity models were having positive integers as identifiers, I would use negative integers for the special effects.  And thanks to this tiny trick, I got all the special effect code working for free with absolutely no effort at all.

Disappearing entities break everything.

When a fox dies, or when a carrot is picked up, their entity disappears.  That crashes the entire game.  Imagine: the carrots are picked up when we collide with them.  It means that the physics engine is in the middle of its iteration doing collision response when we pick up the carrot and it disappears: RuntimeError: dictionary changed size during iteration.

So you think: “okay, let’s not destroy the carrot entity now, instead let’s schedule it from destruction by posting a DestroyEntityRequest which will be processed when the physics has finished running”.  Think again, because you end up with the following possibility: you touch the carrot, and your friend touch the carrot, so you both pick it up and then it’s scheduled for destruction twice.  It may not crash (although I did ask the event manager to crash when something is unregistered twice) but it’s buggy: only one of you should get the carrot.

So we need:  to remove the dead entity immediately, but also to keep it around, alive.  At the same time.  Schrödinger would have loved this.

Imagine if the wave function had collapsed the other way :(.

Solution: add a boolean variable on our entity saying “I (don’t) exist”. Since the entity stays in memory the dictionaries don’t splode. And since we can tell that the entity doesn’t exist, we can skip it in the physics step. We must really get rid of the entity at some point though, so after setting this variable to False, we post a DestroyEntityRequest.  Neat!

Now, the same is true for appearing entities, except that I do not see any reason to create new entities during a physics iteration. Yet. I’ll think about it tonight.

Not all entities are tangible.

Carrots are supposed to represent small things on the floor.  They should not be obstacles, they should not be pushable.  Sure they won’t block the bunny since the bunny picks them up when she touches them, but they should not be an obstacle for the foxes either.  So we want an entity that detects collisions (so that they detect that a bunny touched them) but does not trigger any collision response code from the physics.

Easy: just add a “I’m (not) solid” boolean variable on the entity body and use it well.  Neat, again!

I tried for fun to make the bunny non solid: she crosses the walls and everything, awesome!  Now we can have ghosts \o/.

We need to pause the physics.

The physics engine should not run all the time: we may be on the title screen, or paused, or maybe there is not even a world yet.  It was not easy to add a pause function to my game loop because of the way I wrote it, so a lot of code has changed in there.  Surprisingly, the code got cleaner ô_O.

Partition space for entities.

My collision code for entity vs entity was brute force: test every entity against every other.  This O(n2) algorithm is of course very poor, but I didn’t know how poor, so I chose not to optimize it early.  Well, after having seen how the performance was crashing once I was reaching 50 entities (I’m talking about 5 FPS here), I HAD to optimize.  I did not use any quadtree or cool stuff like that yet, I just cut my map in chunks of 8×8 tiles and query entities by chunks.  8 is a quite random number, I could probably reduce it to 4, 2 or maybe 1, but that creates more chunks containing nothing and therefore more overhead when updating or searching the chunk map.  I need to test to find a good value.  In any case, as soon as we don’t look at the entire map, we’re fine.

That’s all…

At least all I can think of right now.

The engine source files changed quite a lot ; there is no point in merging the two branches.  I will branch out of Apocalypse Bunny and remove the code related to this specific game (it’s all in the bunny package!) to have my new codebase for infiniworld.  I’ll be doing some refactoring in the next days.  Then, new fun stuff!

Prelude of the Chambered, a game by Notch.

It took Notch 48 hours to make this fully playable game from scratch. I can’t play it right now because I’m at work, but I’ll beat it tonight!

It’s amazing because yesterday night I re-installed my old Might and Magic 3 to have a feel of old-school 3D. Prelude of the Chambered is more on the Wolfenstein side, but that’s a perfect timing.

Here, have a glimpse of how a real coder (not me) works:

Youtube link: Creating Prelude of the Chambered.

It should be quite possible to render Infiniworld with such a 3D engine.  It’s actually one of my goals for Infiniworld 2 or 3 :].

Edit, later that evening:

I died, I was so close! I got lost on my way back from the temple, the ghost boss running after me while I had only 4 health points left. Now I’m scared.

No save/reload buttons, like in real life :(.

Full game: Apocalypse Bunny.

You’ve waited for one week; now is your patience rewarded. Behold my first game, Apocalypse Bunny.

Misadventures of a bunny.

You play as a bunny in a post apocalyptic world. The only place where carrots still grow are in cemeteries because of their fertile soil. However, zombies grow in cemeteries too, especially zombie foxes. They are a bit slow and a bit dumb, but they are legion. You hop and run between your foes and try to gather all the carrots before too many zombie foxes hit you. Fortunately, the radioactive carrots give you strange abilities. With each carrot you eat, your super bunny mind can create a telekinetic shock wave that will repel and maybe even kill the zombie foxes.

Let’s see how you long you can survive ! Don’t become a zombie bunny.

Nyuszi the bunny wakes up in a sinister cemetery, very hungry and very lost. What happened to the world?

Oh, after a long walk near the beach, Nyuszi spots a delicious carrot floating on the murky water. It must be eaten!

Oh no, Nyuszi is not alone, horrible rotten creatures want to nibble her cute ears!

Enough ear nibbling ! Nyuszi gathers the radioactive power of her carrots to blast zombie foxes into oblivion. Good riddance.

Too bad Nyuszi sucked at managing her stock of carrots, she did not last long :(.

How to download.

Here is a direct link to the zip archive: Apocalypse Bunny v1.0.1.

The Git users will find a new branch on the infiniworld repository called “apocalypse_bunny”, ready to be pulled.

As usual your machine will need Python 2.7 or 2.6 and pygame 1.9.

How to play.

Deflate the zip archive or pull the git branch.

Run the solo.py script that’s in the src directory.

Controls.

  • [W][A][S][D] keys to move.
  • [Space] key to blast a psy-wave.
  • [M] key to take a screen shot (it’s close enough to the space key so that you don’t have to look for it too much).
  • [Esc] key to quit.

If you’re using a French keyboard, then it’s ZQSD to move and [,] to take a screen shot.  So it’s the position of the keys that matter, not what’s written on them.

Hey Taurus my friend, I have not merged your code for configuring the keys as you’ll notice that the code changed a LOT.  On the good side, the new code makes configuring the keys easier.  Little work is needed to adapt your code to the new codebase.  I’ll take care of it :).

Goal.

Survive as long as you can.  Like with real life you cannot win, you can only delay the inevitable horrible end of your cute fluffy bunny.  Who wouldn’t want to help her?

To survive, avoid the foxes (they bite you) and kill them with the psychic powers that the uranium-enriched carrots give you.  Foxes appear every 3 seconds somewhere on the map (there’s a zombie counter on the screen).  Carrots appear every 10 seconds.

Send me your screen shots!

We’ll see who survives the longest :D.  Remember: pics or it didn’t happen.

Feedback.

If the game crashes, refuses to start, is horribly slow or jerky, maxes at 20 FPS or whatever, please tell me.  I did spend time optimizing performances, and I tried to make sure the code was cross platform (Windows and Linux have totally different ways of measuring time even with python as a common language) but I don’t have that many computers to try the game.

No need to tell me the sound doesn’t work: I have not put sounds yet.

And if it works, tell me that too !  Along with a words telling what kind of operating system and CPU you use.

In the next post…

In the next post I’ll tell you what I learned when writing Apocalypse Bunny.  Trying to make a complete working game out of the minimalistic game engine of Infiniworld took quite some effort, and I have a much better insight into what features the engine needs to support.  Not much of the engine changed, which is relieving because it means I didn’t get too many things wrong.  But many things should be added in.  There shall be refactoring soon!

Until next time, folks, until next time.

Edit, 30/08/11.

Python 2.6 didn’t like the version 1.0.0 of the game: it complained about a syntax error.  I corrected it and made it the version 1.0.1.  The download link above is already updated.  Thanks for the bug report, MilanFIN!

Apocalypse Bunny, first sreenshot.

Super quickly before going out with friends, this screen shot!

There are 50 zombie foxes on the map.  I want to be able to handle 100 or 200 but I didn’t optimize anything so we run at 40-50 FPS.  It’s not too dramatic.

They run toward you when you get too close. You’re faster, but you can get stuck.

I think the Bunny's pretty much dead :(.

Next steps: timer for the score, life meter of course, and these carrots !

Let’s make a quick and dirty game.

Hello hello!

With my previous post regarding the game loop, I wrapped up the basics of what could become a game. It has physics, interactivity, display. However, technical demos are not very interesting to download and run. I thought I should craft a very simple game using the primitive engine I have built. That game will have very little to do with Infiniworld, but it will serve as a proof of concept: this engine can support a game. So let’s do that.

You play as a bunny in a post apocalyptic world. The only place where carrots still grow are in cemeteries because of their fertile soil. However, zombies grow in cemeteries too, especially zombie foxes. They are a bit slow and a bit dumb, but they are legions. You hop and run between your foes and try to gather all the carrots before too many zombie foxes hit you. Fortunately, the radioactive carrots give you strange abilities. With each carrot you eat, your super bunny mind can create a telekinetic shock wave that will repel and maybe even kill the zombie foxes (that’s for using the physics engine :p).

Let’s see how you long you can survive ! Don’t become a zombie bunny.

ZOMBIE BUNNY by ~RM73

ZOMBIE BUNNY by ~RM73 on deviantART.

And let’s code that :D.

A wild game loop appears!

Figure 1: Game loop, I choose you!

I told you in my previous posts that the physics would update at 20 Hz while we would render frames at 60 Hz.  It is now implemented and available in the v0.0.6.b of Infiniworld.

There were two things to do:

  • make the game loop smarter,
  • make the view able to interpolate.

Frame interpolation.

If we update the frames three times faster than we update the physics, then we end up rendering three times the same scene with all the entities in the same positions, making our game look like it is rendered at 20 FPS instead of 60.  Nobody wants that.  To avoid this, we can modify the AreaView so that it can perform some interpolation between two physics states.

It felt immediately obvious to me that I should interpolate between the last known physics step and the next one.  Of course the next one hasn’t occurred yet, so I should predict it.  I can predict it for example by using a simple Euler integration: this is computationally cheap and noone is likely to notice any error on a time span of a twentieth of a second.  Then I realize it cannot work because it does not predict the collisions at all.  I need to run the full physics engine in order to have my predicted future. But that does not work either: I cannot predict what the user will do.  I can predict what the Entities will do by running their AI, but the player is a mystery.  And then, what ?  At the next time step I have to recompute the same physics step again, this time with the right player input.  This means that I run the physics twice for every step, and half of these computations give a wrong result because the player cannot be easily predicted.  It sounds like a bad idea doesn’t it?

When we try to guess the future we are not really interpolating, we are extrapolating.  And this, for the reasons given in the previous paragraph, will not work well.  What we should do is interpolating between two known physics steps in the past.  This has the strange consequence that the scene we render on the screen does not show the present state, but a state from a very close past.  This made me feel strange at the beginning, until I realized that we are talking about a delay of a sixtieth of a second, which nobody will notice.

I chose to apply a linear interpolation: we can compute it very fast and it looks good enough.  In short, it means that our entities are smoothly moving in straight lines between the positions given by the physics engine.  I could do some splines or fancy things, using more physics steps, but that would not look nicer.

Figure 2: We render frames using positions interpolated from the last two known physics steps.

The EntityView objects need to store three positions now: the position at the last physics state, the position before that, and an interpolated position.  The latter comes from this very simple line of code:

# Snippet from pygame_.EntityView.interpolatePosition
self.int_pos = (self.old_pos * (1 - ratio) + self.new_pos * ratio)

Each RenderFrameEvent now comes with a ratio.  We use this ratio to interpolate the position of all the EntityView sprites.  Then we draw the scene using these interpolated positions.

Note that only the view does this: the model does not know anything about this interpolation.  Not a single line of code is changed in the model and its physics engine.  We respect our Model-View-Controller pattern.

A smarter game loop.

In order to feed the AreaView with a ratio for its interpolation, the game loop has to compute this ratio. But that’s not the only thing the game loop should do. It should:

  • read the inputs from the keyboard/mouse/joypad/touchscreen but also from the network if we play online ;
  • run the physics ;
  • render the frames with the proper interpolation ratio.

But that’s not it, it also should

  • run the physics at a rate that does not depend on the speed of the machine, which means catching up if the rendering takes so much time we are getting late ;
  • have the highest FPS we can achieve, while still limiting it to what makes sense with the refresh rates of out monitors, independently from the physics ;
  • save some battery and keep the CPU cool by sleeping as much as we can.

I am giving you here links to two very famous and well written articles about game loops:

They present various game loops and their behaviors on fast and slow hardwares.  That’s a good read for people who develop on PC and have to worry about guys like me who change their computer once every five years (and buy each time a cheapos one).  The loop I came up with looks pretty much like what they present at the ends of their articles: everything is independent from everything else, the physics is able to catch up when it’s getting late but even in that case it renders frames once in a while (better have horribly slow game than no game at all).  What I added is the possibility for the CPU to take a rest, and some protection against time jumps that the Network Time Protocol can cause on some machines.

There is a weird thing on the tubes…  I was wondering whether my game loop should sleep or not and many people seemed to find perfectly normal to have the game loop eat ALL the CPU (that’s just one source, I read that in several places).  Even Fiedler and Witters do that.  Why ?  I’ve seen screenshots of Minecraft with absurd frame rates (see Figure 3). Do these people know that their monitor is limited at something like 60 Hz ?

Figure 3: Some dude running Minecraft at 556 FPS. Testosterone much?

At the old times of CRT monitors, 100 Hz was not a luxury, it was a need-to-have if you didn’t want to be staring at a stroboscope all day.  Believe me, I can see a refresh rate smaller than 100 Hz on a CRT.  But we have LCD/TFT/Plasma/dunnowhat monitors now where 60 Hz is perfectly healthy.  Why would you render 10 frames to only display one ?  Maybe it makes sense when you use accelerated graphics cards, but that’s still dumb.  It’s going to make your fans turn at full speed which is never pleasant to the ears and prevent you from playing in summer.  And if you are one of these weirdos who like playing with a laptop on battery in the train (or worse, a Pandora!) you are pretty much doomed.

Now, sleeping is not super reliable, we can wake up if a signal is sent to our process, or we may sleep a bit longer than we hoped.  But I designed a game loop robust enough to handle change in speed, so let’s just do it!  I’ll put the CPU to sleep.

Here you can read the code of my game loop: https://github.com/Niriel/Infiniworld/blob/v0.0.6.b/src/loop.py.

Conclusion.

Figure 1 shows the new game loop in action: This picture is totally representative of what Infiniworld will look like in the end{.} Dear font nerd Pokémon fan: I know I didn’t use the right character font, that’s because I pixel-arted the text in the picture myself ; now, go glitch yourself a Mew. Dear rest of the Universe, let this video blow your mind:

Physics engine – collisions, wrap up.

New version, with ∞ % more physics.

It took a few days but it’s here: the new physics engine that handles collision detection and collision response.

A screen shot.

I should try to make videos, they would show the physics better.

Figure 1: The tile map shows regions of tiles of the same material. This allows us to explore their physical properties more easily than with the previous maps.

Figure 1 shows a screen shot from the last version. The tiles with a ‘3D’ border are raised: they are obstacles on which you collide and bounce more or less according on their material. The flat tiles have a friction coefficient that also depends on their material, which slows you down as you walk. Materials pictured here are sand, rock, shallow water, deep water and rubber (rubber is stupid but I wanted to try 100% bounce).

You may have noticed that the entities looked circular now: I represent their bounding box. I chose to give them a diameter of exactly one meter, which corresponds to the width of a tile. That allowed me to make sure that entities could squeeze in exactly in the tightest conditions.

Small misadventure.

Everything worked pretty much immediately which really makes me appreciate having spent some time doing the analysis in my previous posts.

One thing went wrong though: I implemented the position correction before implementing anything about velocity correction. Which is okay. I wanted to have a perfectly working position correction before moving on. I unfortunately included in the code a couple of lines that made perfect sense for a game with position correction only, but which bugged weirdly later with the velocity correction added: entities would stick to walls, but only sometimes, and they couldn’t fit in a one-meter-wide corridor, but sometimes they teleported to the end of that corridor. Creepy! It took me about one hour to find what was wrong :(. Once I removed the few lines, it all worked smoothly. I shall try to pay more attention to these kind of things: I should not polish a my code before it’s finished.

One step away from the design.

The implementation followed the design very closely. There is one difference though, and it has to do with a suggestion I made in my previous post in the section about Simultaneous collisions. I suggested that I could apply all the position corrections at the same time by adding their penetration vectors.

It wouldn’t have worked: I should not add everything. I should pick the biggest correction in X and the biggest in Y. It would force me to start projecting on some axis, and projections are expensive. Actually, they are more expensive than my collision detections (I’m lucky to have such a simple geometry). Also, I don’t even know what to do in case of corrections that cancel each other, because how do I define the biggest then ?

Wine helps too.

Do not worry if the previous paragraph confuses you. I hardly understand it myself: it’s messy, complicated, it treats position and velocity differently, and wouldn’t even make the code faster. So I ditched that. The code is so simple now!

Download the demo.

Have it your way:

Thoughts.

  1. I dislike the tangential efficiency applied in collisions. You can feel it when you move in diagonal against a wall: a kind of friction is there, slowing you down. It’s particularly strong on waterfalls (raised water tiles) but you can feel it on piles of sand or other tiles too. Although it makes sense to be slowed down when you run against a wall, it’s just annoying to play. I think I will just set this tangential efficiency to 1.0 unless I really need it different.
  2. I do not make any difference between entities that walk and entities that fly or entities that are pushed (like a boulder). The friction to apply is very different in these cases. The engine does not handle it at all.
  3. The friction of the floor slows you down, but there is nothing that makes you have difficulties starting. Imagine sanding on ice: the low friction makes it hard to stop –which my engine can reproduce– but the same low friction reduces the grip of your soles and steals some of your walking force –which my engine does not handle at all–.

I will implement the point 1 because it’s just a matter of changing a few constants. However I shall not on the points 2 and 3 in the near future. I think that we have enough physics to make things interesting: we can move around and push things. Now that we can explore, we need something to explore. It is time to spend some time on procedural content generation \o/.

Follow

Get every new post delivered to your Inbox.