AtariBox, RetroN 77 teasers 

In the past few days, I’ve become aware of chatter about two potentially exciting new bits of hardware for Atari 2600 fans: Atari’s AtariBox, and Hyperkin’s RetroN 77.

Atari (well, the company who now owns Atari’s trademarks) has scant information about the AtariBox. Beyond the name, we know basically nothing about it so far.

RetroN 77 is a new console from Hyperkin, which is designed to play real Atari 2600 carts, apparently through emulation via the excellent open source Stella emulator, with real controllers, using the same ports as the original, so compatible with 3rd party Atari controllers, and outputting 1080p over HDMI.

Since I know nothing about the AtariBox yet, my early excitement is for the RetroN 77, but that could easily change. Hopefully Hyperkin will do the venerable VCS justice for the HDTV Age.

My hope for the AtariBox is that it will be a retro-inspired platform that caters to indie developers who want to make games in an old school style, that look like they could have been at home in the late 70’s/early80’s, albeit not strictly constrained by the hardware limits of that time. Think what Shovel Knight was to the NES; I’d love it if AtariBox were a platform for the equivalent of such games for the Atari 2600/5200/7800/400/800/Intellivision/Colecovision era of home videogames.

YoYoGames: GameMaker Studio 1.4 sunset annonced for 2018

Today, YoYoGames announced that GameMakerStudio 1.4 support will sunset in 2018.

Over the next 14 months, until 31 July 2018, we will continue to mend major issues and support platform updates for Studio 1.4. After the 14-month period, Studio 1.4 will still function normally however, we cannot guarantee it will remain compatible with every platform’s future updates.

While this day has been expected to come since the release of the 2.0 beta back in November 2016, this is quite a bit sooner than expected. YoYoGames support for the 8.x version of GameMaker continued for years after GameMakerStudio 1.0 was released, only ceasing very recently.

It’s not entirely bad for the company to focus itself on development and support for the latest version of their product, but it’s unfortunate for users who for whatever reason are not able to move to the new version so quickly. This also makes it all the more important that GMS2 be as good as it can be. Hopefully, by focusing on the latest version exclusively, this will enable YYG to develop it even faster, adding new features, fixing bugs, and addressing UX issues with the brand new IDE.

SMW persistent jailbreak hack the best of all time?

I think in terms of impressiveness, this amazing glitch exploit that allows you to permanently reprogram mods into the save data of a Super Mario World cartridge using only in-game input is right up there, neck and neck with the Apollo Moonshot missions.

I can’t even fathom how they figured this out, it’s beyond anything anyone could reasonably come up with. Impressive doesn’t begin to describe it.

 

E.T. was not the worst game of all time.

I’ve talked about this before, but today NPR covered it again.

This is a well known story in the lore of videogame history… There’s a certain amount of misconception about it.

Howard Scott Warshaw likes to talk about how E.T. has the reputation of being the worst game ever, and how between it and the highly regarded Yar’s Revenge, it gives him the greatest range of any game developer. But even he doesn’t think E.T was really the worst of all time. As he carefully states, E.T. is “the game that is widely held to be the worst video game of all time.” That’s a bit distanced from accepting that it is the worst.

It makes for a good story, and he likes to tell the story, and he’s a good storyteller, and he likes to set the record straight when he tells the story, because telling the story takes away the power of the failure to hurt him. He’s a really good sport about it, and a good guy, and was a good game developer when that’s what he was doing. He has a great attitude about failure, and it’s served him well in life. So more power to him.

Howard Scott Warshaw’s game was actually pretty good. I owned E.T. and liked it. It was ambitious, and it definitely had its share of flaws, but it was a much more complicated game than the arcade style action games that Atari was known for, and that was a problem for a lot of gamers who weren’t ready for a deeper game design and complex puzzle solving. The game was difficult, and solving the puzzles was a bit arcane, and the pits that you fall into frequently were rather annoying, but it was not the “worst game of all time” that it has been labeled as.

What it was, it was a huge commercial failure — mainly because Atari overpaid Steven Spielberg $26 million for the license rights to make an exclusive ET videogame. It was one of the better selling games for the Atari, moving 1.5 million units. Unfortunately, Atari had produced 5 million copies, vastly overestimating the market. And reviews of the game were mostly bad, in spite of the high sales. The sales came through more through name recognition and the success of the film, but once people played the game, many of them felt like it wasn’t good enough. And it was rushed. But it’s a very impressive achievement to create something as big and complex as E.T. with the tools that Warshaw had at the time, in as little time as he was given.

Atari were counting on ET to drive more console sales, and it didn’t happen. By 1983, the VCS was a 7 year old dinosaur, and badly needed a replacement. But Atari had a hard time leading the launch of the next generation of hardware, because doing so would have obsoleted their market-dominating 2600 model. They tried with the 5200, but it had several design problems, and this combined with lack of backward compatibility (they did release an adapter later) and expense made it unpopular.

At the time, there wasn’t really a precedent for the idea of computer equipment becoming obsolete in just a few years time, and so many consumers of the day felt like buying a new console every few years, particularly if their old games wouldn’t play on it, was a ripoff. They viewed electronics like a radio or television or record player, which could last for decades if cared for, and newer models could continue to play old media. And old game consoles may still work four decades on, but they are obviously obsolete and can’t play newer games, and newer machines don’t play old Atari games (other than through emulation.)

Meanwhile, Atari corporate had alienated some of their best developers, by refusing to credit them for their work on the cover of the box, or pay royalties, They left to found Activision, which opened the door to any third party releasing games for the 2600, including many fly by night operators who could barely program for the 2600, who put out horrid garbage games that glutted store shelves and gave the Atari a poorer reputation than it deserved, and resulted in the Great Crash.

It’s popular to blame ET for being the cause of the great crash of ’83, but it wasn’t.

 

LD38 results for TARJECTORIES

I think this may have been my best showing to date. I’ve ranked higher in individual categories before (Bad Puppy: #70 in Humor, Alamogordo: #71 in Humor) but I think this is the best that I’ve ranked in Overall and in Fun, which are perhaps the two most important categories. I’m very happy with how the game was received by the LDJam community this time around.

Thanks to everyone who played TARJECTORIES!

ld38 results

 

Great Plays from Ludum Dare 38

Planet Desumaton – siegfriedcroes

Planet Desumation

The gif speaks for itself… Control a small small planet, picking up Asteroids into orbit, and smash them into a large “boss” planet.

Path of the Rabbit – Managore

Path of the Rabbit

A turn based tile strategy game similar to Pipe Dreams. Managore’s games are always top notch, and this is no exception.

Sticky Keys – thevaber

Sticky Keys

A really well polished typing game, with a twist. The keys keep popping off, due to some nasty creepy crawly insects that have infested the keyboard. You have to interrupt yourself and pop the key caps back on in order to keep typing.

Monolith – samlo and david-carney

A rail shooter bullet hell game where you have to lock on to your target by holding still, leaving you vulnerable to enemy fire. It’s high speed and frenetic. The art style is b/w, with what looks to be a procedurally generated fractal landscape, and a monolith that looms over the horizon, and seems to never get any closer.

TARJECTORIES – csanyk

Tarjectories by csanyk for LD48-38: A Small World

Yes that’s right! My own game, this time I think is good enough to qualify as a recommended play. It’s a casual target shooting game played on tiny planetoids that rotate, with procedurally generated levels for added replayability. Patience and accuracy are the keys to doing well. Learn to estimate the gravity and rotation speed of the planet so you can aim your shots correctly. I plan to develop this one a bit further, so stay tuned.

Antivirus – kappaixAntivirus

A nicely designed 2D top down shooter, reminiscent of classics like Gauntlet, 2D Wolfenstein, Berzerk, and Frenzy. When you die you get a fake BSOD game over screen, which adds to the fun. Battle through an area and the size scale changes, making for an interesting and novel transition mechanic.

Plutus – jason-varnell, nathan-hicks, and Apostate Games

Plutus

Hilariously written backstory makes this charming katamari-like feel special. Control the jealous planet (let’s not quibble) Pluto on a quest for revenge and ever greater mass.

Space Mailman – kepons

Space Mailman

Gorgeous but bare-bones wireframe graphics and hard core difficulty make this game tough to play. Deliver mail between planets to make money.

Flight of Claude – lyxil and colm-eccles

Flight of Claude

A beautiful, touching visual story about a baby bird and his nest mates.

Aphosis – urban-logic-games

Aphosis

Divert a doomsday rock on a collision course with Earth by attaching thrusters to stabilize its spin, then attaching a main thruster to push it away. Beautiful graphics, a fantastic musical backing, and extremely challenging game play make this one to try.

That Tiny Pea – thendash

That Tiny Pea

A fairly realistic update of the classic Lunar Lander. Land safely and you are rewarded by being able to step outside and take in the view. It’s hard!

The Life Amoebic – baby-dino-herd

The Life Amoebic

A convincing simulation of an amoeba. Control your amoeba by extending pseudopods with the mouse, and try to grab food to survive, grow, and divide. It’s pretty challenging.

Vixa – spav

Vixa

Spin the world around to dump balls into the green-lit sections and away from the red-lit sections. Green multiplies your balls, red destroys them. Lose all your balls and you’re done. Great graphics and sound, and solid game play make this one a trip to play.

Tiny World Defense – ianmorrison

Tiny World Defense

Fly your spaceship over the surface of the planet, defending it from enemies who want to shrink the planet into nothingness. There were a number of other entries in LD38 with a similar look and feel, a 3D orb-based shooter, where your shots skim over the surface of the planet. Almost like it were a newly-invented genre or something. But out of them all I think this one is probably my favorite of them.

Super Kaiju Dunk City – radmars, emarcotte, steakzzz, ninjavitis

Super Kaiju Dunk City

This is an amazing entry in the Jam category. Super polished, it’s a cross between an infinite runner and a rhythm game, where you control a basketball-dribbling Godzilla-like Kaiju creature, as you relentlessly smash through level after level of targets. I had a blast playing this, and would love to see it as a full-fledged title. There’s not much more to ask for, except maybe an epic boss battle against another Kaiju or super robot, and some kind of breath attack.


That’s all for now… I still have a lot more games left to play. As I find more “great plays” I’ll be adding them here. If you have played something that you think deserves a larger audience, post a comment below.

Until next time!

Other People’s Code

A GameMaker user recently posted an interesting question in one of the communities that I watch:

So, I’ve known for a long time now how helpful it is to go through source code you haven’t written, just to pick up good habits, and generally understand how things work.

I got the source code for several games including Home and Ink from a Humble Bundle deal a while ago, and am just starting to take a look at them now. I’m finding it really difficult to get a grasp of what’s going on/which objects and scripts relate to what though – mainly because I’m having to switch between several windows of code.

Does anyone have tips about how to learn to understand GM projects? I usually have no problem understanding singular sections of code, it’s more getting to grips with how everything fits together, especially in full-length games. And generally, any tips about how you work through other people’s code.

This happened to be a very timely question, as I’ve recently been going through this myself.

I find it very enjoyable to code my own projects from scratch. I know what I’m trying to do, and I know why everything I put into the project is there. Especially when the project is something I’ve recently worked on.

It’s quite a different thing for me to try to look at a project that someone else has coded. I don’t know what the author was trying to do, or why they did anything they way they did it. Oftentimes the code is not well organized, and very frequently the code is done in a style very different from how I code, or the programmer’s approach is very different from my own, or they use math that I don’t understand well without explaining what they’re doing or why or how it works, and so on. This can make it very difficult to get anywhere.

It’s of course vitally important to be able to work with code that other people have developed unless you have no aspirations to be anything more than a solo coder for your entire life. But even if you never work with other people collaboratively, it can be very valuable to look at other people’s code and learn from it.

If the code is well-documented, this shouldn’t be too hard. I like to say it’s the original author’s  responsibility to ensure that the code they write is easy to understand.  But well-documented code is unfortunately rare. Documentation (ideally) tells you what you need to know in order to understand the code. How does the author know what you need to know to understand their code? No project can afford to be a 101-level tutorial for new programmers. People will come to the project code with all levels of knowledge and from many different backgrounds, and you can’t anticipate everyone’s needs. Nor should you have to — it should be expected that someone reading your code comes prepared. Working code is rarely intended to be a textbook example for neophytes. Most often, the programmer, if they document their code at all, documents it for themselves, and doesn’t care about anyone else’s needs if they should ever read the code.

So it’s quite understandable, it’s still all too common for code to not be well documented, or just not documented in a way that is useful to you.

Getting into big project that you didn’t author can be overwhelming.

What to do:

  1. Before doing anything else, make sure the project builds and runs.

    Play it for a while, and try to catch any runtime errors that may already be in the code. Don’t make any changes to the project until you’re satisfied that it is working. But recognize that there may still be bugs that are hidden more deeply than your playtesting was able to reveal. These may not be the fault of the programmer, either; it’s always possible that some update in GameMaker caused a bug.

    It can be really frustrating to open an (unknown to you) already-broken project and make changes to it, then try to build it and find that it’s broken. The assumption will be that it’s your changes that broke the project, but if the bug was already there before hand, you’ll waste a lot of time focusing on your changes, not where the problem really is. So to avoid that, test the project first before you do anything else to it.

    While  you’re running the project, observe it and take note of any objects that seem important.  Guess at what these might be called in the project, and look for them when you start exploring the project in the IDE.

  2. Start with the first Room in the project.

    Open it, and see what’s in there. In GameMaker, the project always starts with the first room in the resource tree. Start taking notes about what you find in this room. What objects are present in the room editor, or being created in code? These should be the first objects to examine.

  3. Look at how resource groups are used.

    The project may use folders to group things together, especially if it’s a large project. If the author used folders to organize their projects, this will give you some insight as to how the author thought about the project and its parts, and how they relate to each other.

  4. Look for parent objects and see how they are organized.

    The inheritance structure of objects will reveal a lot about how the game works. The game may have a lot of objects, but if the author organized them effectively, it’s likely that many of them are related to each other through inheritance, so you may have a comparatively smaller number of object families that you’ll need to familiarize yourself with, and understanding the family broadly will convey much of what is needed to be understood to understand the project as a whole.

  5. Look for dead code and other resources that aren’t used.

    It’s very common for developers to leave stuff in a project that never gets used at runtime. This is the “cutting room floor” of the project; it represents stuff the developer worked on for a little bit, but for whatever reason never finished and didn’t end up using. Sometimes there can be a lot of it. Identifying the dead code can be helpful because then you can ignore it, and focus on the live code.  Once you’re sure the code isn’t used by the project, you may want to move it to a folder of dead code where it is out of the way and can be ignored, or just delete it from the project entirely.

    There isn’t really an easy to way to identify dead code.  But a few things to look for are code that is commented out, scripts that are never called anywhere in the project (use GMS’s “search in scripts” feature to find everywhere a script is called in the project.) Objects that are not present in any of the rooms, and are not referenced in code anywhere. Logical conditions that can never be satisfied can lead to dead code branches in if or switch statements, also, but these are a little harder to spot.

  6. Look at scripts.

    Scripts (often) support objects. Scripts are also (usually) well isolated and self-contained, so as to be reusable. Depending on the project’s size and the programming style, scripts may call other scripts.  This can become difficult to follow if you  have to jump between a bunch of different codefiles, but at least on your first pass this shouldn’t matter as much — just recognize that a script call is abstracting some detail, and you don’t necessarily need to get into the detail yet.

  7. Look at objects.

    First, scan the resource tree for objects that have sprites that you recognized from playing the game. Those are probably a good place to start.

    Look at the player object(s), then enemies, and other things like terrain objects, weapons, pickups, or whatever. There may be some important objects that are invisible during gameplay and don’t have sprites. Look at the name for a clue about what the object is for.

    As you get into each object in detail, probably the most important Events to understand are the Create, Step, Collision, and Draw events. Start there if the object has these Events defined, and take note of any other events it may use, and what it is doing in them.

    You may find GML code, or you may find Drag-and-Drop actions, or a little of both.

    As you start looking through the code, it’s going to be very tempting to make small changes, perhaps to conform to your ideas about code style and good practices. But try to resist the temptation to do too much of this at first. Even seemingly simple fixes can have consequences that you don’t realize. And you might find after “cleaning up” a bunch of code that it’s not needed at all, and can just be discarded.

    The only thing you should really do on your very first pass through the code is leave comments. I like to prefix my comments with my initials, and what the comment is about: Question, reminder to do something later, explanation, bug, possible bug, etc. This helps me as I go through the whole project and find answers to the questions I initially had when I first started digging into the project. And my initials help me to keep straight whether the comment is mine or the original author’s.

  8. Take notes.

    As you review the project code, add comments with your notes, explaining where needed. Comments can be questions, eg “What’s this for?” or notes for things to do later (“This looks interesting, come back later and understand this fully.”
    You can (and should) also take notes outside of the project. It depends a bit on the purpose — are you just looking at this project to learn from it, or are you working on the project to maintain or modify it? If you’re conducting a learning exercise, the notes should be the takeaway of what you learned by exploring the project files. If you’re actively working with the project, then the notes can be a guide to accumulate the understanding that you gained as you explored the project, a list of questions you still have, problems you intend to work on, bugs that need to be fixed, or other work to be done.

  9. Focus on the interesting parts.

    (The stuff you don’t yet know, but are interested to know/figure out.) Don’t worry about stuff you don’t understand, but aren’t interested in. Don’t worry about the stuff that’s simple/obvious to you.

  10. Don’t assume perfection.

    The programmer knew what they were doing. Well, maybe. Programmers make mistakes. Or do experiments. Or half-formed thoughts.  Or just don’t know a better way to do something.

    Code often has bugs. Code is usually sub-optimal.

    As you take ownership of the project, you will need to start being the decision maker who knows what they’re doing.  It’s easiest and best to carry forward with a good understanding of the previous author’s thinking, but it’s almost never available to us directly, and we have to infer it from what we do have.

    If you’re new to programming and lack experience and are looking at advanced, complex code in a big project, it’s hard to do this.  But start with small changes, test constantly, and build confidence as you learn and grow familiar.

  11. Ask questions.

    Ask questions about the stuff you can’t figure out. Contact the author directly if you can, be respectful and appreciative if they’re open to talking about it, and understand if they’re not interested. If they’re not responsive, or you still have questions, take them to the GMC Forums. Lots of people are there who will take an interest and try to help. Find a friend who is willing and able to mentor you, or even work with you on the project.

GameMaker tutorial: high speed collisions

If you have a small object, such as a bullet, collisions can be problematic for GameMaker if the bullet’s speed is faster than the length of the bullet. Any time an object moves faster than the size of its collision mask, it is possible for the object to skip over object in its way that it should have collided with.

The illustration below shows why:

high speed collision skipping

Here’s a simple, elegant solution for your high speed object to avoid this problem, regardless of its top speed.

Make the bullet sprite’s length as long as the bullet’s speed. If your bullet moves 16px per step, then its sprite should be 16px long.

If the bullet’s speed is variable, then the thing to do is vary the length of the bullet as the speed of the bullet varies. You can use this using the image_xscale property to scale the bullet.

Say the base bullet speed is 16px. If the bullet can somehow accelerate to 32px per step, then it should lengthen to 32px, by setting the image_xscale to 2. We can see from this that a general expression that solves the problem for any sprite width and speed would be:

image_xscale = speed/sprite_width

But it’s probably a good idea to use image_xscale = max(1, speed/sprite_width), to keep the bullet from shrinking if it is moving slowly.

A nice thing about this effect is that it makes high speed bullets look like elongated streaks, very similar to a blurry action photo where the subject of a photo is moving too fast for the shutter speed. In effect, that’s exactly what’s happening in GameMaker, if we consider the game speed to be like the shutter speed of a camera. So this creates a very natural looking visual effect, and solves a problem with high speed collision skipping.

This technique may be applicable to other objects besides bullets, but it works best with smaller objects because the stretching isn’t as noticeable. As the instance is moving at a high speed while being stretched, it can trick the eye into thinking it’s just a motion blur effect. With larger objects, this illusion is not as convincing, and the apparent distortion is more obvious.

Pinpointing the point of impact

Let’s say you need to know the exact point of impact from your high speed bullet. Since the bullet is stretched out, the x, y coordinates are no longer approximate enough.

high speed bullet point of impact

We an use point_direction to find the angle at which the impact occurred.

point_of_impact = point_direction(other.x, other.y, bullet.x, bullet.y);

If the target object is a circle, then calculating the point of impact is simple from whatever angle:
impact_x = other.x + lengthdir_x(other.radius, collision_direction);
impact_y = other.y + lengthdir_y(other.radius, collision_direction);

The above will work as long as the high-speed bullet isn’t positioned such that the x,y origin of the sprite is on the far side of the target object. If it is, the point of impact will be on the opposite side of the target object. If this is a problem, you can do additional calculations using the direction of the bullet’s travel as a clue to determining where the true point of impact was. You can also reduce the problem by making the bullet sprite’s x-origin 0, so the bullet’s [x,y] position will always be at the rear of the bullet.

If the target object is non-circular, or non-centered, you’ll need to do a bit more work to determine the point of impact, and exactly how to do that is outside the scope of this article. But using built-in variables image_xoffset, image_yoffset, bbox_top, bbox_bottom, bbox_left, bbox_right, you should be able to figure it out, at least approximately enough to be useful.

Writing files in GameMaker Studio

The levels in TARJECTORIES are procedurally generated, using a lot of calls to the Random Number Generator. The output of the RNG is repeateable for a given seed, so the only variability from one run to another is the number of calls made to the RNG. Since the number of calls to the RNG in TARJECTORIES happens to be deterministic, this gives the game the same random procedurally generated levels each time the game is played. Fortunately, it turned out that those randomly generated levels aren’t too bad to play.

The RNG sequence will vary if you die and play a new game without quitting/relaunching the game, but if you do quit/relaunch it will be the same sequence of levels every time.

I became worried that the game was too sensitive to the RNG, and wanted to capture the level data so that I could re-generate any of the levels in the procedurally generated sequence if I wanted to, even if the game ends up getting modified in such a way that the number of RNG calls changes, which would otherwise screw up the level generation.

To that end, I just wrote up a little script that writes the level data to a .json file, and played through the game, going through two cycles of the 18 procedurally generated levels, so I could get the original sequence plus the level sequence from GE Mode. This was pretty straightforward, except the part about where GameMaker writes the file.

It’s complicated and not easy to understand. GameMaker runs sandboxed, so you can’t just write files anywhere you want. There’s documentation that explains this in the manual, but even after reading it several times, it’s still not entirely clear where you should look to find a file.

My intent in this post isn’t to write a tutorial that guides you to a complete understanding of where GMS writes its files, but I will explain how I found the location.

GML has a built-in variable, working_directory, which is a path on the filesystem where the game.exe is running. The confusing thing about working_directory is that it can return two different values. In certain contexts, the working directory is literally the location where the game.exe is located. You can read files from here, so if you have any “included files” in your project that you need to read from, this is where they’ll be. The thing is, this location is read-only (to GameMaker) so you can’t have your application write any data here, not even to update existing included files. You have a separate location where GameMaker (and all well-behaved Windows applications) can write files, in %LocalAppData%.

This is where it gets weird for me, and I still don’t entirely understand what’s going on.

I run the project out of GMS, and to help me find the file I’m writing, I draw the working_directory to the screen, and I get this:

C:\Users\XXXXX\AppData\Local\gm_ttt_20698\gm_ttt_1803\

So I go there, and I do not see the file that I wrote!

Eventually, I found the file I was looking for in C:\Users\XXXXX\AppData\Local\[project_ name]

I was able to find it because I went to %LocalAppData%, sorted by date last modified, and looked for the most recently updated directory until I found it.

What’s the first directory, then? That’s where GMS builds your project when you run it through the IDE! GMS also uses %LocalAppData% to store the temporary build that it creates when you click Run Project. But this is the read-only working_directory location that is where the game.exe resides. The game.exe then creates its own directory in %LOCALAPPDATA% which is named whatever you named your project (eg., [project_name]) and this is the directory that GMS will allow itself to write to. And of course you can also read files from here, too.

The confusing bit is when you call working_directory in the context of, say, draw_text(x, y, working_directory) and working_directory returns the read-only path, but when you call working_directory in the context of fileID = file_text_open(working_directory+"file.txt");
file_text_write_string(fileID, "text")
, working_directory returns the writeable path.

The behavior of working_directory is what’s confusing. It would be a good idea, I think, if YYG were to create a GML variable called “working_directory_writeable” which was an alias of the writeable working_directory that always returns the writeable path. There should then also be a companion variable called working_directory_readonly They could leave the behavior of working_directory as it is, to avoid breaking anything already written. It can return the readonly directory or the write-able directory, just as it does currently. But if you need to be sure the path to the writeable directory, then you could use “writing_directory”.

So, moral of the story, if your your GameMaker Studio project wrote a file to working_directory, you will find it in C:\Users\XXXXX\AppData\Local\[project_ name] — not the location given by working_directory if you draw it to the screen.

Related

Debugging TARJECTORIES: a Ludum Dare 38 postmortem epilogue

If you haven’t played TARJECTORIES yet, I encourage you to download and give it a try first.

Next, I encourage you to read the project postmortem article I wrote about the experience I had creating TARJECTORIES over a 48 hour period.

Back? OK.

In the wee hours of Sunday morning, in the midst of my debugging hell hours, I posted this on Facebook:

Debugging a program sometimes is like converting one system of thinking into an equivalent system of thinking, only one that works where the other one fails.

Since you can do this only one keystroke at a time, it’s pretty rough when you’re looking at transitional code and are looking for signposts to remind you of where you are. It’s common when you get distracted briefly to come back to looking at your code, desperate for these signposts.

This can end up making you very confused and waste a lot of time.

How to avoid this?

To put it in more familiar terms, pretend you’re writing a novel, and you want to change some of your characters around, so you need to update the text so that everything Smith says is now said by Roberts. Halfway into this, you’ve forgotten who’s who anymore, and there’s nothing in the manuscript that can help you tell what’s been changed already and what still needs to be changed.

If you keep versions of files, you can run a diff of the current manuscript against the most recently checked in version. If you check in versions at the right time, when things are self-consistent, not in a transitional state, this can be very useful.

If you don’t have, or don’t make use of, these tools, you’re putting a massive cognitive burden on yourself that prevents you from higher order thinking about the problem you’re trying to solve. If you get distracted in the midst of your transitional revision work, it’s like a juggler dropping their balls. One hiccup in the routine and the entire thing falls apart, and the only thing left to do is try to pick it all back up and start over.

The hardest thing is when you keep having ideas and thoughts about what else you’re going to need to do next. Often times a change will have a cascade of changes. Not necessarily code changes, but feature changes, or new features. Each one of these is like someone throwing another ball at the juggler. Even the best juggler can only handle so many things before they slip up and have to drop it. And while a person is juggling, there’s very little else they can do.

If you want to get real work done, don’t be a juggler. They spend most of their time repeating a cycle of familiar tasks that just maintain a status quo, and hardly have time to make any progress with anything else. It looks impressive, but it’s monumentally wasteful.

Learning not to juggle is even harder than learning to juggle, though.

The thing is, when you’re doing game development, design and development are tightly interwoven. It’s not even iterative, it’s sub-iterative. You’re figuring out what’s possible, what’s fun, what you can make work, and figuring out how to make it work, making it, and then seeing what else it needs — all at the same time. It’s inevitable that you will have ideas at every step in that process. And each idea is a ball to juggle. I found it works best to leave myself “TODO” comments throughout the code whenever I have an idea come to me while I’m still in the middle of working on something else, and keeping a notepad handy for things that I observe at runtime. Otherwise, you need to be able to split your conscience like a fractal if you want to have any hope of being able to do all the things that occur to you while you’re in the middle of development.

Holy s—. I’ve been at it since 10pm, and I think I finally just fixed a bug that I’ve been puzzled by for several hours. I can’t even begin to explain all the stupid details that I’d need to in order to convey what I just did.

But here goes anyway.

In my project, I have a planet which has a player on it. I had this working just fine with a single planet.

I wanted to create mutli-planet levels, but when I added a second planet to the game all kinds of things started going wrong because of all these hidden assumptions my code was making about there always only ever being one planet.

So I started disentangling the planet, which was really doing a lot of extra stuff that it didn’t really have any business doing. This stuff was managing other game state, and when you had multiple planets, they ended up screwing with each other as they both were updating the game state. Sort of like a race condition, I guess.

It caused some REALLY bizarre bugs, though.

The level counter went up smoothly until it hit 11, and then it started repeating itself a few times, then skipping a head several numbers, like 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 11, 11, 14, 16.

It also had a strange tendency sometimes to not spawn any player at all, on the second level 11.

I fiiiinally got the problem solved, without realizing that was what I was doing. I just started to give up and work on other problems, when I decided that the planet object should not create its own player. I’d done that early on because it made sense when there is only one planet. With two planets, each would create its own player instance, and then I’d have to go back after and delete one of them at random. This SEEMED to work, but somehow became responsible for the weird level number glitch, and the missing player object on the second level 11.

I STILL don’t get how that exactly worked. It still doesn’t make any sense to me. But when I decided to de-couple the player-spawning duties from the planet object, and instead of two planets each creating a player on it, and then randomly selecting one of those two to delete, I re-did the code to spawn two planets, then randomly choose one of the planets to spawn a single player on.

That fixed it. Like, whoa.

Update: A day later, it finally occured to me what happened, and why. This may not interest many, but for posterity, here’s what was going on:

When I made the game, I started out with a 1-planet room. I had this working so well that I didn’t want to screw it up, so when I was ready to start work on a 2-planet room, I created a new room so I could mess around in it. I had my level counter set up in such a way that after level 8, it would switch rooms to the 2-planet room for planet 9.

I had some code in the LevelUp object that handles this. But the thing about the Level Up object is, it doesn’t do those things when the game room loads. So on the transition into the 2-planet room, there were certain things that weren’t happening. To compensate, I (this was a bad move on my part) copied some code out of the LevelUp object and put it into the Creation code for the 2-planet room, and then failed to maintain this code adequately as I continued to make further changes on the LevelUp object.

So what happened was, when Level 8 is cleared, the LevelUp object does its end-of-level thing, and increments the global level variable, and creates new planets for the next level. It then checks to see if the level is 9, and since it is, it moves to the 2-planet room. The 2-planet room starts, and there’s 2 planets there from the room editor, not from the LevelUp object resetting the level. So nothing weird happens until after Level 9 is cleared, because that’s the first time the LevelUp object levels up in a 2-planet room.

I’m still unclear why the level incrementer goes from 9 to 11 — it seems obvious that it has something to do with there being two planets, but I didn’t have the level incrementer tied in any way to the number of planets. And it’s more mysterious to me still that it gets stuck on level 11, and so displays level 9, 11, 11, 11, 14. If GameMaker Studio had a better debugger, I might have bothered to trace through the script and watch the variables change to understand what’s going on, but I figured out enough to fix the problem without completely understanding it (well let’s hope so).

As to why there was no player at all on level 12, I do understand that. The planet’s Create event creates a player instance, and stores its ID in an instance variable, so it can update the player’s x,y position as the planet rotates. In the two-planet world, of course, I ended up with a player instance on each world. I didn’t need or want both of them, so I figured I’d just randomly destroy one of them, rather than fix it so that there would only be one. So I used a for loop and iterated over an array that should have been as long as the number of planets (2), and picked 1 array index to keep, and destroy all others. I figured I might want to make a 3-planet room at some point, and was trying to make the code work for N-planet rooms, rather than solve the 2-planet problem and leave a 3+ planet problem still unresolved. But sometimes the random chooser picked an array index that was out of bounds for the “keeper”, and so the for loop would go through and destroy all of the player instances. This happened to happen on level 12. It happened consistently on level 12 because the RNG seed value was always the same, and the same number of calls to random() always happen between the start of the game and getting to level 12.

I fixed the code by removing the player create from the Planet object, and put it after the planets are created, using choose() to select which planet if there’s more than 1.

The code works and appears to be bug free, but from a design standpoint it’s still messy. When I get around to doing it over, I will clean things up by removing the 2-planet room, which was only ever supposed to be an experimental room, and re-writing the code so that rather than move to that room when the level incrementer hits 9, it will spawn two planets, instead. This will enable move to remove the duplicate code by getting rid of the now-obsolete experiment room entirely. In retrospect that’s what I should have done in the first place, but because I was so concerned about not screwing up my working 1-planet room, I didn’t want to risk it. But really, all I needed to do was check-in to source control and create a fork to experiment in.

As easy and fast as the progress I made Friday night was, Saturday night was an absolute nightmare of a debugging session, just to figure this thing out and get it working. It’s SO weird how it was sortof almost working. Sometimes it’s a lot better to have something completely not working and obviously wrong. Those kind of bugs are much easier to fix.

The good news, though, is that I kept my Friday momentum through Saturday until I took my long break. I implemented a lot of features and had the game 95% complete, or so I thought. Just that last little bit of debugging took about 7 hours, and now the game is basically done.

So I made excellent progress Friday, and most of Saturday, although I unwittingly introduced this nasty puzzling bug during that progress, which stalled me for the entire night. But I still got so much done so quickly that I’m basically done now.

I have until 9pm Sunday to work on it, but I think it’s pretty good right now.