The Daily Click ::. Forums ::. Klik Coding Help ::. Need some help following an article.
 

Post Reply  Post Oekaki 
 

Posted By Message

Deleted User
5th January, 2009 at 04:05:51 -

http://www.create-games.com/article.asp?id=1761

I think the author kind of just skips a few steps, well to me. Especially the part where he talks about collecting underpants and then jumping all the way to profit.

But seriously, as far as the angles are concerned, I'm not sure how you're supposed to actually determine what is the AI's angle of sight, maybe I missed it, but I'm lost. Also, I'm not exactly getting how to get the detector to just be an XY value. I set two alterable values on my AI's character, but I don't know how it's supposed to detect collisions.

Help?

 

Deleted User
5th January, 2009 at 23:57:15 -

Ba bum bump bump.

 

Sketchy

Cornwall UK

Registered
  06/11/2004
Points
  1960

VIP MemberWeekly Picture Me This Round 43 Winner!Weekly Picture Me This Round 47 WinnerPicture Me This Round 49 Winner!
6th January, 2009 at 02:18:52 -

Yeah, that article's a little harder to follow without the diagrams

As some people point out in the comments at the bottom, the article does some things in the wrong order, making it less efficient than it could be.

I'm going to describe it as though there is just one enemy, and one player, to keep things simple - in practice, you would need to use fastloops to check the line-of-sight between every combination of enemy and player objects.



DISTANCE

Anyway, contrary to the order of the original article, the first thing you need to do, is calculate the distance between the enemy and the player (you do this first because MMF can calculate it quickly, and it will immediately "rule-out" a lot of objects).

The easy way to calculate the distance is to use Pythagoras' theorum:

Distance("Enemy") = SQR(((X("Enemy") - X("Player")) POW 2) + ((X("Enemy") - X("Player")) POW 2))

Alternatively, you can use an extension, or there is a more complicated but slightly faster forumla in my article "Useful Formulae".

Once you've found the distance, you compare it to your enemy's maximum vision range. If the player is too far away, it means they remain undetected. There is no need then to continue checking the angles / obstacles etc. If you have multiple enemies, you move immediately onto the next one, and start over.


ANGLE

Assuming the enemy doesn't literally have eyes in the back of their heads, you want them only to see the player whilst they are more or less infron of them. If you've ever played "Commandos: Behind Enemy Lines" then you'll know exactly what I'm talking about.

The first thing you need to do, is find the angle from the enemy to the player - I'm calling it "Bearing" to stop things getting confusing later on.

Bearing("Enemy") = ATan2(Y("Player") - Y("Enemy"), X("Enemy") - X("Player"))

I may have got the player and enemy the wrong way round in that formula? Again, the Advanced Direction extension makes it much easier.

Now, you need to compare that to the enemy's heading. Let's say anything within 45 degrees either side of the direction in which they are facing, might be visible.

If Bearing("Enemy") < EnemyHeading - 45

or

If Bearing("Enemy") > EnemyHeading + 45

...then the player is not within their field of view. Again, there is no need to move onto the final step.


OBSTRUCTIONS

If you wan't only background objects marked as "obstacle" to block the line of sight, then you don't need to use detectors (you can use the "collision mask" instead). Otherwise, detectors will be required, but it's really not a problem. I'm going to assume you're doing the former.

You need to use fastloops and some simple trigonometry for this.

Since we're not using detectors, we need to store some things in alterable values / counters / etc.

Always(?) (probably "always" would make the game run too slow - experiment)
* start fastloop("Scan"), "Distance("Enemy") / "Accuracy") times
* set flag0 to "off"

On Loop("Scan")
* set XScan to X("Enemy") + (Cos(Bearing("Enemy"))*LoopIndex("Scan")*Accuracy)
* set YScan to Y("Enemy") - (Sin(Bearing("Enemy"))*LoopIndex("Scan")*Accuracy)

If XScan,YScan is an obstacle (use the collision mask, under "storyboard controls")
* stop fastloop("Scan")
* set flag0 to "on"

If flag0 is "on"
* -> a clear line-of-sight does not exist (player is not detected)

In case you're not familiar with it, "LoopIndex" is just a variale to tell you how many times the fastloop has repeated so far.

Using an "accuracy" value makes the process more efficient. The larger the number, the faster it will work, but the more likely it will be to fail to detect small obstructions. A value of 1 will check every single pixel between the enemy and the player - however a value of 5+ is probably sufficient.

If you want to use detectors, just set their position to XScan, YScan and detect for collisions in the normal way.

Also, Pixelthief made a really good line-of-sight example, that's definitely worth a look.

Now I need to go throw up (forgot I had a mild peanut allergy )


Edited by Sketchy

 
n/a

Deleted User
6th January, 2009 at 07:09:30 -

Oh god, thank you. That explains things alot better. I was going about it all wrong. The author gave no indication to weather or not the line of sight was a condition or a product. I got most of it down pat now, although I have to change some of my code up because apparantly I've got it backwards, instead of checking if there is line of sight, it seems you're leaning more towards if the enemy does not. I was pretty sure the obstacle check was in the wrong spot, I haven't even really tinkered with it yet, but eh, who knows. Thanks again.

 

Sketchy

Cornwall UK

Registered
  06/11/2004
Points
  1960

VIP MemberWeekly Picture Me This Round 43 Winner!Weekly Picture Me This Round 47 WinnerPicture Me This Round 49 Winner!
6th January, 2009 at 13:29:01 -

A couple of corrections:


Always(?) (probably "always" would make the game run too slow - experiment)
* set flag0 to "off"
* start fastloop("Scan"), "Distance("Enemy") / "Accuracy") times


On Loop("Scan")
* set XScan to X("Enemy") + (Cos(Bearing("Enemy"))*LoopIndex("Scan")*Accuracy)
* set YScan to Y("Enemy") - (Sin(Bearing("Enemy"))*LoopIndex("Scan")*Accuracy)

On Loop("Scan")

+ If XScan,YScan is an obstacle (use the collision mask, under "storyboard controls")
* stop fastloop("Scan")
* set flag0 to "on"

If flag0 is "on"
* -> a clear line-of-sight does not exist (player is not detected)


I've also noticed another potential problem with the Angle part - if heading is say, 30 degrees, the player should be visible if bearing = 310. However, 310 > 30+45 so it wouldn't be.
Instead, you need to find the difference between Bearing and Heading:

If Abs(((Bearing - Heading + 540) mod 360) - 180) > 45
* -> player is outside enemy field of view

Sorry to make it confusing again

Edited by Sketchy

 
n/a

Deleted User
6th January, 2009 at 16:24:53 -

Oh no, I'm following you completely. The only thing I'm not familiar with is the collision mask. What exactly is that? And what's the difference between or filtered and or logical?

Edited by an Administrator

 

Sketchy

Cornwall UK

Registered
  06/11/2004
Points
  1960

VIP MemberWeekly Picture Me This Round 43 Winner!Weekly Picture Me This Round 47 WinnerPicture Me This Round 49 Winner!
6th January, 2009 at 16:53:10 -

The collision mask is a feature built into MMF, that works kind of like a detector object.

You can look for it under the "storyboard controls" (the chessboard icon in the event editor).

It provides two conditions; "Is Obstacle" and "Is Ladder". Both of these ask for an X- and Y- coordinate. They then check those screen coordinates to see whether there is an obstacle (or ladder) there. Both conditions can of course be negated (ie. "Is NOT Obstacle").

The other way to use the collision mask, is to retrieve the "Value of collision mask".

CollisionMask(>Enter X coordinate<, >Enter Y coordinate<

Again, this checks the coordinates you specified. If there are no obstacles there, it returns "0". If there is an obstacle it returns "1". If there is a ladder, it returns "2".

It can't detect active objects - for that you'd need to use detectors.
Hopefully clickteam will fix that sometime - I'd like it to return the fixed value of an active if one is present.

Filtered/logical - No idea. Never really understood that, so I don't worry about it. Does it say in the help file?

Edited by Sketchy

 
n/a

Deleted User
6th January, 2009 at 16:58:07 -

Alright, the angles lost me again.

"I've also noticed another potential problem with the Angle part - if heading is say, 30 degrees, the player should be visible if bearing = 310. However, 310 > 30+45 so it wouldn't be.
Instead, you need to find the difference between Bearing and Heading:

If Abs(((Bearing - Heading + 540) mod 360) - 180) > 45
* -> player is outside enemy field of view"

It makes perfect sense, but I have no idea where I'm supposed to plug everything in. I have the Bearing figured everytime the player enters within 200 pixels of the enemy and then it calculates the viewing angle by the Absolute value formula then a separate condition checks that if the player is within 200 pixels and the viewing angle is lower than 45 than the character is within view.

 

Sketchy

Cornwall UK

Registered
  06/11/2004
Points
  1960

VIP MemberWeekly Picture Me This Round 43 Winner!Weekly Picture Me This Round 47 WinnerPicture Me This Round 49 Winner!
6th January, 2009 at 17:07:52 -

Ok, once the player is within 200 pixels;

* calculate bearing using an extension or
Bearing("Enemy") = ATan2(Y("Player") - Y("Enemy"), X("Enemy") - X("Player"))

* calculate difference between heading and bearing
Abs(((Bearing - Heading + 540) mod 360) - 180)

-> if this value is >45, the player is outside the field of view.


-------------------------------------------------
This part we ge rid of altogether:

If Bearing("Enemy") < EnemyHeading - 45

or

If Bearing("Enemy") > EnemyHeading + 45


 
n/a

Deleted User
6th January, 2009 at 17:14:17 -

You see, I got it backwards again. I did just that, but instead of it being outside of the view, I said it was inside of the view. Duy.

 

Sketchy

Cornwall UK

Registered
  06/11/2004
Points
  1960

VIP MemberWeekly Picture Me This Round 43 Winner!Weekly Picture Me This Round 47 WinnerPicture Me This Round 49 Winner!
6th January, 2009 at 17:25:20 -

If you don't mind waiting a day or so, I could probably make an example, if you want (I'm quite tempted to make a massively simplified Commandos:BEH clone myself).

Edited by Sketchy

 
n/a

Deleted User
6th January, 2009 at 18:12:48 -

I don't mind. I think I've got it okay, but just in case that might be pretty good to look at.

 

Deleted User
6th January, 2009 at 20:01:37 -

Agh. Everything works except the angle thing. I'm debuging it and it comes up with all kinds of large numbers, but it's like the AI notices my player no matter where he's looking.

EDIT: Here's my current Code

Detection process
Always
--Distance Algorithm
--set flag 1 off
Pick one enemy with a distance of less than or equal to 200
--Calculate Beariing
--Calculate Viewing Angle
--set flag 2 off
Pick one enemy over the distance of 200 and internal flag 1 off
--set internal flag 1 on
Pick one enemy with a viewing angle less than 45 and internal flag 2 off
--set internal flag 2 on
If internal flag 1 and 2 are off
--start scan loop
--set internal flag 0 off
On loop scan
--Set the detector x and y
On loop scan when detector touches obstacle
--stop loop scan
--set internal flag 0 on
if flags 0 1 2 are off and no targets
--create target at player
if flags 0 1 2 are off and there is a target
--center target at player



Edited by an Administrator

 

Sketchy

Cornwall UK

Registered
  06/11/2004
Points
  1960

VIP MemberWeekly Picture Me This Round 43 Winner!Weekly Picture Me This Round 47 WinnerPicture Me This Round 49 Winner!
6th January, 2009 at 22:09:25 -

Well, I made an example but my usual filehost is down, so I emailed it you (at the address in your profile).
Hope it helps

 
n/a

-J-



Registered
  05/10/2008
Points
  228

VIP MemberThe Cake is a Lie
6th January, 2009 at 22:12:19 -

It's good to know the differences between the Filtered and Logical OR operators, it doesn't really seem like much of a difference but it can be really useful in some situations

So here they are, I'll explain Logical OR's first as they're easier:

Logical:

----------------------------------------------
+User clicks with left button on "apple"
+ OR (Logical)
+User clicks with left button on "orange"

> Destroy apple
> Destroy orange
----------------------------------------------

In this event, if the user clicks either the apple or the orange, both of them will be destroyed. The OR Logical operator makes all the actions occur if the conditions above and/or below are true. If the user clicked the apple and the orange at the same time, both would still be destroyed. This would have the same outcome if you used the OR Filtered operator...


Filtered:

----------------------------------------------
+User clicks with left button on "apple"
+ OR (Filtered)
+User clicks with left button on "orange"

> Destroy apple
> Destroy orange
----------------------------------------------

In this event, if the user clicked the apple then only the apple will be destroyed! Same goes for orange, so no matter which fruit the user clicks, the one that is clicked will be the only one destroyed. The filtered OR operator will go through all the conditions of the event, and mark all the conditions as "inspected". The conditions that have returned false are also marked, but the action related to them will not occur. So only the actions related to the true condition above or below the OR Filtered operator will occur. Which also means that if the conditions on both sides of the OR Filtered operator return true, then every event will occur. So if the player clicks the apple and the orange at the same time, both will be destroyed, which would give the same outcome no matter which OR operator you used.

 
n/a ...
   

Post Reply



 



Advertisement

Worth A Click