Collectorvision Phoenix demoed at Portland Retro Gaming Expo

I attended the Portland Retro Gaming Expo this past weekend, and enjoyed myself very much.

One of the many highlights of the show was getting to try out the new Phoenix console from Collectorvision.

Having seen it in person and tried it firsthand, I can say that it is the real deal, and is absolutely worth the money they’re asking for it on kickstarter.

The campaign is a bit behind the pace with their funding goal, and they need and deserve support. Just 1000 pre-orders are all that’s needed to successfully fund the project and make the system a reality.

You can back the project here:

https://www.kickstarter.com/projects/1408938247/collectorvision-phoenix-an-fpga-colecovision-conso/description

For just $200, you get an enhanced, 100% compatible, 100% accurate ColecoVision with HDMI output, built in Super Game Module and FA-18 mods, cartridge slot and SD card slot, original and SNES controller ports, and a ps2 keyboard port. Collectorvision announced Atari 2600 compatibility, and plans for supporting other vintage game systems such as the Adam and MSX.

ColecoVision is an underrated and underappreciated console, both in its heyday and today. With graphics capabilities between the Atari 2600 and the NES, it has a small but very loyal following, and a decent library of original games and an active homebrew community releasing new games. It’s a great time to get into the system if you are vintage gamer.

CollectorVision Phoenix: A modern, premium FPGA-based ColecoVision compatible retro console

Help CollectorVision reach their crowdfunding goal and make the Phoenix a reality!

Earlier this week, CollectorVision announced the crowdfunding campaign launch for their Phoenix console on Kickstarter. CollectorVision has in the past developed modern homebrew games for the 1982 ColecoVision videogame console, and in addition to that have partnered with OpCode games, developers of the ColecoVision Super Game Module expansion, which augments the system with more RAM and improved graphics capability.

I’m very excited about this system. ColecoVision was a great system, which died too young due to the videogame industry crash of 1983. It offered graphics nearly on par with the NES, a full year before the Famicom was released in Japan, and delivered home ports of early 80s arcade games that offered greater fidelity to the originals than was possible on the Atari 2600.

The Phoenix’s feature list is amazing: FPGA hardware implementation for 100% compatibility and fidelity with the original system, HDMI-out video, SD card slot, built-in Super Game Module and F18A enhancement hardware, 10 built-in ROMs of modern ColecoVision homebrew games, DB9 controller ports for original ColecoVision controllers, as well as SNES controller ports for compatibility with more common/comfortable SNES gamepads, and even a PS/2 keyboard connector. There’s even been talk of including an FPGA core for support of Atari 2600 games, much like the original ColecoVision’s Expansion Module 1 adapter for Atari 2600 games.

This is a dream system, and considering that, its price tag of $200 is very reasonable. Compared to the RetroUSB AVS system and the Analog Super NT, the Phoenix will fill a nice in retrogame preservation and it deserves to make its crowdfunding goal of $230,000.

To hit this goal, CollectorVision will need about 1000 backers to sign up. The kickstarter campaign is off to a somewhat slow start, however — three days into the campaign, they’ve only managed to secure $28,000 in pledges. Usually, a system like this would be fully funded in the first day, or even the first hour of the crowdfunding campaign going live. If the campaign received steady contributions every day at the level they have for the first 3 days, they would make goal, but it’s most typical for kickstarters to get most of their funding on the first few days, and the last few days. So I’m worried that they will not hit their goal. 

Perhaps retro gamers are wary of crowdfunding for yet another modern retro game console. People enthusiastically backed Ouya to the tune of $8 million dollars several years ago, and the recent AtariBox/Atari VCS crowdfunding was also successful in reaching goal, but only made $3 million dollars amid serious doubts about the current company calling itself Atari’s capabilities to deliver on what it has promised, and alleged mis-representation of their prototype hardware.

I don’t have any insider knowledge of CollectorVision, but everything I have seen from them about the Phoenix looks good, and I have faith that they care capable of delivering on their promises, if they can make their fundraising goal. Their hardware really exists, and all they need is capital for manufacturing. If you have fond memories of the ColecoVision and the early-80’s era of videogames, definitely check out the project, and consider becoming a backer.

GameMaker Tutorial: Configuration system

Many games have options or settings that are configurable.  The specifics can vary widely, from graphics options to music and sound effects volume to to input configuration to in-game options such as difficulty level and which rules are enabled/disabled.

This article will cover how to create a basic configuration system, using external file i/o, ds_map, and json.

Define your configuration requirements

First, before you develop it, design the system. Things to consider:

  • What variables does your game have?
  • What variables would you like the user to be able to modify?
  • What are the upper and lower bounds that make sense, or are reasonable for an enjoyable game? What values will break the game?

A little planning, and you can quickly list out all the variables you’ll want to manage with the configuration system.

Not every variable in your project needs to be subject to customization. Decide what configuration options you want, and define the variables that will be needed to control them, and decide on your default values. 

That said, having an editable, external configuration file can be very valuable for testing and tweaking the game, as well as convenient for the player. By having an external config file, you can modify game constants and variables without having to re-build the project each time. Since building the project takes time, being able to avoid building the game each time you want to test a variable can potentially save you time — for larger projects, potentially minutes per build.

Storing the config externally will also enable a tester to play around with the game variables without the need for the tester to be a programmer, or have GameMaker Studio installed. They can simply edit the config file, save it, and run the game again.

Nobody said that you must create a UI in the game program that can access every variable that you store in the config file. So, your testers can play around with configuration in a text editor, while your will eventually include a configuration UI for the game, to be used by players, and accessed through a title screen menu or a pause menu. This UI only needs to expose those configurable options that you think it should, or can have a secret mode that exposes more (or all) of them.

The default configuration should be safe to run on all devices the game is intended to run on, and should have the “standard” or “recommended” settings for the best or recommended game experience. 

Having defaults is important in case the external config file is missing or corrupted, and needs to be regenerated.  Create a ds_map called defaults, and use it to store all the default values.

Coding the config system

Coding a simple config system is actually very easy.

First, define variables to store the default configuration and the actual configuration, and create ds_maps for them.  The best time to create these ds_maps is immediately on launch, as soon as the program starts.  You may want to make these global variables, so that they will be accessible anywhere and will persist for the entire runtime.

global.defaults = ds_map_create();
global.config  = ds_map_create();

Of course, when we are about to exit the game, we will need to remember to destroy these data structures, to properly free up the RAM:

ds_map_destroy(global.defaults);
ds_map_destroy(global.config);

Next, initialize the defaults ds_map with all the variables that are part of the configuration, and their default values. It’s easiest to learn the shortcode for accessing ds_map values:

defaults[? "key"] = value;

In the code above, “key” is the name of your variable, in quotes, as a string. The value is the literal value of the variable.

So you can do this:

global.defaults[? "starting_lives"] = 3;

or

global.defaults[? "starting_lives"] = default_starting_lives;

As you can see, the ds_map’s key indexing allows you to choose meaningful names for the keys, which makes it easy to recall them later.

When you apply the configuration to the variables in your project, assign the value from the ds_map, like this:

variable = config[? "key"];
starting_lives = config[? "starting_lives"];

Once you have your ds_map populated with your configuration data, it’s time to write it to disk.  This is will save the file so that the configuration state can be read and applied to the game state the next time the program runs.

The gml function json_encode() makes it very easy to write the ds_map to a file, by converting the ds_map into json, or JavaScript Object Notation, which is just a commonly used data format, and can be thought of as a specially formatted string. You don’t need to know anything about the syntax of json in order to use the encoding/decoding functions — GML handles this for you.

Create a json-encoded string version of the config ds_map:

config_string = json_encode(global.config);

Check to see if an external config file exists already, and if not, create it and fill it with the default configuration:

if !file_exists(working_directory + "config.json")
{
config_file = file_text_open_write(working_directory + "config.json");
file_text_write(config_file, defaults_string);
file_text_close(config_file);
}

If the config file already exists:

  1. read the content of the file into a string variable,
  2. decode the json string to convert it back into a ds_map,
  3. validate the data in the ds_map, and,
  4. if valid, apply the configuration data to the game variables.
//First read the json data out of the config file
config_file = file_text_open_read(working_directory + "config.json");
config_json = file_text_read_string(config_file);
file_text_close(config_file);

//Next, decode the json, converting it to a ds_map
global.config = json_decode(config_json);

//Now, validate the configuration data to verify the settings are good
if !config_validate(global.config) //config_validate is a script that you wrote to validate your custom configuration data.
{
   //if we failed validation, destroy the config and create a good copy using defaults. 
   ds_map_destroy(global.config);
   config = ds_map_copy(global.default);

   //(Or, alternately, just correct the specific variables that were invalid, leaving any valid non-default values intact. This is more work for the programmer, but more convenient for the user.)
}

[...]

//apply data stored in global.config to the variables in your project as needed, where and when appropriate.
configurable_game_variable = config[? "key"];

The exact details will vary depending on your project, but the above is a good example to follow to get  you started.

Implementation: Data and File I/O

It might help to explain the above, in plain English, without the code examples getting in the way.

When the game runs, the very first thing the program should do is check to see if a configuration file exists.   If it exists, we read the data out of the file using file_text_string_read(fileid) and convert the string to Javascript Object Notation (JSON) with json_decode(string).  This returns a ds_map of key:value pairs that contain all the configuration data. If the config file does not exist, then we create it, populating it with our default data values.

If the config file exists, but contains invalid data, then we restore the invalid data using defaults.

Once we’ve successfully read data out of our config file, we need to validate the configuration data that we read from the file in order to ensure that the game is being run with sensible values that won’t result in the game crashing or glitching. If the configuration data is invalid, depending on the setting and the value, the game not work properly, and may crash, or may perform unexpectedly, or break. 

How the invalid data got into the configuration, you’ll want to investigate and fix, if the program was at fault. Your program may have written the data incorrectly, or it might have a bug that results in a corrupted file, or you may have read the wrong value out of the file, and those are all errors that you would need to debug and fix.

But it’s also possible that the user may find the file and manually edit it, make a mistake, and thereby introduce errors.  So check each value in the configuration ds_map, and verify that it is valid by checking to see if the key was found in the configuration file, that its value is of the correct data type (string, number, or boolean), and that it is within the range of acceptable values for that variable. However the bad data got there, your program will need to handle it and correct it.  Write a script that does this, according to the particular needs of your game.

If validation fails, whether because the file is missing, or because one of the values found within it is incorrect, we can handle this in several ways.  One way is to reset all values back to their default values. Another way is to correct just the bad value, on a per-setting basis, restoring the invalid value back to the default value.  Or we can simply display an error message to the player and exit the program. Decide what is best for your project, and implement it that way.

Usually, I recommend checking whether the file exists, and if not, regenerate it using defaults, and if it exists, restore individual settings to default one by one if there is an invalid value, rather than resetting the entire configuration back to the defaults if any of the values is invalid.  This way, a small error in the config file doesn’t blow out all the settings, and program will leave any valid customized settings alone, so that the user will only need to correct the values that were reset to default.

If we have a valid configuration, the next step is to apply those values to the game variables. We do this by assigning values to variables in the objects that use them, and the values we assign are copied out of the config ds_map, so that they are local to the owning object, and can be modified during the lifetime of the object without altering the configuration data.

Once the game variables have been set, the game is now ready to run.

Where did that file get written to?

While you’re developing the game, you might want to know where GameMaker is writing the files, in case you want to open them with a text editor and double-check that they’re being written correctly, or if you want to edit them. If you’re running the game through the IDE, the location may be trickier to find than if you built an executable and installed it. For help in finding the location of the writeable directory for your project, see this article.

Editing the configuration

One great thing about storing the configuration data in an external file is, we no longer need to re-compile the game every time we wish to tweak the settings.  This can greatly speed up testing, as compilation can take a minute or more each time, and this rapidly adds up when  you’re quitting, coding, re-launching again and again as you develop. So use the configuration system as  you test your game design.

We can edit the configuration in various ways.

The simplest to develop is to develop nothing; just rely on the user to find the configuration file on disk, open it up with a text editor, and change values, save the file, and run the game again.  You’ll find the writeable working directory for your game somewhere inside of %appdata% in a Windows build, but if you’re building the project for other platforms, you’ll need to find it.

While this is the easiest approach, this isn’t the most user friendly solution. A better user experience would be to put a GUI in the game to change the settings, and let the game program edit the config file.  This will be safer for the user, as you can constrain the input and check it for valid values before saving the config file.

The downside is that this can take a lot of extra work to build the user interface. Sadly, GameMaker does not provide a library of user input controls, such as buttons, checkboxes, text boxes, sliders, and so on. So to build the UI, we first have to build these controls.

This is a great opportunity for beginner programmers to get some experience designing and programming their own controls.  But it’s also a time-consuming task, and can be a frustrating challenge for a newbie programmer to figure out how to make a collection of robust, bug-free UI controls that are easy to use, work together, and behave in a way that the user expects based on their experience using other software. And doing this takes time away from developing the game part of the project.

It’s a lot of work, so having an easy way out is a good thing. There are assets available through GameMaker marketplace, which can be purchased for a few dollars, and provide the needed functionality. Either way, it’s good to have a set of reusable controls that you can put into any project, so whether you buy some, or you decide to make your own, you can get a lot of value out of them.

Advanced concerns

Storing arrays, ds_structures inside json

Up until now, the examples I’ve given have all been simple data types.  If you want to store something else, like an array, or a data structure, or graphics data, it gets more complicated.  This article is just an intro level tutorial, so it won’t cover these advanced topics.  But I expect I may cover them in the future, at some point.  Many games will not need the advanced techniques to store the basic configuration data.

Applying config to application state

Certain configuration changes, such as display size settings, will require the room or game to be restarted before they take effect.  In such case, you may need to use game_restart() or room_restart(). If you are confident that the data is being applied correctly to update the game variables, but you’re not seeing the change, try a room restart and see if the changes take effect.

But any room or game restart will restart the game in progress, and that may not be what you want to happen at all!  If you have a game where you can change the configuration from the Pause screen, for example, you will not want to disrupt the running game.  In that case, you’ll need to go further and handle this in some way, such as:

  1. Display a message to the user saying that the changes will take effect after they quit and relaunch the game.
  2. Give the play the option save the present game-state and then restore it with the new configuration in effect.

Details on exactly how to do this will vary considerably depending on your game’s design, but if you need to do this, you’ll essentially be building a save state feature for your game, and then calling it to save and then restore the game after the restart.

The basic logical flow of this process is as follows:

If <config change will require restart> and <game is in progress>{ save game-state to external file; restart;}

On re-start, check for existence of a game-state file, and if it exists, clear the room of default starting instances; restore room from game-state; then delete the game-state file.

This sounds fairly straightforward and simple, and, in concept at least, it is.  The difficulty is with storing all of the instances and their state data. Depending on the game, you may have hundreds of instances, and each instance may have a lot of data, and all of it needs to be written to file, then read back out of file, in order to reconstruct the game in the state where it left off.

Making it tamper resistant

You may welcome the user tinkering with the config file, or you may want to protect the config file against unwanted tampering. Usually this isn’t critical for a config file, but for a save file or a high scores file, it might be important to prevent cheating. If your game uses password-protected user accounts, or stores any kind of financial data or purchase records, you should be storing that data securely.

This should be all you need. I won’t get into technical detail here, but will outline a few tools you can make use of.

  1. Use ds_map_secure_save() and ds_map_secure_load() to securely store the configuration data in an encrypted file. The encrypted file will not be editable by a curious user. The manual doesn’t give detail about what encryption is used.  Depending on how serious you are about protecting the data, you will want to research encryption and use an algorithm that hasn’t been broken. Don’t attempt to invent your own encryption.
  2. Create a cryptographic hash of the configuration data string, and store the hash with the file.  When you read the file, re-hash the data you read out of the file, and verify that the hashes match.  If they don’t, something has changed, and you know the file has been tampered with or corrupted.  In this case, you should re-generate the entire config file from defaults. 

    Look at GML’s md5 functions to get started.  GML also provides sha1 hashing for this purpose. MD5 hashes are no longer considered secure, and sha1 is also no longer considered secure, but may be “good enough” for non-critical needs. While not “hacker proof” they will prevent casual tinkerers from being able to modify the data.

Saving external data for other purposes

Now that we know how to store data in an external file, retrieve it, validate it, and use it at runtime, there are other applications we can use these techniques for. 

The most obvious one that comes to mind is save states.  I’ve already touched on this above, in brief.  Other ideas include:

  1. High score, leaderboard, and achievement data.
  2. Telemetry data for debugging or analytics.
  3. User profiles (to allow multiple users of the same machine to each have their own configuration and save file preference).
  4. Level Editors.
  5. Mod packs, to allow a community of players to make custom modifications to your game, such as level data, or other external resources like sprites and sound effects, etc.

As these features become more and more advanced and complicated, they’re really best left to professionals working on commercial projects.  But by following the approach described in this article to do a simple configuration system, you’ll have taken the first steps toward getting your skills up to that level.

GameMaker Tutorial: Audio speedup with sync

In so many games, music speedup is a great way to get the message to the player that they need to hurry up and get things done.

It’d be great if you could simply set a new tempo with a simple GML function, and have the current background music adjust on the fly. Something like audio_sound_set_speed(sound, speed) would be lovely. But it’s not as simple as that in GameMaker, as I found out recently.

Here’s how I implemented a speedup for my GMLTetris project:

First, I created two music tracks, one at normal speed, and one at double speed, and added them to the game project as sound assets.

Everything else is just programming:

if <condition> {stop slow_music; start fast_music;}

This is easy enough, the trickiest part is probably getting the condition right to switch tracks, but depending on the game, that condition could be very simple, too.  The only real complication is that if you’re checking the condition repeatedly, as you normally would every Step, you only want to trigger the changeover once.  So to do that, set up a variable to track whether the switch has happened already, and check it, too, even if the condition that triggers the changeover continues to remain true on successive steps.

if <condition> && !music_switched {stop slow_music; start fast_music; music_switched = true;}

The music speedup that happens in a game like Super Mario Bros., where the music speedup occurs when the level timer hits 100, is a typical example of such a technique. If you only need to do a single, one-way switch, this is all you need.

If your game needs to switch back and forth between slow and fast music, your conditional needs to be more sophisticated.

if <condition>
{
   if !<fast_music_already_playing>
   {stop slow_music; start fast_music;}
}
else
{
   if !<slow_music_already_playing>
{stop fast_music; start slow_music;}
}

Here, because the game can switch multiple times, when the condition check happens, we can’t get away with a music_switched variable that changes one time. What we need to do is check to see if the music we need to switch to is already playing, and if not, stop the current music and switch to the other music.

One thing to keep in mind, this basic technique will start the fast music from the beginning of the track. This might be what you want, but it would also be good if you could start the fast music at the position where the slow music was, for a seamless transition.

GML has the functions to do this: audio_sound_get_track_position() and audio_sound_set_track_position(). But in order to make use of them, we need to do a bit more work.

First, since the gml functions return the absolute time position of the track, and since two tracks play at different speeds, we need to adjust the position proportionately when we switch tracks, so that the position is at the same position percentage-wise. This is actually easy, as long as we know the tempo change, which we do. Since the fast track is double speed, we can easily calculate the equivalent position in the other track by multiplying or dividing by 2.

Slow to fast: position *= 0.5;

Fast to slow: position *= 2;

Where I ran into trouble was, I needed to be able to switch both ways. It seemed like it should be simple — just check whether the desired track is already playing, and if not, get the position of the current track, adjust it proportionately, start the desired track, set the position. Easy, right?

Let’s look at it in pseudocode first:

if <condition to switch to fast music>
{
   if audio_is_playing(slow_music)
   {get position; stop slow music; start fast music; set position;}
}
else
{
   if audio_is_playing(fast_music)
   {get position; stop fast music; start slow music; set position;}
}

This was when I discovered that audio_play_sound() returns a handle for identifying the specific instance of the sound that is playing. This is necessary to use to set the track position of the playing sound. You can’t just set the position for the sound_index; you have to set it for the specific handle of the currently playing instance of the sound. If you set the track position for the sound_index, any time that sound resource is played in the future, it will start from that position.

///Create Event:
bgm = audio_play_sound(slow_music, 10, true);
///Step Event:
if <condition>
{
  if audio_is_playing(slow_music)
  {
  var pos = audio_sound_get_track_position(bgm);
  audio_stop_sound(bgm);
  bgm = audio_play_sound(fast_music, 10, true);
  audio_sound_set_track_position(bgm, pos * 0.5);
  }
}
else
{
  if audio_is_playing(fast_music)
  {
  var pos = audio_sound_get_track_position(bgm);
  audio_stop_sound(bgm);
  bgm = audio_play_sound(slow_music, 10, true);
  audio_sound_set_track_position(bgm, pos * 2);
  }
}

I also discovered that detecting which track is playing with audio_is_playing() does not work for this purpose. I still don’t have a clear understanding of what was happening in my code, but some debugging showed that my track position calculations were being distorted by being called multiple times. This doesn’t make sense to me because the song should no longer be playing after the first step when the switch condition is met. But my theory is that since the audio is played in another process from the main program, there’s some messaging going between the two processes asynchronously, and as a result audio_sound_is_playing() can still return true a step later, even after the message is sent to stop the track playing.

By trying to set the track point multiple times in quick succession, weird and unexpected results happened, and the tracks switched but did not set to the correct position.

So I had to come up with a surer method of knowing which music is playing.

Debugging was tricky, since I couldn’t tell from listening where the audio position was. To aid debugging, I drew the position of the playing track to the screen, and then I was able to see that the position was not being set correctly as expected. Somehow, switching from slow to fast would drop the track back from about 10 seconds to 2 seconds, and then switching from fast to slow would jump from 2 seconds to 38 seconds. It wasn’t consistently the same timing, but depending on when the switch was triggered, it would jump around, seemingly at random, but within a range of a second or so around these positions.

I couldn’t figure out why that was happening, so I tried using show_debug_message() and watched the output console, and saw that the track position would update 2 or 3 times when the tracks switched; I was expecting it to only update once.

This is what clued me in to what I believe was happening due to the multiple processes communicating asynchronously.

The solution I used in the end was easy and simple: instead of checking which track was currently playing using the audio functions to directly check whether it was playing, and then switching from slow to fast or vice versa based on the currently-playing audio asset, I just added a new variable, condition_previous, and compared condition to condition_previous, and made the switch happen only when the current condition didn’t match condition_previous. This only happens in one step, when the condition changes from false to true, or vice versa, and so the track position is set once, when the bgm switches tracks and syncs up the new track to where the old track left off.

switch_previous = switch;

switch = <condition to check for switching to the fast music>;

if switch && !switch_previous
{
var pos = audio_sound_get_track_position(bgm);
audio_stop_sound(bgm);
bgm = audio_play_sound(fast_music, 10, true);
audio_sound_set_track_position(bgm, pos * 0.5)
}
else
{
if !switch && switch_previous
{
var pos = audio_sound_get_track_position(bgm);
audio_stop_sound(bgm);
bgm = audio_play_sound(slow_music, 10, true);
audio_sound_set_track_position(bgm, pos * 2);
}
}

This works, because it guarantees that the condition checks will be accurate, as they do not depend on checking the status of the audio playing in another thread.

GML Tetris, a GameMaker Demo project

My latest asset for the GameMaker Marketplace is a Tetris demo. Fully-featured, and configurable, it requires only sound files to be added to complete the project.

It’s meticulously researched, beautifully coded, fully documented, and rigorously tested, and represents approximately 150 developer hours of work, for only $4.99. It’s playable as is, right out of the box. It’s easy to understand the code, easy to configure with simple changes to the code, and modding is encouraged.

Colin Kaepernick, Nike, and Pat Tillman

Two days ago, Nike made headlines with a new advertising campaign featuring NFL quarterback Colin Kaepernick, who hasn’t worked in professional sports for several years due to being blacklisted for his protest of police violence against minorities during the pregame rendition of the national anthem.

A day after the unveiling of the campaign, a response using the image of Pat Tillman, an NFL player who left his NFL career behind in order to enlist in the military, and who died fighting in Afghanistan, in an attempt to mock and discredit the Nike campaign, and to make a statement seemingly in opposition to the protest against police violence.

Opponents of justice and phony patriots have attempted for years to cast Kaepernick’s protest as unpatriotic and disrespectful to veterans.

See, here’s the thing about that. If you wanted to cast Pat Tillman’s death in the most flattering possible light, you would say that Pat Tillman walked away from a multi-million dollar career to selflessly give his life defending American freedom. There’s a lot of problems with that, but for the moment let’s grant it, to give pro-Tillman/anti-Kaepernick advocates their strongest argument.

For the freedom that Tillman died defending to be worth anything, it must be freedom for all Americans. Wrapped up in the concept of freedom are the rights that, although enshrined in our Constitution and in the Declaration of Independence, are routinely denied to black and brown people without due process or recourse.

This is at the very heart of Colin Kaepernick’s protest during the national anthem. If Pat Tillman died to protect the rights and freedoms of Americans, that must include those rights and freedoms that are denied to Americans whom Colin Kaepernick is speaking for through his protest. And if so, then using Pat Tillman’s sacrifice to denigrate Colin Kaepernick also denigrates Pat Tillman.

Kaepernick has stood on principle for his right to express his views and to make peaceful protest against injustice, which is a right guaranteed to him by the Constitution, and has done so at the cost of his NFL career, representing tens or even hundreds of millions of dollars. The fact that Nike would contract with Kaepernick, paying him money to endorse their products does not in any way negate this, any more than the act of resigning in protest from a job for reasons of principle would be negated by finding other employment.

Kaepernick may not have died in a foreign battlefield, but his sacrifice is nonetheless real. Death is not the only sacrifice, and though people be willing to give their lives, none should ask or require this as the only measure for “true” sacrifice.

Using Tillman’s image and sacrifice in this way is an attempt to drive a wedge between Tillman’s life and the highest, most sacred principles that the nation he died serving was founded upon, and an attempt to drive a wedge between Americans. Recognizing this, I am able to recognize the sacrifices of both men as being for the same cause.

GameMaker Tutorial: Delta Time

What is “delta”?

Delta is a term often used in math and science to indicate change. For example, in physics calculations, the term ΔV (pronounced “delta-vee”) is used to quantify a change in velocity as measured at two different moments in time. If you didn’t have an introduction to this concept in your education, it can seem mysterious why we talk about “delta” like this, but it is a common convention.

Background

In videogames, the game program incorporates a routine called an update loop, which repeatedly applies the rules of the game to the game’s present state in order to create the next game state. Normally, it is desirable that the program control its frame rate, the number of times this update loop executes per second, so that a consistent frame rate is achieved, in order to have the game run smoothly and consistently. Ideally, this frame rate would be constant and unvarying.

Achieving this in practice can be quite complicated. Back in the old days, when games were programmed in Assembly for specific hardware platforms, and the game program ran on the bare metal, the programmer relied on the CPU clock and the timing it took to perform various operations to ensure that everything worked in sync. This required great effort and intimate understanding of the hardware and program code.

For the most part, GameMaker makes things simple enough for basic game development, and you don’t have to worry about regulating the frame rate yourself.

In older versions of GameMaker, there’s a room property, room_speed, which sets a target number of steps the update loop will attempt to execute per second.  Typically, this is set to a value that aligns nicely to the refresh rate of the display — often 30 or 60.

In GMS2, room_speed is replaced by a global option in the project’s properties.  (Cog symbol) -> Main options -> General and set “Game frames per second”.

This simple approach, simply setting a frame rate through the Game FPS or room_speed properties, works well enough for many projects.  Just set the desired frame rate and let GameMaker manage itself to try to achieve this target frame rate.  As long as the program is able to do so, everything will run as desired.

We can run into problems, though, because of the limitations of the computer hardware to perform all the calculations needed during the update loop to generate the next game state.  As long as the computer has plenty of resources, it should have plenty of time to generate the next game state.  But if those resources are not available, or if the game demands too much work be done to allow the available system resources to create the next game state in time, the game will not run smoothly.  The program will not crash, but it may slow down or stutter, or perform in a jerky manner.

It’s not really avoidable; to avoid the problem completely, you would need to write the game in such a way that it was guaranteed that the program always requires the same amount of calculations to be performed per step, and always has the same system resources available to perform those calculations.  The first is very unlikely, and would impose constraints that would make the program’s design very rigid. The second is well beyond your control, unless you’re writing software that has direct control over the hardware it’s running on, rather than writing an application that runs on top of an operating system that also supports numerous other multi-tasking programs and services.

The solution is to write efficient code that has an extremely good chance of running all the calculations for the next game state before that game state is needed for drawing the game to the display, so that there will never be a delay that results in a dropped frame.  Doing this requires that you mostly write small, simple games, and run them on hardware robust enough that it will easily be able to guarantee that sufficient resources are available in order to complete the computation required, on time, every step. Those are both significant downsides, but even so you can create a great many games within those constraints these days, without too much of a problem.

But there’s still things that are out of your control, even if you write a small program with very efficient code. You can’t control what hardware the user will run the game on.  You can’t control what other processes might also be running on that system, in the background, while the game program is running. These uncontrolled factors can defeat all your efficient programming and give a poor experience at runtime on a system with insufficient resources to perform all the instructions that it needs to, on time.

Enter delta time

When the simple approach isn’t good enough, it’s time to turn to a concept involving delta time.  This is simply measuring, each step, the amount of time that has passed since the previous step.  This amount will vary from step to step, depending on how much work the game had to do to generate that step, and how much hardware resources were available to perform that work, in addition to whatever else the operating system may have been doing.

Once you know how much time has passed, you can use this to make adjustments in various things that depend on time, such as movement speed, timers, sprite animation speed, and so on, to keep everything looking smooth.

In a simple game, you would normally just set an instances speed to some value, V, and every step the game would update by moving the instance V pixels in direction theta.

In a delta timed game, you would first measure the amount of time that has passed since the previous step, calculate a ratio between this time and the number of game state updates desired per second (frames per second), and then use that ratio to modify the speed of everything in the game, so that even if the game runs a little behind in calculating everything, the end result is that the instance looks like it moves V pixels in direction theta each step.

Make sense?  It can be a lot to grasp at first, but it’s actually fairly simple.

Let’s look at it now in detail and walk through an implementation.

Implementing delta time

GameMaker provides a built-in global variable, delta_time, which is the time in microseconds that has passed since the previous step.  Since the engine performs this measurement for you, it’s very reliable, and all you need to do is use it.

A microsecond (μs) is one millionth of a second, or 1/1000000, or 0.000001. Typical GameMaker projects target a framerate of 30 or 60 steps per second, so each step is 1/30th or 1/60th of a second, or about 33333.333…μs per step for a 30fps game, and 16666.666…μs for a 60fps game.

So, if your game were running ideally, updating the game state every step exactly on time, every step’s delta_time should be exactly 33333.3… or 16666.6…  In the real world, you won’t hit those numbers exactly, but you’d expect that they should be very close, most of the time. (And in GameMaker, the value of delta_time drops the decimal, which introduces a problem down the road that we’ll have to deal with somehow… [[Hmm… maybe it’d be better to use a room speed that yields a whole number ideal delta_time?]] We’ll get to that in a bit.)  To the extent that delta_time differs from this ideal value, you can adjust all of the time-based variables that influence the game state, and if you do it all correctly, thereby smooth everything out.

It would be nice if you could just have a “use delta time” checkbox in your project, and all the built-in time-dependent variables — speed, hspeed, vspeed, image_speed, alarm[], etc. would just receive these adjustments by virtue of the engine, automagically.  Wouldn’t that be nice?

But for whatever reason, they don’t give us that feature, but at least they give us the built-in delta_time variable to work with.  So we’ll have to do that.  And of course, every other user-defined variable that we add to our project that depends on time will also need to be adjusted with delta_time.

So, if the game is running too slow, delta_time will be higher than the ideal value, because the amount of time that passed was longer than the ideal time.  In the game, instead of moving N pixels per step for 60 steps in a second, the instance would move N pixels per step, but only hit some number less than 60 steps per second, resulting in slowdown and jerky movement and animation.

To fix this, we should be able to see how:

ideal_delta_time = 1/room_speed * 1000000; //typically 33333 or 16666

This simplifies to 1000000 / room_speed. Next, we need to compare the measured delta between the previous step and this step (delta_time) to the ideal delta time:

dt_ratio = delta_time / ideal_delta_time

Now that we have the ratio for this step, we must use this ratio for all time-dependent calculations 

speed = ideal_speed * dt_ratio;

or, since computers multiply with fewer cpu instructions than they can divide:

speed = ideal_speed * delta_time * room_speed * 0.000001;

Or in other words, to move at an average speed of N pixels per step, you adjust the actual speed every step by multiplying it by delta_time/ideal_time:

speed = ideal_speed * (delta_time/ideal_time)

(Note, many games that use delta_time eschew the built-in speed system, instead using variables that are not managed by the engine, to give the programmer complete control over the motion. This is a very common approach taken with GameMaker projects, because the way the built-in variables are managed by the runner don’t offer the flexibility and control needed.)

Once we have the dt_ratio defined for this step, we don’t want to have to re-calculate this delta/ideal ratio again and again for every calculation performed in this step, so it’s best to do it once per step as a global variable, and have every instance that needs to use it reference this global value:

global.step_delta = delta_time/ideal_time;

That’s the basics of it.

Difficulties

The main problem that people have is that they have to adjust every variable in their game that is time-dependent.  Not just speed, but alarms, image animation, and possibly even such things as the pitch and duration of sound effects.  This can get tricky and drive you nuts.  Especially when you have things going on in your game like non-linear acceleration.

Another tricky problem with delta_time is the accumulation of rounding errors.

Let’s look at what happens when we want to use delta_time to achieve an average speed of 6 pixels/step:

speed = ideal_speed * delta_time * room_speed * 0.000001;

speed = 6 * delta_time * 30 * 0.000001

Let’s say that delta time is always exactly the ideal delta_time, 33333 microseconds.  That would give us:

speed = 6 * 33333 * 30 * 0.000001

speed = 5.99994 //shit. um...

Close enough, right?  Well, it adds up over time.  And keep in mind, if delta_time varies from the ideal_delta_time, the error can be larger.

Can’t we just round it?

Well… no.  We can’t.  Because it’s entirely possible, and even likely, that you can have a legitimate fractional speed as a result of delta_time adjustments, especially in the event that your game is lagging frames!  And rounding the value in that case would actually result in even more error.

Well, so what? Can’t we just live with it?

Maybe? I’m not sure what else you can do, honestly.  But this does leave us with problems. Even in the simple demo project that I’ve created, after just a minute or so, I can observe my control object deviate out of sync with the various delta-based objects.  Even the different delta-based objects will fall out of sync with each other, due to tiny differences in the way they calculate their deltas.

Most distressing of all, I’ve seen the objects glitch at their reversal point, getting stuck in the edge of the screen.  This isn’t consistent, and seems to depend on fluctuations in delta_time at just the right time to adjust the instance far enough outside of the room that the Intersect Boundary event will be triggers on two successive steps, resulting in the instance oscillating, becoming stuck on the boundary.

I’m still looking for a solution for how to fix this issue.

Manual errata

The manual gives us the following incorrect example:

speed = spd * (ot - delta_time);

Where ot is the value of delta_time from one step ago, e.g. a “delta_time_previous”.

This is wrong. The manual is in error, this is not how delta_time works.  It seems whoever wrote the manual was under a mistaken impression that delta_time is basically a point-in-time value of System.DateTime(Now) that is updated every Step, and that you would then need to calculate the actual delta by subtracting the current value for Now by the value of Now from the previous step.

The way delta_time really works, it is the number of microseconds since the previous step, essentially it is already the result of the expression “ot - delta_time” used in the example.  The correct implementation for the example should be:

speed = spd * delta_time/ideal_delta_time;

Alarms and animations

If you want to use delta_time to smooth out your movement, you should also consider whether you need to also consider delta_time with other time-based variables, such as image_speed.

Sprite animation is controlled by image_speed, and is normally set to a value of 1 by default, resulting in the sprite cycling through its sub-images at a speed of 1 per step.

An instance’s image_speed can be adjusted to speed up or slow down the animation speed.  At speeds slower than 1, the same sub-image will be drawn for more than 1 step in a row.  At speeds higher than 1, the animation will skip over sub-images.  At speeds less than 0, the animation will cycle in reverse.

If you’re using delta_time, and want your animation speed to also be delta_time-based, then the best thing to do is set image_speed to 0, and control animation manually.  Each step, increment image_index by 1 * ideal_time/delta_time:

image_index += ideal_time/delta_time;

Sprites can be set up and used in too many different ways to achieve customized ends, so if you’re storing sub-images in a sprite resource and selecting them in some other way than cycling through them as an animation, this is not necessarily going to apply.

For Alarms, you’ll want to stop using the Alarm Events that are built into GameMaker, and implement your own timer system. This is simple to do.

Step Event:

if timer >= -1
{
    timer -= ideal_time/delta_time;
    if timer <= 0
    {
          //do stuff
    }
}

You can have as many timer variables as  you need, and name them however you want, store them in an array if you want, or another data structure if you want.

Once you get used to it, you’ll probably like this better than the built-in Alarm system. YellowAfterlife’s article on Custom GameMaker Alarms is a great read for more information.

Capping the delta

Delta_time is intended to smooth out minor variations in fps, but if you have a longer interruption, delta_time will break your game. It’s useful to understand why and how, so you can prevent problems.

You’ll need to cap the amount of delta that you want the game to react to.  For example, if your game loses application focus, it will stop processing, essentially pausing the action.  The timer that delta_time is based on still keeps track of time however. This means that when you return application focus to the game, so much time will have passed that the ratio between ideal_time and delta_time will be enormous.  If your game uses this enormous ratio to adjust your game speed, it will almost certainly break the game.

Say you have switched application focus for a second to respond to an instant message you receive in another app. The instant you return to the game, the delta_time between the next step and the step your game paused at is going to be several seconds, instead of a value close to 1/30th or 1/60th of a second.  This means that in that step, everything in the game is going to move the equivalent of several seconds worth of distance, missing collisions that would have happened during those “missing” seconds”, and skip several seconds worth of animation frames, and count down several seconds worth of alarms, in just one step.  Things will go haywire — unless you cap the ideal:delta ratio.

You’ll want to experiment with your game and see where this limit should be set. It should be a value that is well short of any game-breaking bugs that a too-large ratio would cause. The exact value will depend on the specifics of your game.

To implement the cap is simple, though. Revising our earlier dt_ratio expression, we just use clamp() to cap it:

dt_ratio = clamp(delta_time / ideal_delta_time, min_cap, max_cap); 

The value of max_cap is your maximum allowed delta_time/ideal_time; min_cap is your minimum allowed delta_time/ideal_time.

Controlling the tempo

Delta_time can be used for more than just smoothing out your frame rate.  You can use these same ideas in slightly different ways to “control time” — that is to create a slow motion effect, or to speed things up like a “fast forward” effect.  To do this, just add in an extra factor, which I’ll call tempo:

speed_this_step = ideal_speed * (delta_time / ideal time) * tempo;

  • If tempo is equal to 1, the game will run at normal speed.
  • If tempo is >1, the game will speed up, moving faster than normal.  You can do this within some limits, but if you speed up the game too much, you’ll start having to deal with “high speed collisions” — situations where an instance moves so far that it can skip over objects that it should have collided with — which will require more work to handle correctly.
  • If tempo <1, the game will slow down.
  • if tempo == 0, the game will freeze.
  • If tempo < 0, the game will run backwards! (Not perfectly, though; any use of randomization will cause a loss of determinism which means that things won’t run backwards exactly as they ran forwards, only in reverse — and negative tempo won’t cause events like Collision, Create, and Destroy to “undo” or run in reverse.  But for certain uses, especially if used briefly and sparingly, this may not matter.)

How cool is that!  You can do a lot of things with this.

You can have a global.tempo, for controlling the overall speed of your game, and an instance.tempo factor that is unique to each instance.  Change the value of global.tempo, and the entire game will speed up or slow down; change the value of instance.tempo for selected instances, and only that instance will be affected.

speed_this_step = ideal_speed * (delta_time / ideal time) * global.tempo * instance_tempo;

A good range for tempo, for most games, is probably anywhere from 0.10 to 2.0 or 3.0 or so. But it will depend a lot on the specifics of your project, so you’ll need to experiment and test.

You use tempo to create a pause system easily, by applying delta_time to objects that are used in the game, setting global.tempo to 0, and controlling the global.tempo using objects that are not bound by delta_time so that they will remain responsive when the rest of the game is paused.

You could also create a script that performs this function:

///delta(ideal_value, global.tempo, instance_tempo) 
///@description returns value_this_step computed from ideal_value based on delta time, global and instance tempo values.

return argument[0] * (delta_time / ideal_time) * argument[1] * argument[2]; // We assume here that ideal_time is defined elsewhere in the project, probably as a #macro, or is represented inline with the direct calculation here.

Then when you use this script, you avoid code duplication, and it will make the code more readable:

speed = delta(10, 1, 1);

Beware bogus approaches

There are a few common approaches to implementing delta_time-like solutions that you may run into if you look at other people’s code.  I’ll touch on them briefly here, in order to explain why they’re not ideal.

Changing room_speed.  In older versions of GameMaker, before Studio, the program could change the room_speed and the GameMaker engine would adjust its speed on the fly.  This was very easy to do, but wrong.  For example, if you set the room_speed to 0, or a negative number, that would break the game.  A room_speed of 0 would freeze the game, and make everything stop, even the runner, so that the game would never update again.  And negative room_speed values are not allowed.

Later on, GameMaker was updated so that the room_speed variable could be changed during runtime (so it wasn’t a read-only variable) but that changes did not take effect at runtime for the current room, meaning you could not change room_speed in the current room and see immediate results; only by leaving and returning to the room, or restarting the room would the new room_speed be in effect.  This effectively ended adjusting room_speed as a viable approach.

Programmers who have the idea of how to do a technique like delta_time, but haven’t heard of it before, will sometimes “re-invent the wheel”, usually by using fps_real and room_speed to create a ratio similar to delta_time/ideal time.  This approach can seem at first to work, but it is always off because fps_real is the actual, achieved fps for the previous frame.  For the current frame, however, fps_real could actually be a very different value from what it was one step ago, meaning that if your game just did a huge amount of work in the previous frame, say to initialize new instances that were just created, and it doesn’t need to do that work in the current frame, the calculations could be way off, giving a poor result.  As long as fps_real is not changing dramatically from one step to the next, and is reasonably close to the target fps for the game, it will appear to work well, but when fps is very inconsistent, which is when you really need it, it will not work well.

If you see these techniques in use in a project, it can be a pain to convert from the bogus delta time technique to the good technique.  You’ll need to meticulously review the code for the entire project and find every place that uses the bad technique, and refactor it to use the good technique. Depending on how well documented the code is, and how expressive the code style is, this can easily get out of hand.  The best thing to do is to use version control and create a branch, and work on the conversion in the branch, and just focus on converting the delta time system before you go about making any other changes.  Take notes and put comments in the code to keep track of your progress, remind you of things that you need to do, need to test, or need to figure out.

Demo

In writing this article, I created a demo project to help me understand the concept of delta_time, and test various approaches. You can download it for free and play with it yourself.

Summary

  • Delta_time is simply the number of microseconds that have elapsed since the previous step. This value can be used to smooth out unevenness in frame rate if the program drops below the ideal frame rate.
  • It’s easier to implement delta_time if you decide to use it from the very beginning.
  • The basic delta time expression is: 
    N * delta_time * room_speed * 0.000001
  • You can adjust the tempo of the game even more by using global and instance tempo variables, and multiplying by those as well:
    N * delta_time * room_speed * 0.000001 * global.tempo * tempo
  • You can create a simple pause system (in part) by setting the global.tempo (or a custom pause factor varable) to 0.
  • Remember to consider things like animation speed and timers as well as movement.
  • Avoid using the built-in Alarms Events, movement functions and speed variables; it’s easier to manage everything if you take complete control over the position, speed, etc. by using your own system.
  • Cap the amount that delta_time can adjust your game, to keep things from going out of control after a long pause between frames.
  • Delta_time will result in values that are slightly off the ideal target value due to decimal imprecision/rounding errors.
  • Test thoroughly!

A look back at GameMaker: Studio 1.x

YoYoGames released GameMaker Studio 1.4.9999 today, the last planned release for the 1.x branch. With GMS2 out for almost two yers, it’s time, right?

No. It’s really not.

When YYG released GameMaker Studio, they continued to support their old product, GameMaker 8, for about six years. Supporting a “professional” tool for only two years after a new version is released is not good enough. Businesses expect long-term support, plain and simple. No matter when they end-of-life GMS1, there will be complaints, but two years is far too soon.

Transitioning from GMS1 to GMS2 was supposed to be easy. Project conversion was a dream, it worked beautifully. Just import your GMS1 project into GMS2, and it would handle any obsolete code by generating conversion scripts, and for most projects, they worked without any further work needed. Import, compile, and it runs. Brilliant.

But the stability problems and project corruption problems that I’ve had with GMS2 make it too unreliable for everyday use. And for all the improvements introduced to the product, there are numerous usability issues with the new IDE, some minor, some major.

Looking back at GMS1.x, YoYoGames delivered a great, but not perfect, product, introduced many new features, and made the product worth the price hike. When I started using GM8, it cost just $20, later $35 for the full version, but there was a free edition also, which lacked certain features but was still useful for students and hobbyists. It was a no-brainer to pay for the full featured version, as cheap as it was.

GMS was much more expensive, starting at $200 for the basic Professional, but it delivered. YYG introduced some great new features. Building to HTML5, Mac OS X, Android, iOS, Linux, and other platforms. Box2D Physics, Shaders, language improvements, the Marketplace, and more. And they were delivered quickly. New major features arrived, regularly.

Then the PlayTech acquisition happened. YoYoGames CEO Sandy Duncan left. And I think that marked a major change in the way the product was managed and developed. Sandy Duncan had been talking about porting GameMaker to enable development on Linux as well as Mac OS X. With his departure, the Linux port was dropped. The Mac OS X port of GMS2 is currently in beta. The quality of the Windows version of GMS2 is sadly, still beta.

I’ve been using GameMaker since 2010, and it was exciting to see how quickly features and fixes were coming in 2012-15. Since then, it’s been slow, and what has been delivered has been plagued with problems.

I follow numerous communities around GameMaker, and from what I see, adoption of GMS2 is only about 50%, with most of the rest of users still on GMS1, and maybe a tiny number of users still using GM8.1, 8 years after it was released, and 2 years after YoYo officially dropped all support for it. In many forum posts, I see mostly complaints about project corruption, IDE crashes, and complaints about the user experience.

The peak years of the GMS1 era were optimistic, forward-looking, and fun. That feeling has, sadly, mostly gone. I still like working in GMS1, but knowing it will never be updated again, never be improved, and that all remaining issues with remain issues forever, is sad. Knowing that, in time, it will no longer support building to the latest versions the relevant platforms that gamers use, is sad. Knowing that the promised future represented by GMS2 arrived malformed and ridden with defects, and that YoYo hasn’t supported the product well at all since it was released, is sad.

I believed in YoYo, once, and I enjoyed using their product, making games, and fulfilling the dreams of my childhood. I’ll probably continue to use GameMaker for a while longer, and hope that the issues that prevent me from using GMS2 get resolved one day.

But I don’t have a lot of hope or optimism about it any longer, and I’ll be really surprised if someday they do fix the problems that have prevented me from adopting it. And that is perhaps the saddest of all.

GMS2 Grievances

GameMaker Studio 2 has been out for almost two years now. I have been using GameMaker since version 8.0, in 2010. I loved the direction YoYoGames took with the product when they introduced GameMaker: Studio, and had been an enthusiastic supporter of the tool, looking past its shortcomings.

When the 2.0 beta hit, I had some issues with it, but I wasn’t worried, because it was a beta. There were many long-standing shortcomings and limitations in old GM:S 1.x, and I was used to working around them as best I could. GMS2 represented a new beginning, a complete re-write of the IDE which was to have fixed many long-standing issues, and put YoYoGames into a position where they could deliver new features more rapidly due to a cleaner, more maintainable codebase.

GMS2 was supposed to be the cure for all that ailed me as a hobbyist wannabe indie game developer. Yet, I still generally prefer to work in GMS1.4, despite the many advances that have been introduced in GMS2.

Why?

Put simply, the improvements in GMS2 are eclipsed by some dire showstopping bugs, along with numerous minor gripes.

YoYoGames ended support for GMS1.4 earlier this year, and so its days as a useful tool are short. So, every so often, I try coming back to GMS2 to see if I can work with it. Each time, I’ve found another reason to stay away from it.

For a long time, I’ve been wanting to publish a list of these problems, in order to raise awareness in the hopes that YoYoGames would address the issues and make necessary improvements to their product. I still like GameMaker, and want to be a tool that I can rely on and continue to use. But it’s a lot of different issues, and to properly explain them requires screen captures and video capture that is time consuming to do, so writing this has been something that I’ve repeatedly put off. But, the more I put it off, the more new issues I discover. One would hope that it would be the opposite — that, over time, the issues would become fewer as they are resolved by the vendor.

YoYoGames takes MONTHS to respond to helpdesk inquiries, bug reports

I get that YoYoGames is a relatively small company, with a relatively large number of users. And I also get that a large proportion of those users may be students, non-programmers, or non-professionals who may tax the support department with questions that could have been better handled by reading the manual or going to the community forums. But that doesn’t make me feel any better about the fact that getting a response from the helpdesk when I submit a ticket can take, literally, months. Plural months.

When I have a problem that I can’s solve on my own, and need to submit a ticket with the YYG Helpdesk, the expectation should be that it will be responded to quickly. The exact definition of “quickly” might mean different things to different people, but it most definitely does not mean months, or even weeks.

A few years ago, I might get a response within a couple of days, which was still long enough to be painful. But since GMS2 has been released, it seems to take them several months to respond. I’m sorry, but there’s no way that can be acceptable for a professional user. And to my knowledge, there’s not a premium support option that’s reserved for corporate clients — maybe they do, but if so I have no knowledge of it. But even if that were the case, don’t solo developers deserve and require an acceptable level of support for the product? Of course they do.

Just today (8/8/18 as I’m writing this) I actually got a response to a Helpdesk ticket that I opened up more than a month ago, on 6/22/18, for the IDE crashes when Windows suspends issue that I describe elsewhere in this post. (That wasn’t the first time I’ve reported this issue, only the most recent. The first time would have been in November 2016, when GMS2 was still in its public beta phase.) The response (paraphrased): “Sorry it’s taken us so long to respond, but could you check to see if you’re still experiencing this issue? We’ve released an update since you reported this bug, and will need new log data using the latest version.”

I don’t know why YYG have fallen backwards in this area, but it’s definitely something that they need to improve on.

Other services that I use are able to reply to issues that I submit to them within 24, 48, or 72 hours; among them: itch.io, github, always reply to me quickly, professionally, and in a way that is helpful to resolving my problem. I don’t even pay anything to use itch.io, and they always have responded promptly, because itch understands that making customer support a top priority is paramount to successfully competing in this day and age.

GMS2 projects corrupt themselves when used with version control

To date, most of my experience with GMS2 hasn’t involved any projects that I’ve worked with in version control. I recently decided to start a new project, and wanted to try using GMS2 to make it. I’ve learned the value of version control, and in the last year especially I’ve taken to putting anything and everything that I work on into version control.

In my most recent attempt to work in GMS2, I used git. I created a new repository on github, and started working on my project. After a few hours, I had made several commits. At one point, my program started behaving strangely, so to try to troubleshoot the issue, I exited GMS2, relaunched, and tried to open the project again, only to find that it had become corrupted. No one else worked on this project, it was just me, making commit after commit on a single branch. And somehow GMS2 managed to make a mess of it.

I noticed the problem gradually — at some point, I had a bug in my code that I couldn’t figure out. An object I had placed in my test room wasn’t there. Or it wasn’t drawing. Or it was drawing where it shouldn’t be, somewhere outside of the viewport. I couldn’t figure out why — I only noticed that when I deleted the object and re-added it to my test room, it was offset a great distance from where I dropped it. Why, I couldn’t understand. After messing around with it for almost three hours, I decided to see if exiting GMS2 and restarting it would fix the problem. Instead, the project wouldn’t open.

Aha, corruption! Well, no problem, I’ve been using git after all, I’ll just roll back to the most recent commit, and start over. Losing a little work isn’t great, but sometimes it happens, and version control gives you assurance that you won’t have to throw out more than the most recent commit if something gets messed up. Well… not in this case. Apparently the project corruption was introduced very early into my git commit history, and rolling way back, I still couldn’t open the project. GMS2 gave an error message about a corrupt view. I dug around in the project files, and sure enough there’s a subdirectory called views within the project folder, with a bunch of xml files with weird file names made from long strings of random characters. I found the one that the error message said was corrupt, and tried deleting it, but even after getting rid of the offending view file, GMS2 still couldn’t open up the project. 

At this point, I gave up on the project, it was a total loss of about a day’s work for me. Very demoralizing. I returned to GMS1.4 to build the project there.

After posting about it on the Forums, I learned that this is a known issue that was submitted over 4 months ago, and is marked as a “High” priority bug. A potential solution recommended by the bug reporter involves engineering changes to the GMS2 project format, but doesn’t sound particularly difficult. But as the poster commented, “You cannot invite serious professional use of GMS 2 if it does not work with source control, period.”

I’ll be submitting a bug report on this issue, but again, the pace at which they respond to and resolve these problems means that it’s not going to be of any practical help.

[Update — Fixed]: GMS2 IDE crashes when I suspend Windows

This is another showstopper bug, but it apparently doesn’t affect everyone. Only certain combinations of hardware and operating system appear to be affected, and I’m one of the unlucky ones. I happen to be using Windows 7 Professional 64-bit Edition on a Lenovo ThinkPad P50. When I Sleep or Hibernate Windows, if GMS2 was running when I suspended the machine, it will have crashed upon resumption. At first, the program would report a bug, but now as of a few updates ago, it just crashes without any error message.

When I first reported this bug, GMS2 was still in its public beta phase. YYG responded that they were aware of the issue, but replicating it wasn’t easy for them. I learned that it affects certain hardware and OS combinations, and they couldn’t test for every combination. I can appreciate that, but I did send them application crash logs and would expect that they could use that information to determine what causes the crash, and handle it. YYG Support suggested that I try running any application, such as a game, that uses GPU acceleration, and see what happens when it suspends. I did so, and found that the game I tested survived a suspend-resume without crashing.

It’s really not acceptable that I should have to exit GMS2 whenever I decide that I need to close the lid on my laptop. Any time I forget to do this, and it’s very easy to forget, I risk losing work or a corrupted project. Professional tools need to be more reliable than this.

Update 10/10/2018: 

Almost TWO YEARS later, I finally have a solution to my long-standing problem of GMS2 crashes when I hibernate Windows! If you are having this problem, see here:

YYG Helpdesk issue 145712

TL;DR: Using the opengl driver resolved my issue.

“What I would suggest is trying the software (mesa) driver. It has far less to try and recover from as everything is CPU based. copy ther opengl32.dll from the “C:\Program Files\GameMaker Studio 2\mesa” folder into “C:\Program Files\GameMaker Studio 2″ folder. This may well give you more stable results.”

Only downside is that your IDE won’t have hardware accelerated graphics anymore, as it will use the CPU instead of the graphics card for rendering. This doesn’t seem to be a big deal so far. (edited)

Workspaces are a UX design fail

The GMS2 IDE consists of modular, dockable window components, and this much is good, and I like it. You can arrange and re-size the components as you see fit, which is how it should be.

The main working area within the IDE window is what GMS2 calls Workspaces. The idea of Workspaces was to allow the user to set up the IDE in a way that suits their workflow. I like the idea of Workspaces, but the way they work in practice is awful. Many users have complained on the forums, and it’s impossible to sum up everything that’s wrong with Workspaces succinctly.

GMS2’s IDE with a new project

Workspaces are just windows, when you get down to it. However, unlike windows in most other application, within the GMS2 Workspace pane, you have an infinite 2D space that can scroll four ways. Within this space are more windows, as many as you happen to open, which float in this space. These windows are your resource editors: object editors, sprite editors, image editors, room editors, whatever. Each one is opened, maximized, and spread out over the vast Workspace plane.

The result: a very space-inefficient design, with lots and lots of scrolling. Scrolling from one resource editor to another. Close an editor window, and it leaves a gap in the Workspace. If you close an Editor, and no other nearby editor is open within the viewpane area of the Workspace, you have no idea what direction you need to scroll in to find the next open editor. You can scroll in the wrong direction literally forever. There’s no purpose for this endless scrolling — it only serves to make Workspaces a pain to navigate, and I can see no excuse for it to work this way. Most windows, when you get to the end of its content, stop scrolling.

Some users have suggested adding a compass or mini-map to the workspace to aid in navigation when you’re scrolling about. But this is an absurd solution to a problem that shouldn’t exist. Rather than a infinite 2D scrolling region of virtual workspace with more windows floating about within it, a tabbed interface would be so much better. Rather than scrolling from editor to editor in a vast 2D space, simply click on the tab for that editor (or use Ctrl+Tab) to flip through the list of open tabs. Each tab could contain a single open resource Editor, maximized to fill the view pane, and thus give the user the most screen area to the task the user is focused on.

YYG have offered various workarounds, but most of them aren’t very good solutions to problems that should not be there in the first place. The Ctrl+T navigational shortcut can be learned, and it does make navigating about the project much speedier and less awkward than scrolling about a Workspace. But this doesn’t fix the awkward mouse navigation so much as replace it. Some users will prefer to use the mouse, for whatever reason, and they should get a better interface for mouse navigation.

I said I liked the idea of Workspaces, but not the implementation. So what’s the idea that I like? Well, I like the idea that the Project could store a view state of specific resources in the project that the user wants to open frequently. Say you have a large project, being worked on by a team, each team member specializing in some feature of the game. The artist may want a Workspace that opens up all the Sprite resources for all the different animations for each character in the game. One programmer might be working extensively on the Player objects, and needs a Workspace that opens the Object and Sprite editors for all the resources having to do with the Player. One programmer might want to configure a Workspace to organize assets needed for creating levels. Etc.

Rather than having to open up these resources manually, one at a time, every time the user opens the project, they could each define a re-useable, sharable Workspace, set up their Workspace(s) that they need (once), and close them when done working for the time being, and return to any Workspace as needed, and be back up and running with just the editors open that are needed for the task at hand. Each user could set up their own Workspace the way that works for them, and return to it whenever they need to do work on the feature that the Workspace was set up to facilitate. Workspaces could be shared across all users of a Project so that they can all benefit from this setup work. And users could ignore any of the previously set-up Workspaces and create a new one, or just open up resources and work on them one at a time, as normal.

Resource Editor Chain View

My complaints about GMS2 Workspaces are made worse by the desgin of the Object Editor. Depending on your monitor resolution, and how the other dockable window regions in the IDE are configured — the Workspace pane is often too small to show a full view of a resource editor. The Object Editor’s “chain view” expands horizontally as you go from the Object’s basic properties, to the Events, to the Code Editor.

When I’m working on the code for an Event in my Object, my focus is on this yellow rectangle. 100% of my focus, but only about 25% of the total area of the screen.

There is a solution, and it is simple enough: In the Preferences>Text Editors. Open [scripts|shaders|object events] in a full screen editor.

Chain view could be easier for non-programmers to understand, since the code window is directly linked to the Object Editor. But the layout wastes a lot of space, and creates a scrolling region (the Code Editor) within a scrolling region (the Workspace), which makes for awkward usability, particularly if the Code Editor overflows the Workspace pane, or if you need to scroll the Workspace horizontally to see whichever end of the Object Editor chain you need to look at.

What I want and need is for the editor I’m using to be maximized, to fill out the pane occupied by the Workspace entirely, or to fill the screen entirely. I don’t want resource editors that float about in an infinite 2D scrolling workspace.

There’s a workaround for this as well, which is to pop out the Workspace into its own window, so it can be maximized to fill the entire screen. But this means you lose the other UI components, which are now in another window beneath the Workspace window. You can flip back and forth between the two, and of course this is what you do. But at this point you’ve essentially abandoned the original concept and design of the GMS2 IDE window and workspaces.

GMS2 IDE UI theme doesn’t follow OS standards

For some reason, YYG loves making the IDE as dark as possible. I guess it’s partly due to their branding. Many programmers prefer to look at code with a dark background and light colored text, because this makes the syntax higlighting easiest to read for most people. I do as well.

And some graphic designers prefer their graphics editors to have a completely desaturated interface, so that their perception of color in the image isn’t influenced by nearby colors in the UI. I do, as well. 

GM8 and GMS1 were dark grey, with mostly green accent color. But GMS2 took this even further — too far, in my opinion, making the IDE mostly white on black, with almost no color anywhere.

But I like the window chrome to be not quite so black as YYG have designed their interface, and I like for toolbar icons to be less monochromatic. I find that color helps me recognize the icon I’m looking for. YYG’s UI icons are hard to read, and this slows me down, and makes it harder to enjoy working with the IDE.

This is a relatively minor gripe, and now is largely mitigated by the option of using a custom skin which someone developed that makes GMS2 conform to the default Windows theme colors, giving it a look almost like Microsoft VisualStudio.

However, since custom skins aren’t yet officially supported, any time you update GMS2, the update removes the previous version, and deletes the skin. Then you have to re-install it. And since skinning isn’t officially supported, there’s every possibility that the custom skin you installed today may not work with some future update.

All YYG need to do to make me happy here, is to support alternative skins officially, and allow users to customize their IDE with a skin that won’t break with an update, or need to be reinstalled after an update.

Better would be to offer an official skin that follows the OS desktop theme, and include that among the choices available to the user out of the box.

Better still would be to make this their default, but I just want the choice, and for the choice to be free of inconveniences.

More Issues

The Code Editor

I am a pretty fast typist — 80wpm or better, sometimes as fast as 110 wpm if I’m sharp and fresh. I don’t like to take my hands off the keyboard when I’m doing heavy typing, it ruins my speed.

Many, many years ago, I learned how to use the keyboard to navigate text documents: in nearly every text editor I’ve used, the arrow keys can be combined with Ctrl and Shift to select text rapidly and accurately, and if you’re good at it, you can do it faster than someone with a mouse can do the same thing.

Add to that the Home and End keys, and Page Up and Page Down, and I can grab a block of text, cut/copy it, and paste it where I decide it needed to go, blindingly fast.

Except in the code editor for GMS2. Here, the usual arrow key behavior isn’t quite the same as it is in nearly every other application I’ve ever used. For some inexplicable reason, when I hit the end of a line in GMS2 with my selection, it doesn’t wrap down to the next line if I hit the Right Arrow. It just stops at the end of the line. Why doesn’t it wrap? Instead I have to hit the Down Arrow, but this isn’t the same — instead of the cursor advancing one word, wrapping to the start of the next line, the cursor drops down a line, appearing in the middle of the line wherever the cursor happened to be.

The effect of this is that I can’t quickly or easily select text in the code editor. I select to the end of the line, stall; my mental focus interrupts while my brain processes what happened and I recognize why the text selection is stalled: GMS2 text editor doesn’t work like every other text editor I’ve used. I switch from Right Arrow to Down Arrow, and continue selecting my block of text. Now too much text is selected, and I have to back it up with the Left Arrow for a few keystrokes.

This probably sounds minor, but if you’re a heavy keyboard user doing a lot of cursor navigation with the keyboard, it’s very annoying.

If you’re going to go through all the effort to build your own IDE for a commercial software product intended for professionals, you really need to make the text editor part of the IDE good, and a big part of that is following conventions.

AutoSave is poorly designed

In GMS1, and previous versions, and in most other applications where you make changes to files, Save was a deliberate action. If you didn’t do it, the program didn’t do it for you. If you wanted to close the file without saving, the program would ask if you wanted to discard your changes made during the current session, or save them. This is a long-established convention and is the way the vast majority of software has worked for decades.

Of course, things can happen. Applications and computers crash. Power goes out unexpectedly. About 20 years ago, better programs started to introduce auto-save, which periodically saves any changes made to the file since the last deliberate save was initiated by the user. In the event of an unexpected exit, the autosave file was saved, as a separate file, and on next application launch the user would be alerted to the existence of these files, and have the opportunity to review them to see if they recovered anything that they would have wanted to keep.

This was a great feature. It absolved the user of having to remember to hit save every few seconds as a matter of habit, and relegated the task to the computer. It also didn’t overwrite anything that the user didn’t explicitly want overwritten.

The way GMS2 works is very different. Whatever state your open code file or editor is in, it’s saved. When you close a file, you’re not prompted to save any unsaved changes. Every time you make so much as a keystroke, your file is saved, whether you wanted it saved or not.

If you’ve made some experimental edits that you didn’t want to save, the only thing you can do is Undo, as much as you need to, until the file has been reverted back to the state that you wanted it — if you have enough levels of Undo to go through, and if you can recognize that file state when you get there. Or to pull an old version of the file out of your version control repository.

It’s ridiculous to have to Undo some large number of edits to get back to a prior state, when in the old paradigm, all you had to do is close the editor and say “No” when it asks if you want to save the changes. And it’s not always the case that you’re going to have a check-in for the file in version control.

Further reading

New Phoenix console by CollectorVision announced

This week a CollectorVision released a pre-release announcement for a new videogame console, called Phoenix.

CollectorVision Phoenix
CollectorVision Phoenix conceptual drawing courtesy of CollectorVision.com

Phoenix is a Field Programmable Gate Array-based clone of the 1982 ColecoVision videogame console, featuring old-school input ports for compatibility with authentic Coleco controllers, and HDMI-output for modern HDTV sets. It promises to be 100% compatible with the entire ColecoVision library, including newer homebrew games that have been released in recent years — even those that depend on the Super Game Module expansion by OpCode Games. The Phoenix will have the SGM circuitry built in to its FPGA. The console will have a cartridge slot for plugging real ColecoVision games into, as well as a SD card slot for loading ROMs. Curiously, it will also have input ports for SNES/SFC controller, and for PS/2 keyboards.

This is an exciting development for ColecoVision fans. The system is very similar in concept to the AVS, a FPGA-based NES clone that RetroUSB released in 2016, and the Super Nt, FPGA-based SNES clone by Analogue.

The announced price point is expected to be “around $200”, so right in the same ballpark as these upgraded clone systems. As an owner of the Super Nt and AVS, I’m very happy with both systems, and so am very excited about this news.  

The ColecoVision is underappreciated in the history of videogames, as it came out just before the Crash of ’83, and was knocked out of the market after only a few short years by the NES, but Coleco still has a following even today. The system had a solid library of games which featured better graphics and sound than the Atari 2600, its main competitor, and Mattel’s Intellivision, its closest technical rival. The games were not quite as sophisticated as the action/adventure style of games that the NES introduced, but there are many standout ports of classic early 80’s arcade titles for the system — including Donkey Kong, Zaxxon, BurgerTime, Gorf, Frenzy, Pepper II, and others.