Hey guys and gals, Davide here! :v:
I partecipated to LD50 with BLACKSUN, a resource management game based on the Aztec myth of the Fifth Sun and the subsequencial destruction of the Earth.

The postmortem will be a little more on the technical side, mainly because I am a developer by myself and my art skills suck :robot:
I will talk about Unity, C# and shaders (just a little). There is also a little chapter on the release, matter I'm not really expert, but during the compo I got some knowledge worth sharing.
About any suggestion, critique or challenge to a duel to the death, please write them in the comment section. Happy reading you all! :v:
P.S.: you can find the complete source code at https://github.com/DavideRoss/BLACKSUN!
Singleton Pattern
The singleton pattern is a very diffuse software pattern that let you instantiate a specific class (MonoBehaviour in our case) once, like it is a global variable. This is often seen as anti-pattern (something to avoid because prone to problems later in the project), but I find it very useful in Unity.
In practical usage let you access a MonoBehaviour object almost as static, so you don't have to link the object around the scene. Usually I have a block of important objects I use frequently called managers, like in my case the GameManager, the ResourceManager and the AltarManager.
There are different ways to create a singleton in Unity, each one with its bonus and malus, personally I use this one:
```csharp
using UnityEngine;
public class GameManager : MonoBehaviour
{
static GameManager instance;
public static GameManager Instance
{
get
{
if (instance == null) _instance = FindObjectOfType();
return _instance;
}
}
// Public variables
public bool IsPlaying;
}
```
The script declare a static property of the GameManager object returning the non-static _instance variable. If _instance does not exists yet, then search for it. That means if also you put two GameObject in your scene, both with the GameManager component attached, GameManager.Instance will refer to only one of these two. Then, if I want to get the IsPlaying variable from anywhere in the project, I just have to write GameManager.Instance.IsPlaying.
The theory behind a generic singleton pattern is not really intuitive to get in the beginning, but trying the pattern on Unity really shows how it's used and why. Give it a try!
Defining the ticks per second
In the beginning there was nothing, then Unity created Start and Update. But Update has a problem! It runs every frame, not caring if the game is running at 5 or 500 FPS, and I cannot calculate the duration of a job based on Update!
(small trivia: a lot of games from 80s/90s cannot be played without a proper support because modern CPU are much faster. This problem is still present nowadays: a famous Doom 2016 speedrun strategy depends a lot by the FPS. And about the speedrun: do you know that speedrunners prefer running on NTSC SNES instead of a PAL one because has a higher refresh rate?)
Yes, I could have used FixedUpdate, running on a fixed physics engine timeframe, but it's not really meant for that and I wanted more granular control. So I went for writing a tick clock by myself!
The system is actually pretty easy, it consists of three components: the interface, the registration and the propagator (not real computer science name, I like to be a little dramatic).
The interface is barely a couple of lines: its job is define a method that a class must have when it's inherited. The benefits of this method is that I can inherit the interface on multiple objects, and still I can fit them all into a single List. This is the code for the interface:
csharp
public interface IOnTickHandler
{
public abstract void OnTick();
}
Pretty simple, huh? The interface just defines the signature of the method that must be implemented later in the class. Every class can implement the method as needed, like this:
```csharp
using UnityEngine;
public class JobView : MonoBehaviour, IOnTickHandler
{
private void Start()
{
GameManager.Instance.Register(this);
}
public void OnTick()
{
// Do stuff here
}
}
```
This script do three things: inheriting the interface, implementing the method and registering the object. But why the registration is needed? You can find the solution on the GameManager code:
```csharp
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
// Singleton implementation, see above
public float TickPerSecond = 20f;
float _time;
long _ticks = 0;
List<IOnTickHandler> _jobs = new List<IOnTickHandler>();
private void Update()
{
if (_playing)
{
_time += Time.deltaTime;
if (_time > 1f / TickPerSecond)
{
_ticks++;
_time -= 1f/ TickPerSecond;
foreach (IOnTickHandler jv in _jobs.ToArray()) jv.OnTick();
}
}
}
}
```
The object with the interface inherited is added to a List<IOnTickHandler>, then in the Update function I sum Time.deltaTime (the time past from the last time Update is called) and check for a new tick. If the new tick has happened, cycle every object that inherit the interface and basically propagate the information that there is a new tick.
And that's conclude the whole lap. It's a little convoluted and probably overengineered for a game jam, but in this way I can control from the GameManager component the speed of the game during the game itself, and it could be extremely useful!
Difficulty ramp
I am not a game designer, and resource management games needs a lot of balancing, because there is the risk that a skilled player can manage to gather enough resources to keep playing the game indefinitely.
To solve this problem I've implemented an incrementing difficulty ramp. The variable is defined in the GameManager script:
```csharp
using UnityEngine;
public class GameManager : MonoBehaviour
{
public float Difficulty = 1f;
private void Update()
{
// ...
if (_time > 1f / TickPerSecond)
{
// ...
Difficulty += .0001f;
// ...
}
}
}
```
For each tick, increment the Difficulty variable a little. Then this variable is used in various places around the game, like in the AltarManager script to pick the amount of resources to demand:
```csharp
using UnityEngine;
public class AltarManager : MonoBehaviour
{
public void SpawnHead()
{
// ...
int count = Mathf.RoundToInt(Random.Range(1, 3) * GameManager.Instance.Difficulty * (Random.value < .5f ? 3 : 5));
// ...
}
}
```
In this way the amount of resources is not only dependent from a random value, but it's also biased by the difficulty of the game. In the end some players managed to survive basically forever, but this method shoud have worked for most of the games.
The names of the gods
This is a last moment addition, only for giggles: on the tooltip for the god head you can found the god's name and his/her domain. This elements are generated randomly, you can find the code in the GodHead script:
```csharp
using System.Collections.Generic;
using UnityEngine;
public class GodHead : MonoBehaviour
{
public static List Names = new List() {
"Macuilcozcacuauhtli", "Macuilcuetzpalin", "Macuilmalinalli", "Macuiltochtli", "Macuilxochitl", "Cuahuitlicac", "Patecatl", "Ixtlilton", "Ometochtli", "Tezcatzoncatl", "Tlilhua",
"Toltecatl", "Tepoztecatl", "Texcatzonatl", "Colhuatzincatl", "Macuiltochtli", "Iztacuhca", "Tlatlauhca", "Cozauhca", "Yayauhca", "Cipactonal", "Huehuecoyotl", "Huehueteotl",
"Mictlanpachecatl", "Cihuatecayotl", "Tlalocayotl", "Huitztlampaehecatl", "Quetzalcoatl", "Xiuhtecuhtli", "Mictlantecuhtli", "Acolmiztli", "Techlotl", "Nextepeua", "Iixpuzteque", "Tzontemoc",
"Xolotl", "Cuaxolotl", "Tloque-Nahuaque", "Ometeotl", "Ometecuhtli", "Tonacatecuhtli", "Piltzintecuhtli", "Citlalatonac", "Tonatiuh", "Nanauatzin", "Tecciztecatl", "Tlahuizcalpantecuhtli",
"Xolotl", "Xocotl", "Tezcatlipoca", "Quetzalcoatl", "Xipe-Totec", "Huitzilopochtli", "Painal", "Tlacahuepan", "Tepeyollotl", "Itzcaque",
"Chalchiutotolin", "Ixquitecatl", "Itztlacoliuhqui", "Macuiltotec", "Itztli", "Amapan", "Uappatzin", "Itzpapalotltotec", "Miquiztlitecuhtli", "Tlaloc", "Tlaloque", "Chalchiuhtlatonal",
"Atlaua", "Opochtli", "Teoyaomiqui", "Tlaltecayoa", "Cipactli", "Itztapaltotec", "Cinteotl", "Ppillimtec", "Omacatl", "Chicomexochtli",
"Chiconahuiehecatl", "Coyotlinahual", "Xoaltecuhtli", "Xippilli", "Xochipilli"
};
public static List<string> Domains = new List<string>() {
"stars", "medicine", "fertility", "underworld", "ballgame", "sacrifice", "earth", "art", "excess", "pleasure", "gluttony", "music", "gambling",
"healing", "peyote", "maize", "astrology", "old-age", "deception", "wisdom", "winds", "light", "fire"
};
public string Name;
public string Domain;
public void Initialize()
{
Name = GodHead.Names.PickRandom();
Domain = Random.value < .5f ? "Goddess of " : "God of ";
Domain += GodHead.Domains.PickRandom();
}
}
```
It's not really remarkable, if not for the PickRandom() method: this method is not native of the List<string> object, instead is added by the developer using what's called an extension method. You can find them on the EnumerableExtension script:
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
public static class EnumerableExtension
{
public static T PickRandom(this IEnumerable source)
{
return source.PickRandom(1).Single();
}
public static IEnumerable<T> PickRandom<T>(this IEnumerable<T> source, int count)
{
return source.Shuffle().Take(count);
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
return source.OrderBy(x => Guid.NewGuid());
}
}
```
Those methods are using generics and LINQ queries, but the gist of it is that returns the first element of a shuffled list.
Pretty neat, huh? You can achieve the same result using a static method asking the list as parameter, but I'm a sucker for syntactic sugar, hence the expansion :stuckouttonguewinkingeye:
Clicking on the elements
I have doing UI stuff. I really despise it. And of course my games are heavily UI based, guess I hate myself a little too. Making the player interact with UI, but still keeping a GameObject is boring: you can create a canvas for each GameObject that needs UI elements, or you can set your UI in world space and move GameObject and UI element together, and both methods seems a little hacky.
I need that the player can click on a GameObject, but usually require casting a ray from the camera to the mouse position, but converted in world space and not in screen space. Then the method that shoots the ray should propagate the event to the correct object and make sure that the object handles it. A lot of work, isn't it?
Luckily, Unity ~~warlords~~ developers provide us a couple of useful interfaces: IPointerClickHandler, IPointerEnterHandler and IPointerExitHandler. An explanation about the interface is provided a little above.
This those three interfaces I can handle all mouse events without caring to shooting rays, setting up colliders and propagating things. Thank you Unity devs!
I used them mainly in GodHead and JobView scripts to handle the assignations and the tooltip. The methods provides also an object with a lot of useful informations, like the mouse position and the button clicked. This is the JobView script:
```csharp
using UnityEngine;
using UnityEngine.EventSystems;
public class JobView : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerClick(PointerEventData e)
{
if (e.button == PointerEventData.InputButton.Left)
{
// Assign a villager to this job
}
if (e.button == PointerEventData.InputButton.Right)
{
// Remove a village from this job
}
}
public void OnPointerEnter(PointerEventData eventData)
{
Tooltip.Instance.ShowJob(Job);
}
public void OnPointerExit(PointerEventData eventData)
{
Tooltip.Instance.Hide();
}
}
```
I found this method straightforward and easy to use. The only thing you have to care about is setting up a Collider2D component (otherwise the events won't trigger) and be careful to not overlapping them with other UI elements blocking the raycasting.
A little take on shading
I didn't used so much shaders for this project: the only one is a shader assigned to the god heads, changing the color of them while the time is running out. The shader itself is pretty basic, plus a couple of lines to make it work with the alpha.
The shader is pretty hacked up together, time was running out, the shader is called GodHead_Shader (here's only the interesting part):
```glsl
sampler2D _MainTex;
float _Timer;
float _Darken;
fixed4 frag (v2f i) : SVTarget
{
fixed4 col = tex2D(MainTex, i.uv) * i.color;
float4 alt = col * _Darken;
float blend = step(_Timer, i.uv.y);
clip(col.a - 0.5f);
return lerp(col, alt, blend);
}
```
In the fragment shader I use a step between the UV on the Y axis and an external property to change the color to a darker one. I can control the external property via script, like in the GodHead script:
```csharp
using UnityEngine;
public class GodHead : MonoBehaviour
{
public SpriteRenderer Head;
public float TotalTicks;
float _pastTicks = 0f;
public void OnTick()
{
_pastTicks++;
Head.material.SetFloat("_Timer", Mathf.Clamp01(1f - (_pastTicks / TotalTicks)));
}
}
```
The clip function on the shader basically skip rendering the pixels when its argument is below zero. Writing the fragment shader this way make a cutout shader, where a pixel can be fully opaque or fully transparent, with to actual transparency.
Building and delivering
That's the part I was not really so expert. And to be honest I'm still not really that expert. I wanted to build the game for Windows and WebGL, so first thing I did is installing the "WebGL Build Support" module through Unity Hub. It took a dozen of minutes, pretty easy.
Second step was changing the Project Settings, specifically the Player section. For the Windows build I just changed a couple of settings, mostly the Fullscreen mode and the Default Screen Width/Height.

Third step: open Build Settings and add all required scenes to the Scenes in Build box, roughly ordered by the order of loading. I left all the other settings as they are and press Build: after a dozen of seconds it was done, zip the folder and upload it to my Drive. Done!
To build for WebGL the first thing you have to do is to switch platform from Build Settings: grab a snack, it will take a while. With WebGL had a little more problems: the first build I did has the resolution too high and for some users went out of screen, not good. So I limited the resolution and make the UI Canvas adapt the size for good measure.

Then I had a couple of problems with Itch.io: with the default settings the browser cannot load the game, complaining about decompression issues. I solved disabling the compression from the Publishing Settings: the build is a little more heavier, but still manageable by any modern device.

Done! Finally I can rest my old and worn body!
Outro
Whoa! That took a good time to write. If you are still reading, thank you very much! I hope that this postmortem can help you in the future. If you want to go deeper down the rabbit hole of game programming you can check the code from the other Compo participants: understading other people code is an awesome tool to learn!
Keep up the good work people, share as much you can without fear or doubt, we are not here to judge, but to help. Davide out!
