Mercurial > projects > openmelee
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;