Ready for another #30daydev round. So far, in the previous 30 days, I managed to (almost) complete the simple pixel-art for the game. I’ve been studying the game internals and I began designing the game structure accordingly. The current code-base is voluntarily kept at the bare minimum, with no over-engineering.
Within the end of this round, I aim to complete the game AI, leaving the final touches for the next month.
Day #1 (2018-05-12)
Worked on two very important parts of the game, that is the actors management system and the animation manager. Both have been implemented as generic as possible, in order to be pretty much reusable in future projects.
The interesting part for the AMS module is the adoption of a deferred spawn/kill policy. That is, when a new actor is to be added/ removed from the set, it is at first stored in a table. Later, during the updating step, the actor is moved from/to the active actors’ list (an optional event callback is called for the actor to perform additional operations). The list is, then, sorted by priority eventually draw the actors with the proper z-order. Perhaps, I’ll be revising this in the near future in favour of a more versatile and generic method.
For the animation module, the interesting part is how the animation modes are implemented. With a scripting language such as Lua once can use closures and functions as first-class-citizens to implement an iterator(s) capable of handling different cases in a smart way, keeping the main module readable.
-- `t` is the frames' index table, that traces the drawing order. -- `mode` is a string value indicating the animation mode. local function iterator(t, mode) local i = 0 local n = table.getn(t) local d = 1 if mode == 'loop' then return function() i = i + 1 if i == n + 1 then i = 1 end return t[i] end elseif mode == 'bounce' then return function() i = i + d if (d > 0 and i == n) or (d < 0 and i == 1) then d = -d end return t[i] end elseif mode == 'once' then return function() i = i + 1 if i == n + 1 then return nil end return t[i] end end end
Day #2/#3 (2018-05-13/14)
I’m definitely fallen into a closure rage. In the last two days, I’ve been implementing some utility modules (animation, typewriting, and tweening among the others) only to found that in each of them using closures really simplify the code. It is somewhat more difficult to follow at first since some parts of the logic are decoupled, but they end up being far more polished than a plain imperative/procedural approach.
There’s a popular saying to explain what closures are which depicts them as poor’s man objects (and vice-versa). This is pretty accurate, as far as we only examine their usage to encapsulate data and functionality in a single logical unit. The enable to define a proper lexical scope and help in keeping things separated. None is better than the other and usage of one over the other need to be carefully weighed.
Of course, I’m not acknowledging the memory footprint of the case. From this point of view, an imperative approach is more considerate and conservative.
Day #4/#5 (2018-05-15/16)
Spent some time in implementing more other utilities, namely a finite-state-machine and a functions-stack module. The nice thing is that, finally, by combining the animation and the finite-state-machine modules I can implement rather complex animation sets (not to be used in this project, but will be certainly useful in the future).
I also perfected the tweening module. By chaining/triggering other tweens when the
on_finished callback is called complex loops and combinations can be achieved (as a proof-of-concept I created an infinite tweening loop that alternates two different actions). It still does not implement parallel/grouped tweens, sometime in next days. Also, I wonder if something like an object properties tweener would be useful, that is a tweener that automatically changes the object properties during the updates.
Early this morning I had an idea for a possible future design. I do like the idea of a sandbox/procedurally-generated game, and a space-ship that shoots asteroids in order to collect debris to sell them to alien races intrigues me… :P
Day #6 (2018-05-17)
I swear these are going to be the last utility modules I’m creating as a preparation to the core game development. Problem is, I like developing libraries, SDKs, and APIs a lot. Anyhow, two core modules that were missing are a timer management module and an input handler. Having (almost) implemented them I’m not ready to focus on the game itself.
No more delays. Hopefully. Well, one thing I’ll be doing tomorrow is to separate into folders the different modules, in order to better access them.
Day #7 (2018-05-18)
Today I fixed a nasty bug hidden in the
update() method of the tweening module. When the time delta was larger than the tweening duration (and this could happen when you dragged the game window across the screen), the application would hang. This was due to the updating loop that became infinite due to the tweening-loop example I wrote. It was really difficult to catch, mostly because with a non-looping tween it wouldn’t happen.
After reorganizing the code-base in “namespaces” I started working to the Pac-Man actor (yay, the first actor at last). Rapidly I tweaked also the animation module by adding a pause/resume feature. However, I’m unsure of keeping it, since this is not required as one can pause the animation by simple not calling its
update() method. I need to reflect further on it…
At last, I started the scene management module (wasn’t I saying that In won’t be developing utility modules for some time? Guess I simply can’t spare myself to work on ancillary modules). Implementing it on top of the finite-state-machine module seems like a no-brainer. No, not by derivation but by composition (which I prefer over the former).
Day #8/#9/#10/#11 (2018-05-19/20/21/22)
Really unproductive in these last days. I feel I’m approaching that moment in #gamedev when the impulse is losing power and one begins to thinker about other projects.
Nope, I need to stick with this project. In order to regain momentum, I needed to concentrate on something prolific. So, apart from the draft Pac-Man actor, I worked on the scene manager, which is built on top of the finite-state-machine module. The scene-manager is also in charge of applying scene transitions… however, I’m in doubt if whether adopting this strategy or leaving the transition effects to be applied by the scene itself (for example, with a tweener) in order to enable transitions with animated backdrop scenes.
Also, I perfected the class module by adding a
mix() method to merge functionalities in a mix-in way.
In the meantime, I’m stuck with a #codersdilemma. Should I prepend callback methods with
on_XXX() when they are used to indicate some kind of event notification? I’m not really convinced this convention suits my style, especially when then callback does something meaningful for the callee itself (e.g. an object), such as changing its internal state. The
on_XXX() prefix seems to be more appropriate as a without-side-effect notification.
Day #12 (2018-05-23)
Guess I cracked my #codersdilemma, at least for a while. I’m not using the
on_XXX() prefix since they are not mere notifications but methods to be called in order to request what we are calling (entering, exiting, and receiving an event for a machine state). I devised a method to support both updated and not-updated scene transitions, with a single parameter. This might not be the more optimized possible, but it’s quite elegant and simple and (most of all) it completely re-uses the finite-state-machine module. This is rendered easy thanks to closures… one can’t love them.
Day #13/#14 (2018-05-24/25)
Collision detection time. I re-implemented a module for the purpose, this time as a separate client module that access/queries the * actors’ system. For the moment I’m adopting the naive (basic) method since there won’t be a lot of checks to be done. In the future, I’ll add *spatial hashing (which I prefer over quadtrees, more on the subject in a later devlog entry) to optimized things up. The algorithm uses axis-aligned bounding boxes to detect overlaps.
To implement Pac-Man’s collisions I just need to compute the AABBs using the actors’ map cell-locked position. That is going to be fairly easy to do.
Time for just another #codersdilemma (I’m getting used asking one on a daily basis). Are the pills better handled as actors? Also, should special maze zones be encoded as invisible actors? It is definitely not the way the original game was modeled, but it might be a nice proof-of-concept for the collision detection routines… also, it might be quite polished.
Day #15-#18 (2018-05-26 to 2018-05-29)
Really, really, really unfruitful days. I’m considering shifting to a weekly devlog update, but I fear that it would be even more difficult to manage.
I’m approaching a low-potential zone. I’ve been indulging in fabricating modules without having a proper feedback for quite a bit. As a consequence, I’m getting bored of the project itself. The only way to avoid it is to test the modules and build something that moves.
The plan for tomorrow is to test the scene manager and implement some intro-to-game (or something similar) demo.
As for the last #codersdilemma, I think that I will implement pills and maze zones as actors. Is far more attractive from a developer point of view, albeit almost certainly different from the way it was implemented in the arcade.
This morning, while having a coffee, I was thinking about bees and a #gamedevidea popped to mind. They are very interesting, as a whole. But, specifically, their swarm behaviour is phenomenal. Might a game be modeled over this, in an interesting way? Something like a god-game in which you control the bees through external stimuli (placing flowers, putting hazards, blowing wind, etc…). It could be somewhat educational, too…
Day #19-#24 (2018-05-30 to 2018-06-04)
Almost two years ago, during my two weeks long summer vacation, I was reading yet another gamedev book. It wasn’t a particularly interesting book, yet I forced myself into reading it from the beginning to the end (skipping just a couple of tiny sections). One thing that I learned is that you can find a little of precious information even in the (apparently) most useless book. The book, in fact, made me ponder how would I implement a nice screen-transition where nice is something different from white/black/cross-fading. A stencil-driven transition, for example.
Was I still in the Amiga days, this would have been easily done with the help of the Blitter (although scaling the image runtime would have been quite a challenge). In the
Mode 13h days, this could have been accomplished even more easily with a custom blitting function selectively skipping the transfer of the masked pixels. In either case, quite a bit of code is required with the first most likely being the one with better performance (while the second being the one with a relatively less convoluted approach)
Coming from that long-lost-in-time era of metal banging #gamedev at first one can easily be puzzled and feeling with the hands tied up.
How on Earth can we possibly achieve these advanced effects if we don’t even have access to the frame-buffer and almost everything is controlled and hidden by the system?
Truth is that those days are far gone behind ourselves and we have much more powerful tools under our sleeves. We just need to embrace some sort of paradigm-shift and approach things with a different point of view.
Let’s go back to the initial problem. Breaking down the problem to the basic elements we can describe the stencil-driver screen transition effect as follows.
Selectively draw an image on top of another, letting pass only the what is above the black pixels of a centered-zooming image.
- draw the background image;
- advance a tweener from zero to some big enough scaling factor (let’s say, ten);
- use the tweened-value to pass the scaled-centered stencil image through a shader and fill the stenci-buffer with the result;
- draw the foreground image with the stencil-buffer “active”.
The only single caveat is in the choice of the stencil image format and, consequently, the shader. In this case, I went for a PNG image with the non-transparent pixels being the only part sent through the stencil buffer, in order to preserve the background (outgoing) image.
With some minor effort, we can replace the background and foreground image with the (animated) output of two different game states, with some solid colour, or with some gradually fading overlay.
We really should appreciate the power we have at hand, and let the hardware do what we did in the past with clever asm-fu.
Here’s the result. Simple as that.