diff ai/steer.d @ 24:441eb7672404

impleneted steer to avoid
author zzzzrrr <mason.green@gmail.com>
date Fri, 27 Mar 2009 16:05:24 -0400
parents e79347dd38a3
children 88cca12cc8b9
line wrap: on
line diff
--- a/ai/steer.d	Thu Mar 26 20:35:58 2009 -0400
+++ b/ai/steer.d	Fri Mar 27 16:05:24 2009 -0400
@@ -33,6 +33,7 @@
 module openmelee.ai.steer;
 
 import tango.io.Stdout : Stdout;
+import tango.util.container.LinkedList : LinkedList;
 
 import blaze.common.bzMath: bzDot, bzClamp, bzVec2;
 import blaze.collision.shapes.bzShape : bzShape;
@@ -41,12 +42,19 @@
 
 import openmelee.ships.ship : Ship, State;
 import openmelee.ai.utilities;
+import openmelee.ai.ai : Threat;
+
+alias LinkedList!(Ship) ObjectList;
 
 class Steer 
-{
+{
+
+    ObjectList objectList;
+    
     // Constructor: initializes state
-    this (Ship ship)
-    {
+    this (Ship ship, ObjectList objectList)
+    {
+        this.objectList = objectList;
         m_ship = ship;
         m_body = ship.rBody;
     }
@@ -132,250 +140,79 @@
         bzVec2 avoidance = obstacle.steerToAvoid (this, minTimeToCollision);
         return avoidance;
     }
-
-    // avoids all obstacles in an ObstacleGroup
     */
-    
-    bzVec2 steerToAvoidObstacles (float minTimeToCollision, bzBody obstacles) {
-
-        bzVec2 avoidance;
-        PathIntersection nearest, next;
-        float minDistanceToCollision = 10; //minTimeToCollision * m_speed;
-        
-        next.intersect = false;
-        nearest.intersect = false;
-
-        // test all obstacles for intersection with my forward axis,
-        // select the one whose point of intersection is nearest
-        for (bzBody o = obstacles; o; o = o.next) {
-            
-            if(o is m_body) continue;
-            
-            // This code which presumes the obstacle is spherical
-            findNextIntersectionWithSphere(o, next);
-
-            if (!nearest.intersect || (next.intersect && next.distance < nearest.distance)) {
-					nearest = next;
-            }
-        }
-        
-        // when a nearest intersection was found
-        if (nearest.intersect && (nearest.distance < minDistanceToCollision)) {
-            // compute avoidance steering force: take offset from obstacle to me,
-            // take the component of that which is lateral (perpendicular to my
-            // forward direction), set length to maxForce, add a bit of forward
-            // component (in capture the flag, we never want to slow down)
-            bzVec2 offset = m_position - nearest.obstacle.position;
-            avoidance = perpendicularComponent(offset, m_forward);
-            avoidance.normalize;
-            avoidance = m_body.localPoint(avoidance);
-            ///avoidance *= m_maxForce;
-            //avoidance += m_forward * m_maxForce * 0.75f;
-        }
-
-        auto state = cast(State) m_body.userData;
-        state.avoid = avoidance;
-        return avoidance;
-    }
     
-    bzVec2 getSteering(bzBody obstacles) {
+    // Steer to avoid
+    void collisionThreat(inout Threat threat, float maxLookAhead = 10.0f) {
 
         // 1. Find the target that’s closest to collision
-
+        
         float radius = m_radius;
-        float rad;
-        // Store the first collision time
-        float shortestTime = 0.5;
+        float rad = 0.0f;
+        float shortestTime = float.max;
+    
+        // Loop through each target
+        foreach(obstacle; objectList) {
 
-        // Store the target that collides then, and other data
-        // that we will need and can avoid recalculating
-        bzBody firstTarget = null;
-        float firstMinSeparation = 0;
-        float firstDistance = 0;
-        bzVec2 firstRelativePos;
-        bzVec2 firstRelativeVel;
-        bzVec2 relativePos;
-        
-        // Loop through each target
-        for (bzBody target = obstacles; target; target = target.next) {
-
+            bzBody target = obstacle.rBody;
+            
             if(target is m_body) continue;
             
             // Calculate the time to collision
-            relativePos = m_body.localPoint(target.position); // - m_position;
-            bzVec2 relativeVel = target.linearVelocity - m_velocity;
+            bzVec2 relativePos = target.position - m_position;
+            bzVec2 relativeVel = m_velocity - target.linearVelocity;
             float relativeSpeed = relativeVel.length;
-            float timeToCollision = bzDot(relativePos, relativeVel) /
+            // Time to closest point of approach
+            float timeToCPA = bzDot(relativePos, relativeVel) /
                                     (relativeSpeed * relativeSpeed);
-
-            // Check if it is going to be a collision at all
+                            
+            // Threat is separating 
+            if(timeToCPA < 0) {
+                continue;
+            } 
+            
             float distance = relativePos.length;
-            float minSeparation = distance - relativeSpeed * shortestTime;
+            
+            // Clamp look ahead time
+            timeToCPA = bzClamp(timeToCPA, 0, maxLookAhead);
             
-            float eRad;
-            for (bzShape s = target.shapeList; s; s = s.next) {
-                if(s.sweepRadius > eRad) {
-                    eRad = s.sweepRadius;
-                }
-            }
+            // Calculate closest point of approach
+            bzVec2 cpa = m_position + m_velocity * timeToCPA;
+            bzVec2 eCpa = target.position + target.linearVelocity * timeToCPA;
+            relativePos = (eCpa - cpa);
+            float dCPA = relativePos.length;
                 
-            if (minSeparation > radius + eRad) continue;
+            // No collision
+            if (dCPA > radius + obstacle.state.radius) continue;
 
-            // Check if it is the shortest
-            if (timeToCollision > 0 && timeToCollision < shortestTime) {
-                
-                // Store the time, target and other data
-                shortestTime = timeToCollision;
-                firstTarget = target;
-                firstMinSeparation = minSeparation;
-                firstDistance = distance;
-                firstRelativePos = relativePos;
-                firstRelativeVel = relativeVel;
-                rad = eRad;
+            // Check if it's the closest collision threat
+            if (timeToCPA < shortestTime && dCPA < threat.minSeparation) {
+                shortestTime = timeToCPA;
+                threat.target = obstacle;
+                threat.distance = distance;
+                threat.relativePos = relativePos;
+                threat.relativeVel = relativeVel;
+                threat.minSeparation = dCPA;
+                rad = obstacle.state.radius;
             }
         }
         
         // 2. Calculate the steering
 
         // If we have no target, then exit
-        if(!firstTarget) return bzVec2.zeroVect;
-
-        Stdout(shortestTime).newline;
+        if(!threat.target) return;
         
         // If we’re going to hit exactly, or if we’re already
         // colliding, then do the steering based on current
         // position.
-        if(firstMinSeparation <= 0 || firstDistance < radius + rad) {
-            relativePos = firstTarget.position - m_position;
-        } else {
+        //if(threat.minSeparation < m_radius || threat.distance < radius + rad) {
+            //threat.steering =  m_position - threat.target.state.position;
+        //} else {
             // Otherwise calculate the future relative position:
-            relativePos = firstRelativePos + 
-                          firstRelativeVel * shortestTime;
-        }
-
-        // Avoid the target
-        bzVec2 steering = relativePos;
-        steering.normalize();
-        //steering.linear = relativePos * maxAcceleration
-
-        return steering;
+            threat.steering = threat.relativePos; 
+        //}
     }
 
-    bzVec2 avoid(float maxLookAhead, bzBody obstacles) {
-        
-        float avoidMargin = 1.0f;
-        float maxLookahead = maxLookAhead * m_speed;
-        
-        // Make sure we're moving
-		if (m_velocity.length > 0)
-		{
-            for (bzBody o = obstacles; o; o = o.next) {
-            
-                if(o is m_body) continue;
-                
-                // Find the distance from the line we're moving along to the obstacle.
-                bzVec2 movementNormal = m_velocity;
-                movementNormal.normalize();
-                bzVec2 characterToObstacle = o.position - m_position;
-
-                real distanceSquared = bzDot(characterToObstacle, movementNormal);
-                distanceSquared = characterToObstacle.lengthSquared - distanceSquared*distanceSquared;
-
-                // Check for collision
-                float oRad = 0;
-                for (bzShape s = o.shapeList; s; s = s.next) {
-                    if(s.sweepRadius > oRad) {
-                        oRad = s.sweepRadius;
-                    }
-                }
-                
-                real radius = oRad + avoidMargin;
-                if (distanceSquared < radius*radius)
-                {
-                    // Find how far along our movement vector the closest pass is
-                    real distanceToClosest = bzDot(characterToObstacle, movementNormal);
-                    
-                    // Make sure this isn't behind us and is closer than our lookahead.
-                    if (distanceToClosest > 0 && distanceToClosest < maxLookahead)
-                    {
-                        // Find the closest point
-                        bzVec2 closestPoint =  o.position + movementNormal * distanceToClosest;
-
-                        // Find the point of avoidance
-                        bzVec2 target = o.position + (closestPoint - o.position).length * radius;
-
-                        target -= m_position;
-                        
-                        auto state = cast(State) m_body.userData;
-                        state.avoid = m_body.localPoint(target);
-
-                        return target;
-                    }
-                }
-            }
-		}
-        
-        auto state = cast(State) m_body.userData;
-        state.avoid = bzVec2.zeroVect;
-                            
-        return bzVec2.zeroVect;
-
-    }
-
-		void findNextIntersectionWithSphere(bzBody obs, 
-                                            inout PathIntersection intersection) {
-                                                
-			// This routine is based on the Paul Bourke's derivation in:
-			//   Intersection of a Line and a Sphere (or circle)
-			//   http://local.wasp.uwa.edu.au/~pbourke/geometry/sphereline/raysphere.c
-            
-			float b, c, d, p, q, s;
-			bzVec2 lc;
-
-			// initialize pathIntersection object
-			intersection.intersect = false;
-			intersection.obstacle = obs;
-
-			// find "local center" (lc) of sphere in coordinate space
-			lc = m_body.localPoint(obs.position);
-
-			// computer line-sphere intersection parameters
-			b = 0;
-            
-            // Find radius of obstacle
-            float obsRadius = 0;
-            for (bzShape shape = obs.shapeList; shape; shape = shape.next) {
-                if(shape.sweepRadius > obsRadius) {
-                    obsRadius = shape.sweepRadius;
-                }
-            }
-        
-			c = square(lc.x) + square(lc.y) - square(obsRadius + m_radius);
-			d = (b * b) - (4 * c);
-            
-			// when the path does not intersect the sphere
-			if (d < 0) return;
-
-			// otherwise, the path intersects the sphere in two points with
-			// parametric coordinates of "p" and "q".
-			// (If "d" is zero the two points are coincident, the path is tangent)
-			s = sqrt(d);
-			p = (-b + s) * 0.5f;
-			q = (-b - s) * 0.5f;
-
-			// both intersections are behind us, so no potential collisions
-			if ((p < 0) && (q < 0)) return;
-
-			// at least one intersection is in front of us
-			intersection.intersect = true;
-			intersection.distance =
-				((p > 0) && (q > 0)) ?
-				// both intersections are in front of us, find nearest one
-				((p < q) ? p : q) :
-				// otherwise only one intersections is in front, select it
-				((p > 0) ? p : q);
-		}
-
     /*
     // ------------------------------------------------------------------------
     // Unaligned collision avoidance behavior: avoid colliding with other
@@ -522,14 +359,7 @@
         return (myFinal - otherFinal).length;
     }
 
-    // ------------------------------------------------------------------------
-    // pursuit of another vehicle ( version with ceiling on prediction time)
-
-    bzVec2 steerForPursuit (State quarry) {
-        return steerForPursuit (quarry, float.max);
-    }
-
-    bzVec2 steerForPursuit (State quarry, float maxPredictionTime) {
+    bzVec2 targetEnemy (State quarry, float maxPredictionTime) {
 
         // offset from this to quarry, that distance, unit vector toward quarry
         bzVec2 offset = quarry.position - m_position;