1 package Steerings;
2
3
4 import SteeringStuff.SteeringManager;
5 import SteeringStuff.RefBoolean;
6 import SteeringProperties.ObstacleAvoidanceProperties;
7 import SteeringProperties.SteeringProperties;
8 import SteeringStuff.IRaysFlagChanged;
9 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
10 import java.util.concurrent.ExecutionException;
11 import java.util.logging.Level;
12 import java.util.logging.Logger;
13 import javax.vecmath.Vector3d;
14 import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
15 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.AutoTraceRay;
16 import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
17 import SteeringStuff.ISteering;
18 import SteeringStuff.RaycastingManager;
19 import SteeringStuff.SteeringRay;
20 import SteeringStuff.SteeringTools;
21 import SteeringStuff.SteeringType;
22 import java.util.HashMap;
23 import java.util.LinkedList;
24 import java.util.Random;
25 import java.util.concurrent.Future;
26 import javax.vecmath.Tuple3d;
27 import javax.vecmath.Vector2d;
28
29
30
31
32
33
34
35 public class ObstacleAvoidanceSteer implements ISteering, IRaysFlagChanged {
36
37
38 private UT2004Bot botself;
39
40 private RaycastingManager rayManager;
41
42
43
44 private int repulsiveForce;
45
46
47
48
49 private int forceOrder;
50
51
52
53
54 private boolean frontCollisions;
55
56
57
58
59 private boolean treeCollisions;
60
61
62 private static double FRONT_RAY_WEIGHT = 1;
63 private static double SIDE_FRONT_RAY_WEIGHT = 0.8;
64 private static double SIDE_RAY_WEIGHT = 0.5;
65
66
67
68
69
70
71 private boolean raysReady;
72
73 private HashMap<String, Future<AutoTraceRay>> myFutureRays;
74
75
76 protected static final String LEFTFRONT = "oleftfront";
77 protected static final String LEFT = "oleft";
78 protected static final String RIGHTFRONT = "orightfront";
79 protected static final String RIGHT = "oright";
80 protected static final String FRONT = "ofront";
81
82
83
84
85 boolean sensorLeft = false;
86 boolean sensorRight = false;
87 boolean sensorLeftFront = false;
88 boolean sensorRightFront = false;
89 boolean sensorFront = false;
90
91
92
93
94 AutoTraceRay left, right, leftfront, rightfront, front;
95
96
97
98 final int shortRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * 8);
99 final int longRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * 25);
100
101
102
103 Random random = new Random();
104
105
106
107
108
109
110 public ObstacleAvoidanceSteer(UT2004Bot bot, RaycastingManager rayManager) {
111 botself = bot;
112 this.rayManager = rayManager;
113 prepareRays();
114 }
115
116
117 private void prepareRays() {
118
119 LinkedList<SteeringRay> rayList = new LinkedList<SteeringRay>();
120 rayList.add(new SteeringRay(LEFT, new Vector3d(0, -1, 0), shortRayLength));
121 rayList.add(new SteeringRay(LEFTFRONT, new Vector3d(Math.sqrt(3) * 2, -1, 0), longRayLength));
122 rayList.add(new SteeringRay(RIGHTFRONT, new Vector3d(Math.sqrt(3) * 2, 1, 0), longRayLength));
123 rayList.add(new SteeringRay(RIGHT, new Vector3d(0, 1, 0), shortRayLength));
124 rayList.add(new SteeringRay(FRONT, new Vector3d(1, 0, 0), longRayLength));
125
126
127 rayManager.addRays(SteeringType.OBSTACLE_AVOIDANCE, rayList, this);
128 raysReady = false;
129 }
130
131 public void flagRaysChanged() {
132 myFutureRays = rayManager.getMyFutureRays(SteeringType.OBSTACLE_AVOIDANCE);
133 raysReady = false;
134 listenToRays();
135 }
136
137
138 private void listenToRays() {
139 for(String rayId : myFutureRays.keySet()) {
140 Future<AutoTraceRay> fr = myFutureRays.get(rayId);
141 if (fr.isDone()) {
142 try {
143 if (rayId.equals(LEFTFRONT)) {
144 leftfront = fr.get();
145 } else if (rayId.equals(RIGHTFRONT)) {
146 rightfront = fr.get();
147 } else if (rayId.equals(LEFT)) {
148 left = fr.get();
149 } else if (rayId.equals(RIGHT)) {
150 right = fr.get();
151 } else if (rayId.equals(FRONT)) {
152 front = fr.get();
153 }
154
155
156
157
158 raysReady = true;
159 } catch (InterruptedException ex) {
160 Logger.getLogger(ObstacleAvoidanceSteer.class.getName()).log(Level.SEVERE, null, ex);
161 } catch (ExecutionException ex) {
162 Logger.getLogger(ObstacleAvoidanceSteer.class.getName()).log(Level.SEVERE, null, ex);
163 }
164 }
165 }
166 }
167
168
169
170 public Vector3d run(Vector3d scaledActualVelocity, RefBoolean wantsToGoFaster, RefBoolean wantsToStop, Location focus) {
171
172 wantsToGoFaster.setValue(false);
173 Vector3d nextVelocity = new Vector3d(0,0,0);
174
175 if (!raysReady) {
176 listenToRays();
177 return nextVelocity;
178 }
179
180
181 Vector3d actualVelocity = botself.getVelocity().getVector3d();
182 Vector3d originalVelocity = botself.getVelocity().getVector3d();
183 originalVelocity.normalize();
184 originalVelocity.scale(0);
185
186
187 if (leftfront != null)
188 sensorLeftFront = leftfront.isResult();
189 if (rightfront != null)
190 sensorRightFront = rightfront.isResult();
191 if (left != null)
192 sensorLeft = left.isResult();
193 if (right != null)
194 sensorRight = right.isResult();
195 if (front != null)
196 sensorFront = front.isResult();
197
198
199
200
201
202
203
204
205
206 boolean sensor = sensorFront || sensorLeft || sensorLeftFront || sensorRight || sensorRightFront;
207
208
209
210
211
212
213
214
215
216 double multiplier;
217
218
219 Vector3d normal;
220
221
222 Vector3d botToHitLocation;
223
224
225
226
227
228
229 if (sensorLeft) {
230 botToHitLocation = new Vector3d(left.getHitLocation().x - botself.getLocation().x, left.getHitLocation().y - botself.getLocation().y, 0);
231 normal = left.getHitNormal();
232 multiplier = Math.pow((shortRayLength - botToHitLocation.length()) * 2f / shortRayLength, forceOrder);
233 normal.scale(SIDE_RAY_WEIGHT * repulsiveForce * multiplier);
234 nextVelocity.add((Tuple3d) normal);
235 }
236 if (sensorRight) {
237 botToHitLocation = new Vector3d(right.getHitLocation().x - botself.getLocation().x, right.getHitLocation().y - botself.getLocation().y, 0);
238 normal = right.getHitNormal();
239 multiplier = Math.pow((shortRayLength - botToHitLocation.length()) * 2f / shortRayLength, forceOrder);
240 normal.scale(SIDE_RAY_WEIGHT * repulsiveForce * multiplier);
241 nextVelocity.add((Tuple3d) normal);
242 }
243 if (sensorLeftFront) {
244 botToHitLocation = new Vector3d(leftfront.getHitLocation().x - botself.getLocation().x, leftfront.getHitLocation().y - botself.getLocation().y, 0);
245 multiplier = Math.pow((longRayLength - botToHitLocation.length()) * 2f / longRayLength, forceOrder);
246 normal = leftfront.getHitNormal();
247 if (treeCollisions && (!sensorRightFront && SteeringTools.pointIsLeftFromTheVector(actualVelocity, normal) ) ) {
248 normal = computeTreeCollisionVector(normal);
249 }
250 if (frontCollisions && !sensorFront) {
251 normal = computeFrontCollisionVector(normal);
252 }
253 normal.scale(SIDE_FRONT_RAY_WEIGHT * repulsiveForce * multiplier);
254 nextVelocity.add((Tuple3d) normal);
255 }
256 if (sensorRightFront) {
257 botToHitLocation = new Vector3d(rightfront.getHitLocation().x - botself.getLocation().x, rightfront.getHitLocation().y - botself.getLocation().y, 0);
258 multiplier = Math.pow((longRayLength - botToHitLocation.length()) * 2f / longRayLength, forceOrder);
259 normal = rightfront.getHitNormal();
260 if (treeCollisions && (!sensorLeftFront && !SteeringTools.pointIsLeftFromTheVector(actualVelocity, normal) ) ) {
261 normal = computeTreeCollisionVector(normal);
262 }
263 if (frontCollisions && !sensorFront) {
264 normal = computeFrontCollisionVector(normal);
265 }
266 normal.scale(SIDE_FRONT_RAY_WEIGHT * repulsiveForce * multiplier);
267 nextVelocity.add((Tuple3d) normal);
268 }
269 if (sensorFront) {
270 botToHitLocation = new Vector3d(front.getHitLocation().x - botself.getLocation().x, front.getHitLocation().y - botself.getLocation().y, 0);
271 multiplier = Math.pow((longRayLength - botToHitLocation.length()) * 2f / longRayLength, forceOrder);
272 normal = front.getHitNormal();
273 if (frontCollisions) {
274 normal = computeFrontCollisionVector(normal);
275 }
276 normal.scale(FRONT_RAY_WEIGHT * repulsiveForce * multiplier);
277 nextVelocity.add((Tuple3d) normal);
278 }
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 if (!sensor) {
308 wantsToGoFaster.setValue(true);
309 } else {
310 wantsToGoFaster.setValue(false);
311 }
312
313 return nextVelocity;
314 }
315
316
317 private Vector3d computeTreeCollisionVector(Vector3d normal) {
318 Vector3d av = botself.getVelocity().getVector3d();
319
320
321
322
323
324 * a navíc jde normálová síla v místě kolize stejným směrem jako jde paprsek, tedy doleva ==> pak by se neměla přičítat tato normála, ale spíše síla na durhou stranu.
325 * Značí to situaci, kdy jsme narazili na úzkou překážku (strom) a levý přední paprsek prošel levým krajem překážky.
326 * Bez tohoto ošetření by nás to stočilo doleva, což nechceme.*/
327
328 Vector2d start = new Vector2d(botself.getLocation().x, botself.getLocation().y);
329 Vector2d end = new Vector2d(start.x-av.x, start.y-av.y);
330 Vector2d point = new Vector2d(start.x + normal.x, start.y + normal.y);
331 Vector2d pata = SteeringTools.getNearestPoint(start, end, point, false);
332 Vector2d pointToPata = new Vector2d(pata.x - point.x, pata.y - point.y);
333 pointToPata.scale(2);
334 Vector2d mirrorPoint = new Vector2d(point.x + pointToPata.x, point.y + pointToPata.y);
335
336 Vector3d result = new Vector3d(mirrorPoint.x - start.x, mirrorPoint.y - start.y, 0);
337
338 if (SteeringManager.DEBUG) {
339 System.out.println("Obstacle avoidance tree collision. " + result.length());
340 }
341 return result;
342 }
343
344
345 private Vector3d computeFrontCollisionVector(Vector3d normal) {
346 Vector3d av = botself.getVelocity().getVector3d();
347 Vector3d result = new Vector3d(normal.x, normal.y, 0);
348 Vector3d negativeActual = new Vector3d(-av.x, -av.y, 0);
349
350 if (SteeringManager.DEBUG) System.out.println("Angle "+SteeringTools.radiansToDegrees(normal.angle(negativeActual)));
351 if (result.angle(negativeActual) <= Math.PI/2) {
352 boolean turnLeft;
353 if (result.angle(negativeActual) == 0) {
354 turnLeft = random.nextBoolean();
355 } else {
356 turnLeft = SteeringTools.pointIsLeftFromTheVector(av, result);
357 }
358 Vector3d turn = SteeringTools.getTurningVector2(av, turnLeft);
359 turn.normalize();
360 turn.scale(0.5);
361 result.add(turn);
362 result.normalize();
363 if (SteeringManager.DEBUG) System.out.println("Obstacle avoidance front collision: turn left "+turnLeft);
364 }
365 return result;
366 }
367
368 @Override
369 public void setProperties(SteeringProperties newProperties) {
370 this.repulsiveForce = ((ObstacleAvoidanceProperties)newProperties).getRepulsiveForce();
371 this.forceOrder = ((ObstacleAvoidanceProperties)newProperties).getForceOrder();
372 this.frontCollisions = ((ObstacleAvoidanceProperties)newProperties).isFrontCollisions();
373 this.treeCollisions = ((ObstacleAvoidanceProperties)newProperties).isTreeCollisions();
374 }
375
376 public ObstacleAvoidanceProperties getProperties() {
377 ObstacleAvoidanceProperties properties = new ObstacleAvoidanceProperties();
378 properties.setRepulsiveForce(repulsiveForce);
379 properties.setForceOrder(forceOrder);
380 properties.setFrontCollisions(frontCollisions);
381 properties.setTreeCollisions(treeCollisions);
382 return properties;
383 }
384 }