Gunpoint is a stealth puzzle game that lets you rewire its levels to trick people. This video will explain it.
Windows only for now, hopefully Mac and Linux later.
By Tom Francis. Uses Adaptive Images by Matt Wilcox.
No! Don't tell them my scheme!
There's now a mailing list for people who'd like to be told when it's out, and what we do in future. Join it why not!
I tweet news, shots of things I'm working on, and despair at the complexity of coding.
Here's the formal permission bit.
Every aspect of its clever design, laugh-out-loud noir story, tiny but expressive art, and moody music work harmoniously with one another.
A framework for a puzzler that rewards cleverness and convoluted sadism in equal measure. JC Denton would be proud.
Gunpoint’s current save system is rough, but functional if you know how to use it. The game autosaves every ten seconds, and when you die, a message pops up telling you to press L to load the latest one, O to load the one before, or R to start the mission completely. It’s just placeholder, but it’s close to what I want: you should never have to repeat a chunk of progress you’re happy with, only the bit you actually screwed up.
But watching people play at GDC revealed a weird problem. Many people would get a long way through the level, die, and restart it completely. If they want to do that it’s fine, of course, but some of them seemed pretty frustrated. I’d tell them, “You can just press L and it’ll put you back much closer to where you were,” and they’d say “Ah!” and use that from then on.
Obtuse hotkeys are not how the final system will work, of course, but here’s why it’s weird: the message that tells you to press L to load the last autosave is the same one that tells you to press R to restart. If these players hadn’t seen that, how did they know to press R to restart the level?
I discovered they knew the key, they just didn’t know what it would do. Last save? When was that? I’m not gonna hit a button that might take me back three levels.
I could have an on-screen notification every time it saves – maybe a big sign that says “Saving content – please don’t turn off your PC, because apparently there’s some kind of epidemic of people randomly doing that in the middle of a game.” Much as I love patronising bullshit, Gunpoint saves a lot – any notification would be a constant distraction.
I already knew what I wanted, I just hadn’t built it yet: a small menu showing the last few autosaves and how old they are:
I wanted that just because it’s nice, but the GDC problem made it an actual priority. Hurray!
It gets tricky when you think about where to store that data. If you store it as a variable in-game, then how does the game know which one is the most recent when you start it up again? It won’t have that data until it loads one of the autosaves, and each of them thought they were the latest one when they saved.
I tried messing around with renaming savegames so the latest one always had the same name, but it got awkward fast. So did the times themselves. Even seemingly simple systems get complicated to think about and test when you’re dealing with savegames, because loading a savegame is essentially time travel. You’re going back in time, then creating a new parallel timeline from there.
I was handling it, keeping it all straight in my head, until this happened:
Minus what. What.
I had a savegame created 47 seconds in the future. I tried loading it. It was the past – about 15 seconds in the past. And now it claimed the last two autosaves were made at the same time.
I ended up drawing a pen and paper diagram that started to look like the plot of Primer in an attempt to understand how repeated and overlapping backward time travel could create a paradox like this.
Sure enough, I eventually found a bug in Game Maker’s time-keeping code that causes the number of seconds since the game started to occasionally reset. I made my own clock, but that behaved strangely for savegames too. It’s just super hard to keep track of time when the player is time-travelling, and the filenames he’s creating and loading can mean different things in different contexts.
The system I settled on picks a new filename for each successive save, so it’s easy for both the code and me to see which one is newest at any given time. And if it has trouble figuring out the save times, it can just look at the numbers – if the save interval is 10 seconds and this one’s 2 saves ago, it’s 20 seconds plus the time since the last autosave.
The last change it needed was one I didn’t expect to have to make. I’d had this great idea, throughout all these systems, to avoid Groundhog Death: the problem where an autosave happens just before you die, so when you load it you instantly re-die. It’s less of a problem with multiple autosaves anyway, but I thought I had a clever way to avoid it completely.
The game would save every 5 seconds, but assume the most recent save was ‘bad’. Only once the player has survived more than five seconds since the last autosave does it become a valid one to load. So with a 10 second save interval, the latest autosave will still be 10-15 seconds ago, but it’s guaranteed to be at least 5 seconds before you died.
Once the rest of the issues were ironed out, I discovered this system sucks. It’s possible, and actually pretty common, to load a point in your game when you did survive beyond five seconds, but you didn’t this time. Maybe you had a guy at gunpoint, or were in the middle of a tense situation, and when it loads you’re disoriented and screw it up.
My instinct as a gamer is not to think “This save sucks, take me further back!” It’s “Let’s go again, I can do this!” But now that we’ve time-travelled, that savegame is the latest one. And the latest one is always left off the load menu to be sure it’s not gonna screw you.
Instead, you feel extremely screwed. You deleted my savegame? The one I just loaded? I get one chance at this, with no knowledge of what I’m getting into, and then you take it away? Fuck you, Tom Francis. You are a shitty, shitty designer.
So I backed out of that: now you can load any save you like, and I give you three just to make sure you’re not screwed in all of them. You can even hammer the ’1′ key to repeatedly retry the same tricky situation if you want to.
Saves are tiny, take no time to create, and load instantly too. I’ve noticed that Gunpoint’s incredibly sudden, sometimes shocking deaths are often a positive thing – a lot of players at GDC would laugh when they got shot. So I never want that buzz to be dampened by the pain of having to repeat stuff you don’t want to, or being screwed by the save system.
More Gunpoint Development
Dave: You could have a timeline allowing the user to select which save to load.
When highlighting each option, the state of the game could be shown, letting the user see what state they will be in if they load that save.
ynp7: Is there a reason that check pointing at known "safe" points wouldn't work? I haven't played the game so maybe that wouldn't work into the design.
Jorma: Rewind seems like the best solution for this kind of game. No idea how easy/hard that is to implement tho :)
Gary the Llama: Couldn't you solve the last issue by keeping the just-loaded game paused upon load, until you press a key to start the action? That way you have a chance to get your bearings before you action starts. Just an idea.
grobitbox: I guess the the best system for this would be one where you rewind time naturedly to a point that you're happy with, like in the first world of braid, but I'm guessing that would be ridiculously difficult to do. I was also wondering about some system that some how predicts when you are about to enter a dangerous situation and saves, but I doubt that would work.
MLeoDaalder: Sorry to ask, but will there be a new test build in March?
It might be interesting to try out this new save feature.
Tom Francis: I love rewind systems, but you do need to design for them from the ground up. And if it's not your core feature, that's a lot of work for a small benefit.
I dislike checkpoints and positional saves because they dictate what counts as progress. If a player wants to spend ten minutes in the same place just messing around with the wiring of a building, I want Gunpoint to value that as progress and save every step of the way, so he doesn't lose it all if something goes wrong.
No-one suggest a better save system! I just finished the save system!
Philippe: I'm not in on the beta (meaning: I haven't played, just seen videos), but perhaps you could save based on certain actions: elevators, doors, cross-link.
I agree that rewinding a la Braid would be the least jarring (and pretty cool), but it means all your update() functions need to accept negative time deltas (assuming you're coding like most games I've seen), and you still need to keep track of certain decisions to "undo" them.
relikd: yep Dave's idea sounds great. A horizontal line with some dots on it (like your hand-drawn timeline). Hovering will show a screenshot in the background (you said its loading immediately so this shouldnt be the problem loading the state)
DeliriumWartner: Would it not work to log the save games according to the time on the PC's clock? Then they would be in literaly chronological order. Indeed, you could then use a comparison (I assume) to say how long ago the save was.
Then again, I know nothing of programming, so that could be really hard to implement.
grobitbox: A more simple idea: what if when you die, the last save is loaded, paused and you can move backwards and forwards between the paused saves to select one you like the look of. I think something like this where you can see what the saves are would be better than just a list.
DeliriumWartner: "No-one suggest a better save system! I just finished the save system!"
You just wrote a big post on different types of saving systems. It was kind of inevitable that this would be a "kick myself" comment section. Too-late crowd-sourcing FTW!
Corintho: Its interesting to read your reasoning and think "That makes sense." And when you say what the problem is, it goes like "How the hell didn't I think of that before".
I actually felt a little bit like developing the idea of the system.
Thanks for sharing that.
Tom Francis: In my case 'better' always means 'better and less work' - this system only took me an evening and solves all the problems I need it to. I just didn't want anyone to put loads of effort into a suggestion hoping I'd do it: I'd never finish if I spent time making good systems nicer.
Optimaximal: Does Game Maker not support system timestamps? That's usually the best way to deal with time handling, regardless of whether they're datetime or epoch-based.
Ash47: Loads instantly, saves instantly? It would be really cool to have a timeline popup, and you drag it backward and forth and it loads the game paused, so you can see where you were, that way you can pick the best save quickly :P
Dave: I feel your pain with save games. When I was in the industry I worked on the save system for a big open world game. The technical side was way more complex, but it was always the basic save logic (when, how, etc) that ended up being the harder problem to solve. Sounds like you've got a pretty good philosophy/logic for your game fleshed out, which is helpful when making the tons of tiny decisions necessary for implementation.
Andytizer: Please please put your savegames in a logical place such as that suggested by John Walk: http://www.rockpaper... ...ave-games/
That path would be:
C:\Users\[user]\Documents\My Games\[game name]\Saves\
Cyanyde: I would like to see something like Braid, where you can drag a slider or something in order to rewind "time"
I'm sure whatever you come up with will suffice, you definitely are *not* a "shitty, shitty designer" :)
Rei Onryou: I know your happy with your system, but you could display a little snapshot image of what was happening at each save. A player may not be able to remember exactly what status the world was in 10 seconds ago, but a screenshot might help them go "No, I was already on the path to failure, I need to go further back in time!"
I'd also go with system timestamps if possible. Determining time inside a system where time can change is difficult, but time relative to an outside system is easier to work with. Unless I misunderstood how time (and time travel) work in GP.
joxp: Well, I'd say you should later on implement a rewind/timeline. My Duke Nukem 3D for the Xbox has a rewind feature, and it works great. And do release a new build :D
HuCares:): Sorry don’t understand you’r problem? :)You think in not right direction.
Every 5 sc game do save game using system time like this
When player die let say in 12:16:22
You have last save games like
2:16:11 - 11 sec ago
12:16:06 -16 sec ago
And so on;
If you want skip save-games in dif time line you need
Add to save game field like previus save_game
Hire is our saves
12:16:01 prev null
12:16:06 prev 12:16:01
12:16:11 prev 12:16:06
Die in 12:16:12
new save 12:16:16 prev 12:16:06 and so on ..
so you can handle last 3-5 … saves and can display real time or time line with offset in 5 sec(if save every 5 sec)
let I show :) :
last save 12:16:16
diy in 12:16:18
12:16:16 – 2 sec ago (2 sec real)
Take prev 12:16:06
12:16:06 -7 sec ago(12 sec real);
LionsPhil: Why dance about with filenames when surely you can get the age of an arbitrary savegame by looking at its modification time? Doesn't GameMaker let you stat() files?
SirFry: One way you could do saves, if you have time to implement it, is to have a sort of rewind interface that allows you to press back in certain intervals, like 5 seconds, and see a picture of that save state before you jump in. I have seen other games do something similar, and it makes for a fairly intuitive interface, but I have no idea how long it would take to make or if its really feasible. Just an idea.
Flavio: If I may, i don't mean to offend, but the system is completely wrong and I think the test you write about demonstrate it.
I guess this can work for a demo but for a final release you must move to a checkpoint based system: in 5-10 seconds i'm probably still idle thinking what to do next, so there's no difference between the saves or, as you highlighted, you are in the heat of action and you could die.
I don't get this animosity that comes out of your words about informing about the autosave, you don't need a big banner to tell you are saving the game... console games are not intrusive in this, there's just some kind of spinning icon in the bottom corner. The banner comes when starting the game, so I don't see the problem.
I'd say that quicksaves are the solution, but in the HL times it happened often, because of the default bindings, to save while falling in pit and get stuck in a dying cycle.
Personally i can figure myself just hitting reload in a game like this, because i don't think levels will be so long to complete, like more than 5 minutes... but i don't know that and it could get frustrating.
In the end the perfect solution would be checkpoints on key moments of the levels (that you must break up in "stages", at least just for you) _and_ quicksave.
Another nice idea that would integrate in the game would be for the player to manually save at some point with the character interacting with a particular object, i'm thinking about Flashback, where you had your avatar interacting with a computer-stand, or Resident Evil and the beloved typewriter.
Benjamin: "I guess this can work for a demo but for a final release you must move to a checkpoint based system: in 5-10 seconds i'm probably still idle thinking what to do next, so there's no difference between the saves or, as you highlighted, you are in the heat of action and you could die."
Perhaps auto-save after the player takes a few significant actions, rather than geographical checkpoints?
LongShad: I think - best use save-triggers in safe areas, like in "Stealth Bastard".
When player enter in safe-trigger (they place level-designer) - game is saving and safe-trigger destroying (saving run once).
Anonymous: shut up and take my money
URLs get turned into links automatically. You can use <i>HTML</i> but not [b]forum[/b] code. If your comment doesn't show up, e-mail me - the spam filter's just detained it for questioning.