Mercurial > projects > openmelee
annotate ai/steer.d @ 26:88cca12cc8b9
added ship explode
author | zzzzrrr <mason.green@gmail.com> |
---|---|
date | Fri, 27 Mar 2009 19:26:01 -0400 |
parents | 441eb7672404 |
children |
rev | line source |
---|---|
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
1 /* |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
2 * Copyright (c) 2009, Mason Green (zzzzrrr) |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
3 * http://www.dsource.org/projects/openmelee |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
4 * Based on OpenSteer, Copyright (c) 2002-2003, Sony Computer Entertainment America |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
5 * Original author: Craig Reynolds |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
6 * |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
7 * All rights reserved. |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
8 * |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
9 * Redistribution and use in source and binary forms, with or without modification, |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
10 * are permitted provided that the following conditions are met: |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
11 * |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
12 * * Redistributions of source code must retain the above copyright notice, |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
13 * this list of conditions and the following disclaimer. |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
14 * * Redistributions in binary form must reproduce the above copyright notice, |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
15 * this list of conditions and the following disclaimer in the documentation |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
16 * and/or other materials provided with the distribution. |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
17 * * Neither the name of the polygonal nor the names of its contributors may be |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
18 * used to endorse or promote products derived from this software without specific |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
19 * prior written permission. |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
20 * |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
32 */ |
18 | 33 module openmelee.ai.steer; |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
34 |
19 | 35 import tango.io.Stdout : Stdout; |
24 | 36 import tango.util.container.LinkedList : LinkedList; |
19 | 37 |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
38 import blaze.common.bzMath: bzDot, bzClamp, bzVec2; |
19 | 39 import blaze.collision.shapes.bzShape : bzShape; |
40 import tango.math.Math : sqrt; | |
15 | 41 import blaze.dynamics.bzBody: bzBody; |
42 | |
18 | 43 import openmelee.ships.ship : Ship, State; |
44 import openmelee.ai.utilities; | |
24 | 45 import openmelee.ai.ai : Threat; |
46 | |
47 alias LinkedList!(Ship) ObjectList; | |
0 | 48 |
9 | 49 class Steer |
24 | 50 { |
51 | |
52 ObjectList objectList; | |
53 | |
9 | 54 // Constructor: initializes state |
24 | 55 this (Ship ship, ObjectList objectList) |
56 { | |
57 this.objectList = objectList; | |
19 | 58 m_ship = ship; |
59 m_body = ship.rBody; | |
15 | 60 } |
61 | |
62 struct PathIntersection | |
63 { | |
64 bool intersect; | |
65 float distance; | |
66 bzVec2 surfacePoint; | |
67 bzVec2 surfaceNormal; | |
68 bzBody obstacle; | |
9 | 69 } |
0 | 70 |
9 | 71 // reset state |
72 void reset () { | |
73 // initial state of wander behavior | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
74 m_wanderSide = 0; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
75 m_wanderUp = 0; |
9 | 76 } |
77 | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
78 void update() { |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
79 m_position = m_ship.state.position; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
80 m_velocity = m_ship.state.velocity; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
81 m_speed = m_ship.state.speed; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
82 m_maxForce = m_ship.state.maxForce; |
12 | 83 m_forward = m_ship.state.forward; |
22 | 84 m_radius = m_ship.state.radius; |
9 | 85 } |
0 | 86 |
9 | 87 // -------------------------------------------------- steering behaviors |
0 | 88 |
9 | 89 bzVec2 steerForWander (float dt) { |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
90 // random walk m_wanderSide and m_wanderUp between -1 and +1 |
9 | 91 float speed = 12 * dt; // maybe this (12) should be an argument? |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
92 m_wanderSide = scalarRandomWalk (m_wanderSide, speed, -1, +1); |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
93 m_wanderUp = scalarRandomWalk (m_wanderUp, speed, -1, +1); |
0 | 94 |
9 | 95 // return a pure lateral steering vector: (+/-Side) + (+/-Up) |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
96 return (m_side * m_wanderSide) + (m_up * m_wanderUp); |
9 | 97 } |
0 | 98 |
9 | 99 // Seek behavior |
100 bzVec2 steerForSeek (bzVec2 target) { | |
101 bzVec2 desiredVelocity = target - m_position; | |
102 return desiredVelocity - m_velocity; | |
103 } | |
0 | 104 |
9 | 105 // Flee behavior |
106 bzVec2 steerForFlee (bzVec2 target) { | |
107 bzVec2 desiredVelocity = m_position - target; | |
108 return desiredVelocity - m_velocity; | |
109 } | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
110 |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
111 /* |
9 | 112 // xxx proposed, experimental new seek/flee [cwr 9-16-02] |
113 bzVec2 xxxsteerForFlee (bzVec2 target) { | |
114 bzVec2 offset = m_position - target; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
115 bzVec2 desiredVelocity = bzClamp(offset.truncateLength (maxSpeed ()); |
9 | 116 return desiredVelocity - m_velocity; |
117 } | |
0 | 118 |
9 | 119 bzVec2 xxxsteerForSeek (bzVec2 target) { |
120 // bzVec2 offset = target - position; | |
121 bzVec2 offset = target - m_position; | |
122 bzVec2 desiredVelocity = offset.truncateLength (maxSpeed ()); //xxxnew | |
123 return desiredVelocity - m_velocity; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
124 } |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
125 */ |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
126 |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
127 /* |
9 | 128 // ------------------------------------------------------------------------ |
129 // Obstacle Avoidance behavior | |
130 // | |
131 // Returns a steering force to avoid a given obstacle. The purely | |
132 // lateral steering force will turn our vehicle towards a silhouette edge | |
133 // of the obstacle. Avoidance is required when (1) the obstacle | |
134 // intersects the vehicle's current path, (2) it is in front of the | |
135 // vehicle, and (3) is within minTimeToCollision seconds of travel at the | |
136 // vehicle's current velocity. Returns a zero vector value (bzVec2::zero) | |
137 // when no avoidance is required. | |
138 bzVec2 steerToAvoidObstacle (float minTimeToCollision, Obstacle obstacle) { | |
0 | 139 |
9 | 140 bzVec2 avoidance = obstacle.steerToAvoid (this, minTimeToCollision); |
141 return avoidance; | |
142 } | |
15 | 143 */ |
21 | 144 |
24 | 145 // Steer to avoid |
146 void collisionThreat(inout Threat threat, float maxLookAhead = 10.0f) { | |
23 | 147 |
148 // 1. Find the target that’s closest to collision | |
24 | 149 |
23 | 150 float radius = m_radius; |
24 | 151 float rad = 0.0f; |
152 float shortestTime = float.max; | |
153 | |
154 // Loop through each target | |
155 foreach(obstacle; objectList) { | |
23 | 156 |
24 | 157 bzBody target = obstacle.rBody; |
158 | |
23 | 159 if(target is m_body) continue; |
160 | |
161 // Calculate the time to collision | |
24 | 162 bzVec2 relativePos = target.position - m_position; |
163 bzVec2 relativeVel = m_velocity - target.linearVelocity; | |
23 | 164 float relativeSpeed = relativeVel.length; |
24 | 165 // Time to closest point of approach |
166 float timeToCPA = bzDot(relativePos, relativeVel) / | |
23 | 167 (relativeSpeed * relativeSpeed); |
24 | 168 |
169 // Threat is separating | |
170 if(timeToCPA < 0) { | |
171 continue; | |
172 } | |
173 | |
23 | 174 float distance = relativePos.length; |
24 | 175 |
176 // Clamp look ahead time | |
177 timeToCPA = bzClamp(timeToCPA, 0, maxLookAhead); | |
23 | 178 |
24 | 179 // Calculate closest point of approach |
180 bzVec2 cpa = m_position + m_velocity * timeToCPA; | |
181 bzVec2 eCpa = target.position + target.linearVelocity * timeToCPA; | |
182 relativePos = (eCpa - cpa); | |
183 float dCPA = relativePos.length; | |
23 | 184 |
24 | 185 // No collision |
186 if (dCPA > radius + obstacle.state.radius) continue; | |
23 | 187 |
24 | 188 // Check if it's the closest collision threat |
189 if (timeToCPA < shortestTime && dCPA < threat.minSeparation) { | |
190 shortestTime = timeToCPA; | |
191 threat.target = obstacle; | |
192 threat.distance = distance; | |
193 threat.relativePos = relativePos; | |
194 threat.relativeVel = relativeVel; | |
195 threat.minSeparation = dCPA; | |
196 rad = obstacle.state.radius; | |
23 | 197 } |
198 } | |
199 | |
200 // 2. Calculate the steering | |
201 | |
202 // If we have no target, then exit | |
24 | 203 if(!threat.target) return; |
23 | 204 |
205 // If we’re going to hit exactly, or if we’re already | |
206 // colliding, then do the steering based on current | |
207 // position. | |
24 | 208 //if(threat.minSeparation < m_radius || threat.distance < radius + rad) { |
209 //threat.steering = m_position - threat.target.state.position; | |
210 //} else { | |
23 | 211 // Otherwise calculate the future relative position: |
24 | 212 threat.steering = threat.relativePos; |
213 //} | |
23 | 214 } |
215 | |
15 | 216 /* |
9 | 217 // ------------------------------------------------------------------------ |
218 // Unaligned collision avoidance behavior: avoid colliding with other | |
219 // nearby vehicles moving in unconstrained directions. Determine which | |
220 // (if any) other other vehicle we would collide with first, then steers | |
221 // to avoid the site of that potential collision. Returns a steering | |
222 // force vector, which is zero length if there is no impending collision. | |
223 | |
224 bzVec2 steerToAvoidNeighbors (float minTimeToCollision, AVGroup others) { | |
0 | 225 |
9 | 226 // first priority is to prevent immediate interpenetration |
227 bzVec2 separation = steerToAvoidCloseNeighbors (0, others); | |
228 if (separation != bzVec2::zero) return separation; | |
0 | 229 |
9 | 230 // otherwise, go on to consider potential future collisions |
231 float steer = 0; | |
15 | 232 Ship threat; |
9 | 233 |
234 // Time (in seconds) until the most immediate collision threat found | |
235 // so far. Initial value is a threshold: don't look more than this | |
236 // many frames into the future. | |
237 float minTime = minTimeToCollision; | |
0 | 238 |
9 | 239 // xxx solely for annotation |
240 bzVec2 xxxThreatPositionAtNearestApproach; | |
241 bzVec2 xxxOurPositionAtNearestApproach; | |
0 | 242 |
9 | 243 // for each of the other vehicles, determine which (if any) |
244 // pose the most immediate threat of collision. | |
245 for (AVIterator i = others.begin(); i != others.end(); i++) | |
246 { | |
15 | 247 Ship other = i; |
248 if (other !is this) | |
0 | 249 { |
9 | 250 // avoid when future positions are this close (or less) |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
251 float collisionDangerThreshold = radius * 2; |
9 | 252 |
253 // predicted time until nearest approach of "this" and "other" | |
254 float time = predictNearestApproachTime (other); | |
0 | 255 |
9 | 256 // If the time is in the future, sooner than any other |
257 // threatened collision... | |
258 if ((time >= 0) (time < minTime)) | |
259 { | |
260 // if the two will be close enough to collide, | |
261 // make a note of it | |
262 if (computeNearestApproachPositions (other, time) | |
263 < collisionDangerThreshold) | |
0 | 264 { |
9 | 265 minTime = time; |
266 threat = other; | |
267 xxxThreatPositionAtNearestApproach | |
268 = hisPositionAtNearestApproach; | |
269 xxxOurPositionAtNearestApproach | |
270 = ourPositionAtNearestApproach; | |
0 | 271 } |
272 } | |
273 } | |
9 | 274 } |
0 | 275 |
9 | 276 // if a potential collision was found, compute steering to avoid |
277 if (threat) | |
278 { | |
279 // parallel: +1, perpendicular: 0, anti-parallel: -1 | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
280 float parallelness = m_forward.dot(threat.forward); |
9 | 281 float angle = 0.707f; |
282 | |
283 if (parallelness < -angle) | |
0 | 284 { |
9 | 285 // anti-parallel "head on" paths: |
286 // steer away from future threat position | |
287 bzVec2 offset = xxxThreatPositionAtNearestApproach - m_position; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
288 float sideDot = offset.dot(m_side()); |
9 | 289 steer = (sideDot > 0) ? -1.0f : 1.0f; |
290 } | |
291 else | |
292 { | |
293 if (parallelness > angle) | |
0 | 294 { |
9 | 295 // parallel paths: steer away from threat |
296 bzVec2 offset = threat.position - m_position; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
297 float sideDot = bzDot(offset, m_side); |
0 | 298 steer = (sideDot > 0) ? -1.0f : 1.0f; |
299 } | |
300 else | |
301 { | |
9 | 302 // perpendicular paths: steer behind threat |
303 // (only the slower of the two does this) | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
304 if (threat.speed() <= speed) |
0 | 305 { |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
306 float sideDot = bzDot(m_side, threat.velocity); |
0 | 307 steer = (sideDot > 0) ? -1.0f : 1.0f; |
308 } | |
309 } | |
310 } | |
311 } | |
312 | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
313 return m_side() * steer; |
9 | 314 } |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
315 */ |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
316 |
9 | 317 // Given two vehicles, based on their current positions and velocities, |
318 // determine the time until nearest approach | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
319 float predictNearestApproachTime (State other) { |
9 | 320 |
321 // imagine we are at the origin with no velocity, | |
322 // compute the relative velocity of the other vehicle | |
323 bzVec2 myVelocity = m_velocity; | |
324 bzVec2 otherVelocity = other.velocity; | |
325 bzVec2 relVelocity = otherVelocity - myVelocity; | |
326 float relSpeed = relVelocity.length; | |
327 | |
328 // for parallel paths, the vehicles will always be at the same distance, | |
329 // so return 0 (aka "now") since "there is no time like the present" | |
330 if (relSpeed == 0) return 0; | |
331 | |
332 // Now consider the path of the other vehicle in this relative | |
333 // space, a line defined by the relative position and velocity. | |
334 // The distance from the origin (our vehicle) to that line is | |
335 // the nearest approach. | |
336 | |
337 // Take the unit tangent along the other vehicle's path | |
338 bzVec2 relTangent = relVelocity / relSpeed; | |
339 | |
340 // find distance from its path to origin (compute offset from | |
341 // other to us, find length of projection onto path) | |
342 bzVec2 relPosition = m_position - other.position; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
343 float projection = bzDot(relTangent, relPosition); |
9 | 344 |
345 return projection / relSpeed; | |
346 } | |
0 | 347 |
9 | 348 // Given the time until nearest approach (predictNearestApproachTime) |
349 // determine position of each vehicle at that time, and the distance | |
350 // between them | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
351 float computeNearestApproachPositions (State other, float time) { |
0 | 352 |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
353 bzVec2 myTravel = m_forward * m_speed * time; |
9 | 354 bzVec2 otherTravel = other.forward * other.speed * time; |
355 | |
356 bzVec2 myFinal = m_position + myTravel; | |
357 bzVec2 otherFinal = other.position + otherTravel; | |
0 | 358 |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
359 return (myFinal - otherFinal).length; |
9 | 360 } |
361 | |
24 | 362 bzVec2 targetEnemy (State quarry, float maxPredictionTime) { |
0 | 363 |
9 | 364 // offset from this to quarry, that distance, unit vector toward quarry |
365 bzVec2 offset = quarry.position - m_position; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
366 float distance = offset.length; |
9 | 367 bzVec2 unitOffset = offset / distance; |
368 | |
369 // how parallel are the paths of "this" and the quarry | |
370 // (1 means parallel, 0 is pependicular, -1 is anti-parallel) | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
371 float parallelness = bzDot(m_forward , quarry.forward); |
9 | 372 |
373 // how "forward" is the direction to the quarry | |
374 // (1 means dead ahead, 0 is directly to the side, -1 is straight back) | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
375 float forwardness = bzDot(m_forward , unitOffset); |
0 | 376 |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
377 float directTravelTime = distance / m_speed; |
9 | 378 int f = intervalComparison (forwardness, -0.707f, 0.707f); |
379 int p = intervalComparison (parallelness, -0.707f, 0.707f); | |
380 | |
381 float timeFactor = 0; // to be filled in below | |
0 | 382 |
9 | 383 // Break the pursuit into nine cases, the cross product of the |
384 // quarry being [ahead, aside, or behind] us and heading | |
385 // [parallel, perpendicular, or anti-parallel] to us. | |
386 switch (f) | |
387 { | |
388 case +1: | |
389 switch (p) | |
0 | 390 { |
9 | 391 case +1: // ahead, parallel |
392 timeFactor = 4; | |
0 | 393 break; |
9 | 394 case 0: // ahead, perpendicular |
395 timeFactor = 1.8f; | |
0 | 396 break; |
9 | 397 case -1: // ahead, anti-parallel |
398 timeFactor = 0.85f; | |
0 | 399 break; |
400 } | |
9 | 401 break; |
402 case 0: | |
403 switch (p) | |
404 { | |
405 case +1: // aside, parallel | |
406 timeFactor = 1; | |
407 break; | |
408 case 0: // aside, perpendicular | |
409 timeFactor = 0.8f; | |
410 break; | |
411 case -1: // aside, anti-parallel | |
412 timeFactor = 4; | |
413 break; | |
414 } | |
415 break; | |
416 case -1: | |
417 switch (p) | |
418 { | |
419 case +1: // behind, parallel | |
420 timeFactor = 0.5f; | |
421 break; | |
422 case 0: // behind, perpendicular | |
423 timeFactor = 2; | |
424 break; | |
425 case -1: // behind, anti-parallel | |
426 timeFactor = 2; | |
427 break; | |
428 } | |
429 break; | |
430 } | |
0 | 431 |
9 | 432 // estimated time until intercept of quarry |
433 float et = directTravelTime * timeFactor; | |
434 | |
435 // xxx experiment, if kept, this limit should be an argument | |
436 float etl = (et > maxPredictionTime) ? maxPredictionTime : et; | |
437 | |
438 // estimated position of quarry at intercept | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
439 bzVec2 target = quarry.predictFuturePosition(etl); |
26 | 440 return target; |
9 | 441 } |
442 | |
443 // ------------------------------------------------------------------------ | |
444 // evasion of another vehicle | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
445 bzVec2 steerForEvasion (State menace, float maxPredictionTime) { |
0 | 446 |
9 | 447 // offset from this to menace, that distance, unit vector toward menace |
448 bzVec2 offset = menace.position - m_position; | |
449 float distance = offset.length; | |
0 | 450 |
9 | 451 float roughTime = distance / menace.speed; |
452 float predictionTime = ((roughTime > maxPredictionTime) ? maxPredictionTime : roughTime); | |
453 bzVec2 target = menace.predictFuturePosition (predictionTime); | |
454 | |
455 return steerForFlee (target); | |
456 } | |
0 | 457 |
458 | |
9 | 459 // ------------------------------------------------------------------------ |
460 // tries to maintain a given speed, returns a maxForce-clipped steering | |
461 // force along the forward/backward axis | |
462 bzVec2 steerForTargetSpeed (float targetSpeed) { | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
463 float mf = m_maxForce; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
464 float speedError = targetSpeed - m_speed; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
465 return m_forward * bzClamp(speedError, -mf, +mf); |
9 | 466 } |
0 | 467 |
468 | |
9 | 469 // ----------------------------------------------------------- utilities |
470 bool isAhead (bzVec2 target) {return isAhead (target, 0.707f);}; | |
471 bool isAside (bzVec2 target) {return isAside (target, 0.707f);}; | |
472 bool isBehind (bzVec2 target) {return isBehind (target, -0.707f);}; | |
0 | 473 |
9 | 474 bool isAhead (bzVec2 target, float cosThreshold) |
475 { | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
476 bzVec2 targetDirection = target - m_position; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
477 targetDirection.normalize(); |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
478 return bzDot(m_forward, targetDirection) > cosThreshold; |
9 | 479 } |
0 | 480 |
9 | 481 bool isAside (bzVec2 target, float cosThreshold) |
482 { | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
483 bzVec2 targetDirection = target - m_position; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
484 targetDirection.normalize(); |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
485 float dp = bzDot(m_forward, targetDirection); |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
486 return (dp < cosThreshold) && (dp > -cosThreshold); |
9 | 487 } |
0 | 488 |
9 | 489 bool isBehind (bzVec2 target, float cosThreshold) |
490 { | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
491 bzVec2 targetDirection = target - m_position; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
492 targetDirection.normalize(); |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
493 return bzDot(m_forward, targetDirection) < cosThreshold; |
9 | 494 } |
495 | |
496 private: | |
497 | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
498 Ship m_ship; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
499 |
9 | 500 bzVec2 m_position; |
501 bzVec2 m_velocity; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
502 bzVec2 m_up; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
503 bzVec2 m_side; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
504 bzVec2 m_forward; |
19 | 505 float m_radius; |
506 bzBody m_body; | |
11
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
507 |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
508 float m_speed = 0; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
509 float m_maxForce = 0; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
510 |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
511 // Wander behavior |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
512 float m_wanderSide; |
d998bf1b0654
Added utilities and AI; fixed steer
Mason Green <mason.green@gmail.com>
parents:
9
diff
changeset
|
513 float m_wanderUp; |
9 | 514 } |