csanyk.com

video games, programming, the internet, and stuff

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 finishing doing 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, 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.

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, or skip several seconds worth of animation frames, or 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 for the current room at runtime, 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 room_speed adjustments as a method.

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.

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.

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, 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 Editors.  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.  Etc.  Rather than having to open up these resources manually, one at a time, every time the user opens the project, they could use Workspaces to remember its state, set up the Workspace(s) that they need once, and return to them as needed. 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.  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.

I’m aware that many programmers prefer to type with light text on a dark background, because it’s easier on the eyes.  I do, as well. 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 this skin isn’t 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 may not work with the latest update. 

All YYG need to do to make me happy 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.  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.

Adventure (Atari, 1979) appreciated

Adventure is commonly regarded as one of the best games on the Atari 2600, and is certainly a top original title for the console. Out of all the games released for the system, this one stands out as being the one that best represents what was unique to the system.

A great introduction

It’s also a fantastic example of game design, with a built-in tutorial. Super Mario Bros has been recognized as having an excellent introductory level for teaching the fundamental concepts of the game, but Adventure did this just as well a good five+ years earlier, with game variation 1. Intended to be an easy difficulty version of the game, suitable for young children, it also works as a way to introduce the gameplay basics to new players of any age.

In Game 1, you start out in front of the Gold Castle, right in front of the gate.

This communicates to the player that this is your home base.  The castle is locked, but the Gold Key is conveniently right there on the screen.  Since the key and the castle are the same color, this communicates a strong clue that the key must unlock the castle. Since there’s an item in the starting room, and that item is usable in that very room, every basic element of the game is present on the first screen, so the player has the opportunity to learn the game immediately, before they start wandering and get lost.

If the player grabs the key and opens the castle, very likely they will enter inside, where they will find the Sword.  The player may drop the Key by pressing the button, but more likely will run to the Sword and pick it up, and in so doing discover that picking up one item drops an already-held item. Either way, the player learns an important aspect of the core mechanic of the game, carrying an item.

This rewards the player for exploring, and for solving a simple puzzle with one of the objects found in the Adventure world.

If the player doesn’t enter the castle, regardless of which direction they explore, they will run into one of the two dragons:  left, and they will encounter the Yellow dragon, and right, they will run into the Green dragon. 

Without the sword, either encounter forces the player to run away, or be eaten — unless the player is carrying the Gold Key, in which case the Yellow dragon will flee from him.

Whichever is the case, something unique and different happens — thus demonstrating to the player that the inventory of items found in the game each change the game in distinct ways.

This is enough to encourage the player to experiment with each item they find in the game, in order to discover all the possibilities. But some of the most interesting special item properties in the game are introduced right away.

If the player has the sword, what happens will depend on the difficulty switch position, and the orientation that the sword is held.

If the right difficulty switch is set to A, dragons will flee from the Sword.  If set to B, the dragons attack. 

If the player is positioned such that the sword is between him and the dragon, the outcome is almost certain victory for the player as the charging dragon runs straight into the sword and dies. Thus, the game teaches the player how to kill dragons in a basic, direct way.

Otherwise, the combat can get exciting, as the player must dodge and move to touch the dragon with the Sword. In other variations, roaming dragons can and will often randomly encounter the player, coming at him from any angle, and this is good practice for such situations.

Again, the game design subtly hints the player toward the more exciting combat — the Sword sprite is always positioned with the hilt to the left, blade to the right.  Despite the fact that the player can pick up the Sword (or any of the items) from any direction, most new players will instinctively grab the sword by the hilt-end, which will put the player in front of the sword when they encounter either dragon, making for a more challenging and more interesting combat.

If the right Difficulty switch is set to A, dragons flee from the Sword. Otherwise, they will directly charge the player. If the player is carrying the sword on the side the dragon approaches from, the combat is usually over quickly, as the dragon impales itself on the sword, and is slain.

But if the dragon flees, the player will have a much harder time slaying it — it will take a bit of luck for the player to enter the room positioned in such a way to have a chance at reaching the dragon with the Sword before it runs away. It’s very difficult to do this. One tactic that is effective is to walk near the edge of the screen, such that the Sword is actually off the edge of the screen, then wait for the dragon to approach near, and then attack.

If the player encounters the Green dragon, they will find the Black Key, which the dragon guards.  The dragon guards the key, which is positioned on the left side of the screen, so will always charge the player from the left when the player enters the room from the top of the screen.

If the player runs away, the Green dragon will not give chase, as it is programmed to guard the black key, and will stay on the same screen as the key.  This gives the player the ability to flee and return to the room repeatedly, and try several approaches to dealing with the dragon.

If the player grabs the Black key before running off, he will be pursued by the dragon.  

If the player encounters the Yellow dragon first, the dragon will chase the player from screen to screen, as the dragon does not have an item to guard. But if the player happens to be carrying the Gold Key, this will scare the Yellow dragon off.  If the player has entered the castle and grabbed the Sword, the Yellow dragon will approach the player at a slow, deliberate pace, and attempt to eat the Player.  If the player is grabbing the sword by its “hilt” side, the player will be to the left of the sword, and this will cause the dragon to trigger its bite attack before it runs into the sword and becomes slain. Thus, the player will learn a) how the dragon moves and attacks, b) that the dragon is temporarily invincible while it in its bite attack mode, but also temporarily fixed in place, and c) that the dragon is dispatched by the Sword by touching it.

If the player is grabbing the sword from its right side, he may slay the dragon directly, without triggering its attack; in this way the player discovers that the sword is lethal regardless of its orientation. Later, the player may discover that the sword is always lethal to dragons, even if it is not in the player’s hand! This is perhaps surprising, but it is highly useful knowledge once discovered, as the player may run around the sword while carrying another object, and lure a pursuing dragon to run into the sword, killing itself.

Once both dragons are dead, the game is easily winnable.  The player simply has to take the Black Key to the Black Castle, unlock it, retrieve the Chalice, and bring it back to the Gold Castle, and the game is over.

In order to do that, however, the player must first solve the blue labyrinth.  The labyrinth is illogical — it is comprised of 6 screens of interlocking passages which cannot be mapped onto a Euclidean plane.

When you try, certain pathways overlap others, creating a bizarre, confusing maze. The maze is actually fairly easy to traverse, but how the different screens connect to each other don’t quite make sense — space here is warped, somehow.

There are several pathways through the labyrinth, but only one will take you to the Black Castle. 

However, due to the placement of the Bridge, there’s a second possible way through the labyrinth. In the first room of the Blue Labyrinth, there are four branching paths: left is the true path through the Labyrinth; right is the secret Bridge shortcut, and the middle two paths loop around to connect to each other, returning the player to the start of the maze.

So, regardless of the direction chosen by the Player, they’ll either a) quickly loop back to the start of the labyrinth, where they can start over without a lot of frustration or risk of getting hopelessly lost, b) go left and make their way through the labyrinth to discover the Black Castle, or c) go right and discover the Bridge shortcut, and a shorter path through the Labyrinth to the Black Castle. 

This again shows good design, by demonstrating to the player a) how the Bridge functions, and b) a reward that shows how the Bridge can provide an advantage to the Player, thus demonstrating its value.  It’s likely that the player will inadvertently touch the Bridge as they pass over the wall, and thus discover that the Bridge may be picked up like any other object, and that its portability makes it even more useful.

When the Player discovers the Black Castle, they’ll probably know immediately what the Black Key is for, and if they don’t have it with them, will know from their experience in the first screen that they will need to go back to retrieve the Black Key in order to proceed. If the player has yet to encounter the black key, their previous experience with the Gold Castle will have taught them that this Castle must also have a Key that will open its gate, found somewhere.

Upon unlocking the Black Castle, the Player enters into a room where they discover the Magnet.  It’s common for players to drop the key upon entering the castle, perhaps in order to retreat and grab the Sword, which they may have also brought with them, just in case there is another dragon to fight — and if they do drop the key, they’ll immediately discover what the Magnet does: attract other objects.

The Player may pick up the Magnet and interact with it, dragging it around as it slowly attracts the key to follow it about the room.  This invites the Player to see what else the Magnet will attract. (It works on all the other items in the game, but not the dragons or the Bat.)

When the player proceeds to the last room of the Black Castle, they’ll find the Chalice.  From here, all they need to do is bring it back to the Gold Castle, and they win the game.  There’s nothing in the game to tell the player that they need to do this, but it is provided in the written instructions pamphlet that comes with the game.

Otherwise, the purpose and use of the Chalice is mysterious. The Chalice is unlike the other items in the game, in that its color flashes and shimmers. This makes the Chalice stand out as a special object, and probably more likely for the player to pick it up, even if they skipped reading the instructions and don’t know what to do with it.  Since it flashes a golden color, that may be enough of a clue to the player that they should bring it to the Gold Castle, as they did with the Gold Key.

Once the player knows what to do, they can complete Game 1 in a minute or less. Even without knowing what to do, it’s likely that a first time player can complete the quest in just a few minutes.

The tightness and self-teaching design of Game 1 of Adventure is nothing short of impressive. Considering how early this game came out in the life of the system, the level of refinement present in the level design is amazing.  As obvious and intuitive as the placement of the objects and dragons is, we must recognize that these were the result of deliberate design choices, and that any other arrangement would have made the introductory level of the game less inviting, less intuitive, and less fun.

Advanced Adventures

Game Variations 2 and 3 introduce the player to a larger world, with a third castle (White), and two Catacombs (in the Black Castle, and en route to the White Castle).  The White Castle itself adds another Maze, and in total the world has about doubled in size.

The Epic Quest

Game 2 is the canonical full Adventure experience. You have to visit every castle and use every item in order to complete the quest. This game introduces the Bat, which appears on the start screen, and swipes the Sword which appears where the Gold Key was in Game 1.

The timing here is tight enough that it must have been deliberate — try as you might, there’s no way to beat the Bat to the Sword. It will get there just barely ahead of you no matter how fast you can get there. 

Another thing about this introductory encounter: the Bat continues in a straight line, continuing to wrap from bottom to top of the screen in an endless cycle, which lasts until the Player either leaves the room, or touches the Bat or the Sword. 

Because the Player has learned the value of the Sword, very likely they will try to grab it and fight the Bat for control of it. The screen wrapping behavior of this initial encounter invites and practically guarantees that this will happen.  The Bat is programmed to win these contests, thwarting and frustrating the player.

This teaches the player everything they need to know about the Bat, immediately: the Bat steals the item you need.

Best case, you can grab the Bat, and carry it with the sword until the Bat either drops the sword, or picks up another item. If the player does manage to grab the Bat, capturing it, sometimes it can struggle free, often at the wrong time.

Going to the right, where in Game 1 you found the Green dragon guarding the Black Key, you’ll encounter the Catacombs that lead to the White Castle.  In the Catacombs, you’ll find the Yellow Key, the Bridge, and in the room South of the White Castle, the Magnet.  The Green Dragon is wandering nearby, and will likely encounter the Player in a situation where the Bat has dropped the Sword, and picked up one of the other items.

If you’re lucky, you may dispatch the Green Dragon in the catacombs without much trouble, but it’s just as likely that you’ll get stuck in the catacombs without the Sword, which is very dangerous — especially prior to learning how to navigate the catacombs.  If you can, kill the Green Dragon as quickly as possible, but if you lose the sword, try to grab the Gold Key and run for it so you can at least get the Gold Castle open.  The Green Dragon will always guard the Magnet or the Black Key, so you can use the Magnet to “trade” for the Gold Key so he’ll ignore you while you run to the Gold Castle and unlock it.

Here, the Player is carrying the Bat, who is carrying the Bridge, just after the Player killed the Green Dragon with the Sword. With so many objects on the screen, they flicker, so this is a composite image of several screen captures.

The White key is found in the Blue Labyrinth along the path to the Black Castle, and inside the White Castle is the Yellow Dragon, and the Black Key.  If you’re new to Game 2, you’ll probably head up the familiar path to the Black Castle, and discover the White Key here. 

You’ll need to run with the White Key to unlock the castle, then come back with the Sword so that you can face the Yellow Dragon and slay it.  If you can, once you open the Gold Castle, go back and grab the other items in the game and bring them to the Gold Castle.  The Bat does not enter the Gold Castle ordinarily (he will only be found there if you grab him and drag him there yourself) so anything you store in the Gold Castle is generally safe from the Bat randomly picking it up and moving it somewhere. 

If you can, put the Sword in the Gold castle for safekeeping, and then go unlock the White Castle, run back to retrieve the Sword, and return to the White Castle and slay the Yellow Dragon.  The White Castle’s maze is divided into two interlocking sections.  To get to where the Black Key is, you’ll need the Bridge.

To get the Black Key, you need the Bridge, and the insight that the maze is larger than it seems.
The Black Key is well-hidden inside the inner chamber of the White Castle maze.

Once you have the Black key, you’re ready to take on the final challenge.  Take the key to unlock the castle, then return to the White Castle and grab the Sword, and return to the Black castle. You’re about to face the Red Dragon, who is the fastest and fiercest of them all. He guards the Chalice in the catacombs of the Black Castle.  All you have to do is kill him and take the Chalice.  Fighting this dragon in the tight confines of the catacomb is tricky, but not too difficult.  Just keep the Sword between you and the Dragon.

Once the Dragon is defeated, there’s nothing left to threaten you; run back to the Gold Castle with the Chalice and win the game.

The way this variation is laid out guarantees the player will take the longest path through the game, and experience all of it.  It’s well designed from that standpoint. The Bat’s mischief can greatly lengthen the time taken to complete this quest.  It’s very common for the Bat to grab the item you need right when you are about to use it, and leave you with something you don’t need, or even bring a live Dragon to eat you! If you’re accustomed to the layout of Game 1, you’ll probably spend a lot of time exploring the Blue Labyrinth, where you’ll find nothing of value, only dead ends.  But by exploring the new catacombs area, you’ll quickly find most of the items in the game, and it’s just the chance interactions with the Bat, and the risk of being caught without the Sword when a Dragon draws near that can lengthen the game.

The randomness of the Bat makes Game 2 somewhat different each time you play, but the initial position of the items is always the same, and the order in which you must unlock the castles always is the same. So playing this variant repeatedly doesn’t offer a lot of replay value. Even so, the random element introduced by the Bat still gives this variation a decent amount of replayability.

The Random Remix

Game 3 randomizes the starting position of every item in the game. There are a few constraints, of course: no key can be locked in its own castle (although, there is a bug, by which the Gold key can sometimes start out locked in the Gold Castle, rendering the game unwinnable), the Chalice never can start in the Gold Castle, but otherwise everything is random.  It can happen that you start out getting attacked by all three Dragons immediately, with no Sword in sight to save you.  You’ll have to explore everywhere and anywhere to find the Chalice, and the items needed to get to it.

This is my favorite variation of the game. It’s the most replayable, because every time you play you’ll have to figure out where things are and which ones are needed in order to unlock the Gold Castle and retrieve the Chalice — the only two things in the game that you must do to win. Everything else is optional.  And due to that fact, it’s often possible to complete the quest more quickly than is possible in Game 2.

Screwing Around

Once the Dragons are killed, the Player is safe. This frees him to explore the game and experiment. The Bat can get annoying, but it’s fairly easy to grab it, run to one of the castles, and lock it inside.

It’s an interesting discovery that you can carry the Bat into a castle, run out quickly, locking the gate behind you, and never have to see the Bat again.  The insight may be learned by the fact that in Game 2, the Yellow Dragon never appears in the game until you unlock the White Castle.  Since that is the case, the Yellow Dragon must have been confined in the White Castle. Might this work with the Bat also?  It does!

It’s also possible to gain this insight by locking a Key in its own Castle.  It’s possible!  To do this, you need to touch the open castle gate with your Key, which causes the gate to lower.  If you drop the key in the doorway, as the gate lowers, the Key will disappear, apparently into the castle.  Now behind the locked gate, the key and anything else inside that castle is forever locked, inaccessible to the player evermore.

At this point, Adventure becomes a sandbox game. You can play around with the items and figure out all kinds of things to do with them. Mainly this means playing around with the Bridge and Magnet. The Bridge may be placed at various walls, and you can even try to use it to cross the boundary of a room that is normally blocked by a solid wall.  This sort of, almost works — you can see into an adjacent room this way, but not quite enter into it. 

Experimentation is at the heart of what makes Adventure special.

Eventually, through much trial and error, but more likely through reading about it or being shown by someone who knows, you may discover the Easter Egg, the hidden room with the Dot, which is used to access a secret room where the author’s name is hidden.

Items with purpose

One of the great aspects of Adventure is how purposeful every item and character in the game is. The items in the game give the player the capability to do anything they might need to do, and give the game’s design a sense of completeness.  There’s nothing missing, and nothing obvious to add. 

Keys unlock Castles, and there is one key per Castle. They give the player something to find and something to do in order to access parts of the map that are locked when the game begins. They give the Dragons something to guard (or flee):  The Yellow dragon runs from the Gold key; the Green dragon guards the Black key, and the Red dragon will guard the White key.

The Dragons exist to create danger and tension for the player, something to overcome and defeat. They make Adventure be a game about more than simply exploring.

The Bat exists to give the game randomness that makes the game world feel “alive” as the Bat randomly moves items around the world, which would otherwise only move if the Player moved them.  The Bat is a mischievous and frustrating enemy, who cannot be killed, but may be dealt with by locking it in a castle.  The Bat makes the Dragons more dangerous while they’re alive, since it can take the Sword or bring a Dragon at an inopportune time.  But the Bat’s randomness also means that it can sometimes aid the player, by taking a threatening Dragon away, or dropping a needed item that the player had trouble finding. This redeems the frustrating aspect of the Bat, to a degree, and makes it an entertaining character.

The Sword gives the player a way to defeat the dragons.

The Magnet gives the player a way to grab items that are stuck in walls, or otherwise inaccessible, making it much less likely that the player will get stuck in an unwinnable situation due to a trapped object that they cannot reach.

The Bridge serves a similar purpose to the Magnet, in that the Bridge can enable to Player to get around dead Dragons that may block narrow paths. But the Bridge also has several specific purposes:  A) To enable a short-cut to the Black Castle by Bridging over the dead-end of the right branch of the Blue Labyrinth; B) access the inner chamber of the White Castle maze, necessary to complete the quest in Game 2; C) to reach the hidden room in the Black Castle labyrinth, where the Dot is hidden, necessary to unlock the now-legendary easter egg and find the secret screen with the creator credits. 

The Chalice gives the player a goal, and something to do to give the game an ending.  The existence of the Chalice makes the game about more than merely exploring, more than merely slaying dragons.  It gives the player a quest and a purpose.

Speculating on a Sequel

Adventure has been a frequent target of homage for homebrew and hacks and indie game developers. I don’t know how many projects I’ve seen over the years that took direct inspriation from Adventure, but I can recall a Quake mod from 2002, and unofficial sequels for the Atari 5200 and Atari Flashback system, a pair of homebrews called Evil Magician Returns and Evil Magician Returns 2, and certainly others too obscure for me to find with a quick search.

I’ve played some of them, and of those that I have played, I have found them to be lacking in some way — they just don’t feel as good as the original, for various reasons. Either they offer more of the same, without offering enough new, or they attempt to update the graphics in ways that spoil the utter simplicity of the original graphics.  The graphics weren’t really the point of the original — the Player is represented by a simple square pixel, after all — and so I would like to see a sequel that focuses on gameplay, but retains the graphical style and overall feel of the original, but adds new items and new areas to explore.

Making it my own

I think anyone who loved the original has probably thought about what they’d want in a sequel. So in that spirit, here’s my proposal for how I would extend the original game.  Perhaps I’ll try to program it at some point.

My idea is more like a “Game 4” variation of the original than it is an Adventure II. A “Game 5” variation would be a randomized version of  the game with all of the elements from Game 4, much as Game 3 is a randomized version of Game 2.  

Here’s what I would add:

  • There are three empty rooms in the area (Marked 1, 2, 3 in the map below) where the White Castle is found:Adventure MapThese feel like unfinished, purposeless rooms in Adventure. This is where I would extend the world map. I would replace these empty rooms with entrances to new mazes that lead the player to new areas of the game. Perhaps I’d have all three entrances lead to three inter-twined mazes, which require the use of the bridge to go between them.  The Brown Key would be hidden somewhere in this new maze.  The exact details of the maze aren’t shown, but the maze would occupy the empty region shown in the map detail below, with the new Brown Castle somewhere in there, perhaps where indicated… but possibly not.Adventure-Variation 4 Detail
  • I’d add at least one new castle, but probably just one, found at the other end of one of the mazes. The existing castles are White, Black, and Gold, this castle would be some new color.  Which color?  It should be a color that is possible with the Atari 2600, and not already in use as a Castle or Dragon color, or a color that is close to one of those colors. This rules out Green and Red, Yellow, Black, and White. Probably a good color for a fourth castle would be Blue, or Brown.
  • I’d add a new Dragon. The existing Dragons are Red, Yellow, Green. The new dragon should be a color that is possible with the Atari 2600, and not already in use as a background or Dragon color.  This rules out:  Black, White, Gold, Yellow, Green, Red, and Blue.  I’d also avoid Purple, since that’s the color of the Bridge.
  • The trick with the colors is that the Atari 2600 can only produce 128 distinct colors in NTSC, as shown by this chart. While the RGB color space isn’t exactly gamut compatible with what the Atari 2600’s TIA chip generated, this is close enough for our purposes.
    Atari 2600 NTSC paletteThere are only 16 hues to choose from, and we don’t want to pick something too close to what’s already in use. This may not be exact, but my best guess as to which colors are already reserved in Adventure is as follows:
    There’s a lot of possible colors still available, but many of them are too light or don’t contrast well enough. But a purple, green, aqua, or brown would seem to be the best candidates.  Brown seems like a good choice for a Castle, or Blue, while an aqua or orange shade seems like the best choice for a Dragon.
  • Spider Spider (New Character).  The spider’s purpose is to create Webs. Like the Bat, the Spider is black. The Spider cannot be killed. Can he be picked up and carried? I haven’t decided — probably not, just to make him different from the Bat. The Spider lurks in the Brown Castle, spinning webs inside, making the catacombs inside the Brown Castle more challenging to get through. When the Brown Castle is unlocked, the Spider is set free, and can roam about the rest of the world.
  • Web WebWebs are obstacles which slow the player down, but do not block him.  Webs will stick fast to any Object in the game, so that they cannot be moved, will not be attracted by the Magnet.  When the Player is holding the Sword, he can cut through the Webs, so moves at normal speed. Cutting the web destroys it, freeing up any trapped objects so that they can once again be picked up and carried, or moved by the magnet.  Dragons ignore Webs, and are not impeded by them.  The Bat can pick up a web and move it to another part of the world.  The Bridge can be used to navigate over webs without being slowed down.
  • TorchNew item: The Torch.  The Torch serves to light up catacombs areas, making them easier to see in when present.  It can also be used to destroy Webs, by touching them.  The Torch will destroy Webs whether or not the Player is holding it, and the Torch will light up a catacomb maze whether or not the Player is holding it.  The Bat may pick up the Torch. The Torch is found in one of the new maze areas in the game.  This maze area is very dark, and has the shortest catacomb sight radius yet, when the Torch isn’t present.

Anyhow, this idea isn’t quite fully formed, particularly in terms of the map. But as a general sketch of a concept for an extended “variation 4” game, I think it’s got potential. I think the Torch and Spider give the game new features that have purpose, without wrecking the balance of the existing items.

Who knows if I’ll develop it — it’d definitely be a challenge to build.

Pixel Art Chess Set: Communicating function through design

My five year old nephew started learning to play Chess recently, as I discovered on a visit a few weeks ago.  We played two games, and I didn’t have too much trouble beating him, but for a five year old he’s not bad. He knows all the pieces and their basic moves and their relative value.

I thought it would be fun to build a video Chess game that he could use to help learn strategy and how to see the board. So this is my latest project. I’ll be posting more about that as I work on it.

My first step was to design graphic resources. I didn’t want to spend too much time on it, just a basic “programmer art” chess set, that I could use to build the program with. Of course, it didn’t end up that way, and I’ve gone down the rabbit hole designing variations on sets of minimalist pixel art chess men. It’s too fun and fascinating not to.

My first attempt was actually rather good, I thought. I went for 16x16px representations of the classic chess pieces. I drew them very quickly, but was very pleased with my results, particularly the Knight.

I could have stopped right there, but it was so fun to make this set that I wanted to continue exploring and see if I could refine my pixeling technique further.

I decided to search the net for images of chess pieces to see what variety there was, and found a lot of examples of beautiful sets. I started to take notes and to infer design rules for chess men:

  1. Chess pieces are called “chess men” which seems antiquated and sexist, especially given that the most powerful piece in the game is the Queen.
  2. The modern standard chessmen are a design named for English chess master Howard Staunton, and have been in use only since the mid-19th century. A strength of its design is that each piece is easily distinguished from the others, making errors from mistakes in identifying a piece — a problem with other sets — unlikely. Previously, chess men of different types had a less distinct appearance from one another, and were not as standardized.
  3. In a Staunton set, the Knights are the most detailed, ornate, varied, and realistically represented pieces. 
  4. In Staunton sets, there is a standard height order: pawn, rook, knight, bishop, queen, king. (This surprised me, since Rooks are more valued in Chess I would have expected them to be taller than Bishops.)
  5. The pieces are differentiated by their tops. Each type of piece has a distinct, unambiguous shape.
  6. The body/base of the pieces have a common design, to create unity among the pieces in the set.

I tried to apply design choices to my chess set following these insights.

A follower on Twitter offered feedback that the pieces should be different heights, so I tried that. With a 16×16 pixel tile size, I could only shorten the back row pieces by 1-3 pixels.  I also tweaked the King piece by adding a few more pixels to its top, to make it a bit more distinct from the Queen, and moved the Pawn so that it wold be more centered in its square.

I do like the result:

Staunton pixel chessmen

I think my initial 16×16 Staunton set look like they’re in ALL CAPS, while this set is more “readable” by using “mixed case” heights for the pieces.

I wanted my chess game to be focused on usability and instruction. I needed each piece to be immediately recognizable, and not to convey a bunch of extraneous information to the player that has nothing to do with play mechanics. 

My next attempt was a different take altogether. I wanted the look of each piece to suggest its rules for movement. I also thought that it would be clever if the pieces communicated the rules for using them through their visual design.

I ended up being very pleased with this set as well, although I went through many more variations, particularly with the Pawn. This one also came together easily and rapidly.  When your tile size is 16×16 and you’re working in just a few colors, it’s easy to work fast.

Things I like about this set:

  1. The shape of the piece is a built-in tutorial for how the piece moves.
  2. The Pawns still have a pawn-like shape (at least the black pawns; white pawns are “upside down”).
  3. The Knight’s shape may be read as an abstraction of the horse’s head shape of the Staunton piece.

I think out of these variations, my favorites are: P9, Kn2, B3, R1, K?  I’m least certain which King I like.  I think K4 and K5 are my top two, but I also liked the idea of incorporating a crown motif into the design, to signify the King’s special property of being the King.  K1, K2 and K6 were attempts at this, but I think K1 looks too much like a Staunton Rook, unfortunately.

I wasn’t sure which of my designs to use for my final set, so  I posted my sets on Twitter and a pixel art community on Facebook. @Managore responded to my request for feedback by coming up with a set of his own design, which I quite like.

His design was retweeted and liked over 500 times, and received many positive compliments from his followers, many of whom are game developers. One of my favorite indie developers, @TerryCavanaugh, who made VVVVVV and Don’t Look Back, pointed out an physical chess set that had been designed a few years ago which incorporated the same ideas.

It’s exciting to see my idea get picked up and reworked by fellow game developers who are inspired by the concepts I am exploring. So fun! Getting that validation that what I’m working on is interesting to others is very motivating. But it’s particularly good to get some attention from developers whose work I’ve admired for years, however modest.

I’m excited about this project and look forward to working on the program. I have more design ideas that I’m looking forward to getting into soon.

Life is funny

Life is really funny.

For most of my time, I haven’t thought much about refrigerators, or had any choice in which refrigerator I had.

Growing up, there was The Fridge. It was yellow. It had food in it. It made stuff cold.

I went to college, I had a tiny dorm refrigerator that, I guess, worked OK. I never had any problems with it that I’m aware of.

I rented apartments, they came with appliances, they worked, I neer had any problems.

They were never anything fancy. Just an insulated box with a compressor and a light inside that goes off when you close the door. No ice maker, no water dispenser. No fancy finish, just some boring neutral color.

I bought a house, and it came with appliances, and the worked. I didn’t have extra money to drop on something better if what I had was fine. The refrigerator that came with the house was made in the 1980s, and was about 30 years old this year. It worked very well. I never did anything to maintain it, it never broke. It just worked non-stop for 30 years, the way an American made major appliance should be expected to. I’ve enjoyed about half of that time, if enjoyed is a word you can use with owning a boring kitchen appliance that does nothing except for work for three decades without complaint.

The only problem with it was that the light socket didn’t make good contact with the bulb, so when the door opened, it would flicker, and for the last however many years, most of the time the light wouldn’t come on at all. I fiddled with it, but it didn’t help.

Then one day my mom sells her house and is giving away stuff, and I claimed the baesment refrigerator. It was nice, slightly bigger, and only twelve years old. A Maytag. They’re dependable. I rented a truck, and my cousins helped me move it to my place, and then I gave my old, still working refrigerator to one of them.

Only, the Maytag had its door hinge on the wrong side. But that wasn’t a problem, that’s reversible. Easy to do with a screwdriver and the manual, which my mom kept in a ziplock bag in a manila folder, along with the warranty info, long since expired, and the original receipt.

So we switched the door, so it opens to the side that is convenient for accessing food when I’m cooking, which happens sometimes. And the light works. And it’s slightly bigger. And a decade newer. I figured I was set for another 20 years at least.  Who knows?

I noticed in the first couple of days that the “new” refrigerator was taking a long time to get down to temperature.  I think it took about 2 days, maybe it was 3.  But it did eventually get cold. 

Then it got really cold. The refrigerator was down around 33F, and then the next day I opened it and found that a bottle of water had frozen, shattering fragments of glass all over the place.  I cleaned it up and adjusted the temperature setting, and it warmed up a degree or two, still staying around freezing.  The thermometer I kept in there said 31F, but that’s below freezing, and nothing else in there was frozen, so I think it’s not quite accurate.  I love drinking ice cold water, so I was happy.

One thing the new refrigerator didn’t have was a tray for storing ice cube trays. This was annoying, since having a place to put the trays so they could work without spilling was a big convenience, and meant that you could use the rest of the space in the freezer more efficiently. I searched online for parts, and found out that pretty much everything for the Maytag wasn’t available any more — discontinued, out of stock. What’s more, I couldn’t even find a rack or shelf or tray for storing the ice cube tray. I tried eBay, there wasn’t much, and it was confusing to confirm that a part was for my model. It was annoying. I found a bin for finished ice cubes, but nothing to hold the trays while they were working. 

I don’t use the freezer nearly as much, so it wasn’t until maybe a week or more that I noticed the frost problem. I went to get an ice cube and noticed that frost had accumulate along the top edge of the door. I surmised that the door seal wasn’t sealing completely, allowing some air in, bringing with it moisture that would condense and freeze, turning into frost.  The ice built up and made the seal worse.  I’d open the door, knock off all the ice, wipe down with a towel, and close the door again, pressing firmly. 

It didn’t work.  I kept the ice at bay, but it kept returning. From 12 years of being on the left hinge, the door seal had compressed, and now that the hinge was on the right side, that left a gap that closing it firmly just couldn’t close.

I also noticed that the refrigerator made a high pitched whine, loud enough to be annoying. In reading the manual, I found out that this was normal. I didn’t like it. I thought about buying a new refrigerator at that point. But I didn’t want to spend the money right now, so I figured maybe next year. I’d take my time and do research and wait for a good sale.

This week, the temperature in the refrigerator compartment went north of 40F.  I worked at a grocery store once, so I knew that this was the threshold for safe food storage. I was concerned.  I tried turning the temperature setting back down, but a day or two later, it was still 40°, maybe 41°.  Then 42°.  Then 43°.

I took a look inside the freezer, it was still holding steady at 0°F, a good strong temperature. I cleaned the frost off the door, and looking more closely, noticed more frost along the ceiling. I cleaned that off too.  There was more frost along the back wall. I noticed that there was an air vent on the back wall, and that it was covered with ice.  Oh.

I looked inside the refrigerator. There were a couple of holes in the ceiling, which I felt no air flowing through.  I tried putting my finger into the holes to see if I could feel ice, but I couldn’t.  I only felt the foam insulation.  It felt warm.

I took my hair dryer and tried to defrost the freezer compartment.  I succeeded in melting the ice I could see, but if there was ice in the duct connecting the freezer compartment to the refrigerator compartment, I don’t think I got it.

The temperature in the refrigerator went up to 47°. Nothing in there was safe to eat any more. It had turned into a botulism farm. The freezer compartment temperature went up to 11°F, but it went back down to 0° by the next morning.  The temperature in the refrigerator went up to 49°.

I started shopping. After a lifetime of not caring or thinking about refrigerators, suddenly I had to make a choice, and suddenly now everything mattered.

I measured the nook in the kitchen and noted the dimensions the new unit would need to fit. I researched styles, features, manufacturers, models. I went to six stores and looked at them in person.  I considered shelving. Ice makers. Water filtration. Top Freezer. Bottom Freezer. Side By Side.  French Door. I compared warranties.  I read reviews.  I checked prices.  I made a spreadsheet.  I opened tabs by the dozen in my browser. I read reviews. 

I questioned the reviews.  What did some random refrigerator owner know?  Did they have the same concerns as me?  Do they understand engineering and manufacturing? Have they tried all the other models out there and therefore know that theirs is really the best? Was their specific experience representative of all examples of that model, or did they get a lemon? Were they even humans writing real reviews, or were they fake reviews written by shills trying to sway public opinion to buy the wrong refrigerator? The more I read, the less I knew. The more uncertain I became.

Within 72 hours, I’d saturated my mind with research and reached the limits of my patience for indecision.  I needed to dispose of my botulism farm and put this episode behind me so that life could resume. I told myself that I didn’t need to make the perfect or even the best decision, I just needed to make an adequate decision. I reminded myself that for 43 years, any old refrigerator was just fine. Why should this purchase be such a conundrum?

Based on the in-person impression I’d gotten from store visits, my internet research, and my meticulous note keeping, I had decided that I liked one model in particular more than the others I’d looked at.  I wasn’t sure that it was the best for me, it wasn’t vastly superior in every way. But I liked the size, the shelves, the price. The reviews were very positive, but one or two of them mentioned that the freezer compartment didn’t get down to 0°F like it should at the recommended setting. Some reviewers recommended turning it up to max cooling, others said it wasn’t a good model because of this deficiency, and to look for something else. 

Concerned, I thought about it overnight. I shopped some more, and found a merchant that was running a sale, and it was the cheapest price I had found yet for this model, and several hundred less than most of the other models I’d considered. I added to cart and got the complete price for it, and printed it out.

I reasoned that I could go to the store in person and ask questions about returns, and if I could do a return after delivery, and if I liked the answer I got, I’d go ahead and buy it, try it out for a time, and if it didn’t get cold enough for me, I’d return it and pick some other model.

This saga is far from over.  Delivery will take place on Wednesday.  I’ll have to observe the temperatures over several days to see how it performs. I’ll have to decide what to do.  I hope I won’t have to return it and start over. I hope I won’t have to think about it again for a decade at least, and three would be better.

It’s just weird that something that never mattered for my entire life so far should become such a dilemma when a situation arises where I have to make the decision. Even though it’s only a couple hundred bucks, it’s a decision with potentially decades of repercussions.  So much responsibility!

Sometimes life is better when you don’t have so much control, and don’t have to make choices.

The Debt We All Owe to Emulation

Emulation is a broad topic within computer science. This article is specifically about emulation of video games.  There are many other purposes to which emulation may be applied as well, and it’s important not to lose sight of that.  Emulation is a general purpose tool, not merely a tool for piracy.

Old video games have become valuable to collectors in recent years. My generation grew up with video games, and much as the previous generation valued comic books and baseball cards from their youth to the point where they became worth serious money in the 1980s and 1990s, antique videogames have similarly grown in value.

It wasn’t always thus. For a good couple of decades, old videogames were considered obsolete junk. No one wanted them (except maybe a few very geeky people such as myself.) Mostly when a new system hit the market, people forgot about the old generation and within a year or two they weren’t available in the retail channel anymore, or were perhaps on clearance in dollar bins.

Importantly, the manufacturers didn’t continue to manufacture old generation hardware.  Although it became cheaper and cheaper to do so, there still wasn’t enough demand in old systems to keep them viable in the face of new competition. More to the point, manufacturers would have been competing against themselves.  And when trying to recoup the cost of major R&D budgets that produced that next generation, they wanted (and needed) the market to be focused exclusively on that new system. Keeping the old generation system alive would have cannibalized sales, and hurt profitability, and this would have stalled the progress of innovation.

We saw this with Atari. The 2600 was the system that broke through into nearly half of American households in the late 70’s and early 80’s. At the time, it wasn’t obvious to the general public that there was going to be a new generation every several years as Moore’s Law continued to work its magic to enable cheaper, more powerful computing technology.  Internally, Atari struggled with releasing their next generation system, the 5200. With tens of millions of 2600 consoles already in homes, the revenue stream represented by cartridge sales for the established console was too important for Atari to walk away from it. The 5200 wasn’t backward compatible (although an adapter for 2600 games existed) and Atari felt that the average consumer might feel alienated and abandoned if they had to go out and buy a new, expensive console.  As a result, Atari kept the 2600 alive an incredible 15 years, finally stopping production in 1992.  The 5200, launched in 1982, was hampered by a variety of factors, and never had the same level of success — it was expensive, lacked backwards-compatibility, the library was mostly the same titles as were available on the 2600, only with better graphics, the controllers were delicate analog joysticks that annoyingly didn’t automatically re-center, it contended in the market with rivals Coleco and Mattel, and then the 1983 crash of the North American market cut short its heyday.

The business data was always very clear on this. With video games, what was hot today was gone a few weeks or months later, or in the case of smash hits, maybe a year. New product constantly distracted and replaced old product, with a few notable exceptions such as Pac Man and Donkey Kong, most video games didn’t have staying power in the market.

Obviously, that’s not to say that old games started sucking and were no longer fun to play. They didn’t. But their enduring appeal didn’t translate into sustainable marketability.  And that’s why successful games spawn franchises of endless sequels and a multiverse of linked-IP titles. And the old constantly gave way to the new. And the business always wanted the market to be focused on the new, because that’s where sales were.  (But yet, in other market segments, they keep making chess sets, decks of cards, balls, copies of popular board games that have been enjoyed for generations, such as Monopoly, etc.) For some reason, the prevailing wisdom was you couldn’t sell a videogame that everyone had already bought.

Well, until recently. A little over a decade ago, Nintendo introduced the Virtual Console on Wii, and started selling us games that they had made in the 1980s and 1990s.  And we bought them. In many cases, we bought them again. For some, it may have been the first time.

Even that wasn’t a completely new thing.  Every console has had classic games ported to it.  Atari has continually re-packaged its greatest hits into collections that have been sold on just about every console and platform that has been released since the original system exited the market. Virtually every big game developer has done it as well: Activision, Sega, SNK, Midway, Namco, and on and on.

And what made that possible?

Emulation.

Without emulation, putting an old game on a new system would have meant porting it, essentially re-writing the game from scratch. And ports were never capable of being entirely faithful to the original. There’s always differences, often substantial, to the point that the nostalgic value of a port is never quite there.  It’s not like playing the original.  You can never go home again.

But with emulation,  you could. Emulators were magic. With an emulator, a new machine could be made to work nearly exactly like some older machine with a completely different architecture, and run software for that older machine without further modification, and the results would be virtually indistinguishable from that software running on original hardware.  

The old systems may burn  out and break down.  The factory could stop making them and shift production to other, more profitable, more in demand product lines. But as long as someone could write an emulator to work on modern machines, old games could live, in theory forever.

Game companies, mostly, did not want that. Especially if there wasn’t some way to make money from it. And once full retail priced sales for a game, or generation of games, stopped being feasible, game companies dropped the product line entirely. Their expectation as the buying public would follow on to the next new thing, and that’s where the industry wanted all focus.  

So game emulation, in its earliest incarnation, was an unauthorized, underground enterprise, a labor of love by gamers desperate to keep the games they loved from disappearing entirely, as they surely would have without their efforts.

And what good is an emulator without something to run on it? This is where ROM dumps come into play. Anyone can tell you that emulation isn’t illegal, doesn’t violate any copyright or patent or trademark law. But ROMs, those are a different story. Copyright law is clear enough about making unauthorized copies of copyrighted works for distribution and especially for profit. There are limited provisions for making copies of works for personal use, of a copyrighted work which you own a copy of, for archival/backup purposes, for academic purposes, for criticism and review purposes, for time shifting and platform shifting, and so on.

Archival/backup purposes fit the context of ROM dumping best, but even so, technically this is a personal use right, meaning that in theory (to my knowledge this has not been tested in the courts) a person could legally dump the ROM of a game that they personally own, for use as a backup, and use an emulator for platform shifting that work onto a new platform.  But that’s a personal copy — they still don’t have any right to distribute that.  And even if my copy of Super Mario Bros. 2 is exactly the same as the copy that someone else already dumped for their own personal use, I can’t (legally) take a shortcut and make a copy of their dump; I have to produce my own.  Which takes time, effort, equipment, expertise, and the vast majority of people do not have that, nor do they have the inclination. So people did the only reasonable thing there was to do: they shared copies of existing ROM dumps. And yes, this meant that many people obtained copies of ROMs that they didn’t own an original copy of. And this was copyright violation.

And yet, for a long time, there still wasn’t enough value in emulation for the rightful intellectual property rights holder to have incentive to do anything about this situation.  And so, as a result, the Abadonware movement began, and the underground emulation scene grew and grew and grew.

You can go to a bookstore today and buy a new copy of a book written hundreds of years ago.  At least, certain ones.  You can’t go to a retail store and buy a new copy of a video game produced 40 years ago.  Not most of them. Sure, today there’s now a few exceptions, if you want to count systems like the Atari Flashback or NES Classic.

But — these systems only cover a small fraction of the catalog of titles that were released for those systems.

And — those systems are only possible because of emulation.  They’re dedicated emulation boxes. That’s right.

For $60, you can buy a tiny selection of really great games, and through the magic of emulation, play them on a modern HDTV. Much of the work that made that possible was pioneered, for free, by enthusiasts and hobbyists who made it their mission to preserve the past and ensure that some game that they loved would be available forever.  For free.

And more than just preserving the popular hits of yesterday, the emulation scene also provided equal attention to games that virtually no one had played, and even fewer people care about, or even knew about.  Rare games that hadn’t performed well on retail release, but were nonetheless good games, have gotten a second wind and rebirth, in large part because someone in the emulation scene ripped a copy of it, and distributed it for free so that thousands of people could experience it.  Games like Little Samson, a NES rarity that sells for thousands of dollars for an authentic copy, could not be experienced by the vast majority of people, without a ROM dump and an emulator.  And probably the black market distribution of this ROM is what helped make people aware of it, to create the demand that gave rise to the premium price that the original now commands.

Companies like Nintendo didn’t want you to play their old games, at one time, for a long time.  But now that the emulation scene proved that those games did have lasting appeal and historic value, now Nintendo would like to sell you those games again. And because they can, they seek to destroy the underground movement that showed it was viable and created the technology that made it possible.

I find this incredibly sad, aggravating, and tragic. I may have a personal collection of physical cartridges in my gaming library, but I certainly couldn’t replace them at today’s prices if they were lost.  And that hardware’s not going to last forever.

Copyright used to have a limited term, and this would have made things a lot easier for the emulation movement to happen in a completely legal way. But over the years, large companies have continually altered intellectual property laws — always to their benefit, never for the public good — to secure a perpetual right to works, robbing the public domain of a rich future. 

Robbing the public.

Robbing all of  us.

csanyk.com © 2016
%d bloggers like this: