Your player collides with another actor and you want the collision (or another event) to be detected only once in your Stencyl game, but it keeps happening over and over. You’re not on your own; it’s a common problem!
Let’s say that you want the health of the actor to decrease, or you want to add a bonus to your score when the collision occurs, or play a sound. The problem is that the collision is detected multiple times until your player moves away from the actor with which it has collided.
There is a nice, easy solution to this problem, and it uses a single attribute to keep track of whether or not a collision has already occurred. Read on to find out how it works, and learn a little about Stencyl’s debugging tools along the way!
Breaking down the problem
Before we continue, let’s make sure that we fully understand the problem…
The collision occurs, and our event is triggered, but the collision doesn’t end immediately; it continues until the actors are not colliding, after which, the event is no longer triggered.
Below is an example of a code block that might cause this problem to occur.
Setting the Stencyl Scene
To demonstrate the problem (and then fix it!), I have created a scene in which a simple tileset has been used to create the ‘ground’; the scene has its gravity set to 85. I have also added two actors: a monkey and a pineapple, and I have added the ‘Jump and Run Movement’ behavior (provided with Stencyl) to the monkey. Note that, for this demonstration, I have not implemented any animations and, of course, you can use any graphics that you have available. My basic scene is shown below:
Let’s create a very simple event that will demonstrate the problem. Rather than go to the trouble of creating behaviors and text labels, we are going to add an event to the monkey and use Stencyl’s built-in debugging tools to tell us what is happening.
In the Dashboard, double-click the monkey actor, and select ‘Events’ (from the buttons across the top, centre of the screen). In the left panel, click ‘+ Add Event’, ‘Collisions’, ‘Actor of Type’ as shown below:
Test the collision
With the debug console on display, move the monkey towards the pineapple and, when the collision occurs, the message ‘Bang!’ should appear multiple times on the console.
The next step is to resolve the problem…
The Magic of Stencyl Attributes
This is where the attribute comes into play; we can give the actor an attribute that will record whether or not it has been hit. If it has not been hit already, then the message will be displayed, but if it has been hit already, the message will not be displayed.
Let’s add an attribute to our actor. If the game us running, close it and go back to the monkey actor in Stencyl. In the code block palette, click the ‘Attributes’ button and then click ‘Create Attribute’. In the ‘Create an Attribute…’ dialogue box, give the attribute a name of ‘Collision Occurred’ and ensure that you have clicked on the ‘Boolean’ button, then ‘OK’. You will now see a blue block in the palette. By default, when boolean attributes are created in Stencyl, they are set to False, but you can check the default setting for the new attribute by clicking on the ‘Attributes’ tab at the bottom, right of the screen below the block palette.
We now need to update the existing collision-detection code block so that it looks like the image below…
Do this Once and Only Once!
Hopefully, at this stage it is clear that we are detecting a collision in the [when] block, but the magic happens inside the [if] block: we are checking to see if the attribute ‘Collision Occurred’ is not set to true. I’ve actually used a shortened version of the code because it is quicker to create and because as far as I am concerned, it is easier to read. The full version of the [if] statement would look something like this: [if 'Collision Occurred' not = True] which would achieve exactly the same effect as my shortened version.
When the code first runs, the attribute ‘Collision Occurred’ is set to False (the default state), so the collision has not yet occurred. In this case, as soon as the collision does occur for the first time, the code inside the [if] block will execute…
The very first thing that happens inside the [if] block is that we change the value of the ‘Collision Occurred’ attribute to True, and then we print the message to the console. Next time the collision occurs (which, as we know, is instantaneously), the [if] block checks the value of the attribute again but, this time, it is already set to True, so that code inside the [if] block will not run! Perfect!
If you haven’t already done so, test the game, ensure that you enable the console and make the monkey collide with the pineapple. As you will see, the ‘Bang!’ message will only appear once.
Okay, Maybe Not So Perfect!
Life’s never so easy is it. At least, the life of a game-coder is never so easy! I am fairly certain that, when testing the game, you will have caused a collision and seen the ‘Bang!’ message, and then you have moved the monkey away from the pineapple and tried to make the collision occur again. If you didn’t do that, try it now!
You will have noticed that the message is only displayed once, and it will never be displayed again!
It’s possible that, in your game, you really do only want the collision to occur once and, if that is the case, that is the problem solved for you. However, for the rest of us, there is more work to do! In many cases, you probably need to detect the collision every time the monkey hits the pineapple – not just once!
As ever, there are many ways to solve this problem, but I am just going to show you one method. I’m going to give the monkey a couple of seconds to get away from the deadly pineapple before the next collision can be detected, and you’ll be pleased to know that this is a very straightforward process…
Setting a Timer to Reset the Attribute
I guess I’ve given the game away already, but we’re going to set a timer to reset the attribute! The code to achieve this is shown below:
Try the game now and you will find that when you collide with the pineapple, the collision message will appear in the debug console only once. If you move the monkey away from the pineapple and then move it back to cause another collision, a second collision message will appear, and so on. There is a disadvantage to this method in that, if you leave the monkey so that it is permanently colliding with the pineapple, the message will appear every two seconds. However, in normal gameplay, if the player hits the enemy and gets a signal that it is a bad thing (a sound and/or health depleting), they are going to move the monkey away from the enemy quite quickly and, if they don’t, they are going to see that Game Over message quite quickly!
I’ve just provided the bare bones of the solution, and I can’t possibly provide an answer for every possibility, but this method is a very common solution to many of the ‘trigger’ problems that arise when creating a game and, if you consider your options, you will find that, one way or another, the process of setting and possibly resetting an attribute will provide the essence of the solution to similar problems.
Incidentally, this method of preventing repeating actions is one example of what is often referred to by programmers as ‘setting a flag‘. The ‘flag’ is the attribute and it is either on or off (True or False) so, if you have seen people writing about ‘flags’, you now know what they mean (unless you’ve been visiting vexillology websites, in which case they are actually talking about flags!).
The Inevitable Exceptions
Of course, there are always exceptions, and these will take more effort. An example of a more ‘sophisticated’ method that I have considered (but not tested) is the use of moveable regions. A brief summary would be:
Create a region that always follows the player (see Stencylpedia!)
Use the [if actor enters region] block to set the collision attribute
Use the [if actor exits region] block to reset the collision attribute
The above method requires more effort, but it may be able provide more accurate detection of whether or not a collision is occurring at any specific time, taking into consideration that setting collision bounds for a region is less flexible than setting them for an actor.
As ever, feedback is welcome, and do let me know if you have used different or better solutions for solving the same problem.
Finally, I must thank Vicki Wenderlich for creating the free game assets. Do visit her website for more wonderful, free game assets (and tell her I sent you)!
Please note, that this article has been recovered from archives, and we regret that comments prior to the archive retrieval are not shown. We thank previous contributors, and apologise for being unable to display your comments. New comments can be added.