Flegma blog header photo
Flegma's c-blog
Fronts 3Posts 1074Blogs 98Following 0Followers 20



Fledgling retrodev: Content design in BSR


Content creation is something I'm not really interested in. In several cases, I've been more interested in writing the game's code first and only then haphazardly thrown together something resembling content, or just giving up halfway through. Bumper Ship Racing was no exception, except this time I got frustrated with coding even before I was done with that part.

This blog looks into the "design" of all the tracks in BSR, a quick look at the early considerations for cups/campaign mode and then a bit more about drawing the graphics.

Earlier blogs about BSR:

  1. Fledgling retrodev: Bumper Ship Racing (general introduction to what the game is, including a link to download the latest version of the game)
  2. Fledgling retrodev: Sprite flickering and permutations (technical details and maths on reducing sprite flicker in this one instance)
  3. Fledgling retrodev: AI and data reuse (how the AI was implemented and taught, and how I wasted effort on a pointless programming trick)

Designing the tracks

All the tracks were designed on a grid paper. Transcribing them to the PC could induce errors, but still, this was something I could do with a notepad and a pen.

The way I implemented the AI added constraints to the level design: the tracks cannot have smaller loops, something even Super Sprint had. That, coupled with the screen size, limits the number of actually fun tracks that can be made.

Let's see some other general considerations. For one, the ships will be bouncing across the track, and that means wide tracks are a must -- but not too wide. Consider the racers making a sharp turn. They'll probably bounce off the wall, and the speed of that probably won't be the same. That bounce will automatically shift the racers sideways on the track so that they can try overtaking another. If the path is too narrow, overtaking may be difficult.

And, of course, the second racer can (and will) always ram into the side of the player in the next corner, which eliminates all the concern of braking in time for the corner, if the player counts on hitting the other player.

The limitation to use only perfectly horizontal and vertical edges was due to limited faith in my coding skills. Original plans included at least edges in 2:1 angle (two pixels one way for every one pixel the other), but detecting collisions and rebounds? Detecting collisions would've been easy enough, but figuring out which way the ship would bounce not so much with my limited understanding of physics.

Sidenote: I can now appreciate Pinball on the NES a whole lot more. Furthermore, I'll just namedrop two pinball games from the 1990s: Pinball Dreams by Digital Illusions (later EA DICE you know of, say, Battlefield V) and Epic Pinball by James Schmalz (later a founder of Digital Extremes of Unreal and Warframe fame).

Narrow bottlenecks are also a problem, because all edges are either perfectly vertical or perfectly horizontal; this way, making a funnel that would actually guide the players to the bottleneck can't be made easily, as every step that narrows the track could bounce the ship backwards. Of course, this can still be used to make "shortcuts", where the player must decide whether or not to take the risk of aiming into a narrow corridor. (Too bad that shortcuts don't really work in this game.)

Again, all straights are perfectly horizontal or vertical to avoid "serrated" edges that would bounce the ships back if they were bumped to the side of the course.

I've used typically four-tile wide tracks; with 4x4 pixel hitboxes for ship-to-ship collisions, that means eight racers could almost race next to one another on the track. It's not terribly congested, so there's still a fair amount of room for taking over... although it's typically better to just ram to the side of the opponent as they're trying to make the turn. (Have I repeated that enough by now?)

Most of the tracks are built around one idea, after the first three tracks anyway that were more "early test tracks" that I never ended up removing from the game. Beside that, new track features were added as I couldn't think of novel track ideas.

The tracks in BSR are far too short to have more than one single distinguishing idea, but as a sequence, the tracks in BSR have a sense of increasing complexity.

Below are all the tracks I ever made to BSR in chronological order. The order matches the extra track elements I added to the game. If you don't want to read about every single level (understandable), just check the first paragraph in the subsections (minus the first subsection) for the main point.

Basic tracks

S-Miler -- The first map I ever made for the game and named so because it's a smiling mouth. And since the first map was already this complex, I never made the expected "oval" track to the game. The complexity was because I wanted to have more testing grounds for bounce coding, how to race effectively and the AI.

Bumpper -- Originally Bump-Er, but I try to be careful with words. Named just after the original track.

Chicane -- Originally Chic Can, again renamed just to be careful. I tried to avoid using actual English words, but I couldn't think of a suitable replacement. I considered axing this because it was too close to being just a mirrored Bumpper.

Despeed -- Showcases my lack of foresight how the game would play, even though I had a playable prototype already when I drew this. I thought the "nooks" at the end of the turns would make the players slow down; hence the track's name. I don't actually know how this should be ideally played; the AI have trouble with it as well.

A-Field -- Asteroid field. This was one of the earliest track designs I had in mind, because this fit nicely in the theme and it was a novel concept. Luck in design: I had for no particular reason decided that track names are at most eight characters long, so I had to shorten it to A-Field. This meant I still had 8+8+8 characters left on that line, and those were eventually used up by the timer and the record, 7 characters both, and the word "RECORD" and three empty spaces to spare.

OSI -- Named so just because that's what it looked like. Only later I was told that I could've named it Qsi as well, but I'm not a fan of poop humor. At this point, I was running out of fundamentally different "traditional" track layouts to try out, since I didn't even name the track after an element.

Masq -- Named because the track looks remotely like the helmet of, say, Boba Fett or Samus Aran. I was running out of feasible ideas at this point. This is one of the few tracks that doesn't have the starting grid on a long straight.

Passage -- A shortcut that might not be very useful (the only track with a shortcut, even, if we ignore Degate). No matter how good the original kart racer is said to be, some ideas won't translate well to all racers. Otherwise, this looks like a copy of Chicane.

Filter -- This was better in theory than in practice. Or not even in theory. The idea was to use a set of narrow passages, but the end result was that there was 50% chance of hitting the filter and bouncing backwards. That was even more about luck than A-Field, which is why I didn't think twice of axing this track from the cups.

Zoned -- I don't actually remember where the name comes from. Maybe because of the wide open area on the left? Yeah, I was really running out of ideas.

Attraction fields

The first idea to spice up the tracks was implementing attractors as points behind a barrier, not unlike a magnet. However, I got frustrated with computing the direction the ship would be attracted to, so that was replaced with simple "conveyor belt"-like areas that straight out said which way they pushed the ship. Most of the tracks were built around one idea and one idea only, because the available room for the track is, after all, small.

Magnety -- The first track I designed to use the attraction fields and made the mistake of thinking this as an introductory race track for the fields. This is the second track I dropped out of the cups because the actual fields were so narrow that their effect was limited. It didn't help that the layout is so similar to Bumpper, either. In hindsight, it could've been made better by making it opposed to Modera by widening the attraction fields and making them beneficial. 

Sqwezz -- "Squeeze" because of the narrow pathway at the top. I hadn't given up on the filter idea yet, and here the repulsors would help in aiming the player through the gap. In hindsight, I should've left the "trap" on the left much, much shallower. The top gap isn't as bad as it could've been, because the ships won't have huge vertical speed unlike in...

Counter -- The main attraction are the two countering repulsion fields, again going for the filter dream. The other part of the track is the help/trap of the attraction fields on the right.

Modera -- minding the speed was supposed to be important in not getting stuck in the attraction fields. Instead, it turned out that hitting the wall fast enough to bounce clear of the field was the better method.

Degate -- the closest I can get to the closing gates in Super Sprint, since the AI couldn't handle dynamic track elements. So not a gate, really, it just needs more deliberate action to get through the narrow gap. Hence, de-gate.

Suaeves -- Named after "sway" and "suave". The attraction fields will guide your ship at the top, and the fields on the sides will probably do absolutely nothing beyond giving the track its name. After having the attraction fields work against the racers, this was the counterpoint in try making the fields a positive influence.

Actual bouncers

Again, at this point I was out of ideas and fed up with coding. That's why the next track elements were more deleting code than writing it: the bouncers would be like regular walls, but hitting them wouldn't cause the subroutines to halve the momentums to be called. Easy!

Bouncer -- Yes, this is a boring name, but its previous name was "Unnamed1" in several versions. I think it's still an improvement. This was about chaining bounces together, usually with unfortunate results, since there's no real "upper limit" on how many rebounds can happen in succession.

Rebound -- If you thought this was called "Unnamed2", you'd be absolutely correct. Here, the idea is to hit the bouncers in an angle to rebound behind the corner at a high speed. 

Spritzel -- Obviously named after the pretzel shape. With skill and luck, the center part can be cleared surprisingly fast. I was again running out of ideas, as evidenced by...

Liimbo -- How low could I go? How narrow could the track be but still be better than Filter? The bouncers thankfully sped up both Spritzel and Liimbo noticeably, otherwise they would have been very boring. Liimbo is actually the easier track of the two, because the rebounds aren't as easy to critically fail and overtaking by ramming to the side of another in the center is easy.


The final additions I made to the track elements were the portals. Because the starting grid and the finish line were fixed to the same position in all tracks, the possible track layouts were unnecessarily limited. This was again because I was not interested in adding custom starting grids for each track. Hence I created "portals" that bound the left and right side of the screen together. That would give a long straight right at the start.

Flyre -- The track looks like a lyre, so add F for fly and that's it. The idea was just to try creating a very fast track. Then I got cold feet and added the repulsor fields to the end of the long straight, something I didn't do in the next track.

Mindgap -- Mind the gap at the top. All the different track elements are used in this track. The repulsors try to push the player to safety, because rebounding back the way they came is really, really annoying. Bouncers to give room for risk-reward flying. And portal to add a long straight at the start. The original design actually had repulsors trying to push the ships to the "pits" at the top, but that would've been too mean. 

In total, I created 22 tracks. Creating more with the extant tools wouldn't be too difficult, but even this leaves two tracks out of the cups. Creating actually fun tracks would've been harder, unless they were not intended for "serious" racing, such as a track with as few walls as possible, only walls with full rebounds and so on.

In fact, I should have created more than 22 tracks, preferably 30 or more, so that there would've been an opportunity to throw out more of the weakest tracks. Or I could have even edited the tracks after they were transported to digital form. As it was, I didn't do much track design QA myself.

Career/cup mode design

One lucky break was in how I had implemented the turning/thrusting by pure luck. Remember that the ships controls are read 50 times a second, so the ship couldn't turn those 22.5 degrees every frame the joystick was turned to the side. Instead, I gave each player a counters telling how many frames of turning had to be registered before the ship itself would turn. Same with thrusting: the larger the initial value for the counter, the slower the ship would turn or accelerate. The difference is therefore not that the faster ships have a different thrust vector applied but that vector is applied more often. Even in the slowest classes, that's at least five increments per second.

This part took a while to decide upon, because there were many different alternatives and each decision would've meant a fair bit of work. Let's see what the options were.

  1. Career with ships getting upgrades like in Rock'n'Roll Racing or RC Pro Am
  2. Career with multiple leagues and ship upgrades tied to the league (all racers in the same league would have identical cars).
  3. Plain cups. The different ship attributes would have been selected at the start rather than by any mid-game progression.

The big hurdle when I was deciding which way to go was that I had really started loathing writing menus. Upgrading ships would've required menus. Another strike against this was that I had already a dozen tracks. Going about it the way Super Off-Road did and introducing a new track to the loop every now and then would've made the game far too long.

Career mode with multiple leagues would've been a single-player only affair, but I still wouldn't have liked creating the menus. Whenever the player won a league of, say, four tracks, they'd advance to the next level with better ships and better opponents. In hindsight, this would've been the more interesting approach, as the AI could have "ramped up" the challenge in the later leagues without needing more than one AI per track.

In the end, I chose to use the same number of classes and tracks as in Super Mario Kart. That was the least minimum amount of work outside of creating a dozen new tracks. However, to perfect this type of campaign mode, more work beyond the minimum in balancing the ship stats would've been needed. The end result is that while Koopa and Toad are good for beginners in Super Mario Kart (from what I remember), in BSR the nimble-but-slow ships are practically universally inferior.


Back in the 1980s, I used to draw sprites on a grid paper first. Actually, no, that's not it. At first, I tried defining sprites as a random string of 32 characters by mashing my fingers on the keyboard and seeing what came up, a bit like looking at the clouds and thinking, "that's a sheep." Which is why the player character of my first platformer was a blue pile of poo with a few flies around it.

The next step was defining the sprites as binary strings. The first 16 bytes (characters) in the sprite pattern tell the leftmost 8 columns of the sprite and the next 16 define the second half, so it was easy to define (and edit) the sprite in BASIC like this:

 Sample 16-by-8-pixel sprite as binary strings and how it could've been read on MSX-BASIC.

So maybe that's why I first defined the sprites and the characters in a textfile of ones and zeros. A Python script would then spit out a binary file I could just tell the assembler to include in the code.

That (kind of) worked for sprites due to the limited colour options and the custom font, because the colouring didn't vary from character to character, but with the tile backgrounds when I could have the ones and zeros coloured differently on successive rows -- no way. That would be why I wrote a script to let me read a PNG file, interpret each pixel (using a fixed palette) and then create binary files containing both the pattern and the colour data.

Past that point, all the tiles were edited in GIMP, and it was easy enough for me to draw five custom images: the title screen image and "congratulations images" when a human player wins a cup. The latter four images were only 40-by-24 pixels in size, so mere stamps. The title screen, though, was much bigger and I applied very basic compression there by encoding the colours using RLE and not repeating pattern definitions for identical tiles (say, one wholly blue tile is indistinguishable from another blue tile). Later I edited the tiles just so to get a few more repeat tiles there, saving about 8 bytes for each.

 One "congratulations image". The yellow marks tiles not to be converted in the image.

While GIMP (at least by default) doesn't adhere to the colour limitations of the VDP, it still made it much easier to draw these images. This was also the first time I made graphics for the MSX with this much care.

Of course, I've now found a new angle to appreciate the graphics the artists at Konami could create. See below an image from Nemesis (Gradius) by Konami in 1986 with black lines added to help in seeing the colour block boundaries. Remember, a fixed palette of 16 colours, only two colours on eight-by-one pixel rows. The lasers that flew in the animation (not shown here) were sprites, I think.

 A static image in Nemesis on MSX1. Bottom-right corner says "Naoki" and "Yutaka". The added "grid" shows the "character" boundaries; each horizontal pixel row limited by the vertical black lines can have at most two different colours. Obviously, this is not an image I made.

The little things that were ignored, or, why I am not a professional game dev

Since this is probably the last blog I'll write on BSR, here's a small selection of various details that I ignored, but real professionals should not.

  1. Outside of the players affecting the CPU racers' trajectories, the AI is deterministic. Don't touch the controls at all and the race will always play out exactly the same way. One simple way to avoid this would have been to add a very small random drift to the CPU ships at the start.
  2. The collision sound -- it is always of the same volume, which is why I very quickly made it happen only when collisions happen at the speed of 60px/sec or higher.
  3. Who won the race? The first racer whose ship is on the finish line, of course, but that's wrong. When the racers update their positions in the same order once per frame, the first player will always win another racer crossing the line in that same frame. The timer really is accurate to only 0.02 seconds (1/50).
  4. Counting the final cup scores. The same as above: in ties, the first/lower player will always win. No tiebreakers with victories or so.
  5. Character. I don't play a car in racing games, I play the driver of the said car. One of the big reasons I don't find Shin'en's FAST games captivating is that there are not relateable characters, only slightly different ships. The same thing happened with BSR. Even just a mugshot of each character in the menus and a few extra words in the manual on the characters' background would have helped in having that identifiable layer.
  6. Not using macrotiles from the start. Rather than specifying one tile at a time in the level map, I hear the typical solution for games of the time was to store the tiles in, say, 2x2 tile "macrotiles". This would've reduced the memory the tracks took significantly, if I had designed the tracks to use this macrotileset from the start.
  7. 60 Hz mode. This game was made for PAL and 50 Hz. Support for 60 Hz was an afterthought, and as I've said, the support is just doubling every 6th frame. A proper 60 Hz version would do *something* each frame. But at least I didn't need to make the 60Hz mode the 30Hz mode.
  8. No non-tank-control control options. Now that the thruster has been bound to the fire button, this is an actual option to implement now. Just because I think this is the Only True Way to play games like BSR, doesn't mean it is, as I've learned from some GDC Youtube videos.
  9. Proper difficulty testing. Only two people played the game during its development: me and one other. And I was the worse player of us two. Yet, the game's too difficult.

Most of these are too involved to solve without doing an overhaul of the game. That's why I might implement only a few of these features at some later date. Maybe. 

What next?

There aren't many points left to talk about BSR. My original 5300-word-blog on BSR has now been split into already four blogs with over 8000 words in total; the only parts of that still not covered by my other blogs are the physics (which are very simple and not really worth talking about), and the overall lessons learned. But given how I've already told of most of that, too, this likely is the last blog on BSR.

I've submitted BSR to a retro game competition, and I don't want it to win anything. Maybe one day I'll be able to have physical copies made of it, but for that to happen, the game would really need actual music. I can't say I'd have an issue with someone else making the music, it's more of "how to handle the playback" issue.

What about ports to modern platforms? Given how Zombie Incident (nenefranz, 2011) got a 3DS version, it's a fair question to ask. However, it's pretty much given there won't be a remake or a port of BSR on a modern platform because it'd be far easier to just make a new game with more features from scratch. Using BSR's name wouldn't have any real value, and only one of the downsides would be having to deal with the crotchety original dev. The big difference to Zombie Incident is that that game already had the world and levels designed, and the music done; BSR can offer none of these to the hypothetical remake.

So what really is next in line for Fledgling retrodev? A new game, probably. Maybe one day. Definitely some other year than 2018.

Login to vote this up!


LaTerry   37



Please login (or) make a quick account (free)
to view and post comments.

 Login with Twitter

 Login with Dtoid

Three day old threads are only visible to verified humans - this helps our small community management team stay on top of spam

Sorry for the extra step!


About Flegmaone of us since 11:34 PM on 01.17.2015

Very much unprofessional writer, don't take anything I write without a truckload of salt.

On a hopefully long-term break from saying anything.

Given the amount of work Niero had to do to purge my Disqus logs the last time, I'm not going to agree to Disqus TOS and use the service again ==> I won't be replying to your comments as much as I'd like to. Except maybe via site PM functionality. If it works.