WarClicker 2 / MiniLD66 post-mortem

Yeah! I finally have time to write on my blog! As promised in the last post, here comes 3 post-mortems, one for each game jam I participated to at the start of April.

First, the Mini Ludum Dare 66 which I started on 28 March and ended the 02 April.
The theme was “You must construct additional RTS games”, I collaborated with Ted Wennerström, a swedish composer / sound designer who created the musics and sounds of the game.

The theme and the game

WarClicker 2

WarClicker 2 isn’t a Real Time Strategy game, you can download it on this page.
In this game you must defend helpless villagers who are assaulted by an army of orcs, you have to kill those orcs by clicking on them. If every villagers die you lose, the orcs will come by waves and you can perform different attacks depending on the mouse button you use.

I started my reflection on the theme by defining what is a RTS and more precisely what makes up the 4X genre: eXplore, eXploit, eXpand, eXterminate. In the limited time of the game jam I thought that focusing on exploration and extermination related mechanisms would allow me to have a more interesting game at the end.
This approach blurs the line between RTS and more action-oriented games, also I was more interested in exploring the interaction with the mouse than making a classical RTS with few chances to finish it in time.

The game concept I wrote for this game contains a lot more features but I wanted to work on the core gameplay: clicking enemies and mouse combos. If this core can be appealing then I’ll try to implement the rest, with just the core the game is similar to Whac-a-mole physical arcade game with slightly more complex controls.

Whac-a-mole game

What went right

  • The communication between Ted and me went well and he made a great job, the sounds fit well in the game.
  • I learned a LOT of things on Unity, mainly in sprites’ usage and creation of simple interface. Also the use of Raycast2D and filtering the results. And many more things…
  • I used the sprites of WarCraft 2 as they are exactly what I needed for this game (and that’s one of the first video game I ever played :p), and this has the visual result expected.
     I don’t own any rights on WarCraft 2, this game was created by and is property of Blizzard Entertainment. I’ve got no intents to use it commercially or make any revenue with it.
  • I made a little settings menu with few customization options including a colorblind mode.
     For the colorblind mode it covers deuteranopia and protanopia, I used the colorimetry tool of Illustrator to define which colors to use on important gameplay elements.

What went wrong

  • The first test was too late, thus preventing me from really working on controls and implementing the mouse combos.
     I took too much time on less important things like the background tiles when I should have test the game with just color boxes right away.
  • There’s only one type of enemy, I wish I had the time to make one or two more.
     With fixed speed and behavior for each, this would have enabled pattern based learning and so improved the learning curve and the coherence of the game.

In general I’m happy with what I managed to accomplish in 5 days and the amount of new things I have learned during those. In its actual state the game isn’t the funniest on earth but at least it’s not totally boring :)
I’ll work on it again later, right now I started to work again on Spirit Run with the team I had at the Global Game Jam 2016.

In the week to come I’ll write my post-mortems of Nordic Game Jam 2016 and Ludum Dare 35, until then, have a nice day/night!

Harvest Nothing 64 / MiniLD64 post-mortem

Hi everybody!

Last week-end I’ve participated to the MiniLudumDare which had for theme the Nintendo64. This was my first game jam ever, I did it alone and this post is about what I learned during those 48 hours.

To put the initial context:

  • I’m a game designer and programmer
  • I’ve made no commercialized games
  • Usually I work with Unity in C#

I wanted to learn to use GameMaker:Studio [GM:S] (never used it before) and decided to replicate Harvest Moon 64 [HM64]. This choice was motivated by two facts: the whole gameplay is made for 2D (legacy of the first episode) and I’m not able to create 3D models or even draw sprites.

I’m not gonna make a hour-by-hour report but rather discuss some special decisions I took and things I learned on GM:S.

Lessons learned

Basics

Some obvious things you had to fail to learn them on your first jam:

  • Don’t eat crap
  • Sleep full nights
  • Don’t abuse caffeine
  • Don’t get stuck for hours on a single problem
  • Take breaks

Doing a game jam alone is a bit sad but permit you to test things that you would fear to try in team. However every times you can participate with a team: do it! I won’t do another jam alone, that one was a missed opportunity to met new people.

Software architecture? in GameMaker? during a jam?…

I spent few hours analyzing the systems in HM64 and designing my software architecture trying to respect the law of Demeter in an environment with no privacy principle and no class concept.
The irony of applying this law to game development is that you can’t avoid the game world object to know part of other systems without adding complexity to the global architecture. And still I think it was useful and necessary, it saved me time by avoiding a lot of bugs and the only one that popped up was isolated in a single system.

I created one permanent invisible object for each system in the game and wrote code in script files whenever it was possible. I kept to write the full path to access variables even if I could had accessed them with something shorter, such as:

o_Game.i_GoldManager.i_GoldTotal
  rather than
o_Gold.i_GoldTotal

Just being certain of what I was calling and spot immediately a strange call that would not respect the architecture.

In brief, the Master object is the first to be instantiated at the “start” of the program, sets constants and context then instantiate core components. When the Game object is instantiated it initialize the calendar and the clock then instantiate all other systems.

Objects hierarchy

Event system overlay

A problem I ran into was getting the clock to notify other systems at specified hours: at the end of day the plants must check their growth, the user interface updates displayed information, … but GM:S has no observer or event-queue patterns built-in.

In fact there’s a set of 16 events called ‘User defined’ and a command event_user(0) to trigger them. The thing that the GML documentation does not say is that these events can only be called by the object that holds them. That means you can’t trigger a custom event you defined on an object by calling it from another one unless you do that:

with(objecttocall){
  event_user(0);
}

What happens if you have radically different types of object to call for the same event?

with(object1tocall){
  event_user(0);
}
with(object2tocall){
  event_user(0);
}
...

At the moment I came up to this part of the program, I already knew I wasn’t even close to finish the core game features before deadline. So I decided to take my time to implement a customised event system on top of the original one.

I had these objectives:
 1. Providers makes only a single-line call to notify event
 2. Providers shall not know who their clients are or even if they have clients at all
 3. Events are named and not numbered (‘g_Events.DayEnd‘ vs ‘0’)

To explain the event system I created we’re gonna take the plants example, plants in HM64 check if they grow at the end of day and rot when the season ends.
There is two events:

enum g_Events{
  DayEnd,
  SeasonEnd
}

The provider of these events is the timeline tl_Clock held by the object o_Game:

Events by tl_Clock side

On the client side the variable i_EventReceived is defined when s_Notify is called on an event the client has s_SubscribeTo:

Events by o_Plants side

The man-in-the-middle is o_EventUserDelegate, it holds a list of subscribers per event and the scripts s_Notify and s_SubscribeTo work on these lists. The lists are lazy initialized to avoid wasting memory on an event that may not happen during the play session.

o_EventUserDelegate

The bottleneck of this design is that a certain amount of boiler-plate code has to be written in the two scripts. Here’s the parts for the DayEnd and SeasonEnd events:

///s_SubscribeTo(Event, SubscriberId)
var l_EUD = o_Master.i_EventUserDelegate;
switch(argument0){
  case g_Events.DayEnd:
    if(!ds_exists(l_EUD.i_DayEndSubs, ds_type_list)){
      l_EUD.i_DayEndSubs = ds_list_create();
    }
    ds_list_add(l_EUD.i_DayEndSubs, argument1);
    break;
  case g_Events.SeasonEnd:
    if(!ds_exists(l_EUD.i_SeasonEndSubs, ds_type_list)){
      l_EUD.i_SeasonEndSubs = ds_list_create();
    }
    ds_list_add(l_EUD.i_SeasonEndSubs, argument1);
    break;
  default: break;
}

///s_Notify(Event)
var l_EUD = o_Master.i_EventUserDelegate;
switch(argument0){
  case g_Events.DayEnd:
    if(!ds_exists(l_EUD.i_DayEndSubs, ds_type_list)){
      var l_Count = ds_list_size(l_EUD.i_DayEndSubs);
      var l_Index = 0;
      repeat(l_Count){
        with(l_EUD.i_DayEndSubs[| l_Index++]){
          i_EventReceived = g_Events.DayEnd;
          event_user(0);
        }
      }
    }
    break;
  case g_Events.SeasonEnd:
    if(!ds_exists(l_EUD.i_SeasonEndSubs, ds_type_list)){
      var l_Count = ds_list_size(l_EUD.i_SeasonEndSubs);
      var l_Index = 0;
      repeat(l_Count){
        with(l_EUD.i_SeasonEndSubs[| l_Index++]){
          i_EventReceived = g_Events.SeasonEnd;
          event_user(0);
        }
      }
    }
    break;
  default: break;
}

In its actual state the event system works fine and is synchronous. However it’s easily expandable with a ds_queue to make it asynchronous to avoid spikes of performance consumption when multiple events happens simultaneously.

Miscellaneous observations on GML

Some special things I discovered on GML:

  • There’s no foreach structure, although it’s generally slow, sometimes you really need it. The substitution I used in s_Notify was repeat(){ with(){ } }
  • GML is NOT fully documented.
  • And the obvious double-edged characteristic: it is easy to use and easy to mess everything with it.

Conclusion

Even if I highlighted several “defaults” of GML, I enjoyed learning and using GM:S and will definitely come back to it in the future.
Concerning the game I’ll keep replicating HM64 as an exercise and discuss some precise points of development here but I won’t share updated version of the project files: don’t mess with Nintendo’s lawyers, that’s not a good idea.

For the record here’s the GM:S project in the state it was at the end of the MiniLD64:
Harvest Nothing 64

By the way I made a color configuration file to get GM:S code editor be closer to VisualStudio2015 C# colors:
Don’t forget to change the font to Consolas 10pt