Hello! I'm Tom. I'm a game designer, writer, and programmer on Gunpoint, Heat Signature, and Tactical Breach Wizards. Here's some more info on all the games I've worked on, here are the videos I make on YouTube, and here are two short stories I wrote for the Machine of Death collections.
By me. Uses Adaptive Images by Matt Wilcox.
Update: Solved! See bottom of post for details.
Hello, more experienced programmers than me! I could use your advice. There’s a code-pattern I’ve been using for a while and I’ve just discovered a problem with it, but I can’t see a great alternative either. I will explain by example:
Right now I’m trying to add a little auto-aim when you’re pointing a gun at people. If you’re holding a gun and the cursor is near an enemy, I want a little reticule to appear on the enemy, the player to point their gun at them, and if you fire, obviously, fire in that direction.
The reticule needs to be an object – that’s the only way to specify a particular depth (z-layer) for it to be drawn at). I called it oReticule.
The code that looks for enemies to aim at is in the PlayerItemControls() script – that handles anything specific to what you’re holding in your hands, and this is a feature of guns and possibly some other item types, but not others. I tell it: if there’s an enemy near the cursor, place oReticule on it and make oReticule.visible = true.
The code that decides which way the player should face is called PlayerMovementControls(). Normally, in this ‘moving around freely’ state, the player always faces the mouse cursor. For auto-aim, I’ve added an exception to say: if oReticule.visible = true, look at that instead of exactly at the mouse. The difference is slight but important: guns fire in the direction they’re facing, so you really do need to look exactly at the reticule.
Lastly, when oReticule has drawn itself, it sets oReticule.visible = false so that it won’t be drawn again unless the auto-aim code tells it to. I don’t want to have to add lines to all other player states telling the reticule to be off, I want it to be always off unless this one specific bit of code activates it.
Currently, the player movement code executes earlier in the step than the player item controls. So:
So the player doesn’t look at the reticule, and never will – it’s checking before the item controls has a chance to turn it on, and after the reticule has turned itself off.
Obviously I can fix this by just moving ItemControls to execute before the MovementControls, but those are separate behaviours, and I don’t want them to be order-dependent. It’s perfectly possible that I might later have the same problem the other way around, and it’s almost certain I will forget that they have this hidden order-dependency.
I also often want a similar relationship where those two scripts would be on different objects entirely, and in that case the order in which their step events execute is unknown. (It can be known, but it depends on something about how you organise your objects in GM that I change regularly, so I can’t depend on it).
What I’ve done for now is to take the ‘visible = false’ bit out of the oReticule’s draw event and put it at the start of ItemControls. Now the player does look at the reticule as desired, but there are still two problems:
This in Game Maker Studio 1.4, which uses its own language GML. It doesn’t have delegates or coroutines or structs, that I know of. All functions are public and can be called from anywhere.
Any thoughts?
Thanks everyone! Lots of very different ideas, many of them involving big concepts I didn’t know about. As usual, finding out all the different ways other people tackle this problem clarifies where the issue is, and I found I could boil it down into something pretty simple and lo-fi: I just need two variables instead of one.
The two types of code I identified above are ones that can set the variable and ones that listen for it. If these two operate on the same variable, order will always be a problem. So instead we’ll call the ones that can set it Signallers, and the ones that listen for it Listeners. And we replace the single variable with:
OnSignal: anyone can set this, but it is never read by anything other than the object.
OnState: only the object can set this, and anything can read it.
So Signallers all set OnSignal, and Listeners all listen for OnState. Then in the object’s code, we say:
OnState = OnSignal
OnSignal = false
Anything that listens for OnState – including this object’s draw code – will trigger once for every step when OnSignal was triggered by anything (it may be the next step). And will stop triggering if nothing set it since last step.
Tested it: it works, is only 2 lines, and most importantly, doesn’t involve adding code where there wasn’t already code for this.
Thanks again for the ideas!