However, some errors are not so easy to track down because they are not syntax errors (i.e. 'illegal' code'); our code just doesn't work as planned. These errors are somewhat trickier to locate, and can take hours to resolve. Even more annoyingly, we can spend an age looking for such errors, only for another coder to glance over our shoulder, and immediately spot the problem! Sometimes a bit of luck may have been involved, but more often than not, it's experience that can assist in locating certain types of error.
The purpose of this article is to discuss refactoring, or rearranging code, to make it easy to read, and to assist in eliminating or (more realistically, reducing) the introduction of errors into our code.
A Practical Example
The resulting code will enable the actor change direction once, but because the changedir attribute is never set to False, the direction of the actor will never be changed to 213 degrees.
If we correct the code, it will appear as shown below:
Forget it and move on?
However, it's always worth a second glance at a newly-completed routine, to see if any improvements can be made.
What needs fixing?
The first target for refactoring is the use of the [if] and [otherwise if] blocks. One change is purely cosmetic, and the other will optimize the code (i.e. make it run more efficiently).
Let's look at the cosmetic change first:
A cosmetic Improvement can mean less work
This is what we can do instead:
That's the first code change taken care of and we've already eliminated two code blocks!
Optimizing code in Stencyl
Because we are working with a Boolean value, it can only ever be True or False. For this reason, if our initial [if] block tests for changedir being true, and that test fails, we do not need to test the value of changedir again, because it must be False!
We can replace the [otherwise if] block with a simple [otherwise] block as highlighted below:
Toggling a Boolean in Stencyl, with a NOT!
In our example code, we know that when we press the mouse button, the direction of the actor will change to 213 degrees if the code in the [if] block is run, or 320 degrees, if the code in the [otherwise if] block is run. However, we also need to change the value of the changedir Boolean, so next time we press the mouse, the direction will change again.
Currently both the [if] and the [otherwise if] blocks contain an instruction to change the value of the changedir Boolean attribute, as highlighted below.
NOT: A Good Idea!
Carefully note the placing of the [set changedir to...] block; it is the final block inside the [if mouse was pressed] container block. This ensures that, regardless of whether changedir was True or False, and regardless of which direction the actor is now travelling, the changedir Boolean value will be toggled.
By using this technique, we have replaced two lines of code with a single line of code, and we have made the code inside the [if] and [otherwise if] blocks easier to read.
one more thing!
However, we have to think about the very first time that the game-player presses the mouse button. If the game starts with the player automatically moving in the direction of 320 degrees, and the starting value of the changedir attribute is False ( which is the default for Boolean attributes in Stencyl), then the actor will not change direction on the first press of the mouse button. This is because, in those circumstances, we would need the direction to change to 213 degrees, but when the mouse button was pressed for the very first time, the changedir Boolean value would be False, so the [otherwise if] code would be run, and the direction of the actor would not change.
There are various solutions to this problem, including:
- Set the default (starting) value of changedir, so that it matches the starting direction of the actor.
- Change the starting direction of the actor.
- Swap the dir values in the [set velocity to...] so that the [if] velocity is 320, and the [otherwise] velocity is 213.
This minor modification is purely a matter a of opinion, and the type of mouse button response required will vary from game to game - I just want to point out that there is a difference between these two mouse button options, and it is worth experimenting to determine which option provides the better feedback in each game.
However, we decided to review our code, to determine if any improvements could be made. We discovered that by making several changes, including cosmetic changes and optimized code, our game now has the potential for better performance. Bear in mind that in, some cases, this type of optimization may result in negligible performance improvements that may not be noticed in game-play. However, it's good practice to use optimized code where possible because, in a large game, several of these small tweaks can make the difference between a game that performs well, and a game that is unplayable due to lag and poor user-experience.
Professional coders can argue for hours (or even years) over which optimization routines are the 'best', but sometimes it just comes down to a matter of opinion. I think the code changes that we have made make the code easier to understand, and will thus be easier to modify or maintain in the future.
Some clever code optimization tricks can provide dramatic performance improvements, but sometimes there can be a trade-off, whereby we create code that is more difficult to understand. If you use 'tricky' optimizations, be sure to add comments to your code, so that it will make sense when you, or someone else, reviews it in the future.
The few changes that we made have reduced the number of coding blocks required inside the main [always] block from 16 to 10; that's around 40% less coding. Coding in this manner reduces the time taken to create a game, and creates code that is less likely to bugged, and is also easier to understand!