Right, this is my first article for some time now, so cut me some slack if it's a little botched, heh.
[size:20pt]QUICK SINGLE-TO-MANY LOS TESTS[/size]
This article is written to help you create fast 'single-to-many' LOS tests. This is ideal for situations where one object must test for a line of sight to many objects.
Your most common use of this I'll wager would be in standard one-player games where the player controls one object and battles multiple enemies (so any platformer, RPG, that kind of thing).
Right, so I think that's enough to let you know where we're aiming at, now let's get onto how it works.
[size:17pt]WHY IS IT QUICK?[/size]
I think it's becoming common knowledge now that I really don't like fast loops. I mean they're alright, but they're not the fastest thing out there when it comes to iterations.
The fastest thing I've found so far is Action Loops. Not event loops, might I add - those are slow as hell, and the reason they invented Fast Loops.
Action loops are the little hidden loops that repeat your actions for each object selected by the conditions. So for an example, we have 50 objects and we do thus:
--- Object: Set speed to 20
One event, yes, but it's actually FIFTY loops. The condition is a kind of setup to decide how many objects we'll operate on, and the actions are repeated for each one. And did I mention that they're blisteringly fast?
This is the technology that will make this system quick. We'll use fastloops, of course - but only where necessary. The bulk of it (the entire object-moving process in fact) will be done using Action Loops. You'll see what I mean by all this as we go on.
The setup is important. In our worked example, we have one player object, and he has 100 NPCs in his world, all of whom need to be LOSsed.
We will create 100 detectors (please don't switch off right now, I know detectorless is all the rage, and maybe you can work on that yourself, but for now just bear with me and make the detectors). So each instance of the NPC type will have an instance of the DETECTOR type.
For every NPC *and* every DETECTOR, we give them an alterable string and name it something like "Can be seen". Note that this could just as well be a flag or value, but I'm using alterable strings here for readability.
So the 'NPC' object type will have a 'Can be seen' property, and the 'DETECTOR' type will also have a 'Can be seen' property.
The objects must assume that they CAN be seen by default, so our first event is:
Next, we start a fast loop. Now the lines traced by the LOS in this example are relative. So unlike many systems which move a detector, say, 3px per step, this system will move all the detectors by a certain percentage, so the step will be larger or smaller depending on the distance between the player and the NPC. It's avoidable, but this article just shows a proof of concept really.
// All detectors and enemies default to visible:
--- Detector: Set 'Can be seen' to "YES"
--- Enemy: Set 'Can be seen' to "YES"
I've decided that 260 steps is sufficient to my purpose, so I'll start a fastloop with my next event line:
Now for the actual loop code. This will use object selection (Action Loops) to move all 100 detectors one step at the same time. Observe:
--- System: Start loop "MAIN LOOP" 260 times
This finds how much of the loop has already been done ((loopIndex + 1) / 260.0) and returns it as a fraction. This fraction is applied to the distance between the player and the detector (X("PLAYER") - Y("DETECTOR")). That then is added to the player position (the starting point).
ON Loop "MAIN LOOP"
--- Detector: Set X position to:
X("PLAYER") + (X("PLAYER") - X("DETECTOR"))
* (loopIndex + 1) / 260.0
--- Detector: Set Y position to:
Y("PLAYER") + (Y("PLAYER") - Y("DETECTOR"))
* (loopIndex + 1) / 260.0
Object selection naturally pairs objects of two types, so Detector #1 will inherently be paired with NPC #1, and it all works like Noah's Ark (#and the animals went in two by two, hurrah! hurrah!#). Neatly giving us a loop of 100 objects which executes much quicker than a fastloop performing the same function.
Next we need to test if we encounter obstacles on the way:
Again, our event processes them all in one go here, much quicker.
ON Loop "MAIN LOOP"
+ Detector: Overlaps Obstacle
--- Detector: Set 'Can be seen' to "NO"
Finally, we're done with the fast loop. We now have 100 Detectors who carry with them the seen/unseen values of their mate. All that's left to do is copy this data from the Detector to the NPC.
Again, object selection pairs them off so each NPC reads his own detector.
--- NPC: Set 'Can be seen' to:
Can be seen("DETECTOR")
Aaaaaand we're done. View the attached example if you wish, as it also contains a more optimised example of this which uses specific steps in pixels rather than ratios.
(NOTE: Example requires Clickteam movement controller extension)