View Javadoc

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