• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Question - Code Break on variable write?

nesrocks

Member
Is it possible to break on writes to a specific variable that belongs to an object instance? I find that I waste a lot of time debugging my game because I can't find what is writting to variables.
 

Tsa05

Member
Quick gif using the debugger to step through a section of code to see how it's getting and setting values:
https://i.imgur.com/90dZLdP.gifv

You can set a Breakpoint in your code (press F9) wherever you want to pause and examine things--I set one during global left pressed. Then you can step through the code, viewing the values of "variables"--local to the event or script that you are currently stepping through--and "All Instances" variables, which remain across events in your object.
 

nesrocks

Member
The problem is that for that I don't need the breakpoint because that would mean I know where in my code the variable is being written to. My project is getting rather large and I'm having trouble finding where in the code the variable is being set the wrong value.
 
The problem is that for that I don't need the breakpoint because that would mean I know where in my code the variable is being written to. My project is getting rather large and I'm having trouble finding where in the code the variable is being set the wrong value.
CTRL + SHIFT + F, do a global search for the variable name and see where it is being set, you could place breakpoints on each line, use the process of elimination until you find the line that's setting the wrong value.
 

nesrocks

Member
That's what I did, but it's a lot of work. I was wondering if there was a way to break on var writes/reads. It's something that makes debugging nes games a breeze using emulator's debugging functions. If it isn't possible in gamemaker I think it would be a nice addition to the debugger.
 
I see. Having hundreds of lines setting this particular variable can be time consuming... I don't think the debugger has this functionality currently.
 

Tsa05

Member
The project I used in that demo has 1150 lines of code in the left pressed event alone, and over 12k lines in total...Honestly, if I were trying to track specific reads and writes of a variable, it would make the process harder. Unlike tracking values in an emulator, cheat engine, and so on, my code isn't finished or basically bug-free. The trick is to decide how best to catch the behavior, and then to get the breakpoints going.

That probably didn't convince you :(
Let me try it this way: If you were able to track all of the places where a variable changes (something like Find All inside the debugger), then you would have a very hard time identifying why the values have changed in a way you didn't want. Jumping from write to write does not allow you to see the more complex interactions in your program--for example, most errors I run into in GameMaker come from the order in which events happen or the order in which objects execute their events. Tracking variable writes only shows me that a variable becomes an undesireable value at a certain place--it does not show me that an event has fired in a different order than I expected, and it doesn't show me that some earlier conditional statement caused a section of code to be skipped (or not skipped).

In other words, often times the source of the error isn't the line of code that changes your variable--that's sometimes the only correct thing! Often, the cause of the error is that the correct change to a variable was made at an incorrect time or under incorrect circumstances. You can only discover this by tracing your code.

In the example I showed, I guess it looks kinda like I know *exactly* where I want a breakpoint but that's not quite what I meant to illustrate. In that example, suppose that every time I click the "Mark" button in my game, something should happen but it's not working properly.

I go to the mouse click event and add a break point at the portion of code that is supposed to detect clicking the "Mark" button. I have now cut the problem in half!!! The issue is either ocurring because the "Mark" button isn't correctly detecting a click, or because something after the click has gone wrong. So, I add the break-point, and then I click. If the code "breaks" then I know that the issue is not anything to do with whether or not the button correctly detected a click (it could have been--the only way to know for sure is to put in a break point).

Once I know that a certain action that I *think* should happen actually happened, I know that a value inside of a ds_map data structure should change. I don't set a breakpoint at that line--I want to verify that everything leading up to it is working. So, I step through my code, watching the temporary values of computations leading up to that line, then confirm that it got the right value.

IF the value is set correctly (99% of the time, it is when you have a bug), then that means something happens after the value is correctly set to make it go wrong. Often, this happens during the same game step, so it looks like the value never changed at all unless you use break points.

If you really, truly have no way to guess where to begin adding a breakpoint, then I can give you ways to guess:
1) Does the value become wrong consistently when the game is in a certain state or a certain room, or when a certain object is created, or when you do a certain interaction? Put a break point at the place where that room starts, that object is created, that state changes, or that interaction is detected.
2) Is the value definitely correct somewhere, after which it somehow gets wrong? Put a break point at the place you know it is right, then trace until it is wrong.

Now, that's foolproof. If your value was never right and never wrong then you've got a paradox, so surely one of those 2 places is a starting point. You can combine strats from there.

For example; set a breakpoint on a variable write line where you strongly suspect that the value is set correctly.
When your code pauses at that point, continue down a line or two and make sure it changed correctly.
At that point, you probably don't want to click "next" 1000 times, right? So in the debugger, scroll down a bunch, past all of the lines that you think have no effect on the variable. Add a breakpoint farther down and "resume" your game--it should break at your next point. If not....you've narrowed down the problem location between 2 breakpoints.

If you think that the entire rest of an event or script has no effect on the variable in question, then click the "step out" button on the debugger instead of setting another breakpoint. "Step Out" tells GameMaker to run the remainder of the script without pausing, and to pause as soon as it reaches a new event or script. This way, you'll see which event or script happened after your breakpoint correctly set the value.

Again, scroll down. Set breakpoints in the "next" event or script where you think things might change the value and hit Resume--or "Step out" if the event has nothing to do with the value in question.

By combining the addition of breakpoints, stepping out of events and scripts that aren't important, and stepping one line at a time through the logic surrounding the lines that do change, you should be able so sift through thousands of lines of code in under a minute and you'll quickly know where the error occurs. Then, you've gotta figure out why :D
 
Last edited:

nesrocks

Member
First of all, thanks for the help! But I did all that. And it is a lot of work. If it wasn't your post wouldn't be that long. : / I'm only saying it is a lot of work because I know it could be a lot less work.

Yes, all of that breakpoint setting is the same thing as the debugger breaking automatically when a variable is written to, except that is done for you, no manual labor. NES roms are not without bugs, so that is a moot point, the process is exactly the same and it is waaaaay easier to debug on NES. I know the NES has a lot less RAM than a modern PC, but still.

Yes, as you said, it's about code execution order. But that's just what I want. If I have the debugger breaking at every time the variable I'm watching is written to I can click "play" and let it continue to see every place the variable is being written to (it will break one by one, in order).
At one point it will break at the line I consider to be the correct one (or as you said I can start the whole process right at that one, and THEN turn on automatic variable write breakpoint). Then it will be really quick to check where exactly the variable is being set the wrong value after that.
 

COWCAT

Member
Sorry for bumping this topic but... this is something that would make my life SO much easier.
For some variables I have HUNDREDS of lines where I change a certain variable value and my only solution is to use a script and replace all the locations I change values... very tedious.

It's STILL not possible to actually add a breakpoint on variable write, right?
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Sorry for bumping this topic but... this is something that would make my life SO much easier.
For some variables I have HUNDREDS of lines where I change a certain variable value and my only solution is to use a script and replace all the locations I change values... very tedious.

It's STILL not possible to actually add a breakpoint on variable write, right?
You can grab the "migration tool" from my Quality Structures page (is a free download) and add your own rules into compfix.gml. Here's a sample for how variables can be handled:
Code:
remap(stat) $1.image_speed ${2:aop} $3 -> image_speed_post(image_speed_pre($1) ${2:op} $3)
remap(stat) $1.image_speed ${set} $2 -> image_speed_set($1, $2)
remap(expr) $1.image_speed -> image_speed_get($1)

remap(self,stat) image_speed ${1:aop} $2 -> image_speed_post(image_speed_pre(id) ${1:op} $2)
remap(self,stat) image_speed ${set} $1 -> image_speed_set(id, $1)
remap(self,expr) image_speed -> image_speed_get(id)
(where image_speed_pre stores id in a global variable so that the expression does not need to be duplicated in image_speed_post)
 

COWCAT

Member
Sorry, just noticed your reply!
Interesting, I may try it - although I usually prefer to keep my GameMaker "vanilla" to make sure nothing gets broken in future updates. But thanks!
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Sorry, just noticed your reply!
Interesting, I may try it - although I usually prefer to keep my GameMaker "vanilla" to make sure nothing gets broken in future updates. But thanks!
The usual approach is to make a copy of your project, butcher it with external tools as you may, figure out the issue on temp project, fix it in the actual project, and remove temp project.
 
Top