Prologue

It’s been really a while since the last time I wrote a blog entry. Well, it’s been a while also since the last time I dedicated myself to a gamedev project. Many real-life duties and shenanigans kept my time and attention from being spent on development (in general). Now it seems that the storm has passed, and I can recall myself to more fun duties. And what’s better than a #30daydev project to re-train my indiedev muscles?

I’m not going to elaborate a lot each. It’s going to be much like a diary-like (mega)entry.

Day #0 (2018-04-10)

Occurred to me that I never developed my own Pac-Man clone. Need to fix this ASAP. It will be a cute exercise in basic AI development and group behaviour.

LÖVE finally reached a new milestone, and the v11.0 version has been released. I will definitely use this engine/framework for this project.

Scanning once again through Jamey Pittman’s “Pac-Man Dossier”. Will use it as a reference for the development. That’s quite a lot of information to digest.

Day #1 (2018-04-11)

For study purposes, I (partially) watched Jamey Pittman’s Perfect Game. It’s astonishing the tactics and the strategies that have been discovered and implemented over the years. A casual watcher could think the player to be without any clue, because of the weird movements and pauses. Not even close.

The ghosts’ AIs are the single most important part of the game. Problem is that if I intend to create a proper remake I would also be implementing their faulty behaviours (such as, for example, Pinky’s and Inky’s when Pac-Man is facing upward).

There are a lot of minor details that could be easily missed, such as the fact that the ghosts and Pac-Man have different speeds when turning a corner (the ghosts appear to “wait” a bit… but how long is this “bit”?). Should the kill-screen worth implementing? Will the safe areas emerge automatically if the AI is properly implemented?

Tomorrow I’ll start and draw some placeholder sprites in order to set the game area up.

Day #2 (2018-04-23)

Still studying Jamey Pittman’s “Pac-Man Dossier”. The sheer amount of detail in this document is amazing. The lack of a “real” path-finding algorithm (e.g. Dijkstra) is neat. With a simple euclidean distance calculation and by setting a priority to movement directions once can be easily fooled that a shortest-route algorithm is applied. Can’t wait to implement this as see it in action!

Started by drawing the maze graphic (using the Pico-8’s palette, which I like very much).

Maze Graphic (v0)

I proceeded in tweaking the colors a bit. I’m not displeased by the result.

Maze Graphic (v1)

Tomorrow I’ll be drawing the sprites. I’m wondering whether the pellets and fruits should be rendered as sprites or as layered tiles over the background tiles. I suppose the original game used tiles, since sprites where not for free and very limited. Also, handling them as tiles seems convenient and easy enough.

Day #3 (2018-04-13)

Ditched sprites to work a bit more with the maze graphics. I’ve been separating the proper maze map from the pellets (which are now on a separate layer). Also, I added a “support” layer to flag the cells and encode specific behaviours.

Maze Graphic w/ Layers (v2)

To answer yesterday’s question, I checked the Namco Pac-man arcade board specifications. The amount of available sprites is very limited (eight) and their size is 16x16 pixels. The rest of the display is generated as an 8x8 tiles background. We can safely conclude that the pellets are rendered by means tiles, while the fruits are sprites (in addition to Pac-Man and the ghosts).

I’m debated on the most practical way to represent the maze flags. Of course, the maze itself is small and a source-code encoded representation won’t imply any difficulty. Nevertheless, I’ll prefer a more sleek and faster-to-handle way. Perhaps a raster bitmap color-representation?

Now that the maze is (mostly) complete, I should really prepare some sprites…

Day #4/#5 (2018-04-14/15)

Deeply busy with real-life duties, weekends aren’t easy when it comes to development.

Worked a little more to some initial sprites. I decided that, for the moment being, I’ll be using some placeholder ones (8x8 coloured blocks that mark the sprite direction and status) while I’m working on some 16x16 ones. I could easily use the real arcade sprite (they are more than available on the net) but I never liked them… and it feels just too much of a rip-off to me.

Tomorrow is time for the maze rendering.

In the meantime, the first LÖVE hotfix (v11.1) has been released. It’s more than welcome.

Day #6 (2018-04-16)

Back in the days of home-computer conversions from the arcade, we simply didn’t know. A game, regardless of the level of “influence” from the original one, was taken as “good”. We played Munch-Man, for example, and we didn’t question whether it was a good or a bad game. It was just as good as the original Pac-Man.

But, deep inside, you felt that something was missing. The contrast wasn’t only in the (much simpler albeit more than decent) graphics. Not even in the sound, that was very simple at the time (and, for example, the Commodore-64’s SID was more than capable to surpass many arcade games)

What ware missing ware the tiny technical details (planned or not) the rendered the gameplay unique. It wasn’t unusual that hard-core players ended in knowing and mastering the game much better than the creators themselves.

Now that we know this, conceiving a faithful clone is quite a challenge. It might be simpler to develop an emulator for the original ROM.

How much I’d like to create a good Bubble-Bobble or Rainbow Islands clone. :-)

Day #7 (2018-04-17)

Drawing sprites is hard for me. I’m definitely not a pixel-artist (at the moment, at least). I tried to draw some simple 16x16 sprites, but I end always in something far too similar to the originals. The best ones, so far, are the ghosts. I managed to change them slightly with nice results. But the main character is too “flat” to elaborate upon.

It hard to resist the temptation to browse through OpenGameArt and grab something nicer. :)

Day #8 (2018-04-18)

I was finally drawing some satisfying sprites when, abruptly, I found the underlying problem. I wrongly assumed the original sprites were using the whole 16x16 call, while in fact they are 13x13 and 14x14 sized (respectively for Pac-Man and the ghosts). I was feeling like cheating when I was simply right in wanting to reduce (and make odd) the size of the characters. So, I reworked the sprites in all their 13x13 pixels opulence and they definitely are nicer. Here’s a quick “before-vs-after” image to render the idea.

Sprites (v0)

Now that the inspiration has been found, it’s just a matter of finishing the sprite-sheet. I’m going to try and make the sprites “squarer” (no pun intended), perhaps the will look nicer. Also, it would be fun to make the tileset 4x4 and the sprites 8x8, anyway. Somewhat it would be like making a micro Pac-Man look-alike. :)

Day #9 (2018-04-19)

At last! I completed the sprite-sheet! I’m pleased with the result, but I’ll iterate and refine more the sprites along the way (I’m curious in trying GameBoy palettized colors, too). Here’s a sneak-peek of the atlas.

Sprites (v1)

Since I switched from the Pico-8 palette to more unsaturated pastel colors I need to fix the tileset, too. This won’t be a hassle, however.

Day #10 (2018-04-20)

Today I began examining how to manage the map. So far I’ve been solely drawing it with Pyxel-Edit. It’s time to plan the in-game representation. Pyxel-Edit exports both to JSON and plain text format. The first one is verbose, and while it carries a lot of detailed information it would require a lot of hacking to be converted into some usable internal representation. The second one is straight-forward. Guess I’ll be writing a simple loader for the latter, then.

I’m aware that Tiled might be a valid alternative, with a format supported by Simple-Tiled-Implementation. However, due to the scope of the project, it seems an abuse to me.

Day #11/#12 (2018-04-21/22)

Two day-long design/programming session, without even touching the computer. That means, reasoning about things in the spare time while attending family duties. :)

Planned the assets and tilemap management modules. I’ll try and keep them very simple and straightforward, without over-generalizing them (as my usual). However, I’d like them to be a bit more sophisticated than what.

Day #13 (2018-04-23)

All together now!

Mock-Up (v2)

The result is quite good but needs quite a bit of tweaking. The most relevant parts to be reworked are related to the maze corridors. I was trying to simplify the management, reducing the number of different tiles. Yet, this produces very narrow hallways due to the actor being somewhat chubby. I need to either make the maze a bit more spacey or reduce the actors’ size. Will try this tomorrow.

In the meantime, I will also draw a Namco-inspired bitmap font. Gosh, how much I was always enamoured with those monochrome fonts. They were essential in making those early masterpieces so special.

Day #14/#15 (2018-04-24/25)

The mock-up served well to check the overall status of the graphical assets.

Reworked the sprite assets, as I prefer to keep the maze tile-set manageable and with a reduced amount of tiles. I chopped one row and one column from each actor (they are now 12x12 pixels sized). To better render the Pac-Man sprite, I steered it from the original shape making it squared in a similar way like to ghosts. Also, I gave it a pair of eyes.

Mock-Up (v3)

I’m planning to make ghosts’ eyes follow their target position. Also, when “dazed” they’ll get some wacky eyes.

Day #16 (2018-04-26)

Making the ghosts follow with the eye the current target cell requires each one of them to have sixty-four different sprites (eight eye-position times two movement images times four directions). That is going to be an overkill and insanely difficult to handle, especially since the game being so simple. I need to switch to composite/stacked sprites, that is we will build the ghosts sprite by composing the single parts: body and eyes.

Stacked Ghost Sprite (v3)

The good part is that I wont’ need to duplicate the sprites to depict the eyes-only ghosts’ state.

Of course the animator is going to be more complicated (but not by a long shot) and will need to be carefully configured, but it’s going to be versatile. More on this, tomorrow.

In the meantime I wrote the tile-map loader, that handles Pyxel-Edit’s plain-text format. With some clever regex (oops, pattern) usage, an efficient parse can be implemented with ease.

local MATCHES = {
  ['^tileswide ([0-9]+)$'] = function(map, value)
                               map.width = tonumber(value)
                             end,
  ['^tileshigh ([0-9]+)$'] = function(map, value)
                               map.height = tonumber(value)
                             end,
  ['^tilewidth ([0-9]+)$'] = function(map, value)
                               map.tile_width = tonumber(value)
                             end,
  ['^tileheight ([0-9]+)$'] = function(map, value)
                                map.tile_height = tonumber(value)
                              end,
  ['^layer ([0-9]+ [%-0-9,]+)$'] = function(map, value)
                                    local layer_id, layer_data = string.match(value, "^([0-9]+) ([%-0-9,]+)$")
                                    local layer = {}
                                    for cell_id in layer_data:gmatch("(%-?[0-9]+),?") do
                                      layer[#layer + 1] = tonumber(cell_id)
                                    end
                                    if not map.layers then
                                      map.layers = {}
                                    end
                                    map.layers[tonumber(layer_id)] = layer
                                  end
}

function load_tile_map(name)
  local map = {}
  local accumulator = ""
  for line in love.filesystem.lines(name) do
    local parse = false
    if string.len(line) == 0 and string.len(accumulator) > 0 then
      parse = true
    elseif string.len(line) > 0 then
      accumulator = accumulator .. line
      if string.match(line, "^layer") then
        accumulator = accumulator .. " "
        parse = false
      elseif string.match(line, ",$") then
        parse = false
      else
        parse = true
      end
    end
    if parse then
      for regex, callback in pairs(MATCHES) do
        local value = string.match(accumulator, regex)
        if value then
          callback(map, value)
          break
        end
      end
      accumulator = ""
    end
  end
  return map
end

Day #17 (2018-04-27)

For this project, I really don’t want to rip-off and use Namco’s font (which I dislike a bit). Also, I’m not going to use a TTF. So, here I am, drawing yet another pixel-font. I always fancied drawing them, I really can’t count how many I’ve drawn over the years.

Not a lot of coding, today. However, I managed to (almost) complete the tile-map manager. For this game is an easy task, since there is not scrolling/movement involved and the map is tiny. For this reason, I also decided that I won’t be implementing a global resource manager. It’s simply not worth the effort (although a part of me ache for not doing it, as I tend to be a perfectionist and to over-generalize things).

Still, I have to finish the sprite-sheet, this will be my task over the weekend (which, as usual, will not be easy for the gamedev side of my life).

Day #18/#19/#20 (2018-04-28/29/30)

Moderately productive days, despite having very little time to work on the game.

I completed both the sprite-sheet and the pixel-font. While on the subject I also coded a (simple) font management module. For the moment it simply draws monochrome glyphs, but I plan to spice things up with a fragment shader to emulate the copper-bar fonts from the C64 and Amiga days.

Now it’s time for the sprite animator to be nailed down. I want it to be versatile enough to be reused in the near future. Almost unquestionably it will be based upon a state-machine with callbacks, in order to be run-time programmable and event-driven (such as sounds to be played when a frame is drawn). The issue will be how to not make it a mess to be configured.

Day #21/#22 (2018-05-01/02)

I’ve been working almost solely on the font for the game. Not in the pixelated font per-se since it was an easy job, with Namco’s original bitmap at hand.

By providing the font atlas as an alpha-channel PNG with only the white color used for the non-transparent pixels, I can deliver both ofand shader-driven font drawing (independently or combined, as well). That is quite neat, indeed, since copper-bar effect are really easy to implement this way (but not distortion effects, that requires a more generic and broad fragment-shader usage).

I know that I’m proceeding in small steps each, but I’m not in a hurry and I prefer to make the this as clean and well-designed as possible. Now it’s time for typewriter effect, which I’ll implement tomorrow (and hopefully post an image sample of that).

In the meanwhile, during research, I stumbled upon Pac-Man Arrangement. I need to try it, as it seems really a good re-imagination of the original game.

Day #23 (2018-05-03)

Today it was finally time to start and adjust the project structure. Also, I created the Git repository and started to use it. I wasn’t using it, yet, and I was starting to succumb with the file revisions between PCs. How we managed to develop software without VCSs (simple answer, we weren’t using multiple computer to develop the same software)?

In the last three years, I’ve been solely using GitHub and (occasionally) GitLab, and I almost forgot of my Bitbucket account (which I was using with Mercurial). So I checked it out, for the sake of curiosity and… holy moly! What a huge leap forward! I decided to use it, for the moment being (and not only because it enables unlimited private repositories).

Day #24/#25/#26 (2018-05-04/05/6)

I like Lua a lot, but there’s no way its 1-based indexing will ever please me. It gives me more headaches it should. Of course one can use ipairs and pairs to avoid indexing at all, and for someone can be more intuitive to start from one rather than zero for arrays/strings. Also, we could just use 0 as the first element, but tables won’t have integer part and would be disrupted. But all the traditional modulo ring cycling simply turns unnecessarily convoluted as instead of i = (i + 1) % N you need to write i = (i % N) + 1 (and circularly moving rearward is even more over-complicated). I don’t like to over-complicate things, and in this case, I fell I don’t get anything as a reward.

As for the game itself, I improved the (simple and unoptimized, at the moment) tilemap drawing routine. I’m not using sprite-batches since the map is small. Also, no camera control is available. They are not needed for the game, but I might add it for later (re)usage and expansions.

In the meantime, I’m trying and devise the best method to handle the map “changes” over the course of the game. How should I remove the pellets when eaten by Pac-Man? The easiest way to do this would require sprites. However, the original Namco hardware hasn’t that many sprites available. Since the tilemap should be modifiable I’m evaluating a topmost “masking” layer to selectively obscure the pellets. Later, by simple clearing the layer I can reset the map.

Day #27 (2018-05-07)

Yesterday’s idea of using a masking layer seemed convincing. I would need to use an opaque “background” tile to hide the pellets, and that’s easy. But the pellet collision check routine would need to query the masking layer, and this is way too much hassle for something so simple. I’m better of reloading the tilemap, when needed, or implement a “layer copying” feature.

I perfected the game initialization to auto-adapt to the screen resolution by (integer) scaling the canvas, give a reference resolution. This is quite neat.

This first #30daydev period is rapidly coming to a conclusion. I really need to better organize the game states and add the Actor Management System (AMS, in short).

Day #28/#29 (2018-05-08/09)

Sprite banking is still a standard and very helpful strategy to handle… sprites. So, I devised a very simple wrapper for quad(s) creation and drawing. This way, I can reuse the same procedure each time a need to cookie-cut a sprite-sheet. I’m not using sprite-batches as said previously, but I’m planning to extend the module to them, too.

This module is crucial for the Actor Management System I’m working on. But, first, animations are to be implemented. Tomorrow I’ll work on them.

Day #30 (2018-05-10)

This is the last entry for these first #30daydev. Was it worth? Yes. In fact, wanting to spend each day even a little effort in the development of the game was useful. I haven’t completed the project, but I didn’t plan to complete it.

So, let’s start with another round with a more specific goal: to have the ghosts’ AI working by the end of the next #30daydev session.

See ya!