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