Mastodon Icon RSS Icon GitHub Icon LinkedIn Icon RSS Icon

Speccy Jam 2014 Postmortem

As I said in a previous post, in these days me and my colleague at Noctua were working in the SpeccyJam 2014. The goal of the jam/competition is to make a game with the same look and feel of an original ZX Spectrum game. This introduces a lot of interesting limitations. First, it constrains our resolution to  256 × 192 (that is, however, a really big improvement respect to the LowRezJam :D), second it forces us to use only 15 colors. But most important of all, the non-strict limitation, is to simulate the color clash effect of the original Spectrum on modern engines. This was the most hard constraint that forced us to explore 2D shaders and a lot of simulated low-level algorithms on top of a modern engine like Unity 3D.

So, now that the jam is ended, is time, as usual, to back over our steps to see what we have done, what we have learned and what we can improve.

First Step: The Concept

The traditional HD disappointing game cover!
Figure 1. The traditional HD disappointing game cover!

The first step for each jam is to think of a concept for the game. We decided to use a game concept that was in the air for a long time but that we never found time to implement. The idea is an economy management game inspired by the daily life of a blacksmith. The original idea was a bit complex, but we thought we could easily strip a lot of feature in order to fit the game into a jam-size project.

The player is a blacksmith in a fantasy world. At the beginning of the game he has nothing but a forge and a bunch of money. The first step is to hire some goblin minions (characterized by two parameters, combat skill and geology skill) and send them in some remote land to mine metals and resources. When the goblins come back with the resources the blacksmith can start forging weapons through a mini-game based on rhythm and coordination.  When the weapon is successfully forged, its time to sell it in order to get gold and fame. Obviously it is important to hire minions wisely to avoid starvation and to go out of business.

Simple but effective. It is time to start working.

Second Step: The Low Level Framework

For our work we chose to use Unity 3D. Also if we have switched to the Unreal Engine 4, the 2D framework for UE4 is still rough and we preferred to use something on which we are more experienced. It is not cool to find out some engine problem in the middle of a jam, so it is better to be safe.
An example of color clash in action. Note the knight sprite assuming the color of the background objects.
Figure 2. An example of color clash in action. Note the knight sprite assuming the color of the background objects.

Before to start implementing the a actual game, we needed to implement a good low-level framework for ZX Spectrum graphic emulation and, in particular, an effective and simple way to emulate the color clash behavior. Let’s explain better what it is. You have to know that the ZX Spectrum, by design, stored pixel bitmap and color information in separate areas of memory. While the bitmap specified the state of individual pixels (either on or off), the color information (or “attributes”) are specified in a 24x32 matrix. This means that there are just one byte per 8x8 pixel character cell. Because each byte can specify two colors (namely INK for the foreground and PAPER for the background, plus two bits for modifiers such as BRIGHT and FLASH), each 8x8 “tile” of the Spectrum screen can have only two colors at the same time. When a sprite with a third color enter in a 8x8 tile with two other different colors, the whole tile get the color of the entering sprite according some nor-really-deterministic behavior.

Now, to simulate this in Unity is really not straightforward. My friend Maurilio did an amazing job into handling this problem. Obviously him can explain this better, but I’ll try to express the key points behind this simulation. The main tools used are sprites and shaders. The idea is to directly simulate the Spectrum graphic system separating the bitmap memory from the color memory (exactly like in the original spectrum). So, we built a fake “video memory” using two textures that store the 24x32 color information matrix for INK and PAPER and used the Unity sprite only for the bitmap.

As you can see in the picture above, each sprite is composed only by two colors (plus the alpha channel). The red parts of the image are the INK pixels, the green one are the PAPER pixels. Combining this to a complex system that can write color information in the fake video memory and a 2d shader to render these sprites, we was able to recreate a really amazing and realistic clashing effect (also too real, for instance there are some glitches when switching from one scene to another because of the fake video memory not being updated fast enough :D).

The shader work in this way: it get two textures, one for the INK color memory and one for the PAPERS color memory and then replaces red/green from the sprite with the INK/PAPER value in the position of that particular fragment in screen coordinate (the INK/PAPERS textures, in fact, map each pixel to a particular screen pixel).

This system is a bit complex and fascinating and really need a more in deep details explanation from its main author, so I ask him to write something and I’ll share that here as soon as possible. :)

Step Three: The Game Logic

Now it is time to start writing the real game logic. To improve our ability to parallelize the effort, we worked in the following way: while Maurilio worked on the low-level stuff, I wrote the full game logic in a low-level-independent. Then, we had merged all together in the last days. I don’t know if I can recommend this workflow, usually is better to work more close and less in a “MCV” way, however it worked well enough.

The whole game logic is fully accessible from a BlackSmithGame class. This class is not a MonoBehavior and it contains the method and the data needed by the game interface in order to access the game mechanics and allow the player to play. Then there are some “object” classes that are used to store information about several game entity: these classes are Metal, Weapon, Location and Minion. The first three classes store also the “data-driven” part of the game. Because metals, weapons and locations are fixed at design time, they also include the only instances available (in fact their constructor is private). As an example, look at the metal code

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Metal {

	public string Name { get; private set; }
	public string Description { get; private set; }
	public int Level { get; private set; }

	private Metal() {}

	private Metal(string name, string desc, int level) {
		Name = name;
		Description = desc;
		Level = level;
	}

	// ----------------------------------------------------------------------------------
	// DATA DRIVEN INITIALIZATION
	public static Dictionary<string,Metal> Metals = new Dictionary<string,Metal>() {
		{"mud",    new Metal("Mud"   ,"It's not metal. But...",1)},
		{"copper", new Metal("Copper","Good conductive metal!",10)},
		{"iron"  , new Metal("Iron"  ,"That's a true metal!"  ,18)}
	};
}

As you can see the class only stores its data (namely Name, Description and Level). At the end of the class there is a static dictionary that I use to store the only existing instances. So, in every class, when I need a metal, I can directly access this dictionary to get the needed instances. The same is for Weapons and Location.

Minions, instead, are a bit different. In fact, we need to create random minions at runtime. So, we have a standard constructor plus a static function that is used to generate a random minion according some input parameters (for instance, we usually create minions whose skill is proportional to the blacksmith’s fame level).

Step four: The minigames

[caption id="attachment_104" align="alignleft" width="300"]The forge minigame. The forge minigame.[/caption]

After the main game logic, we need to implement the forging minigame. As I said before, the forge minigame is a slightly modified rhythm game. The player has to warm up the forge pressing by quickly pressing a key with the left hand and match the signed spot (the yellow square in the image) with Return and the right hand. The game is then divided in two sub-games: the press-the-key-as-quick-as-possible game and a press-at-the-right-time game.

The code for the first one is very simple:

using UnityEngine;
using System.Collections;

public class TemperatureLevel : MonoBehaviour {

	public KeyCode TemperatureKey;
	public float TemperatureDecayRate;
	public float ButtonForce;

	public float TLevel {get; private set; }
	private float intStep;

	void Start () {
		TLevel = 10;
		intStep = Time.fixedDeltaTime;
	}
	
	void Update () {
		if (Input.GetKeyDown (TemperatureKey)) {
			TLevel += ButtonForce;
		}
	}

	void FixedUpdate() {
		TemperatureDecay ();
	}

	void TemperatureDecay() {
		TLevel = TLevel * Mathf.Exp (-intStep / TemperatureDecayRate);
	}
}

The game is just an exponential decay equation plus a key to increase the value. More the value grows, more it decrease quickly in the decay step. The final result is a “game” where it is progressively more difficult to keep an high value for a long time. This is perfect to simulate the blacksmith that has to keep an high temperature to forge the weapon.

The second code is more complex from the code point of view, mostly because it is really bonded with the GUI. However the key idea is very simple: keep a counter and, when the player press the Return button, check if the counter is on a valid spot. No more, no less.

Step Five: Put all together

The last day of the jam me an Maurilio met together in order to assemble all the part of the project. I was very glad that the integration phase was very easy. No problem emerged during this phase. THis is amazing because, you know, it is always difficult to produce two part of a software in a separate way without performing some integration test in between. :)

However there are still a lot of balancing problems. In fact we had no time to balance the game (respect to weapon sell value or minion salaries). Unfortunately we ended a bit late.

Step Six: Take away

At the end we completed the game and published it on the SpeccyJam forum (the game should be soon available in the main page). At the end there are several lessons I learned during this jam. Here there are a summary:
  • First, we always get better, faster and nicer. More we get faster, more we try more complex projects. More the project get more complex, more I have fun developing the game logic. This is really a nice motivation to continue.
  • This is a jam we performed without an "artist" for a long time.  This is nice in some sense because we are having problem dealing with our "graphic department" so I feel better knowing that we can still do something relying only on the two of us.
  • We learned a lot about shader in 2D game. And we learned again how bad can Unity be.
  • There are also some negative stuff. The next time I really like to end the project first in order to concentrate more on the final polishing of the project. This includes: balancing the gameplay, refine graphic and UI, write a tutorial or something to make easier for the new player to play the game. These are really thing that can make a difference between an average product and a great product.
  • I really need had to improve my artistic skills.
At the end, we have another jam on the shoulder and we get more experienced. That's why I love joining jam. Have a nice day!