View Javadoc

1   package Steerings;
2   
3   
4   import SteeringStuff.SteeringManager;
5   import SteeringStuff.RefBoolean;
6   import SteeringProperties.SteeringProperties;
7   import SteeringProperties.WalkAlongProperties;
8   import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
9   import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
10  import javax.vecmath.Vector3d;
11  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
12  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
13  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
14  import SteeringStuff.ISteering;
15  import SteeringStuff.SteeringTools;
16  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.PlayAnimation;
17  import java.util.Collection;
18  import javax.vecmath.Tuple3d;
19  import javax.vecmath.Vector2d;
20  
21  
22  /**
23   * A class for providing obstacle avoiding steering to bots via raycasting.
24   *
25   * @author Marki
26   */
27  public class WalkAlongSteer implements ISteering {
28  
29      /** This steering needs botself. */
30      private UT2004Bot botself;
31      
32      /** ISteering properties: target location - bot approaches this location. */
33      private Location targetLocation;
34      /** ISteering properties: target gravity - a parameter meaning how attracted the bot is to his target location. */
35      private int partnerForce;
36      /** ISteering properties: distance from the partner. */
37      private int distanceFromThePartner;
38      /** ISteering properties: name of the partner */
39      private String partnerName;
40      /** ISteering properties: . */
41      private boolean giveWayToPartner;
42      /** ISteering properties: . */
43      private boolean waitForPartner;
44  
45      private boolean turn = true;
46      private boolean newToPartner = false;
47      private boolean newToPartner2 = false;
48      private boolean newWait = false;
49      private boolean truncateToPartner = false;
50      private boolean truncateNextVelocity = false;
51  
52      private static int MAX_TO_PARTNER = 500;
53      private static int MAX_NEXT_VELOCITY = 500;
54      private static int WAIT_DISTANCE = 100;
55      private static int NEARLY_THERE_DISTANCE = 200;
56  
57      private boolean waiting;
58  
59      /** Partner. */
60      private Player partner;
61  
62      private Vector3d forceToTarget;
63      private Vector3d forceToPartner;
64      private Vector3d forceFromPartner;
65      
66      /**
67       * @param bot Instance of the steered bot.
68       */
69      public WalkAlongSteer(UT2004Bot bot) {
70          botself = bot;
71          waiting = false;
72      }
73  
74      /** When called, the bot starts steering, when possible, he get's nearer the target location. */
75      public Vector3d run(Vector3d scaledActualVelocity, RefBoolean wantsToGoFaster, RefBoolean wantsToStop, Location focus) {
76          //The bot's velocity is received.
77          Vector3d actualVelocity = botself.getVelocity().getVector3d();
78          // Supposed velocity in the next tick of logic, after applying various steering forces to the bot.
79          Vector3d nextVelocity = new Vector3d(0,0,0);
80  
81          if (partner == null || partner.getLocation() == null) {
82              partner = getPartner();
83              if (turn) {
84                  Vector3d turningVector = new Vector3d(actualVelocity.y, -actualVelocity.x, 0);   //Turns 45° left.
85                  turningVector.scale(1/(Math.sqrt(2)));
86                  Vector3d negativeVector = new Vector3d(-actualVelocity.x,-actualVelocity.y,0);
87                  negativeVector.scale(1-1/Math.sqrt(2));
88                  turningVector.add((Tuple3d)negativeVector);
89                  return turningVector;
90              } else {
91                  wantsToStop.setValue(true);
92                  if (SteeringManager.DEBUG) {
93                      System.out.println("We wait for the partner.");
94                  }
95                  return nextVelocity;
96              }
97          }
98  
99          //<editor-fold defaultstate="collapsed" desc="Pomocné předvýpočty a výpisy">
100 
101         /*Následující blok kódu slouží pro určení pozice (target) ve vzdálenosti distanceFTP/2 od cílové pozice na mé straně.
102          Díky tomu si pak každý půjde na své místo kus od cíle a nebudou se o cíl prát.*/
103         Location middlePoint = new Location((botself.getLocation().x + partner.getLocation().x) / 2, (botself.getLocation().y + partner.getLocation().y) / 2, botself.getLocation().z);
104         Vector2d middlePointToTarget = new Vector2d(targetLocation.x - middlePoint.x, targetLocation.y - middlePoint.y);
105         Vector2d middlePointToTargetNormal = new Vector2d(-middlePointToTarget.y, middlePointToTarget.x);
106         middlePointToTargetNormal.normalize();
107         middlePointToTargetNormal.scale(distanceFromThePartner / 2);
108         /*Místo abychom předem zjišťovali na jakou stranu od cíle přičíst tuto normálu, tak si vypočteme obě možnosti a vybereme bližší z nich.*/
109         Location targetA = new Location(targetLocation.x + middlePointToTargetNormal.x, targetLocation.y + middlePointToTargetNormal.y, targetLocation.z);
110         Location targetB = new Location(targetLocation.x - middlePointToTargetNormal.x, targetLocation.y - middlePointToTargetNormal.y, targetLocation.z);
111         Location targetMy;
112         Location targetHis;
113         if (botself.getLocation().getDistance(targetA) < botself.getLocation().getDistance(targetB)) {
114             targetMy = targetA;
115             targetHis = targetB;
116         } else {
117             targetMy = targetB;
118             targetHis = targetA;
119         }
120 
121         /* Jestliže jsme už dostatečně blízko svého cíle, zastavíme se a natočíme na partnera.*/
122         if (SteeringManager.DEBUG) System.out.println("K mému cili "+botself.getLocation().getDistance(targetMy));
123 
124         if (botself.getLocation().getDistance(targetMy) < NEARLY_THERE_DISTANCE) {
125             wantsToStop.setValue(true);
126             focus.setTo(partner.getLocation());
127             if (SteeringManager.DEBUG) System.out.println("We reached the target and we stop.");
128             return nextVelocity;
129         }
130         
131         // A vector from the bot to the target location.
132         Vector3d myVectorToTarget = new Vector3d(targetMy.x - botself.getLocation().x, targetMy.y - botself.getLocation().y, targetMy.z - botself.getLocation().z);
133         // A vector from the partner to the target location.
134         Vector3d partnersVectorToTarget = new Vector3d(targetHis.x - partner.getLocation().x, targetHis.y - partner.getLocation().y, targetHis.z - partner.getLocation().z);
135 
136         /*** START Kontrolní výpis vzdáleností. START ***/
137         if (SteeringManager.DEBUG) System.out.println("Ja k cili "+myVectorToTarget.length());
138         if (SteeringManager.DEBUG) System.out.println("Partner k cili "+partnersVectorToTarget.length());
139 
140         if (partnersVectorToTarget.length() > myVectorToTarget.length()) {
141             if (SteeringManager.DEBUG) System.out.println("Je dal.");
142         } else {
143             if (SteeringManager.DEBUG) System.out.println("Musim ho dohnat.");
144         }
145         /*** END Kontrolní výpis vzdáleností. END ***/
146 
147         //</editor-fold>
148 
149         //<editor-fold defaultstate="collapsed" desc="Deklarace sil">
150 
151         /*--------------------------1-deklarace--------------------------*/
152         /*Vektor k cíli. Ten, kdo je od cíle dál, je přitahován silou attractiveForce + 30 a větší (čím je větší rozdíl mezi tím, kdo je dál, tím je tato síla větší).*/
153         forceToTarget = new Vector3d(targetMy.x - botself.getLocation().x, targetMy.y - botself.getLocation().y, 0);
154         forceToTarget.normalize();
155 
156         /*--------------------------2-deklarace--------------------------*/
157         /*Vektor od spojnice. Pokud je agent moc blízko spojnici, je od ní odpuzován. Čím je spojnici blíže, tím je síla větší. Díky tomu se k sobě nedostanou agenti moc blízko,
158           ale zároveň si automaticky dělají místo. Vzhledem k tomu, že se tato spojnice vždy přepočítá dle aktuálního stavu, funguje to plynule a spolehlivě.*/
159         Vector2d startC = new Vector2d(middlePoint.x, middlePoint.y);
160         Vector2d endC = new Vector2d(targetLocation.x, targetLocation.y);
161         Vector2d myLoc = new Vector2d(botself.getLocation().x, botself.getLocation().y);
162         Vector2d foot = SteeringTools.getNearestPoint(startC, endC, myLoc, false);
163         Vector3d footToBot = new Vector3d(myLoc.x - foot.x, myLoc.y - foot.y, 0);
164         double fromFoot = footToBot.length();
165         Vector3d botToFoot = new Vector3d(-footToBot.x, -footToBot.y, -footToBot.z);
166         footToBot.normalize();
167         botToFoot.normalize();
168         Vector3d footToBotCopy = new Vector3d(footToBot.x, footToBot.y, footToBot.z);
169         
170         Vector3d partnerToBot = new Vector3d(botself.getLocation().x - partner.getLocation().x,botself.getLocation().y - partner.getLocation().y,botself.getLocation().z - partner.getLocation().z);
171         double fromPartner = partnerToBot.length();
172         partnerToBot.normalize();
173 
174 
175         /*--------------------------3-deklarace--------------------------*/
176         /*Vektor k partnerovi. Jsou-li partneři od sebe příliš daleko, táhne je síla k sobě. Čím jsou od sebe dál, tím je větší.*/
177         Vector3d botToPartner = new Vector3d(partner.getLocation().x - botself.getLocation().x,partner.getLocation().y - botself.getLocation().y,partner.getLocation().z - botself.getLocation().z);
178         double toPartner = botToPartner.length();
179         botToPartner.normalize();
180         
181 
182         //</editor-fold>
183 
184         //<editor-fold defaultstate="collapsed" desc="Výpočet sil">
185 
186         /*--------------------------1-výpočet--------------------------*/
187         double diff = (myVectorToTarget.length() - partnersVectorToTarget.length())/500;
188         int add = 0;
189         if (diff > 0) {
190             diff = Math.min(diff, 1.5);
191             add = 30;
192         }
193         forceToTarget.scale(partnerForce*Math.pow(2,diff) + add);
194         if (SteeringManager.DEBUG) System.out.println("ToTarget "+forceToTarget.length());
195 
196         /*--------------------------2-výpočet--------------------------*/
197         if (giveWayToPartner) {
198             if (fromFoot < distanceFromThePartner/2) {
199                 double scale = (distanceFromThePartner - 2*fromFoot) / distanceFromThePartner;
200                 footToBot.scale(partnerForce*scale);
201                 if (SteeringManager.DEBUG) System.out.println("From foot "+footToBot.length());
202             }else {
203                 footToBot.set(0,0,0);
204             }
205             forceFromPartner = footToBot;
206         } else {
207             if (fromPartner < distanceFromThePartner) {
208                 double scale = (distanceFromThePartner - fromPartner) / distanceFromThePartner;
209                 partnerToBot.scale(partnerForce*scale);
210                 if (SteeringManager.DEBUG) System.out.println("From partner "+partnerToBot.length());
211             } else {
212                 partnerToBot.set(0,0,0);
213             }
214             forceFromPartner = partnerToBot;
215         }
216 
217         /*--------------------------3-výpočet--------------------------*/        
218         if (toPartner > distanceFromThePartner) {
219             Vector3d myForceToPartner = new Vector3d(0,0,0);
220             /* Vylepšení: pokud je o dost blíže cíli než partner, tak jde buď ke spojnici (pokud je od ní daleko), či se zastaví (pokud je u ní blízko).*/
221             double diff2 = partnersVectorToTarget.length() - myVectorToTarget.length();            
222             if (waitForPartner && diff2 > 3 * distanceFromThePartner) {
223                 /* Jestliže je agent daleko od partnera, vhodně blízko u spojnice
224                  * a o dost blíže cíli než partner, zastaví se (aby se nevracel k němu).*/
225                 if (fromFoot <= distanceFromThePartner/2) {
226                     waiting = true;
227                     wantsToStop.setValue(true);
228                     focus.setTo(partner.getLocation());
229                     if (SteeringManager.DEBUG) {
230                         System.out.println("We reached the target and we stop.");
231                         if (SteeringManager.Thomas) botself.getAct().act(new PlayAnimation().setName("social_wavefar").setLoop(true));  //social_wavefar Throw
232                     }
233                     return nextVelocity;                    
234                 } else {
235                     double scale = 2 * fromFoot / distanceFromThePartner;
236                     botToFoot.scale(partnerForce * scale);
237                     botToPartner.scale(partnerForce * scale);
238                     myForceToPartner.add(botToFoot);
239                     myForceToPartner.add(botToPartner);
240                 }
241             } else {
242                 if (newWait && waiting) {
243                     double distancesDifference = (partnersVectorToTarget.length() - myVectorToTarget.length());
244                     System.out.println("Diff copy: "+distancesDifference);
245                     if (distancesDifference > WAIT_DISTANCE) {
246                         waiting = true;
247                         wantsToStop.setValue(true);
248                         focus.setTo(partner.getLocation());
249                         if (SteeringManager.DEBUG) {
250                             System.out.println("We are waiting, but partner is already near to us.");                            
251                         }
252                         return nextVelocity;
253                     }
254                 }
255                 /* Jsme-li od sebe příliš daleko, působí na nás přitažlivá síla. Čím jsme od sebe dále, tím je větší.*/
256                 double angleToTarget = forceToTarget.angle(botself.getVelocity().asVector3d());
257                 /* Když se agent vrací k partnerovi (jde zhruba od cíle), tak na něj nepůsobí síla přímo k partnerovi, ale mírně vedle něj.
258                  * To znamená, že se k lokaci partnera přičte vektor od axis o velikost distanceFromPartner/2 --> a vezme se síla k této nové lokaci kousek vedle partnera.
259                  * Díky tomu agent rovnou běží na správnou stranu od partnera a nemusí na něj působit síla fromAxis (ta je totiž původcem otáčení na špatnou stranu).
260                  * Díky totmuto chování se zároveň nedostane příliš blízko k partnerovi - a ve chvíli, kdy se má otáčet, na něj můžeme zapůsobit silou toPointBetween,
261                  * která ho přitáhne trochu k partnerovi (a trochu k cíli) - a nemusíme se bát, že do partnera vrazí.
262                  * Tedy ne, že by do partnera nemohl vrazit, ale pokud nebude ve velké rychlosti/nebudou mít nastavenou příliš malou vzdálenost od sebe, tak by se to stát nemělo.
263                  */
264                 if (newToPartner && (angleToTarget > Math.PI/2)) {
265                     footToBotCopy.normalize();
266                     footToBotCopy.scale(distanceFromThePartner / 2);
267                     Location nextToPartner = new Location(partner.getLocation().x + footToBotCopy.x, partner.getLocation().y + footToBotCopy.y, partner.getLocation().z);
268                     myForceToPartner = new Vector3d(nextToPartner.x - botself.getLocation().x, nextToPartner.y - botself.getLocation().y, nextToPartner.z - botself.getLocation().z);
269                 } else {
270                     myForceToPartner.add(botToPartner);
271                 }
272                 double scale = (toPartner - distanceFromThePartner) / distanceFromThePartner;
273                 myForceToPartner.normalize();
274                 myForceToPartner.scale(partnerForce * scale);
275                 if (SteeringManager.DEBUG) {
276                     System.out.println("To partner " + myForceToPartner.length());
277                 }
278                 /* Když se agent vrací k partnerovi (jde zhruba od cíle) a když už na něj působí malá přitažlivá síla k partnerovi
279                  * (tedy je už blízko němu a brzo se začne otáčet), tak na něj začne působit ještě síla toPointBetween: k místu mezi partnerem a společným cílem.
280                  * Čím je síla k partnerovi menší (což znamená, že je partnerovi blíže a bude se brzy otáčet), tím je síla toPointBetween větší.
281                  * Díky síle toPointBetween se agent otočí na správnou stranu.
282                  * Pozor, toto chování má jednu nevýhodu - agent se otočí trochu dříve, než dojde na úroveň partnera.
283                  * Ale zhodnotila jsem to jako minoritní nevýhodu, neboť se tento rozdíl poměrně brzy srovná.
284                  */
285                 if (newToPartner2 && (angleToTarget > Math.PI / 2)) {   
286                     if (myForceToPartner.length() < partnerForce) {
287                         Location betweenPaT = new Location((partner.getLocation().x + targetLocation.x) / 2, (partner.getLocation().y + targetLocation.y) / 2, (partner.getLocation().z + targetLocation.z) / 2);
288                         Vector3d toPointBetween = new Vector3d(betweenPaT.x - botself.getLocation().x, betweenPaT.y - botself.getLocation().y, betweenPaT.z - botself.getLocation().z);
289                         toPointBetween.normalize();
290                         double scaleBetween = partnerForce - myForceToPartner.length();
291                         toPointBetween.scale(scaleBetween);
292                         myForceToPartner.add(toPointBetween);
293                         forceFromPartner.scale(1 / 2);  //Navíc zmenšíme napolovic sílu od partnera (pouze síla toPointBetween někdy dle pozorování nestačila).
294                     }
295                 }
296             }
297             forceToPartner = myForceToPartner;
298         } else {
299             forceToPartner = new Vector3d(0,0,0);
300         }
301         
302         if (truncateToPartner) {
303             if (forceToPartner.length() > MAX_TO_PARTNER) {
304                 forceToPartner.normalize();
305                 forceToPartner.scale(MAX_TO_PARTNER);
306             }
307         }
308         //Toto bylo super: vectorToPartner.scale(attractiveForce * ((botself.getLocation().getDistance(partner.getLocation()) - distanceFromThePartner) * 2 / distanceFromThePartner));
309 
310         //</editor-fold>
311         waiting = false;
312         nextVelocity.add((Tuple3d)forceToTarget);
313         nextVelocity.add((Tuple3d)forceFromPartner);
314         nextVelocity.add((Tuple3d)forceToPartner);
315         if (SteeringManager.DEBUG) System.out.println("Vektor vysledny "+nextVelocity.length());
316 
317         if (truncateNextVelocity) {
318             if (nextVelocity.length() > MAX_NEXT_VELOCITY) {
319                 nextVelocity.normalize();
320                 nextVelocity.scale(MAX_NEXT_VELOCITY);
321             }
322         }
323 
324         wantsToGoFaster.setValue(false);
325         return nextVelocity;
326     }
327 
328     //A method which gets the identity of the leader.
329     private Player getPartner() {
330         UnrealId myId = botself.getWorldView().getSingle(Self.class).getId();
331         Collection<Player> col = botself.getWorldView().getAll(Player.class).values();
332         for (Player p : col) {
333             if (SteeringManager.DEBUG) System.out.println("Player "+p.getName());
334             if (p.getName().equals(partnerName) && p.getId() != myId) {
335                 if (SteeringManager.DEBUG) System.out.println("Got the partner "+p.toString());
336                 return p;
337             }
338         }
339         return null;
340     }
341     @Override
342     public void setProperties(SteeringProperties newProperties) {
343         this.partnerForce = ((WalkAlongProperties)newProperties).getPartnerForce();
344         this.partnerName = ((WalkAlongProperties)newProperties).getPartnerName();
345         this.targetLocation = ((WalkAlongProperties)newProperties).getTargetLocation();
346         this.distanceFromThePartner = ((WalkAlongProperties)newProperties).getDistanceFromThePartner();
347         this.giveWayToPartner = ((WalkAlongProperties)newProperties).isGiveWayToPartner();
348         this.waitForPartner = ((WalkAlongProperties)newProperties).isWaitForPartner();
349     }
350 
351     public WalkAlongProperties getProperties() {
352         WalkAlongProperties properties = new WalkAlongProperties();
353         properties.setPartnerForce(partnerForce);
354         properties.setPartnerName(partnerName);
355         properties.setTargetLocation(targetLocation);
356         properties.setDistanceFromThePartner(distanceFromThePartner);
357         properties.setGiveWayToPartner(giveWayToPartner);
358         properties.setWaitForPartner(waitForPartner);
359         return properties;
360     }
361 
362     public Vector3d getForceToPartner() {
363         /*if (forceToPartner == null || forceToPartner.length() == 0) {
364             return forceFromPartner;
365         } else if (forceToPartner != null && forceFromPartner != null && forceFromPartner.length() > 0) {
366             Vector3d sum = new Vector3d(forceFromPartner);
367             sum.add(forceToPartner);
368             return sum;
369             //System.out.println("POZOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOR");
370             //System.out.println(forceFromPartner.length());
371             //System.out.println(forceToPartner.length());
372         } else {
373             return forceToPartner;
374         }*/
375         return forceFromPartner;
376     }
377 
378     public Vector3d getForceToTarget() {
379         //return forceToTarget;
380         return forceToPartner;
381     }
382 
383 }