Game Development Community

Adding line of sight to the AIProximityAttackComponent from the book

by Brandon · in Torque X 2D · 01/17/2009 (11:09 pm) · 7 replies

I've worked up some code that adds line of sight to the AIProximityAttackComponent that of course I got from the book. Thought I'd share in case anyone else wants to do the same thing.

In short all you have to do is get the angle to the target and the rotation angle (or facing direction angle) take the abs difference between them and compare it against your own angles.

Thanks to John K. and The complete guide to torque X book for the code that makes this pretty dang easy.

Here is what I changed/added to the _UpdateAttack method:

//determine the distance
            float xDist = System.Math.Abs(_sceneObject.Position.X - _targetObject.Position.X);
            float yDist = System.Math.Abs(_sceneObject.Position.Y - _targetObject.Position.Y);
            double Distance = System.Math.Sqrt(xDist * xDist + yDist + yDist);


             float angle = T2DVectorUtil.AngleFromTarget(_sceneObject.Position,
                _targetObject.Position);

            // dont face target until you are attacking it
            if (_attackInProgress == true)
            {
                // set the rotation of our ship
                _sceneObject.Rotation = angle;
            }

            float lineOfSight = _sceneObject.Rotation; 

            float differenceAngle = Math.Abs(lineOfSight - angle);
           
            //if the target is 180 degrees in front and within the attack distance
            if ((differenceAngle <= 90 || differenceAngle >= 270) && Distance <= _attackDistance)
                _inSight = true;

            // else if the target is behind and much closer
            else if ((differenceAngle > 90 && differenceAngle < 270) && Distance <= (_attackDistance / 4))
                _inSight = true;
               
            else
                _inSight = false;

             if (_inSight == true)
                 //attack!
Took me a couple of hours to figure this out so I figured I'd post it in case anyone else gets to the point in the book where John mentions doing this and checks the forums.

The next step would be to check if any walls are between the enemy and the target before making _inSight = true

Also the angles I'm comparing against are not perfect.. I just played with the values until I got something that I am OK with for now.


#1
01/18/2009 (10:50 am)
Nice! I've been working on this as well, specifically the part about checking for walls in the line of sight. Will post something when I have it working.
#2
01/18/2009 (3:26 pm)
Okay, this is what I have so far. It's only a theory but I wanted to get some input from people here.

We'll start with some nomenclature.

Actor: The scene object doing the detecting.

Detectable Object: The scene objects the actor detects.

Detectable Range/Area: The area in which the actor will detect detectable objects.

Field of View: The area the actor "sees". The is a sub-area of the detectable area.

Line of Sight: The straight line between the actor and a detectable object. This can be blocked by something like a wall.

Blocking Object: An object that blocks the actor's line of sight.

---

The goal here is to get all detectable objects that are within the actor's field of view AND in the actor's line of sight. In practice this means something like only the detectable objects in front of the actor that aren't behind a wall or some other line-of-sight-blocking object.

We'll start by getting all detectable objects withing the actor's field of view.

blog.warkittensoftware.com/wp-content/gallery/third-law-field-of-view/tracking-fov.png
Referencing the above image, we'll detect everything in the dark gray area. This will be accomplished by:

1. Finding all objects within range of the actor (the light gray area).
2. Taking all the objects from 1 and eliminating the ones behind the actor.
3. Create a quadrilateral (you'll see why a quadrilateral in a bit) with two points on the actor and two points at the edge of the range. This is the dark gray area.
3.1. Eliminate all objects from 2 that are outside of the quadrilateral created in 3.

We now have all detectable objects within our actor's field of view. But what if we have something like a wall between our actor and a detectable object.

blog.warkittensoftware.com/wp-content/gallery/third-law-field-of-view/tracking-blocked-fov.png
In this scenario we'd also need to:

4. Detect blocking objects like walls.
5. We can then draw a quadrilateral from the top and bottom of each blocking object (the diagonal area in the above image).
6. We then eliminate all detectable objects from the quadrilateral(s) in 5.

So at the end of all of this we have all the scene objects that are within the actor's detectable range that are also in its line of sight.

I think the process could use a bit of refinement with an eye toward optimization but I think the theory is sound. Thoughts?
#3
01/18/2009 (10:57 pm)
Brandon, this is really good!!!

Sean, great summary for expanding this. I think your outline makes perfect sense. It seems like the code is going to be much easier than it sounds. Just perform the check a few times over within the smaller "visible" angles. The only concern is the poerformance cost of this iterative searching, especially if it's done on a per-tick basis.

John K.
www.envygames.com
#4
01/18/2009 (11:04 pm)
I agree on the performance cost. It will almost definitely be too high, particularly if you aim to have lots of objects on the screen all making use of it.

Right now I'm thinking ray tracing may be a more efficient method. Will post some code in a bit (hopefully).
#5
01/19/2009 (10:18 am)
Here's what I have so far: visioncomponent.zip.

That zip contains two files: VisionComponent.cs and ViewingQuad.cs. ViewingQuad defines a quadrilateral and provides a method to test if a point lies within it. VisionComponent creates a ViewingQuad based on the actor's location and viewing properties (field of view, etc).

Right now it's kinda-sorta working. VisionComponent definitely finds objects just not the ones I expect. For example, it will find objects behind the player's actor, but the quad I'm building should be in front of the actor.

I've been looking at this for hours and I'm thinking I have a logic error somewhere as I believe the code is fundamentally sound. So I'm posting it here in the hope that someone else with fresh eyes can take a look-see and help me out.
#6
01/19/2009 (2:40 pm)
Couldn't you add an ObjectType which defines an object as "obstructive", in other words things behind it are hidden. Then do a ray from origin to target and check if there are objects of this type in the ray's path. If so block the target. This is obviously vague, and object size would need to be applied, but if you grouped obstructive objects into small, medium and large you could put up some rough code on how much they obstruct based on how far away the target object is.

Did that only make sense to me? Or is that already what you are getting at? I will be tackling this in a couple of weeks as well for casting spells at targets so I will update when I get there and test it. Maybe we can compare FPS =)

R.H.
#7
01/19/2009 (3:10 pm)
@Rich

That makes absolute sense to me. You'd just have to cast rays to the top and bottom of your obstructive object. I'm defining SolidPlatforms (from the PSK) as obstructive types as I'm not allowing characters to shoot or jump through them so it makes sense that they would block line of sight.

I think ray tracing is probably going to yield the fastest results. I had thought about creating a collision polygon representing the viewable area and then cutting out obstructed areas, but you can't do concave collision polys in TX.

Hmmm...Thinking about it a bit further as I type this. I guess you could create a collision poly that represents the viewable area then create obstructed collision polys coming off each obstruction. Then any detectable type that is colliding with the viewable area and not the obstructed area would be "seen".

Doing collisions like that would probably be much faster as you'd only ever do processing when some object has the potential to be seen rather than continually searching the viewable area for detectable objects.