Various Tricks Involving Movement, Collision and Line of Sight I Devised Over the Years.

Greetings all, I only recently came across your sight and read some of the rather helpful tutorials, many of the general ideas and details of which I came up with myself over the years of playing with the various clickteam products. Each of these expects the reader to have a certain level of knowledge with the slightly more complex aspects of klik coding, such as static movement, collision detectors etc.

Part 1: Anti-aliased static movement

First of these I'll mention is the problem with aliasing when it comes to static movement. Now, this was the problem I had, I would have say, an active object which is meant to move to a target location, and it would have 2 alterable values representing his inertia in the X and Y axis, with an always loop moving it every step according to how much inertia he had.

Now I wanted this object to slow down as it moved until it ground to a halt (imagine having thrown something from a top down view, or a spaceship that just cut it's thrusters and was floating to a halt) and to do this I did it by setting it's inertia to it's current inertia*0.9. In other words, cutting 10% off it's current speed so it's deceleration looked smoothe and gradual. I found, however, it would have an L shaped motion, sorta like this:

Image

Now the problem here is that by cutting 10% off I'm working with fractions and decimals, but I'm converting that into an integer (since pixels cant be divided by two etc.) integer being a whole number with no decimal, of course. Even real time angle and speed calculations fall pray to this, the problem being in simple terms,that as the object gets slow, it should start moving at, say 0.9 pixels (which rounds down to 0) then 0.8 (which rounds down to zero). So it hasn't move any pixels when it should have moved 1.7

For example, lets say we want to halve the distance traveled every frame and start at a speed of 10 pixels per second and want it to continue for say, 7 frames. What we would want would be:

10 + 5 + 2.5 + 1.25 + 0.625 + 0.3125 + 0.15624 = 19.84374 pixels moved
(though it would round down to 19, and very soon 20)

But what would happen is:

10+5+2+1+0+0+0= 18 pixels.

As you can see, it not only cut off the last 10% of the distance traveled, but the movement stopped after the first 4 frames. And since the X and Y inertia values are of different sizes, one reaches the 'less than 1' range much faster the other, and so in that picture example, the Y stops moving before the X, creating that Kinked motion.

Now, to fix this, we need to add decimals to the motion. To do this I have 2 more alterable values, one being XPos and the other YPos. These values are set at the beginning of the frame to the objects current X and Y *100, and all further changes to location are done instead to these two alterable values, but multiplied by a factor of 100. Then on every event loop, I set the objects actual X and Y to it's XPos and YPos *0.01. In other words returning back to integers ONLY for display, the underlying locations are still decimal (accurate to 2 decimal points due to it being multiplied by 100 I doubt you'll see any error at this scale) Resulting in a nice, smooth movement from start to finish.

Image

NEXT!

Part 2: Collision

(Recently found another article explaining the same concept by Dalal at http://www.create-games.com/article.asp?id=1639 , but since I explain it in a slightly different way, I'll leave it in.)

OK, this one I thought up recently, basically, this is a method of cutting down the amount of position testers when doing custom collision detectors.

Most will know the technique, take an object and have several other objects surround it that start complaining when they collide with backgrounds or other objects, like so:

Image

Now the problem with this is now, instead of one object, we have FIVE. Which if you are using this method in a loop so you have multiple actives with custom collision detection going can get quite expansive (10 enemies = 50 actives!). However, you can reduce this to just 2!

If instead you have simply 1 active for the collision detection you can solve this problem. But, the first problem that comes to mind is, how will it tell which direction the collision is from? (helps to know which way the active should bounce, no point it bouncing up when it hits a wall now is there?) To do this, we hold each of the frames from the 4 objects, in 4 different directions:

Image

(object shown grayed out so you can see the locations of each detector)
so you would have something like:

+Always
- set “Collision” direction to Right
+If “Collision” is overlapping the background
- Set Right collision to yes
+If “Collision” is NOT overlapping the background
- Set Right collision to no

+Always
- set “Collision” direction to Down
+If “Collision” is overlapping the background
- Set Down collision to yes
+If “Collision” is NOT overlapping the background
- Set Down collision to no

And repeat for the other 2 directions and what ever other locations you want to test for collision

Now, what this does is flick through each direction and do a collision check all in a row, in one event loop, before it has a chance to draw the collision object, effectively doing the job of just one object.

BUT WAIT, THERE'S MORE!

If you are clever, you could even reduce it to just ONE object be having the collision object simply be an animation of the object you want to test. All you would need to do is note it's current animation, direction and animation speed (preferably in the objects own Avalues) before the collision test and restore them after. With this you would even be able to eliminate the need for a loop, as each object would simply act independently.

And finally

Part 3: Line of sight

This one, as far as I know, requires MMF2, unsure if it's Dev or not, I use Dev myself. It requires the angle and scaling events.

The classic method of line of sight is to have it so that on every frame, a loop is run, where each active will fire a detector projectile from the active, in a straight line to the target, testing locations at X pixel intervals along the path, and throwing an event when either it hits an obstacle (no line of sight) or the target(line of sight). Now, this I thought was pretty cumbersome. So this was my solution.

First off, take an object, make it 1 pixel by 1 pixel in size, color it blue.
Second, set it's hot spot to be on that very same singular pixel.
Third, use a fast loop to assign each of the enemy targets one of these pixels
(it's a good idea to use the same loop to have objects pass any relevant information back to the parent object during the same loop, such as if the object is obscured or not, I'll get back to this)

Next, (going to need the direction calculator for this one) do something like this:

+ always
- Set Xscale of“LoSPixel” to Distance(LoSPixel, Target, quality 0) (Direction calculator event)
- Set Angle of“LoSPixel” to Angle(LoSPixel, Target, quality 0) (Direction calculator event)

This will stretch and rotate the pixel into a line which points from the active, toward the target!
Now, what you get is this (an image of me using this method in a project im working on):

Image

In this example I have the active at the bottom (a hovering bomb that chases the player, red to signify it's angry and chasing the player) The red circle is the test target that it tests line of sight with, the blue line is our stretched pixel. That grey box is an obstacle.

Now what you want is is a small event like so:

+ If “LoSPixel” is overlapping the background
- Set Obscured to Yes
+ If “LoSPixel” is NOT overlapping the background
- Set Obscured to No

This can be repeated for any other obstacle object you might have

Now I said earlier you should pass information gathered by children(in this case our LoSPixel thats following around our active object)to the parents (The active object being followed) during the loop, so in the loop I would have a:

- Set “Active”'s obscured to “LoSPixel”'s obscured.

Thus now the parent object knows whether there's an obstacle in the way or not! Vwallah, here's a pic of it working:

Image

Now what you see it the target up top, the active below (now a calmed blue to show it's no longer pursuing the player) and our LoSPixel (which I set to be colored red when obscured, so I can debug and see if it's working), the obstacle in the way fouling the line of sight!

BUT! There is still one problem!

The angle action seems to have a fairly heavy load, especially when done at a long distance! And by many objects. And so it's good to put constraints. As such I use, for example:

+ If Distance between LoSPixel and Target is less than 250
- Set Xscale of“LoSPixel” to Distance(LoSPixel, Target, quality 0) <-Direction calculator event
- Set Angle of“LoSPixel” to Angle(LoSPixel, Target, quality 0) <-Direction calculator event

Replacing the always command with a range check, thus not bothering with the resize or turning if the target is out of range anyway. Another example could be:

+ If Target is overlapping A Line of sight mask
- etc.

Where you would, for example, have a cone in front of the active that represents it's field of view, only checking for LoS when the player crosses over it.

I found with this method I can rather comfortably have 50+ enemies on screen with accurate Line of sight detection with only a 5-10 frame slow down (running at a default 50fps), which is barely noticeable.

(With some tweaking from Pixelthief's article on writing good code found at http://www.create-games.com/article.asp?id=1937 , I can actually get 100 enemies on screen without it dropping below 40fps, all the while each enemy having accurate and active collision detection)

There is a down side to this however, with this method you cannot detect WHERE the line of sight is blocked, simply that it is blocked (and what's blocking it). Although, the usefulness of knowing where it is blocked is questionable.

Here's an image of it at work:

Image