Hooray, even more progress! It’s been a while, so I can’t remember all the things I’ve accomplished since then, and there is certainly a good number of them, although not as many as I would like. As promised, GUI is done. As is the laboratory level. Here is a screenshot. Three things to note: fully dynamic light eminating from avatar’s body, things in the dark appear different, and a door. Yes, you can open the door.
Right now the game runs at about 30fps on NVidia 6600. There are four dynamic lights. If I can keep the same framerate and get to 8 lights, I will be satisfied. I am actually glad I have a low level graphics card, because this way I am sure the game will run smoothly on almost all computers.
Previously, I animated the avatar almost by hand. That is, every frame I had to check: is user is trying to move forward and what animating is currently playing. Then I had to setup the next animation, which would start after the current one is finished. It was a jungle of if statements. Clearly, that wasn’t the right way to do it.
What I have now is essentially a Deterministic Finite State Machine, which knows exactly what animation to play based on two inputs: user’s action and current animation. Every frame the program tells it what the user wants to do, but it only uses that information when the current animation is finished playing. In other words, it doesn’t try to predict what the next animation will be until it actually needs it. This simplifies things quiet a bit, since it has at most one animation active at any one point.
Now, there are still several drawbacks. Let’s say the player wants to jump; the game has to play the jump animation. But if the avatar is running, the game has to play the running animation and the jumping animation. Currently, Animation Controller doesn’t support that, so I have to handle it elsewhere. This will be OK if there are only a couple of animations like that, but if there are more, I will have to adapt my solution.
The main shader is done, as you can see. It calculates the color of each pixel by summing up the light from all light sources and adjusting diffuse, specular, and texture colors accordingly. The shader also distinguishes between things in the dark and things in the light, by using different material and texture.
One shader I really want to implement is Bloom Filter for glowing objects, like the crystals. Now, usually I don’t like shaders that only beautify the game and don’t serve any real purpose. But in this case, it is cruicial for the player to know which objects are emitting light (or dark). One way to do it would be through a simple billboard flare texture. I suppose that could work, but Bloom Filter would just look more pleasing to the eye.
Yes, the avatar no longer floats in space. Collision with the floor, the walls, and the game objects is fully implemented. So far I got away by using three types of bounds: tight, box, and point. Tight bounds are triangle based bounds, box bounds are boxes with arbitrary Y-axis rotation, and point bounds are useful for doing line segment collisions.
The biggest problem so far is the collision between avatar and the walls. Since avatar has a cube bound, it’s possible to get too close to the wall and not be able to rotate. While this make perfect sense mathematically, it feels very bad from gameplay perspective and will certainly need to be addressed at some point, perhaps by implementing a cylinder bound.
I’ve also had to do a bit of optimization. The main bottleneck is the shader, so I twicked around with it a bit and discovered (yet again), that yes indeed, ‘if’ statements really do slow it down drastically. In fact, it’s faster to do the entire calculation for a light source, even if it’s not used by the object, than to check if it is used. The only ‘if’ branch I have right now is to check whether the fragment is in the dark or the light area, because this determines what material and texture it will use. I don’t think there is a way to get around that.
I’ve also done some optimizations for CPU. Surprisingly, it’s really easy to do with CodeBlocks and MinGW setup. All you have to do is set -pg compiler flag to profile the code when it’s executed. Once the program runs, it outputs a gmon.out file, which you can run through MinGW’s gprof program to create a really nice text file, showing exactly where the program spends most of its time. Surprisingly, my CPU hot spots weren’t at all where I expected them to be. There were two: rendering a block and getting box bound information. Both were quiet surprising, since neither does much calculation. Now, I render each block into an OpenGL list, which accounted for about 10% of the CPU use. I’ve also added additional values to box bounds, so getting its information is faster too.
Since the player always needs to be able to see the avatar, the objects (mostly walls) that get in the way have to be turned transparent. This, naturally, raises a series of issues. I fixed them by passing each object through a renderer, which detects if the object rendered is transparent. If it is, it’s stored to be rendered later. During that time all transparent objects are sorted based on the distance from the camera and then rendered together, saving on OpenGL state switching and preserving transparency consistency.
Obviously, there is a lot more to be done in each of these areas, and a lot more areas still remain untouched, like dialog system, enemy and NPC AI, fighting and puzzle solving mechanics. For now, however, I am switching my focus back to game design for a bit, to decide exactly what kind of puzzles I want to have in the game. The ideas always seems good while they are in my head, so I need to lay them out on paper to expose all the flaws. I hope by the next update, I’ll have puzzles and fighting implemented. Until then!