Help Me Structure Some Code Better In Heat Signature

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:

What I’m doing

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.

How I’m doing it

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.

What the problem is

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 tried

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:

If we leave this state at a time when the reticule is on, this code won’t execute again, so the reticule will never get turned off. I do have an OnExitState bit I could add a line to, but this feels messy. It’s also possible for the player to get destroyed unexpectedly, and since the reticule is a separate object it would continue to exist and be visible.

It’s perfectly possible that I might want something else to also turn on the reticule.

So what I want is

Several bits of code that can each turn the reticule on

Several other bits of code that need to know whether the reticule is currently on

If none of the bits of code that turn the reticule on execute, the reticule should be off

None of these bits of code know what order they will execute in, on a given step

It’s fine if the listening bits of code respond on the next step instead of this one

Context

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?

Update: Solved!

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.

17 Replies to “Help Me Structure Some Code Better In Heat Signature”

What Engine are you using? If this were Unity, I’d such the reticule to be a child of the gun (or aiming mechanism). Is there only 1 gun? Or can you control multiple guns like when you hijack a ship and have the turrets follow the mouse/reticule?

As I’m understanding it you’re using the oReticule.visible variable to decide whether “auto aim” is active. Why do you turn it off each step always? Why not do something like once “auto aim” is active a “dead zone” is created around the object being aimed at. While the cursor is in the dead zone the “auto aiming” remains active. You might have to dynamically adjust the size of the dead zone so it’s not too sticky when there are multiple objects near each other.

Loose thoughts – but they might be more useful than specific approaches:

– it feels like separating out the visibility of the reticule object, and whether auto-aim should be engaged, might help you here. Ie: you need to work out what object the player is auto-aiming at, and separately, you need to work out whether to show the thing.

– given that, feels like you need a separate ReticuleManager unattached to a visible object. Basically: anything that can turn the reticule on sends a message to this, such as “I am enemy #248 and I should be auto-aimed at”. That probably gets stored on something like a list, if you want to have many reticules, or just a single field if you want one. (Or: might be worth having a list, so you can re-prioritise later, though I think priority order might just be last on first off). Anyhow, then, when it comes to aiming, you ask the ReticuleManager “which object should I point at” – and separately, when it comes to rendering, you ask the reticule manager “entirely separately, which object do I draw the reticule on?”

And then, at the end of your loop, you need something to tidy up – ie, rather than setting reticuleVisible=false immediately, you clear up after yourself at the end of a game loop.

Is this making sense? It might not be what other people do, but what it feels like is you need something abstract to handle all the possible auto-aims and reticules, that you can message and later ask for canonical answers. That’d also help separate out render and logic.

In Unity and C# what I would use would be callbacks. In C# u could create a call back handler on your reticle object and in your other bits of code the call back functions would be called once reticle is visible. I know you use game maker maybe this will help. @jayone74 http://gmc.yoyogames.com/index.php?showtopic=589410

It’s unlikely that I’m a more experienced programmer but what I would do is probably let character always aim at the abstract target which may be on the mouse cursor but may also be somewhere else. Basically you always aim at the small reticle, whether its visible or not. No “aim at the mouse cursor except when xyz”.

But could you potentially make a separate script that turns the reticle on, and while it’s on, everytime you call “IsReticleOn()” it checks for a certain condition, in your case: “Mouse no longer on enemy”, before returning the value?

Kinda similar to James Vokes’ suggestion, actually

Or alternatively, make the reticule ALWAYS drawn, but when it’s not autoaimed, make it’s position off-screen, yet still in the same direction as the mouse. Pretty easy vector math, no?

Maybe just treat the visible state as an integer, e.g. set myVisible=2 whenever you want the reticule to appear. Then, where you currently set visible=false, instead subtract 1 from myVisible and set visible=false when it hits zero. That way your visibiliry state will carry over 2 frames, technically leaving the player auto-aiming for one frame too long but that might not be a big problem.

If you’re happy with your current architecture and just want to fix the ordering problem – then perhaps you could store the frame number that the reticule was turned on, and change the code that turns it off to only do that if the current frame is greater than the stored frame. That way it will prevent the reticule from turning itself off immediately on the same frame, and your other code will get a chance to see that it’s on and update accordingly before it does turn itself off the frame after.

Wow, you got a lot of responses very fast! There might be some bikeshedding going on here :)

Anyway, I think what Duncan Wintle and Frans Kasper are saying is the simple solution you can easily use. But I don’t like it.

I think your problem is that you have both the “Several bits of code that can each turn the reticule on”, and the “None of these bits of code know what order they will execute in, on a given step” requirements. I’m guessing this means that if several bits of code want to turn the reticule on in the same step, it will be set to the place where the last bit of code wanted it to go. So even if you solve this problem now, you might run into a problem later, where every step those code paths run in different order, and your reticule will jump around between two places. And you make it a bit hard to set up any priority between the targeting.

So I think long term what would be best would be to have one function which can decide whether to turn the reticle on and where to target it, and this function would run once each step. Of course this probably requires a larger rewrite of your code, so I understand if you don’t do it. But maybe later, when you are introducing some new “state” into the game, you could try doing it in a way where setting the state only happens in one place, generally that makes working with it less complicated.

I think the problem is you want it to appear whenever but only stick around for one frame from when it appears. However you now have a problem that the time it should disappear is arbitrary.

I think the cleanest solution is to let it stick around for one frame on from a designated point. Ideally this point occurs just after when it gets turned on, but at least this solution will never fail if it happens to be some time before this point. Then both the draw and the auto aim can happen if the reticle is on, and while they may last for one frame more than is ideal, they will never last for longer than that, and they will always be on for at least one frame.

In terms of how you achieve this you need amIOn and stayOn. When you turn the reticle on both amIOn and stayOn need to be true. Then at this designated point if (stayOn)
{
stayOn = false;
}
else
{
amIOn = false;
}

When all you have is OOP, everything looks like an object. But it isn’t. Time to go back to imperative. Let me try to explain (I hate writing English about Code, it’s even harder than writing Code about English).

So you have all this functionality distributed around these “objects”. But they aren’t actual independent entities – you’re actually just doing a single action (aim a gun) and a single blob of logic. So splitting things around the objects is hurting you, and you’re having to add a bunch of book-keeping – stuff that doesn’t make decisions, it just tried to keep all the objects in sync.

I would move all the actual thinking logic into a single place. Doesn’t matter where, but probably PlayerMovementControls(). It will do:

1. Find enemy to point at.
2. Point player at enemy.
3. Tell gun to aim itself that way.
4. Tell reticule to draw itself there.

All the other objects just do what this logic tells them. The information flows one way – from the decision-maker to the children. There’s no back-and-forth or multiple chunks of state. In this case the player object makes the choice, and then the gun and reticle do what they’re told. This will keep things so much simpler, modifiable and debuggable.