2  nbproject/private/private.properties
@@ -3,4 +3,4 @@ do.depend=false
3 3
 do.jar=true
4 4
 javac.debug=true
5 5
 javadoc.preview=true
6  
-user.properties.file=C:\\Users\\Tihomir\\AppData\\Roaming\\.jmonkeyplatform\\3.0\\build.properties
  6
+user.properties.file=/root/.jmonkeyplatform/3.0/build.properties
8 nbproject/project.properties
@@ -2,8 +2,8 @@ annotation.processing.enabled=true
2 2
 annotation.processing.enabled.in.editor=false
3 3
 annotation.processing.processors.list=
4 4
 annotation.processing.run.all.processors=true
5  
-application.title=MyGame
6  
-application.vendor=MyCompany
  5
+application.title=MonkeyBrains
  6
+application.vendor=
7 7
 assets.jar.name=assets.jar
8 8
 assets.excludes=**/*.j3odata,**/*.mesh,**/*.skeleton,**/*.mesh\.xml,**/*.skeleton\.xml,**/*.scene,**/*.material,**/*.obj,**/*.mtl,**/*.3ds,**/*.dae,**/*.blend,**/*.blend*[0-9]
9 9
 assets.folder.name=
@@ -47,7 +47,7 @@ javac.test.classpath=\
47 47
     ${javac.classpath}:\
48 48
     ${build.classes.dir}
49 49
 javadoc.additionalparam=
50  
-javadoc.author=false
  50
+javadoc.author=true
51 51
 javadoc.encoding=${source.encoding}
52 52
 javadoc.noindex=false
53 53
 javadoc.nonavbar=false
@@ -55,7 +55,7 @@ javadoc.notree=false
55 55
 javadoc.private=false
56 56
 javadoc.splitindex=true
57 57
 javadoc.use=true
58  
-javadoc.version=false
  58
+javadoc.version=true
59 59
 javadoc.windowtitle=
60 60
 jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
61 61
 jnlp.codebase.type=local
205 src/com/jme3/ai/agents/Agent.java
@@ -7,6 +7,7 @@
7 7
 import com.jme3.scene.Spatial;
8 8
 import com.jme3.ai.agents.util.AbstractWeapon;
9 9
 import com.jme3.ai.agents.util.GameObject;
  10
+import com.jme3.math.FastMath;
10 11
 import com.jme3.math.Vector3f;
11 12
 import com.jme3.renderer.Camera;
12 13
 import com.jme3.renderer.RenderManager;
@@ -19,12 +20,11 @@
19 20
  *
20 21
  * @author Jesús Martín Berlanga
21 22
  * @author Tihomir Radosavljević
22  
- * @version 1.1
  23
+ * @version 1.2
23 24
  */
24 25
 public class Agent<T> extends GameObject {
25  
-
26  
-    private float tpf;
27 26
     
  27
+    private float tpf;
28 28
     /**
29 29
      * Class that enables you to add all variable you need for your agent.
30 30
      */
@@ -53,6 +53,26 @@
53 53
      * Camera that is attached to agent.
54 54
      */
55 55
     private Camera camera;
  56
+    /**
  57
+     * Size of bounding sphere, for steer behaviours
  58
+     *
  59
+     * @author Jesús Martín Berlanga
  60
+     */
  61
+    float radius = 0;
  62
+
  63
+    /**
  64
+     * @author Jesús Martín Berlanga
  65
+     */
  66
+    public void setRadius(float radius) {
  67
+        this.radius = radius;
  68
+    }
  69
+
  70
+    /**
  71
+     * @author Jesús Martín Berlanga
  72
+     */
  73
+    public float getRadius() {
  74
+        return this.radius;
  75
+    }
56 76
 
57 77
     /**
58 78
      * @param name unique name/id of agent
@@ -159,7 +179,7 @@ public T getModel() {
159 179
     public void setModel(T model) {
160 180
         this.model = model;
161 181
     }
162  
-
  182
+    
163 183
     @Override
164 184
     public int hashCode() {
165 185
         int hash = 7;
@@ -167,7 +187,7 @@ public int hashCode() {
167 187
         hash = 47 * hash + (this.team != null ? this.team.hashCode() : 0);
168 188
         return hash;
169 189
     }
170  
-
  190
+    
171 191
     @Override
172 192
     public boolean equals(Object obj) {
173 193
         if (obj == null) {
@@ -185,11 +205,11 @@ public boolean equals(Object obj) {
185 205
         }
186 206
         return true;
187 207
     }
188  
-    
  208
+
189 209
     /**
190 210
      * @author Tihomir Radosavljević
191 211
      * @author Jesús Martín Berlanga
192  
-     */ 
  212
+     */
193 213
     @Override
194 214
     protected void controlUpdate(float tpf) {
195 215
         
@@ -203,41 +223,42 @@ protected void controlUpdate(float tpf) {
203 223
             weapon.update(tpf);
204 224
         }
205 225
     }
206  
-    
  226
+
207 227
     /**
208 228
      * Calculates the projected location in relation with other target
209  
-     * 
  229
+     *
210 230
      * @param target The other agent
211 231
      * @return The projected location in relation with other target
212  
-     * 
  232
+     *
213 233
      * @author Jesús Martín Berlanga
214 234
      */
215 235
     public Vector3f calculateProjectedLocation(Agent target) {
216 236
         float targetSpeed = target.getMoveSpeed();
217 237
         float speedDiff = targetSpeed - this.getMoveSpeed();
218 238
         float desiredSpeed = (targetSpeed + speedDiff) * this.tpf;
219  
-     
220  
-        if(target.getAcceleration() == null)
221  
-             target.setAcceleration(new Vector3f());
  239
+        
  240
+        if (target.getAcceleration() == null) {
  241
+            target.setAcceleration(new Vector3f());
  242
+        }
222 243
         
223 244
         return target.getLocalTranslation().add(target.getAcceleration().mult(desiredSpeed));
224  
-    } 
225  
-  
226  
-    
227  
-   /**
228  
-    * Gets the predicted position for this 'frame', 
229  
-    * taking into account current position and velocity.
230  
-    * 
231  
-    * @author Jesús Martín Berlanga
232  
-    */
  245
+    }
  246
+
  247
+    /**
  248
+     * Gets the predicted position for this 'frame', taking into account current
  249
+     * position and velocity.
  250
+     *
  251
+     * @author Jesús Martín Berlanga
  252
+     */
233 253
     public Vector3f getPredictedPosition() {
234 254
         
235  
-       if(this.getAcceleration() == null)
  255
+        if (this.getAcceleration() == null) {
236 256
             this.setAcceleration(new Vector3f());
  257
+        }
237 258
         
238  
-       return this.getLocalTranslation().add(this.getAcceleration());
  259
+        return this.getLocalTranslation().add(this.getAcceleration());
239 260
     }
240  
-
  261
+    
241 262
     @Override
242 263
     protected void controlRender(RenderManager rm, ViewPort vp) {
243 264
         throw new UnsupportedOperationException("You should override it youself");
@@ -285,4 +306,138 @@ public Camera getCamera() {
285 306
     public void setCamera(Camera camera) {
286 307
         this.camera = camera;
287 308
     }
  309
+
  310
+    /**
  311
+     * Check if this agent is considered in the same "neighborhood" in relation
  312
+     * with another agent. <br> <br>
  313
+     *
  314
+     * If the distance is lower than minDistance It is definitely considered in
  315
+     * the same neighborhood. <br> <br>
  316
+     *
  317
+     * If the distance is higher than maxDistance It is defenitely not
  318
+     * considered in the same neighborhood. <br> <br>
  319
+     *
  320
+     * If the distance is inside [minDistance. maxDistance] It is considered in
  321
+     * teh same neighborhood if the forwardness is higher than the 1 -
  322
+     * sinMaxAngle.
  323
+     *
  324
+     * @param Agent The other agent
  325
+     * @param minDistance Min. distance to be in the same "neighborhood"
  326
+     * @param maxDistance Max. distance to be in the same "neighborhood"
  327
+     * @param MaxAngle Max angle in radians
  328
+     *
  329
+     * @author Jesús Martín Berlanga
  330
+     */
  331
+    public boolean inBoidNeighborhood(
  332
+            Agent neighbour,
  333
+            float minDistance,
  334
+            float maxDistance,
  335
+            float MaxAngle) {
  336
+        boolean isInBoidNeighborhood;
  337
+        
  338
+        if (this == neighbour) {
  339
+            isInBoidNeighborhood = false;
  340
+        } else {
  341
+            float distanceSquared = this.distanceSquaredRelativeToAgent(neighbour);
  342
+
  343
+            // definitely in neighborhood if inside minDistance sphere
  344
+            if (distanceSquared < (minDistance * minDistance)) {
  345
+                isInBoidNeighborhood = true;
  346
+            } // definitely not in neighborhood if outside maxDistance sphere
  347
+            else if (distanceSquared > maxDistance * maxDistance) {
  348
+                isInBoidNeighborhood = false;
  349
+            } // otherwise, test angular offset from forward axis.
  350
+            else {
  351
+                
  352
+                if(this.getAcceleration() != null)
  353
+                {
  354
+                    Vector3f unitOffset = this.offset(neighbour).divide(distanceSquared);
  355
+                    float forwardness = this.forwardness(unitOffset);
  356
+                    isInBoidNeighborhood = forwardness > FastMath.cos(MaxAngle);
  357
+                //    System.out.println("Offset:" + unitOffset + ";Fordwardness = " + forwardness + "; cosMaxAngle =" + FastMath.cos(MaxAngle) + "; " + isInBoidNeighborhood);//debug
  358
+                }
  359
+                else
  360
+                {
  361
+                    isInBoidNeighborhood = false;
  362
+                }
  363
+            }
  364
+        }
  365
+        
  366
+        return isInBoidNeighborhood;
  367
+    }
  368
+
  369
+    /**
  370
+     * Calculates the forwardness in relation with another agent. That is how
  371
+     * "forward" is the direction to the quarry (1 means dead ahead, 0 is
  372
+     * directly to the side, -1 is straight back)
  373
+     *
  374
+     * @param agent Other agent
  375
+     * @return The forwardness in relation with another agent
  376
+     *
  377
+     * @author Jesús Martín Berlanga
  378
+     */
  379
+    public float forwardness(Agent agent) 
  380
+    {
  381
+        Vector3f agentLooks = this.fordwardVector();
  382
+        float radiansAngleBetwen = agentLooks.angleBetween(this.offset(agent).normalize()); 
  383
+        return (float) FastMath.cos(radiansAngleBetwen); 
  384
+    }
  385
+    
  386
+    public Vector3f fordwardVector() {
  387
+        return this.getLocalRotation().mult(new Vector3f(0,0,1)).normalize();
  388
+    }
  389
+
  390
+    /**
  391
+     * Calculates the forwardness in relation with a position vector
  392
+     *
  393
+     * @param positionVector Offset vector.
  394
+     * @see Agent#forwardness(com.jme3.ai.agents.Agent)
  395
+     *
  396
+     * @author Jesús Martín Berlanga
  397
+     */
  398
+    public float forwardness(Vector3f offsetVector) {
  399
+        Vector3f agentLooks = this.getLocalRotation().mult(new Vector3f(0,0,1)).normalize();
  400
+        float radiansAngleBetwen = agentLooks.angleBetween(offsetVector.normalize());
  401
+        return FastMath.cos(radiansAngleBetwen); 
  402
+    }
  403
+
  404
+    /**
  405
+     * @param agent Other agent
  406
+     * @return Distance relative to another Agent
  407
+     *
  408
+     * @author Jesús Martín Berlanga
  409
+     */
  410
+    public float distanceRelativeToAgent(Agent agent) {
  411
+        return this.offset(agent).length();
  412
+    }
  413
+
  414
+    /**
  415
+     * @param agent Other agent
  416
+     * @return Distance squared relative to another Agent
  417
+     *
  418
+     * @author Jesús Martín Berlanga
  419
+     */
  420
+    public float distanceSquaredRelativeToAgent(Agent agent) {
  421
+        return this.offset(agent).lengthSquared();
  422
+    }
  423
+
  424
+    /**
  425
+     * @param agent Other agent
  426
+     * @return The offset relative to another Agent
  427
+     *
  428
+     * @author Jesús Martín Berlanga
  429
+     */
  430
+    public Vector3f offset(Agent agent) {
  431
+        return agent.getLocalTranslation().subtract(this.getLocalTranslation());
  432
+    }
  433
+    
  434
+    /**
  435
+     * @param agent Other agent
  436
+     * @return The offset relative to an position vector
  437
+     *
  438
+     * @author Jesús Martín Berlanga
  439
+     */
  440
+    public Vector3f offset(Vector3f positionVector) {
  441
+        return positionVector.subtract(this.getLocalTranslation());
  442
+    }
288 443
 }
48 src/com/jme3/ai/agents/behaviours/npc/steering/AbstractSteeringBehaviour.java
@@ -14,11 +14,36 @@
14 14
  *
15 15
  * @author Tihomir Radosavljević
16 16
  * @author Jesús Martín Berlanga
17  
- * @version 1.1
  17
+ * @version 1.2
18 18
  */
19 19
 public abstract class AbstractSteeringBehaviour extends Behaviour {
20 20
 
21 21
     /**
  22
+     * If this is true the new Velocity upated in controlUpdate will be (0,0,0)
  23
+     * 
  24
+     * @author Jesús Martín Berlanga
  25
+     */
  26
+    protected boolean freezeTheMovement = false;
  27
+    
  28
+    /** @author Jesús Martín Berlanga */
  29
+    public void setFreezeTheMovement(boolean freezeTheMovement) { this.freezeTheMovement = freezeTheMovement; }
  30
+    
  31
+    /** @author Jesús Martín Berlanga */
  32
+    public boolean getFreezeTheMovement() { return this.freezeTheMovement; }
  33
+    
  34
+    private float tpf;
  35
+    
  36
+    /** @author Jesús Martín Berlanga */
  37
+    public float getTPF(){ return this.tpf; }
  38
+    
  39
+    /**
  40
+     * Manually update the tpf
  41
+     * @param tpf tpf
  42
+     * @author Jesús Martín Berlanga
  43
+     */
  44
+    public void setTPF(float tpf) { this.tpf = tpf; }
  45
+    
  46
+    /**
22 47
      * Velocity of our agent.
23 48
      */
24 49
     protected Vector3f velocity;
@@ -50,16 +75,16 @@ public AbstractSteeringBehaviour(Agent agent, Spatial spatial) {
50 75
      * @author Jesús Martín Berlanga
51 76
      * @author Tihomir Radosavljević
52 77
      */
53  
-    protected Vector3f calculateNewVelocity() {
54  
-
  78
+    protected Vector3f calculateNewVelocity() 
  79
+    {
55 80
         agent.setAcceleration(this.calculateSteering().mult(1 / agentTotalMass()));
56 81
         velocity = velocity.add(agent.getAcceleration());
57  
-        
  82
+        agent.setVelocity(velocity);
  83
+  
58 84
         if (velocity.length() > agent.getMaxMoveSpeed()) 
59 85
             velocity = velocity.normalize().mult(agent.getMaxMoveSpeed());
60 86
         
61 87
         return velocity;
62  
-        
63 88
     }
64 89
 
65 90
     /**
@@ -110,10 +135,21 @@ public void setVelocity(Vector3f velocity) {
110 135
      * Usual update pattern for steering behaviours.
111 136
      *
112 137
      * @param tpf
  138
+     * 
  139
+     * @author Jesús Martín Berlanga
  140
+     * @author Tihomir Radosavljević
113 141
      */
114 142
     @Override
115 143
     protected void controlUpdate(float tpf) {
116  
-        Vector3f vel = calculateNewVelocity().mult(tpf);
  144
+        this.tpf = tpf;
  145
+        
  146
+        Vector3f vel = new Vector3f();
  147
+        
  148
+        if(this.freezeTheMovement == false)
  149
+        {
  150
+             vel = calculateNewVelocity().mult(tpf);
  151
+        }
  152
+
117 153
         agent.setLocalTranslation(agent.getLocalTranslation().add(vel));
118 154
         rotateAgent(tpf);
119 155
     }
110 src/com/jme3/ai/agents/behaviours/npc/steering/AlignmentBehaviour.java
... ...
@@ -0,0 +1,110 @@
  1
+//Copyright (c) 2014, Jesús Martín Berlanga. All rights reserved. Distributed under the BSD licence. Read "com/jme3/ai/license.txt".
  2
+
  3
+package com.jme3.ai.agents.behaviours.npc.steering;
  4
+
  5
+import com.jme3.ai.agents.Agent;
  6
+import com.jme3.math.FastMath;
  7
+import com.jme3.math.Vector3f;
  8
+import com.jme3.renderer.RenderManager;
  9
+import com.jme3.renderer.ViewPort;
  10
+import com.jme3.scene.Spatial;
  11
+import java.util.ArrayList;
  12
+import java.util.List;
  13
+
  14
+/**
  15
+ * Craig W. Reynolds: "Alignment steering behavior gives an character the ability 
  16
+ * to align itself with (that is, head in the same direction as) other nearby
  17
+ * characters. Steering for alignment can be computed by finding all characters
  18
+ * in the local neighborhood, averaging the unit forward vector of the nearby 
  19
+ * characters. This average is the “desired velocity,” and so the steering vector
  20
+ * is the difference between the average and our character’s forward vector. This 
  21
+ * steering will tend to turn our character so it is aligned with its neighbors."
  22
+ *
  23
+ * @author Jesús Martín Berlanga
  24
+ * @version 1.0
  25
+ */
  26
+public class AlignmentBehaviour extends AbstractStrengthSteeringBehaviour {
  27
+    
  28
+    private List<Agent> neighbours = new ArrayList<Agent>();
  29
+    
  30
+    public List<Agent> getNeighbours(){return this.neighbours;}
  31
+    
  32
+    private float maxDistance = Float.POSITIVE_INFINITY;
  33
+    private float maxAngle = FastMath.PI / 2;
  34
+
  35
+    /**
  36
+     *  maxAngle is setted to PI / 2 by default and maxDistance to infinite.
  37
+     * 
  38
+     * @param agent To whom behaviour belongs.
  39
+     * @param neighbours Neighbours, this agent is moving toward the center of this neighbours.
  40
+     */
  41
+    public AlignmentBehaviour(Agent agent, List<Agent> neighbours){
  42
+        super(agent);
  43
+        this.neighbours = neighbours;
  44
+    }
  45
+    
  46
+    /**
  47
+     * @param maxDistance In order to consider a neihbour inside the neighbourhood
  48
+     * @param maxAngle In order to consider a neihbour inside the neighbourhood
  49
+     * @see  Agent#inBoidNeighborhoodMaxAngle(com.jme3.ai.agents.Agent, float, float, float) 
  50
+     * @see  AlignmentBehaviour#AlignmentBehaviour(com.jme3.ai.agents.Agent, java.util.List) 
  51
+     */
  52
+    public AlignmentBehaviour(Agent agent, List<Agent> neighbours, float maxDistance, float maxAngle){
  53
+        super(agent);
  54
+        this.neighbours = neighbours;
  55
+        this.maxDistance = maxDistance;
  56
+        this.maxAngle = maxAngle;
  57
+    }
  58
+    
  59
+    /**
  60
+     * @param spatial active spatial during excecution of behaviour
  61
+     * @see AlignmentBehaviour#AlignmentBehaviour(com.jme3.ai.agents.Agent, java.util.List)
  62
+     */
  63
+    public AlignmentBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours) {
  64
+        super(agent, spatial);
  65
+        this.neighbours = neighbours;
  66
+    }
  67
+    
  68
+    /**
  69
+     * @see AlignmentBehaviour#AlignmentBehaviour(com.jme3.ai.agents.Agent, java.util.List)
  70
+     * @see AlignmentBehaviour#AlignmentBehaviour(com.jme3.ai.agents.Agent, java.util.List, float, float) 
  71
+     */
  72
+     public AlignmentBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours, float maxDistance, float maxAngle) {
  73
+        super(agent, spatial);
  74
+        this.neighbours = neighbours;
  75
+        this.maxDistance = maxDistance;
  76
+        this.maxAngle = maxAngle;
  77
+     }
  78
+    
  79
+    @Override
  80
+    Vector3f calculateFullSteering() 
  81
+    {         
  82
+        // steering accumulator and count of neighbors, both initially zero
  83
+        Vector3f steering = new Vector3f();
  84
+        int realNeighbors = 0; 
  85
+        
  86
+        // for each of the other vehicles...
  87
+        for (Agent agentO : this.neighbours)
  88
+        {
  89
+            if (this.agent.inBoidNeighborhood(agentO, this.agent.getRadius()*3, this.maxDistance, this.maxAngle))
  90
+            {
  91
+                // accumulate sum of neighbor's positions
  92
+                steering = steering.add(agentO.fordwardVector());
  93
+                realNeighbors++;
  94
+            }
  95
+        }
  96
+        
  97
+        // divide by neighbors, subtract off current position to get error-correcting direction
  98
+       if(realNeighbors > 0)
  99
+        {
  100
+             steering = steering.divide(realNeighbors);
  101
+             steering = this.agent.offset(steering);
  102
+        } 
  103
+        
  104
+        return steering;
  105
+    }
  106
+
  107
+    @Override
  108
+    protected void controlRender(RenderManager rm, ViewPort vp) { }
  109
+
  110
+}
100 src/com/jme3/ai/agents/behaviours/npc/steering/ArriveBehaviour.java
... ...
@@ -0,0 +1,100 @@
  1
+//Copyright (c) 2014, Jesús Martín Berlanga. All rights reserved. Distributed under the BSD licence. Read "com/jme3/ai/license.txt".
  2
+
  3
+package com.jme3.ai.agents.behaviours.npc.steering;
  4
+
  5
+import com.jme3.ai.agents.Agent;
  6
+import com.jme3.math.Vector3f;
  7
+import com.jme3.scene.Spatial;
  8
+
  9
+/**
  10
+ * Arrival behavior is identical to seek while the character is far from its target. 
  11
+ * But instead of moving through the target at full speed, this behavior causes the 
  12
+ * character to slow down as it approaches the target, eventually slowing to a stop 
  13
+ * coincident with the target
  14
+ *
  15
+ * @author Jesús Martín Berlanga
  16
+ * @version 1.0
  17
+ */
  18
+public class ArriveBehaviour extends SeekBehaviour {
  19
+
  20
+    private float slowingDistance;
  21
+    private SlowBehaviour slow;
  22
+    private float errorDistance = 0.01f;
  23
+    
  24
+    public void setErrorDistance(float errorDistance){ this.errorDistance = errorDistance; }
  25
+    public SlowBehaviour getSlow() { return this.slow; }
  26
+    
  27
+    /** 
  28
+     * The slowingDistance is (0.1 * distance betwen agents) by default. <br> <br>
  29
+     * The slow proportion is 0.5 by default.
  30
+     * 
  31
+     * @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent) 
  32
+     */
  33
+    public ArriveBehaviour(Agent agent, Agent target) { 
  34
+        super(agent, target);
  35
+        this.slowingDistance = agent.distanceRelativeToAgent(target) * 0.135f;
  36
+        this.slow = new SlowBehaviour(agent);
  37
+    }
  38
+    
  39
+    /**
  40
+     * The slowingDistance is (0.1 * distance betwen agents) by default. <br> <br>
  41
+     * The slow proportion is 0.5 by default.
  42
+     * 
  43
+     * @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, com.jme3.scene.Spatial) 
  44
+     */
  45
+    public ArriveBehaviour(Agent agent, Agent target, Spatial spatial) {  
  46
+        super(agent, target, spatial); 
  47
+        this.slowingDistance = agent.distanceRelativeToAgent(target) * 0.135f;
  48
+        this.slow = new SlowBehaviour(agent);
  49
+    }
  50
+    
  51
+    /**
  52
+     * @param slowingDistance The distance when this agent will start slowing down
  53
+     * @see ArriveBehaviour#ArriveBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent) 
  54
+     */
  55
+    public ArriveBehaviour(Agent agent, Agent target, float slowingDistance, float slowPercentaje) {
  56
+        super(agent, target);
  57
+        this.slowingDistance = slowingDistance;
  58
+        this.slow = new SlowBehaviour(agent, slowPercentaje);
  59
+    }
  60
+    
  61
+    /**
  62
+     * @param slowingDistance The distance when this agent will start slowing down
  63
+     * @see ArriveBehaviour#ArriveBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, com.jme3.scene.Spatial) 
  64
+     */
  65
+    public ArriveBehaviour(Agent agent, Agent target, Spatial spatial, float slowingDistance, float slowPercentaje) {
  66
+        super(agent, target, spatial);
  67
+        this.slowingDistance = slowingDistance;
  68
+        this.slow = new SlowBehaviour(agent, slowPercentaje);
  69
+    }
  70
+    
  71
+    /**
  72
+     * Calculate steering vector.
  73
+     *
  74
+     * @return steering vector
  75
+     * 
  76
+     * @see AbstractStrengthSteeringBehaviour#calculateFullSteering() 
  77
+     * @see SeekBehaviour#calculateFullSteering() 
  78
+     * 
  79
+     * @author Jesús Martín Berlanga
  80
+     */
  81
+    @Override
  82
+    protected Vector3f calculateFullSteering() 
  83
+    {
  84
+      Vector3f steer = new Vector3f();
  85
+      float distanceToTarget = this.agent.distanceRelativeToAgent(this.getTarget());
  86
+               
  87
+      if(distanceToTarget > (this.getTarget().getRadius() + this.errorDistance))
  88
+      {
  89
+         steer = super.calculateFullSteering();
  90
+      
  91
+         if(distanceToTarget < this.slowingDistance)
  92
+              steer = steer.add(this.slow.calculateFullSteering());
  93
+         
  94
+      }
  95
+      else
  96
+           this.setFreezeTheMovement(true);
  97
+
  98
+      return steer;
  99
+    }
  100
+}
106 src/com/jme3/ai/agents/behaviours/npc/steering/CohesionBehaviour.java
... ...
@@ -0,0 +1,106 @@
  1
+//Copyright (c) 2014, Jesús Martín Berlanga. All rights reserved. Distributed under the BSD licence. Read "com/jme3/ai/license.txt".
  2
+
  3
+package com.jme3.ai.agents.behaviours.npc.steering;
  4
+
  5
+import com.jme3.ai.agents.Agent;
  6
+import com.jme3.math.FastMath;
  7
+import com.jme3.math.Vector3f;
  8
+import com.jme3.renderer.RenderManager;
  9
+import com.jme3.renderer.ViewPort;
  10
+import com.jme3.scene.Spatial;
  11
+import java.util.ArrayList;
  12
+import java.util.List;
  13
+
  14
+/**
  15
+ * Move toward center of neighbors.
  16
+ *
  17
+ * @author Jesús Martín Berlanga
  18
+ * @version 1.0
  19
+ */
  20
+public class CohesionBehaviour extends AbstractStrengthSteeringBehaviour {
  21
+    
  22
+    private List<Agent> neighbours = new ArrayList<Agent>();
  23
+    
  24
+    public List<Agent> getNeighbours(){return this.neighbours;}
  25
+    
  26
+    private float maxDistance = Float.POSITIVE_INFINITY;
  27
+    private float maxAngle = FastMath.PI / 2;
  28
+    
  29
+    /**
  30
+     *  maxAngle is setted to PI / 2 by default and maxDistance to infinite.
  31
+     * 
  32
+     * @param agent To whom behaviour belongs.
  33
+     * @param neighbours Neighbours, this agent is moving toward the center of this neighbours.
  34
+     */
  35
+    public CohesionBehaviour(Agent agent, List<Agent> neighbours){
  36
+        super(agent);
  37
+        this.neighbours = neighbours;
  38
+    }
  39
+    
  40
+    /**
  41
+     * @param maxDistance In order to consider a neihbour inside the neighbourhood
  42
+     * @param maxAngle In order to consider a neihbour inside the neighbourhood
  43
+     * @see  Agent#inBoidNeighborhoodMaxAngle(com.jme3.ai.agents.Agent, float, float, float) 
  44
+     * @see  CohesionBehaviour#CohesionBehaviour(com.jme3.ai.agents.Agent, java.util.List) 
  45
+     */
  46
+    public CohesionBehaviour(Agent agent, List<Agent> neighbours, float maxDistance, float maxAngle){
  47
+        super(agent);
  48
+        this.neighbours = neighbours;
  49
+        this.maxDistance = maxDistance;
  50
+        this.maxAngle = maxAngle;
  51
+    }
  52
+    
  53
+    /**
  54
+     * @param spatial active spatial during excecution of behaviour
  55
+     * @see CohesionBehaviour#CohesionBehaviour(com.jme3.ai.agents.Agent, java.util.List)
  56
+     */
  57
+    public CohesionBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours) {
  58
+        super(agent, spatial);
  59
+        this.neighbours = neighbours;
  60
+    }
  61
+    
  62
+    /**
  63
+     * @see CohesionBehaviour#CohesionBehaviour(com.jme3.ai.agents.Agent, java.util.List)
  64
+     * @see CohesionBehaviour#CohesionBehaviour(com.jme3.ai.agents.Agent, java.util.List, float, float) 
  65
+     */
  66
+     public CohesionBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours, float maxDistance, float maxAngle) {
  67
+        super(agent, spatial);
  68
+        this.neighbours = neighbours;
  69
+        this.maxDistance = maxDistance;
  70
+        this.maxAngle = maxAngle;
  71
+     }
  72
+    
  73
+    @Override
  74
+    protected Vector3f calculateFullSteering()
  75
+    {
  76
+        
  77
+        // steering accumulator and count of neighbors, both initially zero
  78
+        Vector3f steering = new Vector3f();
  79
+
  80
+        int realNeighbors = 0; 
  81
+        
  82
+        // for each of the other vehicles...
  83
+        for (Agent agentO : this.neighbours)
  84
+        {
  85
+            if (this.agent.inBoidNeighborhood(agentO, this.agent.getRadius()*3, this.maxDistance, this.maxAngle))
  86
+            {
  87
+                // accumulate sum of neighbor's positions
  88
+                steering = steering.add(agentO.getLocalTranslation());
  89
+                realNeighbors++;
  90
+            }
  91
+        }
  92
+        
  93
+        // divide by neighbors, subtract off current position to get error-correcting direction
  94
+       if(realNeighbors > 0)
  95
+        {
  96
+             steering = steering.divide(realNeighbors);
  97
+             steering = this.agent.offset(steering);
  98
+        } 
  99
+        
  100
+        return steering;
  101
+    }
  102
+    
  103
+    @Override
  104
+    protected void controlRender(RenderManager rm, ViewPort vp) {  }
  105
+  
  106
+}
39 src/com/jme3/ai/agents/behaviours/npc/steering/CompoundSteeringBehaviour.java
@@ -22,9 +22,20 @@
22 22
  * AbstractSteeringBehaviour.
23 23
  * 
24 24
  * @author Jesús Martín Berlanga
  25
+ * @version 1.1
25 26
  */
26 27
 public class CompoundSteeringBehaviour extends AbstractSteeringBehaviour {
27  
-
  28
+    
  29
+    /** @see AbstractSteeringBehaviour#freezeTheMovement */
  30
+    @Override
  31
+    public void setFreezeTheMovement(boolean freezeTheMovement) { 
  32
+        this.freezeTheMovement = freezeTheMovement;
  33
+        
  34
+        if(freezeTheMovement == true)
  35
+          for(AbstractSteeringBehaviour steerBehaviour : behaviours)
  36
+              steerBehaviour.setFreezeTheMovement(freezeTheMovement);
  37
+    }
  38
+    
28 39
     private List<AbstractSteeringBehaviour> behaviours;
29 40
     
30 41
     protected List<AbstractSteeringBehaviour> getBehaviours() {
@@ -68,10 +79,18 @@ public void addSteerBehaviour (AbstractSteeringBehaviour behaviour) {
68 79
     protected Vector3f calculateSteering() {
69 80
         
70 81
         Vector3f totalForce = new Vector3f();
71  
-        
  82
+         
72 83
         for(AbstractSteeringBehaviour steerBehaviour : behaviours)
73 84
         {
74  
-            totalForce = totalForce.add(this.calculatePartialForce(steerBehaviour));
  85
+            this.setFreezeTheMovement(false);
  86
+            
  87
+            if(steerBehaviour.getFreezeTheMovement() == false)
  88
+                 totalForce = totalForce.add(this.calculatePartialForce(steerBehaviour));
  89
+            else
  90
+            { 
  91
+                this.setFreezeTheMovement(true);
  92
+                break;
  93
+            }
75 94
         }
76 95
         
77 96
         return totalForce;
@@ -89,4 +108,18 @@ protected Vector3f calculatePartialForce(AbstractSteeringBehaviour behaviour) {
89 108
 
90 109
     protected void controlRender(RenderManager rm, ViewPort vp) {  }
91 110
 
  111
+    /**
  112
+     * Usual update pattern for steering behaviours.
  113
+     *
  114
+     * @param tpf
  115
+     */
  116
+    @Override
  117
+    protected void controlUpdate(float tpf) {
  118
+        
  119
+        for(AbstractSteeringBehaviour steerBehaviour : behaviours)
  120
+            steerBehaviour.setTPF(tpf);
  121
+        
  122
+        super.controlUpdate(tpf);
  123
+    }
  124
+    
92 125
 }
150 src/com/jme3/ai/agents/behaviours/npc/steering/LeaderFollowing.java
... ...
@@ -0,0 +1,150 @@
  1
+//Copyright (c) 2014, Jesús Martín Berlanga. All rights reserved. Distributed under the BSD licence. Read "com/jme3/ai/license.txt".
  2
+
  3
+package com.jme3.ai.agents.behaviours.npc.steering;
  4
+
  5
+import com.jme3.ai.agents.Agent;
  6
+import com.jme3.math.Vector3f;
  7
+import com.jme3.scene.Spatial;
  8
+
  9
+/**
  10
+ * This is similar to pursuit behaviour, but pursuiers must stay away from the pursued path.
  11
+ *
  12
+ * @author Jesús Martín Berlanga
  13
+ * @version 1.2
  14
+ */
  15
+public class LeaderFollowing extends SeekBehaviour {
  16
+    
  17
+    private float distanceToChangeFocus;
  18
+    private double minimumAngle;
  19
+    private float porcentajeSpeedWhenCorrectBehind;
  20
+    private float porcentajeSpeedDistance;
  21
+    
  22
+    /** @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent)  */
  23
+    public LeaderFollowing(Agent agent, Agent target) {
  24
+        super(agent, target);
  25
+        
  26
+        //Default values
  27
+        this.distanceToChangeFocus = 5;
  28
+        this.minimumAngle = Math.PI / 2;
  29
+        this.porcentajeSpeedWhenCorrectBehind = 0.18f;
  30
+        this.porcentajeSpeedDistance = 4;
  31
+    }
  32
+    
  33
+    /** 
  34
+     * @param distanceToChangeFocus Distance to change the focus.
  35
+     * @param minimunAngle  Minimum angle betwen the target velocity and the vehicle location.
  36
+     * @param porcentajeSpeedWhenCorrectBehind  Porcentaje of speed when the vehicle is in the correct position.
  37
+     * @param porcentajeSpeedDistance The distance factor of porcentajeSpeedWhenCorrectBehind.
  38
+     * 
  39
+     * @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent) 
  40
+     */
  41
+    public LeaderFollowing(Agent agent, Agent target, float distanceToChangeFocus, float minimunAngle,
  42
+            float porcentajeSpeedWhenCorrectBehind, float porcentajeSpeedDistance) {
  43
+        
  44
+        super(agent, target);
  45
+        
  46
+        this.distanceToChangeFocus = distanceToChangeFocus;
  47
+        this.minimumAngle = minimunAngle;
  48
+        this.porcentajeSpeedWhenCorrectBehind = porcentajeSpeedWhenCorrectBehind;
  49
+        this.porcentajeSpeedDistance = porcentajeSpeedDistance;
  50
+    }
  51
+    
  52
+    /** @see AbstractSteeringBehaviour#AbstractSteeringBehaviour(com.jme3.ai.agents.Agent, com.jme3.scene.Spatial) 
  53
+     *  @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, float, float, float, float) */
  54
+    public LeaderFollowing(Agent agent, Agent target, Spatial spatial, float distanceToChangeFocus, float minimunAngle,
  55
+            float porcentajeSpeedWhenCorrectBehind, float porcentajeSpeedDistance) {
  56
+        
  57
+        super(agent, target, spatial);
  58
+        
  59
+        this.distanceToChangeFocus = distanceToChangeFocus;
  60
+        this.minimumAngle = minimunAngle;
  61
+        this.porcentajeSpeedWhenCorrectBehind = porcentajeSpeedWhenCorrectBehind;
  62
+        this.porcentajeSpeedDistance = porcentajeSpeedDistance;
  63
+    }
  64
+    
  65
+    /** @see AbstractStrengthSteeringBehaviour#calculateFullSteering()  */
  66
+    @Override
  67
+    protected Vector3f calculateSteering(){
  68
+        
  69
+        Vector3f desierdVel;
  70
+        
  71
+        float agentSpeed = this.agent.getMoveSpeed();
  72
+        Vector3f agentLocation = agent.getLocalTranslation();
  73
+        
  74
+        float targetSpeed = this.getTarget().getMoveSpeed();
  75
+        
  76
+        Vector3f targetVelocity;
  77
+        
  78
+        if(this.getTarget().getAcceleration() == null)
  79
+            targetVelocity = new Vector3f();
  80
+        else
  81
+            targetVelocity = this.getTarget().getAcceleration();
  82
+        
  83
+        Vector3f targetTrueLocation = this.getTarget().getLocalTranslation();
  84
+        
  85
+        //Calculate de desired speed
  86
+        float speedDiff = targetSpeed - agentSpeed;
  87
+        
  88
+        float desiredSpeed = (targetSpeed + speedDiff) * this.getTPF();
  89
+        
  90
+        //Vehicle distance from the true location
  91
+        float distanceFromTrueLocation = agentLocation.distance(targetTrueLocation);
  92
+        
  93
+        //Change the focus, non finite posible solutions
  94
+        double focusFactor = this.changeFocusFactor(distanceFromTrueLocation);
  95
+        
  96
+        Vector3f seekingLocation = targetTrueLocation.add(this.getTarget().getPredictedPosition().subtract(
  97
+                targetTrueLocation).mult((float) focusFactor));
  98
+        
  99
+        //Project the location you want to reach
  100
+        Vector3f projectedLocation = seekingLocation.add(targetVelocity.mult(desiredSpeed));
  101
+           
  102
+        //Angle controls
  103
+        if(distanceFromTrueLocation < this.distanceToChangeFocus){
  104
+            if(checkAngle(targetVelocity, targetTrueLocation, agentLocation))
  105
+                //If the vehicle is in the correct position, maintain it using the proper factor
  106
+                desierdVel = projectedLocation.subtract(agentLocation).normalize().mult((agentSpeed * porcentajeSpeedWhenCorrectBehind
  107
+                        * distanceFromTrueLocation)/this.porcentajeSpeedDistance);
  108
+            else{
  109
+                //If not, get out of the way
  110
+                projectedLocation = seekingLocation.add(targetVelocity.negate().mult((targetSpeed / (distanceFromTrueLocation * 0.05f))));
  111
+                desierdVel = projectedLocation.subtract(agentLocation).normalize().mult(agentSpeed);
  112
+            }
  113
+        }else
  114
+            //If is still away from the target, move normally
  115
+            desierdVel = projectedLocation.subtract(agentLocation).normalize().mult(agentSpeed);
  116
+        
  117
+        return desierdVel.subtract(velocity);
  118
+        
  119
+    }
  120
+    
  121
+    
  122
+    //Calculates the factor in order to change the focus
  123
+    private double changeFocusFactor(float distanceFromFocus){
  124
+        double factor;
  125
+        
  126
+        if(distanceFromFocus > this.distanceToChangeFocus)
  127
+            factor = 1;
  128
+        else
  129
+            factor = Math.pow((1 + distanceFromFocus/this.distanceToChangeFocus), 2);
  130
+        
  131
+        return factor;
  132
+    }
  133
+    
  134
+    //Return false if the angle is not correct.
  135
+    private boolean checkAngle(Vector3f targetVelocity,
  136
+            Vector3f targetTrueLocation,
  137
+            Vector3f vehicleLocation){
  138
+        return calculateAngle(targetVelocity, targetTrueLocation, vehicleLocation) > minimumAngle;
  139
+    }
  140
+    
  141
+    //Calculate the angle
  142
+    private float calculateAngle(Vector3f targetVelocity,
  143
+            Vector3f targetTrueLocation,
  144
+            Vector3f vehicleLocation){
  145
+        
  146
+        Vector3f fromTagetToVehicle = vehicleLocation.subtract(targetTrueLocation);
  147
+        return targetVelocity.angleBetween(fromTagetToVehicle);
  148
+    }
  149
+    
  150
+}
56 src/com/jme3/ai/agents/behaviours/npc/steering/MoveBehaviour.java
... ...
@@ -0,0 +1,56 @@
  1
+package com.jme3.ai.agents.behaviours.npc.steering;
  2
+
  3
+import com.jme3.ai.agents.Agent;
  4
+import com.jme3.math.Vector3f;
  5
+import com.jme3.renderer.RenderManager;
  6
+import com.jme3.renderer.ViewPort;
  7
+import com.jme3.scene.Spatial;
  8
+
  9
+/**
  10
+ * Simple move behaviour for NPC. Agent should move  to moveDirection. 
  11
+ *
  12
+ * @see Agent#moveSpeed
  13
+ *
  14
+ * @autor Jesús Martín Berlanga
  15
+ * @version 1.0
  16
+ */
  17
+public class MoveBehaviour extends AbstractStrengthSteeringBehaviour {
  18
+
  19
+    /**
  20
+     * Move direction of agent.
  21
+     */
  22
+    protected Vector3f moveDirection;
  23
+
  24
+
  25
+    public MoveBehaviour(Agent agent) {
  26
+        super(agent);
  27
+    }
  28
+
  29
+    public MoveBehaviour(Agent agent, Spatial spatial) {
  30
+        super(agent, spatial);
  31
+    }
  32
+
  33
+    @Override
  34
+    protected void controlRender(RenderManager rm, ViewPort vp) {
  35
+    }
  36
+
  37
+    public Vector3f getMoveDirection() {
  38
+        return moveDirection;
  39
+    }
  40
+
  41
+    public void setMoveDirection(Vector3f moveDirection) {
  42
+        this.moveDirection = moveDirection.normalize();
  43
+    }
  44
+
  45
+    /** @see AbstractStrengthSteeringBehaviour#calculateFullSteering()  */
  46
+    @Override
  47
+    Vector3f calculateFullSteering() {
  48
+        
  49
+        Vector3f moveDirection = new Vector3f();
  50
+
  51
+        if(this.moveDirection != null)
  52
+            moveDirection = this.moveDirection;
  53
+
  54
+        return moveDirection;
  55
+    }
  56
+}
143 src/com/jme3/ai/agents/behaviours/npc/steering/PursuitBehaviour.java
@@ -8,150 +8,39 @@
8 8
 
9 9
 /**
10 10
  * Brent Owens: "Pursuit is similar to seek except that the quarry (target) is another moving
11  
- * character. Effective pursuit requires a prediction of the target’s future position." <br> <br>
12  
- *
13  
- * Pursuers must stay away from the target path.
  11
+ * character. Effective pursuit requires a prediction of the target’s future position." 
14 12
  *
15 13
  * @author Jesús Martín Berlanga
  14
+ * @version 1.0
16 15
  */
17 16
 public class PursuitBehaviour extends SeekBehaviour {
18 17
     
19  
-    private float distanceToChangeFocus;
20  
-    private double minimumAngle;
21  
-    private float porcentajeSpeedWhenCorrectBehind;
22  
-    private float porcentajeSpeedDistance;
23  
-    private float tpf;
24  
-    
25 18
     /** @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent)  */
26 19
     public PursuitBehaviour(Agent agent, Agent target) {
27 20
         super(agent, target);
28  
-        
29  
-        //Default values
30  
-        this.distanceToChangeFocus = 5;
31  
-        this.minimumAngle = Math.PI / 2;
32  
-        this.porcentajeSpeedWhenCorrectBehind = 0.18f;
33  
-        this.porcentajeSpeedDistance = 4;
34 21
     }
35  
-    
36  
-    /** 
37  
-     * @param distanceToChangeFocus Distance to change the focus.
38  
-     * @param minimunAngle  Minimum angle betwen the target velocity and the vehicle location.
39  
-     * @param porcentajeSpeedWhenCorrectBehind  Porcentaje of speed when the vehicle is in the correct position.
40  
-     * @param porcentajeSpeedDistance The distance factor of porcentajeSpeedWhenCorrectBehind.
41  
-     * 
42  
-     * @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent) 
43  
-     */
44  
-    public PursuitBehaviour(Agent agent, Agent target, float distanceToChangeFocus, float minimunAngle,
45  
-            float porcentajeSpeedWhenCorrectBehind, float porcentajeSpeedDistance) {
46  
-        
47  
-        super(agent, target);
48  
-        
49  
-        this.distanceToChangeFocus = distanceToChangeFocus;
50  
-        this.minimumAngle = minimunAngle;
51  
-        this.porcentajeSpeedWhenCorrectBehind = porcentajeSpeedWhenCorrectBehind;
52  
-        this.porcentajeSpeedDistance = porcentajeSpeedDistance;
53  
-    }
54  
-    
55  
-    /** @see AbstractSteeringBehaviour#AbstractSteeringBehaviour(com.jme3.ai.agents.Agent, com.jme3.scene.Spatial) 
56  
-     *  @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, float, float, float, float) */
57  
-    public PursuitBehaviour(Agent agent, Agent target, Spatial spatial, float distanceToChangeFocus, float minimunAngle,
58  
-            float porcentajeSpeedWhenCorrectBehind, float porcentajeSpeedDistance) {
59  
-        
  22
+   
  23
+    /** @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, com.jme3.scene.Spatial)  */
  24
+    public PursuitBehaviour(Agent agent, Agent target, Spatial spatial) {
60 25
         super(agent, target, spatial);
61  
-        
62  
-        this.distanceToChangeFocus = distanceToChangeFocus;
63  
-        this.minimumAngle = minimunAngle;
64  
-        this.porcentajeSpeedWhenCorrectBehind = porcentajeSpeedWhenCorrectBehind;
65  
-        this.porcentajeSpeedDistance = porcentajeSpeedDistance;
66 26
     }
67  
-    
  27
+
68 28