csanyk.com

video games, programming, the internet, and stuff

Category: Uncategorized

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.

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.  Not every variable in your project need 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. 

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.

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, read it into a string variable, decode the json string to convert it back into a ds_map, validate the data in the ds_map, and, if valid, apply the configuration data:

//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);
}

[...]

//apply data stored in global.config to the variables in your project as needed, where and when appropriate.

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 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.

Next, if we’ve successfully read data out of our config file, we need to validate the configuration data that we read from the file. If the configuration data is invalid, depending on the setting and the value, the game will not work properly, and may crash or may perform unexpectedly or break.  Your program may have written the data incorrectly, or it might have a bug that results in a corrupted file, or the user may find the file and manually edit it, and introduce errors.  So check each value in the configuration ds_map, and verify that it is valid by checking to see if the value is of the correct data type (string, number, or boolean), and that it is within the range of acceptable values for that variable.  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 per-setting, 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. 

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

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 return true a step later 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.

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 synchronously.

The solution I used in the end was easy and simple: instead of checking which track was currently playing, and 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.

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.

Steam and Censorship

A recent announcement by Valve on Steam’s community blog has created a great deal of controversy.

I’m not entirely sure how I feel about this, but my inclination is that Valve is trying to do the right thing, in a situation where they cannot possibly please everyone, and prefer to be neutral and let the market sort this out, allowing gamers to play games they want to play, and developers develop games they want to develop.

I tend to agree with their stance and reasoning.  I haven’t thought about it a whole lot, and I haven’t looked into specifics of what problems have been going on within the Steam community that gave rise to this decision, so this is just a preliminary reaction.  But I like free expression, I don’t like censorship in any form.  I think people should use their discretion when it comes to what they say, and what they choose to experience as entertainment.  I want games to be as powerful a medium as film or literature, and I believe in their potential to be more powerful than either.

Obviously, there’s a lot of nuance to this — we don’t always get to choose our experiences.  Games can surprise and shock people. But I don’t believe that games should be simply light entertainment that never offends anyone.  Part of what makes art powerful is its ability to shock, offend, or even traumatize.  When an authority attempts to exercise control over ways in which it is permissible to shock, offend, and traumatize, you end up with art that is safe for the establishment and promotes the interests of the powerful, and serves to persist the status quo.  Whether that’s good or not, depends on whether your values align to that of the authority.

I believe in authority that defends the rights of individuals to speak out in ways that contradict the establishment, challenge it, and can force it to re-evaluate, change course, and reform as needed, as times and prevailing attitudes change.

Obviously, people can be and are sometimes hurt in the course of this.  This is something I think most of us try to avoid.  Even so, it happens — occasionally deliberately, but often not.  Perhaps some degree of mitigation of this is not bad.  But it is dangerous, and needs to be considered very carefully.  I’d rather allow the offensive, controversial content to exist, and surround it with robust discussion, than to prevent it from being published and distributed.

Adobe Flash EOL in 2020 – how will we preserve games?

Adobe announced today that it would cease development and support of Flash in 2020.

Of course, there were (and are) a lot of issues with Flash:

  • the proprietary nature of the Flash Player plugin;
  • memory and CPU usage;
  • stability problems;
  • security problems;
  • privacy concerns over Flash cookies;
  • Flash advertising/malware;
  • lack of accessibility in many Flash objects, resulting in issues for people with disabilities, screen readers, search engine indexing spiders, or for anyone who simply didn’t have the Flash Player installed, etc.;
  • and poorly programmed Flash objects.

So it’s not entirely a bad thing that Flash’s time is nearly at an end.

While this news doesn’t exactly come as a surprise to those who have been following the life of Flash since the iPhone launched, it does raise a serious question:

What will happen to all the games created in Flash when Flash is dropped from mainstream web browser support?

How will the history of games developed in Flash be preserved?

[Update 5/2/2018:] Here’s an article on one effort to preserve Flash games.

This is no small question. Over the 20+ years that Flash has been around, thousands of games have been built with it. Many of them are good games that still hold replay value. But without a viable platform with which to play them, will they wink out of existence and be forgotten?

I think the best approach to preserving Flash’s historical legacy would be to create a version of the Flash Player in Javascript or Web Assembly, and then any web site can use that to backfill support for any Flash objects that they wish to serve.

What are your favorite Flash games?

The Ongoing Sale

Since I announced yesterday that I’d finally earned my first $100 payout through the GameMaker Marketplace, I dropped my price on all paid assets to $0.99. I had another purchase today, so to celebrate that, I decided to adjust the terms of the sale.

The payday celebration sale will continue through 4/10/17 as planned.

For each paid purchase I get during the sale, I will extend the sale by one day.

Update, I had another sale today, 4/11/17, which will extend the discounts another day.

So as of right now, the sale on all my paid assets will last until 4/12/2017.

Get csanyk GameMaker assets on GameMaker Marketplace!

Galaxian is a triumph on the Atari 2600

As a child of the 1970’s, I’ve been attracted to arcade video games since I was tall enough to reach the controls. This was 1981-84, during the heyday of the arcade’s Golden Age, a time when games like Pac Man, Dig Dug, and Galaga were new, hot, and everywhere. Grocery stores, gas stations, seemingly anyplace people might spend time, you’d find a couple of arcade games, ready to suck the quarters out of anyone who passed by.

Just slightly older than these games were the ever-popular Space Invaders, and its evolutionary next step, Galaxian. Although these titles were top shelf games in their day, I found that I didn’t enjoy them very much.

Space Invaders was just frustratingly slow at first, but then sped up to an unfair pace by the end, and I could never manage to destroy that last invader on the first wave. You had to have perfect aim to hit it, and it moved so fast it was seemingly impossible to track, so you had to be lucky. If you missed, the slow-moving missile took forever to disappear at the top of the screen, and you couldn’t fire again until it did. Usually this delay meant your death, as the hyper-paced final invader would reach the ground, ending your game. Plus, it was black and white. It felt old. I respected it — even then I could tell that it was a important game — but grudgingly, I had to say that I just didn’t enjoy it that much, although I wouldn’t have admitted it to anyone back then.

Galaxian, too, was a game I found too slow and frustrating to play at arcades. It seemed like the next step in the vertical space shooter. Graphics were now in color. A formation of aliens marched back and forth across the screen, but this time instead of descending toward the earth, they stayed at the top of the screen, while one by one, or in pairs, individuals would peel off from their formation and dive bomb you. Their bullet patterns and flight paths seemed to make it all but certain that they would hit you if you didn’t hit them first. I could usually survive for a while, maybe clear a screen, but it never failed that if I happened to miss a dive bombing enemy, it would corner me in the side of the screen and crash into me, or hit me with too many bullets to dodge. You could always dodge one, but there’d always be another one following up, and your first dodge would put you right in its path. It seemed unfair, and so, not very fun. I always gravitated toward the games that I could last a bit longer on, so I could get my money’s worth out of my quarters.

I had a cousin who owned an Atari 5200, and played Galaxian on it once or twice while visiting them. The 5200 port was a very faithful reproduction of the arcade experience, not exactly arcade-perfect, but nearly so. I still didn’t care much for it, because it suffered from the same shortcomings. It wasn’t as bad to lose at home, since it cost nothing, but I still preferred to play games that felt fair.

It never entered into my mind that maybe I just wasn’t very good at Space Invaders or Galaxian. But probably, I was. Ok, not probably. I sucked. But in my defense, I was like 6, and just tall enough to reach the stick and see the screen. But back then, I blamed arcade games for being “greedy” in contrast to home consoles, which seemed to reward players with longer games that were still challenging, but more fun because they weren’t so brutally ass-kicking hard.

I never played Galaxian on the Atari 2600 back in the day. I’d played the 5200 version and was impressed with its arcade-quality graphics, and I remember seeing the pictures on the back of the box on the 2600 version, and being unimpressed. Since I never particularly enjoyed the game, I didn’t have any interest in owning it on the 2600, never knew any kids who had it in their collection, and so never played it. At some point, we had an Atari 7800, which had Galaga, the sequel to Galaxian, and one of my very favorite games, so I played a lot of that.

I’m not sure when exactly, but at some point I picked up a copy of the 2600 port of Galaxian, probably a few years ago. I recognized it was a significant title in videogame history, and so I wanted it for my collection, despite not having favorable memories of it from its heyday.

I finally got around to playing it today, and came away very impressed. Here’s a video review so you can see what it’s like:

The 2600 port plays much better than I remember the arcade. The motion is extremely fluid, which, considering the limitations of the Atari 2600 hardware, is nothing short of amazing. Maybe I’m just better at videogames than I was at ages 5-8, but I found that the game felt very fair, with divebombing enemies that are actually dodge-able. I’m sure, the horizontal aspect ratio of the screen plays into this somewhat, as you have more room to dodge, and also your shots that miss take less time to leave the screen, meaning that you can fire follow-up shots that much faster.

I was always a fan of vertical shooters of the Atari 2600, my favorites being Megamania, Phoenix, Threshold, and Tac-Scan, and Space Invaders. Galaxian is every bit as good as the best of these, and is still fun to play even now.

Playing Galaxian tonight, I found that my strategy was different from how I played the arcade original some 35 years ago. My old strategy was to try to shoot the enemies still in formation. They were easier to hit, since they didn’t swoop or shoot at you, and it seemed to me safer to eliminate them before they could turn into a threat. I’d try to shoot the divebombing aliens as they flew over me, and dodge out of the way of them and their shots, but mostly I concentrated on blowing away he ranks of Galaxians in formation, much as I approached Space Invaders.

My new strategy was much more successful, and rewarding: I ignored the galaxians in formation, since they don’t do anything that can hurt me, and focused on the divebombing aliens. It turns out, this has many advantages. First, by focusing on the divebombers, you are focusing on the only thing in the game that can threaten you. Shooting them is a much more reliable way to avoid them than dodging. You will need to dodge sometimes, but if you focus on developing skill in shooting the moving enemies, it gets pretty easy to pick them off before they can collide with you. The green Galaxians are simple, slow moving, and easy to hit. The purple ones are harder to hit, but with a little bit of practice the timing becomes easily mastered.

Hitting divebombing enemies in mid-flight makes you safer in two ways: enemies are destroyed before they’re low enough to collide with you, and they can’y get all their shots off. Typically, you’ll hit them as they cross ahead of you, and so you’ll be moving in the same direction, to track them, and the shots they do get off will fall harmlessly behind you, and by destroying the alien as it passes directly above you, you prevent it from getting ahead of you where it can drop bombs that would be dangerous to you.

Additionally, by hitting them as they’re diving toward you, your shot has less distance to travel, which means that you can get off more shots — since you can have only one shot on the screen at a time, when they hit something low on the screen, the shots don’t have as far to travel, meaning they hit the target sooner, meaning that your bullet is consumed and you can then fire another shot more quickly. If you miss one of the bombers, you might still end up hitting one of the galaxians still in formation, especially early in the stage, which isn’t so bad either. But the lower your shots are when they connect with an enemy, the faster you can shoot.

This in turn sets up a rapid flow of firing, hitting a dive bomber, then hitting the next dive bomber with a rapid follow-up shot. Once mastered, you can mow through the entire formation in quick succession in this manner. This turns out to be very enjoyable. You feel more skillful, since you’re targeting the fast-moving enemies, getting more points for them, and it looks more risky, since you’re often hitting the enemies pretty low on the screen, when it looks like they’re most dangerous — but at the same time you’re actually playing the least risky style of play. Of course, that’s what skill is — finding the right pattern of actions to minimize your risk, while doing what looks the most daring.

It’s clever, because the more intuitive way to avoid risk would be to try to avoid the dangerous enemies and attack the enemies that aren’t a threat. But counter-intuitively, when you focus on the dangerous enemies, and take the aggressive approach of destroying them rather than running from them, it minimizes the risk they pose to you, while the enemies that aren’t a threat remain a non-threat.

At this point, I recognized what a truly well-designed game Galaxian for the Atari 2600 is. I’m curious to see whether this strategy applies to arcade Galaxian. Since I don’t have ready access to an arcade with Galaxian in it, the next best thing is to watch a YouTube video of a skilled player.

And it looks like this is indeed the strategy to employ, although this player also has enough time to target plenty of enemies still in formation. I think the 2600 and arcade versions are different enough in their game play that they feel like different enough that while the basic strategies are more or less the same, the specifics are different. In the arcade, there’s much more space between the bottom of the screen, where you are, and the top of the screen, where the enemy formation is. But ultimately, I think the Atari port gives you less time to target the enemies in formation, forcing you to spend most of your time focusing on the swooping divebombing enemies.

In any case, Atari 2600 Galaxian is a fantastic game, and if you’re into vertical shooters is a must have, being one of the finest examples of the genre on the Atari, as well as an outstanding port of a historic and classic game.

GameMaker Asset: Rolling Average

In creating my last tutorial and demo, I needed to calculate the rolling average for the fps so I could measure performance differences between Instance Pooling and Create-Destroy.

It turned out that the functions for setting up a rolling average were pretty simple, yet were a pain to do well. So once I got them working, I decided to make them into an asset for GameMaker: Marketplace, so they’ll be easy to re-use in any project, with any series of numeric values, and so I can share them with the community.

Calculating a rolling average over a series of streaming values is now simplified by these new functions:

rolling_mean_create()
rolling_mean_destroy()
rolling_mean_add()
rolling_mean_read()
rolling_mean_size()
rolling_mean_resize()

Rolling Average on GameMaker Marketplace (free download)

Rolling Average on itch.io (free download) (free download)

Full documentation

Ludum Dare 37

Ludum Dare 37 is next weekend!

This is a milestone for Ludum Dare, as they are running this jam on their new website, ldjam.com. The old website had served admirably for many years, but lately the scale of the event has exceeded its capability, and the ad hoc customizations to the wordpress site were such that it was difficult to maintain the site. The new site will be a welcome renovation as well as a new foundation from which a better LD will be possible.

I am planning on using GameMaker Studio 1.4 one last time (probably) for LD37, because GMS2 is still in beta, and YYG have not yet released the HTML5 module, and I prefer to be able to create a HTML5 build of my project so that more people can play it. I’m looking forward to learning what the theme will be.

csanyk.com © 2016
%d bloggers like this: