@@ -3,4 +3,4 @@ do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
-user.properties.file=C:\\Users\\Tihomir\\AppData\\Roaming\\.jmonkeyplatform\\3.0\\build.properties
+user.properties.file=/root/.jmonkeyplatform/3.0/build.properties
@@ -2,8 +2,8 @@ annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
-application.title=MyGame
-application.vendor=MyCompany
+application.title=MonkeyBrains
+application.vendor=
assets.jar.name=assets.jar
assets.excludes=**/*.j3odata,**/*.mesh,**/*.skeleton,**/*.mesh\.xml,**/*.skeleton\.xml,**/*.scene,**/*.material,**/*.obj,**/*.mtl,**/*.3ds,**/*.dae,**/*.blend,**/*.blend*[0-9]
assets.folder.name=
@@ -47,7 +47,7 @@ javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
javadoc.additionalparam=
-javadoc.author=false
+javadoc.author=true
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
@@ -55,7 +55,7 @@ javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
-javadoc.version=false
+javadoc.version=true
javadoc.windowtitle=
jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
jnlp.codebase.type=local
@@ -7,6 +7,7 @@
import com.jme3.scene.Spatial;
import com.jme3.ai.agents.util.AbstractWeapon;
import com.jme3.ai.agents.util.GameObject;
+import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
@@ -19,12 +20,11 @@
*
* @author Jesús Martín Berlanga
* @author Tihomir Radosavljević
- * @version 1.1
+ * @version 1.2
*/
public class Agent<T> extends GameObject {
-
- private float tpf;
+ private float tpf;
/**
* Class that enables you to add all variable you need for your agent.
@@ -53,6 +53,26 @@
* Camera that is attached to agent.
private Camera camera;
+ /**
+ * Size of bounding sphere, for steer behaviours
+ *
+ * @author Jesús Martín Berlanga
+ */
+ float radius = 0;
+
+ public void setRadius(float radius) {
+ this.radius = radius;
+ }
+ public float getRadius() {
+ return this.radius;
* @param name unique name/id of agent
@@ -159,7 +179,7 @@ public T getModel() {
public void setModel(T model) {
this.model = model;
}
@Override
public int hashCode() {
int hash = 7;
@@ -167,7 +187,7 @@ public int hashCode() {
hash = 47 * hash + (this.team != null ? this.team.hashCode() : 0);
return hash;
public boolean equals(Object obj) {
if (obj == null) {
@@ -185,11 +205,11 @@ public boolean equals(Object obj) {
return true;
- */
protected void controlUpdate(float tpf) {
@@ -203,41 +223,42 @@ protected void controlUpdate(float tpf) {
weapon.update(tpf);
* Calculates the projected location in relation with other target
- *
* @param target The other agent
* @return The projected location in relation with other target
public Vector3f calculateProjectedLocation(Agent target) {
float targetSpeed = target.getMoveSpeed();
float speedDiff = targetSpeed - this.getMoveSpeed();
float desiredSpeed = (targetSpeed + speedDiff) * this.tpf;
- if(target.getAcceleration() == null)
- target.setAcceleration(new Vector3f());
+ if (target.getAcceleration() == null) {
+ target.setAcceleration(new Vector3f());
return target.getLocalTranslation().add(target.getAcceleration().mult(desiredSpeed));
- }
- /**
- * Gets the predicted position for this 'frame',
- * taking into account current position and velocity.
- * @author Jesús Martín Berlanga
+ * Gets the predicted position for this 'frame', taking into account current
+ * position and velocity.
public Vector3f getPredictedPosition() {
- if(this.getAcceleration() == null)
+ if (this.getAcceleration() == null) {
this.setAcceleration(new Vector3f());
- return this.getLocalTranslation().add(this.getAcceleration());
+ return this.getLocalTranslation().add(this.getAcceleration());
protected void controlRender(RenderManager rm, ViewPort vp) {
throw new UnsupportedOperationException("You should override it youself");
@@ -285,4 +306,138 @@ public Camera getCamera() {
public void setCamera(Camera camera) {
this.camera = camera;
+ * Check if this agent is considered in the same "neighborhood" in relation
+ * with another agent. <br> <br>
+ * If the distance is lower than minDistance It is definitely considered in
+ * the same neighborhood. <br> <br>
+ * If the distance is higher than maxDistance It is defenitely not
+ * considered in the same neighborhood. <br> <br>
+ * If the distance is inside [minDistance. maxDistance] It is considered in
+ * teh same neighborhood if the forwardness is higher than the 1 -
+ * sinMaxAngle.
+ * @param Agent The other agent
+ * @param minDistance Min. distance to be in the same "neighborhood"
+ * @param maxDistance Max. distance to be in the same "neighborhood"
+ * @param MaxAngle Max angle in radians
+ public boolean inBoidNeighborhood(
+ Agent neighbour,
+ float minDistance,
+ float maxDistance,
+ float MaxAngle) {
+ boolean isInBoidNeighborhood;
+ if (this == neighbour) {
+ isInBoidNeighborhood = false;
+ } else {
+ float distanceSquared = this.distanceSquaredRelativeToAgent(neighbour);
+ // definitely in neighborhood if inside minDistance sphere
+ if (distanceSquared < (minDistance * minDistance)) {
+ isInBoidNeighborhood = true;
+ } // definitely not in neighborhood if outside maxDistance sphere
+ else if (distanceSquared > maxDistance * maxDistance) {
+ } // otherwise, test angular offset from forward axis.
+ else {
+ if(this.getAcceleration() != null)
+ {
+ Vector3f unitOffset = this.offset(neighbour).divide(distanceSquared);
+ float forwardness = this.forwardness(unitOffset);
+ isInBoidNeighborhood = forwardness > FastMath.cos(MaxAngle);
+ // System.out.println("Offset:" + unitOffset + ";Fordwardness = " + forwardness + "; cosMaxAngle =" + FastMath.cos(MaxAngle) + "; " + isInBoidNeighborhood);//debug
+ else
+ return isInBoidNeighborhood;
+ * Calculates the forwardness in relation with another agent. That is how
+ * "forward" is the direction to the quarry (1 means dead ahead, 0 is
+ * directly to the side, -1 is straight back)
+ * @param agent Other agent
+ * @return The forwardness in relation with another agent
+ public float forwardness(Agent agent)
+ Vector3f agentLooks = this.fordwardVector();
+ float radiansAngleBetwen = agentLooks.angleBetween(this.offset(agent).normalize());
+ return (float) FastMath.cos(radiansAngleBetwen);
+ public Vector3f fordwardVector() {
+ return this.getLocalRotation().mult(new Vector3f(0,0,1)).normalize();
+ * Calculates the forwardness in relation with a position vector
+ * @param positionVector Offset vector.
+ * @see Agent#forwardness(com.jme3.ai.agents.Agent)
+ public float forwardness(Vector3f offsetVector) {
+ Vector3f agentLooks = this.getLocalRotation().mult(new Vector3f(0,0,1)).normalize();
+ float radiansAngleBetwen = agentLooks.angleBetween(offsetVector.normalize());
+ return FastMath.cos(radiansAngleBetwen);
+ * @return Distance relative to another Agent
+ public float distanceRelativeToAgent(Agent agent) {
+ return this.offset(agent).length();
+ * @return Distance squared relative to another Agent
+ public float distanceSquaredRelativeToAgent(Agent agent) {
+ return this.offset(agent).lengthSquared();
+ * @return The offset relative to another Agent
+ public Vector3f offset(Agent agent) {
+ return agent.getLocalTranslation().subtract(this.getLocalTranslation());
+ * @return The offset relative to an position vector
+ public Vector3f offset(Vector3f positionVector) {
+ return positionVector.subtract(this.getLocalTranslation());
@@ -14,11 +14,36 @@
public abstract class AbstractSteeringBehaviour extends Behaviour {
+ * If this is true the new Velocity upated in controlUpdate will be (0,0,0)
+ protected boolean freezeTheMovement = false;
+ /** @author Jesús Martín Berlanga */
+ public void setFreezeTheMovement(boolean freezeTheMovement) { this.freezeTheMovement = freezeTheMovement; }
+ public boolean getFreezeTheMovement() { return this.freezeTheMovement; }
+ public float getTPF(){ return this.tpf; }
+ * Manually update the tpf
+ * @param tpf tpf
+ public void setTPF(float tpf) { this.tpf = tpf; }
* Velocity of our agent.
protected Vector3f velocity;
@@ -50,16 +75,16 @@ public AbstractSteeringBehaviour(Agent agent, Spatial spatial) {
- protected Vector3f calculateNewVelocity() {
+ protected Vector3f calculateNewVelocity()
agent.setAcceleration(this.calculateSteering().mult(1 / agentTotalMass()));
velocity = velocity.add(agent.getAcceleration());
+ agent.setVelocity(velocity);
if (velocity.length() > agent.getMaxMoveSpeed())
velocity = velocity.normalize().mult(agent.getMaxMoveSpeed());
return velocity;
@@ -110,10 +135,21 @@ public void setVelocity(Vector3f velocity) {
* Usual update pattern for steering behaviours.
* @param tpf
+ * @author Tihomir Radosavljević
- Vector3f vel = calculateNewVelocity().mult(tpf);
+ this.tpf = tpf;
+ Vector3f vel = new Vector3f();
+ if(this.freezeTheMovement == false)
+ vel = calculateNewVelocity().mult(tpf);
agent.setLocalTranslation(agent.getLocalTranslation().add(vel));
rotateAgent(tpf);
@@ -0,0 +1,110 @@
+//Copyright (c) 2014, Jesús Martín Berlanga. All rights reserved. Distributed under the BSD licence. Read "com/jme3/ai/license.txt".
+package com.jme3.ai.agents.behaviours.npc.steering;
+import com.jme3.ai.agents.Agent;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Spatial;
+import java.util.ArrayList;
+import java.util.List;
+/**
+ * Craig W. Reynolds: "Alignment steering behavior gives an character the ability
+ * to align itself with (that is, head in the same direction as) other nearby
+ * characters. Steering for alignment can be computed by finding all characters
+ * in the local neighborhood, averaging the unit forward vector of the nearby
+ * characters. This average is the “desired velocity,” and so the steering vector
+ * is the difference between the average and our character’s forward vector. This
+ * steering will tend to turn our character so it is aligned with its neighbors."
+ * @version 1.0
+public class AlignmentBehaviour extends AbstractStrengthSteeringBehaviour {
+ private List<Agent> neighbours = new ArrayList<Agent>();
+ public List<Agent> getNeighbours(){return this.neighbours;}
+ private float maxDistance = Float.POSITIVE_INFINITY;
+ private float maxAngle = FastMath.PI / 2;
+ * maxAngle is setted to PI / 2 by default and maxDistance to infinite.
+ * @param agent To whom behaviour belongs.
+ * @param neighbours Neighbours, this agent is moving toward the center of this neighbours.
+ public AlignmentBehaviour(Agent agent, List<Agent> neighbours){
+ super(agent);
+ this.neighbours = neighbours;
+ * @param maxDistance In order to consider a neihbour inside the neighbourhood
+ * @param maxAngle In order to consider a neihbour inside the neighbourhood
+ * @see Agent#inBoidNeighborhoodMaxAngle(com.jme3.ai.agents.Agent, float, float, float)
+ * @see AlignmentBehaviour#AlignmentBehaviour(com.jme3.ai.agents.Agent, java.util.List)
+ public AlignmentBehaviour(Agent agent, List<Agent> neighbours, float maxDistance, float maxAngle){
+ this.maxDistance = maxDistance;
+ this.maxAngle = maxAngle;
+ * @param spatial active spatial during excecution of behaviour
+ public AlignmentBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours) {
+ super(agent, spatial);
+ * @see AlignmentBehaviour#AlignmentBehaviour(com.jme3.ai.agents.Agent, java.util.List, float, float)
+ public AlignmentBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours, float maxDistance, float maxAngle) {
+ @Override
+ Vector3f calculateFullSteering()
+ // steering accumulator and count of neighbors, both initially zero
+ Vector3f steering = new Vector3f();
+ int realNeighbors = 0;
+ // for each of the other vehicles...
+ for (Agent agentO : this.neighbours)
+ if (this.agent.inBoidNeighborhood(agentO, this.agent.getRadius()*3, this.maxDistance, this.maxAngle))
+ // accumulate sum of neighbor's positions
+ steering = steering.add(agentO.fordwardVector());
+ realNeighbors++;
+ // divide by neighbors, subtract off current position to get error-correcting direction
+ if(realNeighbors > 0)
+ steering = steering.divide(realNeighbors);
+ steering = this.agent.offset(steering);
+ return steering;
+ protected void controlRender(RenderManager rm, ViewPort vp) { }
+}
@@ -0,0 +1,100 @@
+ * Arrival behavior is identical to seek while the character is far from its target.
+ * But instead of moving through the target at full speed, this behavior causes the
+ * character to slow down as it approaches the target, eventually slowing to a stop
+ * coincident with the target
+public class ArriveBehaviour extends SeekBehaviour {
+ private float slowingDistance;
+ private SlowBehaviour slow;
+ private float errorDistance = 0.01f;
+ public void setErrorDistance(float errorDistance){ this.errorDistance = errorDistance; }
+ public SlowBehaviour getSlow() { return this.slow; }
+ * The slowingDistance is (0.1 * distance betwen agents) by default. <br> <br>
+ * The slow proportion is 0.5 by default.
+ * @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent)
+ public ArriveBehaviour(Agent agent, Agent target) {
+ super(agent, target);
+ this.slowingDistance = agent.distanceRelativeToAgent(target) * 0.135f;
+ this.slow = new SlowBehaviour(agent);
+ * @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, com.jme3.scene.Spatial)
+ public ArriveBehaviour(Agent agent, Agent target, Spatial spatial) {
+ super(agent, target, spatial);
+ * @param slowingDistance The distance when this agent will start slowing down
+ * @see ArriveBehaviour#ArriveBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent)
+ public ArriveBehaviour(Agent agent, Agent target, float slowingDistance, float slowPercentaje) {
+ this.slowingDistance = slowingDistance;
+ this.slow = new SlowBehaviour(agent, slowPercentaje);
+ * @see ArriveBehaviour#ArriveBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, com.jme3.scene.Spatial)
+ public ArriveBehaviour(Agent agent, Agent target, Spatial spatial, float slowingDistance, float slowPercentaje) {
+ * Calculate steering vector.
+ * @return steering vector
+ * @see AbstractStrengthSteeringBehaviour#calculateFullSteering()
+ * @see SeekBehaviour#calculateFullSteering()
+ protected Vector3f calculateFullSteering()
+ Vector3f steer = new Vector3f();
+ float distanceToTarget = this.agent.distanceRelativeToAgent(this.getTarget());
+ if(distanceToTarget > (this.getTarget().getRadius() + this.errorDistance))
+ steer = super.calculateFullSteering();
+ if(distanceToTarget < this.slowingDistance)
+ steer = steer.add(this.slow.calculateFullSteering());
+ this.setFreezeTheMovement(true);
+ return steer;
@@ -0,0 +1,106 @@
+ * Move toward center of neighbors.
+public class CohesionBehaviour extends AbstractStrengthSteeringBehaviour {
+ public CohesionBehaviour(Agent agent, List<Agent> neighbours){
+ * @see CohesionBehaviour#CohesionBehaviour(com.jme3.ai.agents.Agent, java.util.List)
+ public CohesionBehaviour(Agent agent, List<Agent> neighbours, float maxDistance, float maxAngle){
+ public CohesionBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours) {
+ * @see CohesionBehaviour#CohesionBehaviour(com.jme3.ai.agents.Agent, java.util.List, float, float)
+ public CohesionBehaviour(Agent agent, Spatial spatial, List<Agent> neighbours, float maxDistance, float maxAngle) {
+ steering = steering.add(agentO.getLocalTranslation());
@@ -22,9 +22,20 @@
* AbstractSteeringBehaviour.
+ * @version 1.1
public class CompoundSteeringBehaviour extends AbstractSteeringBehaviour {
+ /** @see AbstractSteeringBehaviour#freezeTheMovement */
+ public void setFreezeTheMovement(boolean freezeTheMovement) {
+ this.freezeTheMovement = freezeTheMovement;
+ if(freezeTheMovement == true)
+ for(AbstractSteeringBehaviour steerBehaviour : behaviours)
+ steerBehaviour.setFreezeTheMovement(freezeTheMovement);
private List<AbstractSteeringBehaviour> behaviours;
protected List<AbstractSteeringBehaviour> getBehaviours() {
@@ -68,10 +79,18 @@ public void addSteerBehaviour (AbstractSteeringBehaviour behaviour) {
protected Vector3f calculateSteering() {
Vector3f totalForce = new Vector3f();
for(AbstractSteeringBehaviour steerBehaviour : behaviours)
{
- totalForce = totalForce.add(this.calculatePartialForce(steerBehaviour));
+ this.setFreezeTheMovement(false);
+ if(steerBehaviour.getFreezeTheMovement() == false)
+ totalForce = totalForce.add(this.calculatePartialForce(steerBehaviour));
+ break;
return totalForce;
@@ -89,4 +108,18 @@ protected Vector3f calculatePartialForce(AbstractSteeringBehaviour behaviour) {
protected void controlRender(RenderManager rm, ViewPort vp) { }
+ * Usual update pattern for steering behaviours.
+ * @param tpf
+ protected void controlUpdate(float tpf) {
+ steerBehaviour.setTPF(tpf);
+ super.controlUpdate(tpf);
@@ -0,0 +1,150 @@
+ * This is similar to pursuit behaviour, but pursuiers must stay away from the pursued path.
+public class LeaderFollowing extends SeekBehaviour {
+ private float distanceToChangeFocus;
+ private double minimumAngle;
+ private float porcentajeSpeedWhenCorrectBehind;
+ private float porcentajeSpeedDistance;
+ /** @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent) */
+ public LeaderFollowing(Agent agent, Agent target) {
+ //Default values
+ this.distanceToChangeFocus = 5;
+ this.minimumAngle = Math.PI / 2;
+ this.porcentajeSpeedWhenCorrectBehind = 0.18f;
+ this.porcentajeSpeedDistance = 4;
+ * @param distanceToChangeFocus Distance to change the focus.
+ * @param minimunAngle Minimum angle betwen the target velocity and the vehicle location.
+ * @param porcentajeSpeedWhenCorrectBehind Porcentaje of speed when the vehicle is in the correct position.
+ * @param porcentajeSpeedDistance The distance factor of porcentajeSpeedWhenCorrectBehind.
+ * @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent)
+ public LeaderFollowing(Agent agent, Agent target, float distanceToChangeFocus, float minimunAngle,
+ float porcentajeSpeedWhenCorrectBehind, float porcentajeSpeedDistance) {
+ this.distanceToChangeFocus = distanceToChangeFocus;
+ this.minimumAngle = minimunAngle;
+ this.porcentajeSpeedWhenCorrectBehind = porcentajeSpeedWhenCorrectBehind;
+ this.porcentajeSpeedDistance = porcentajeSpeedDistance;
+ /** @see AbstractSteeringBehaviour#AbstractSteeringBehaviour(com.jme3.ai.agents.Agent, com.jme3.scene.Spatial)
+ * @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, float, float, float, float) */
+ public LeaderFollowing(Agent agent, Agent target, Spatial spatial, float distanceToChangeFocus, float minimunAngle,
+ /** @see AbstractStrengthSteeringBehaviour#calculateFullSteering() */
+ protected Vector3f calculateSteering(){
+ Vector3f desierdVel;
+ float agentSpeed = this.agent.getMoveSpeed();
+ Vector3f agentLocation = agent.getLocalTranslation();
+ float targetSpeed = this.getTarget().getMoveSpeed();
+ Vector3f targetVelocity;
+ if(this.getTarget().getAcceleration() == null)
+ targetVelocity = new Vector3f();
+ targetVelocity = this.getTarget().getAcceleration();
+ Vector3f targetTrueLocation = this.getTarget().getLocalTranslation();
+ //Calculate de desired speed
+ float speedDiff = targetSpeed - agentSpeed;
+ float desiredSpeed = (targetSpeed + speedDiff) * this.getTPF();
+ //Vehicle distance from the true location
+ float distanceFromTrueLocation = agentLocation.distance(targetTrueLocation);
+ //Change the focus, non finite posible solutions
+ double focusFactor = this.changeFocusFactor(distanceFromTrueLocation);
+ Vector3f seekingLocation = targetTrueLocation.add(this.getTarget().getPredictedPosition().subtract(
+ targetTrueLocation).mult((float) focusFactor));
+ //Project the location you want to reach
+ Vector3f projectedLocation = seekingLocation.add(targetVelocity.mult(desiredSpeed));
+ //Angle controls
+ if(distanceFromTrueLocation < this.distanceToChangeFocus){
+ if(checkAngle(targetVelocity, targetTrueLocation, agentLocation))
+ //If the vehicle is in the correct position, maintain it using the proper factor
+ desierdVel = projectedLocation.subtract(agentLocation).normalize().mult((agentSpeed * porcentajeSpeedWhenCorrectBehind
+ * distanceFromTrueLocation)/this.porcentajeSpeedDistance);
+ else{
+ //If not, get out of the way
+ projectedLocation = seekingLocation.add(targetVelocity.negate().mult((targetSpeed / (distanceFromTrueLocation * 0.05f))));
+ desierdVel = projectedLocation.subtract(agentLocation).normalize().mult(agentSpeed);
+ }else
+ //If is still away from the target, move normally
+ return desierdVel.subtract(velocity);
+ //Calculates the factor in order to change the focus
+ private double changeFocusFactor(float distanceFromFocus){
+ double factor;
+ if(distanceFromFocus > this.distanceToChangeFocus)
+ factor = 1;
+ factor = Math.pow((1 + distanceFromFocus/this.distanceToChangeFocus), 2);
+ return factor;
+ //Return false if the angle is not correct.
+ private boolean checkAngle(Vector3f targetVelocity,
+ Vector3f targetTrueLocation,
+ Vector3f vehicleLocation){
+ return calculateAngle(targetVelocity, targetTrueLocation, vehicleLocation) > minimumAngle;
+ //Calculate the angle
+ private float calculateAngle(Vector3f targetVelocity,
+ Vector3f fromTagetToVehicle = vehicleLocation.subtract(targetTrueLocation);
+ return targetVelocity.angleBetween(fromTagetToVehicle);
@@ -0,0 +1,56 @@
+ * Simple move behaviour for NPC. Agent should move to moveDirection.
+ * @see Agent#moveSpeed
+ * @autor Jesús Martín Berlanga
+public class MoveBehaviour extends AbstractStrengthSteeringBehaviour {
+ * Move direction of agent.
+ protected Vector3f moveDirection;
+ public MoveBehaviour(Agent agent) {
+ public MoveBehaviour(Agent agent, Spatial spatial) {
+ protected void controlRender(RenderManager rm, ViewPort vp) {
+ public Vector3f getMoveDirection() {
+ return moveDirection;
+ public void setMoveDirection(Vector3f moveDirection) {
+ this.moveDirection = moveDirection.normalize();
+ Vector3f calculateFullSteering() {
+ Vector3f moveDirection = new Vector3f();
+ if(this.moveDirection != null)
+ moveDirection = this.moveDirection;
@@ -8,150 +8,39 @@
* Brent Owens: "Pursuit is similar to seek except that the quarry (target) is another moving
- * character. Effective pursuit requires a prediction of the target’s future position." <br> <br>
- * Pursuers must stay away from the target path.
+ * character. Effective pursuit requires a prediction of the target’s future position."
public class PursuitBehaviour extends SeekBehaviour {
- private float distanceToChangeFocus;
- private double minimumAngle;
- private float porcentajeSpeedWhenCorrectBehind;
- private float porcentajeSpeedDistance;
/** @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent) */
public PursuitBehaviour(Agent agent, Agent target) {
super(agent, target);
- //Default values
- this.distanceToChangeFocus = 5;
- this.minimumAngle = Math.PI / 2;
- this.porcentajeSpeedWhenCorrectBehind = 0.18f;
- this.porcentajeSpeedDistance = 4;
- * @param distanceToChangeFocus Distance to change the focus.
- * @param minimunAngle Minimum angle betwen the target velocity and the vehicle location.
- * @param porcentajeSpeedWhenCorrectBehind Porcentaje of speed when the vehicle is in the correct position.
- * @param porcentajeSpeedDistance The distance factor of porcentajeSpeedWhenCorrectBehind.
- * @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent)
- public PursuitBehaviour(Agent agent, Agent target, float distanceToChangeFocus, float minimunAngle,
- float porcentajeSpeedWhenCorrectBehind, float porcentajeSpeedDistance) {
- super(agent, target);
- this.distanceToChangeFocus = distanceToChangeFocus;
- this.minimumAngle = minimunAngle;
- this.porcentajeSpeedWhenCorrectBehind = porcentajeSpeedWhenCorrectBehind;
- this.porcentajeSpeedDistance = porcentajeSpeedDistance;
- /** @see AbstractSteeringBehaviour#AbstractSteeringBehaviour(com.jme3.ai.agents.Agent, com.jme3.scene.Spatial)
- * @see PursuitBehaviour#PursuitBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, float, float, float, float) */
- public PursuitBehaviour(Agent agent, Agent target, Spatial spatial, float distanceToChangeFocus, float minimunAngle,
+ /** @see SeekBehaviour#SeekBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent, com.jme3.scene.Spatial) */
+ public PursuitBehaviour(Agent agent, Agent target, Spatial spatial) {
super(agent, target, spatial);
/** @see AbstractStrengthSteeringBehaviour#calculateFullSteering() */
- protected Vector3f calculateSteering(){
- Vector3f desierdVel;
- float agentSpeed = this.agent.getMoveSpeed();
- Vector3f agentLocation = agent.getLocalTranslation();
- float targetSpeed = this.getTarget().getMoveSpeed();
- Vector3f targetVelocity;
+ // calculate speed difference to see how far ahead we need to leed
+ Vector3f projectedLocation = this.getTarget().getPredictedPosition();
- if(this.getTarget().getAcceleration() == null)
- targetVelocity = new Vector3f();
- else
- targetVelocity = this.getTarget().getAcceleration();
+ //Seek behaviour
+ Vector3f desierdVel = projectedLocation.subtract(this.agent.getLocalTranslation()).normalize().mult(this.agent.getMoveSpeed());
- Vector3f targetTrueLocation = this.getTarget().getLocalTranslation();
+ Vector3f aVelocity = this.agent.getVelocity();
- //Calculate de desired speed
- float speedDiff = targetSpeed - agentSpeed;
- float desiredSpeed = (targetSpeed + speedDiff) * this.tpf;
- //Vehicle distance from the true location
- float distanceFromTrueLocation = agentLocation.distance(targetTrueLocation);
- //Change the focus, non finite posible solutions
- double focusFactor = this.changeFocusFactor(distanceFromTrueLocation);
- Vector3f seekingLocation = targetTrueLocation.add(this.getTarget().getPredictedPosition().subtract(
- targetTrueLocation).mult((float) focusFactor));
- //Project the location you want to reach
- Vector3f projectedLocation = seekingLocation.add(targetVelocity.mult(desiredSpeed));
- //Angle controls
- if(distanceFromTrueLocation < this.distanceToChangeFocus){
- if(checkAngle(targetVelocity, targetTrueLocation, agentLocation))
- //If the vehicle is in the correct position, maintain it using the proper factor
- desierdVel = projectedLocation.subtract(agentLocation).normalize().mult((agentSpeed * porcentajeSpeedWhenCorrectBehind
- * distanceFromTrueLocation)/this.porcentajeSpeedDistance);
- else{
- //If not, get out of the way
- projectedLocation = seekingLocation.add(targetVelocity.negate().mult((targetSpeed / (distanceFromTrueLocation * 0.05f))));
- desierdVel = projectedLocation.subtract(agentLocation).normalize().mult(agentSpeed);
- }else
- //If is still away from the target, move normally
- return desierdVel.subtract(velocity);
+ if(aVelocity == null)
+ aVelocity = new Vector3f();
+ return desierdVel.subtract(aVelocity);
- //Calculates the factor in order to change the focus
- private double changeFocusFactor(float distanceFromFocus){
- double factor;
- if(distanceFromFocus > this.distanceToChangeFocus)
- factor = 1;
- factor = Math.pow((1 + distanceFromFocus/this.distanceToChangeFocus), 2);
- return factor;
- //Return false if the angle is not correct.
- private boolean checkAngle(Vector3f targetVelocity,
- Vector3f targetTrueLocation,
- Vector3f vehicleLocation){
- return calculateAngle(targetVelocity, targetTrueLocation, vehicleLocation) > minimumAngle;
- //Calculate the angle
- private float calculateAngle(Vector3f targetVelocity,
- Vector3f fromTagetToVehicle = vehicleLocation.subtract(targetTrueLocation);
- return targetVelocity.angleBetween(fromTagetToVehicle);
- @Override
- protected void controlUpdate(float tpf) {
- this.tpf = tpf;
- super.controlUpdate(tpf);
@@ -14,7 +14,7 @@
public class SeekBehaviour extends AbstractStrengthSteeringBehaviour {
@@ -61,7 +61,12 @@ protected void controlRender(RenderManager rm, ViewPort vp) { }
protected Vector3f calculateFullSteering() {
Vector3f desiredVelocity = target.getLocalTranslation().subtract(agent.getLocalTranslation()).normalize().mult(agent.getMoveSpeed());
- return desiredVelocity.subtract(velocity);
+ return desiredVelocity.subtract(aVelocity);
@@ -27,7 +27,7 @@
* ignore anything behind the character."
public class SeparationBehaviour extends AbstractStrengthSteeringBehaviour {
@@ -50,7 +50,7 @@ public SeparationBehaviour(Agent agent, List<Agent> initialObstacles){
* @param spatial active spatial during excecution of behaviour
* @see SeparationBehaviour#SeparationBehaviour(com.jme3.ai.agents.Agent, com.jme3.ai.agents.Agent[])
- public SeparationBehaviour(Agent agent, List<Agent> initialObstacles, Spatial spatial) {
+ public SeparationBehaviour(Agent agent, Spatial spatial, List<Agent> initialObstacles) {
super(agent, spatial);
this.obstacles = initialObstacles;
@@ -0,0 +1,112 @@
+ * Slows down the agent velocity in a proportion setted by the user.
+public class SlowBehaviour extends AbstractStrengthSteeringBehaviour {
+ private float maxSlow; //It is a number that work well, Do not chage it.
+ private float unitIncrementSlow = 0.0035f;
+ private float maxPercentajeSlow = 1; //From 0 to 1
+ private float actualSlow = 0;
+ * Sets actualSlow to 0
+ public void resetSlow() { this.actualSlow = 0; }
+ /** @param maxPercentajeSlow Float betwen 0 and 1 */
+ public void setMaxPercentajeslow(float maxPercentajeSlow)
+ if(maxPercentajeSlow <= 1)
+ this.maxPercentajeSlow = maxPercentajeSlow;
+ this.maxPercentajeSlow = 1;
+ public void setUnitIncrementSlow(float unitIncrementSlow) {
+ if(unitIncrementSlow <= this.maxSlow && unitIncrementSlow >= 0)
+ this.unitIncrementSlow = unitIncrementSlow;
+ this.unitIncrementSlow = this.maxSlow;
+ * The unit increment proportion is 0.0035 by default.
+ * @see AbstractStrengthSteeringBehaviour#AbstractStrengthSteeringBehaviour(com.jme3.ai.agents.Agent)
+ public SlowBehaviour(Agent agent) {
+ this.maxSlow = agent.getMoveSpeed() * 10;
+ * @see AbstractStrengthSteeringBehaviour#AbstractStrengthSteeringBehaviour(com.jme3.ai.agents.Agent, com.jme3.scene.Spatial)
+ public SlowBehaviour(Agent agent, Spatial spatial) {
+ * @param unitIncrementSlow The unit increment proportion
+ public SlowBehaviour(Agent agent, Spatial spatial, float unitIncrementSlow) {
+ public SlowBehaviour(Agent agent, float unitIncrementSlow) {
+ if(this.agent.getVelocity() != null && this.agent.getVelocity().lengthSquared() > 0)
+ steer = this.agent.getVelocity().negate().mult(actualSlow);
+ if(this.actualSlow < (this.maxSlow * this.maxPercentajeSlow))
+ this.actualSlow += this.unitIncrementSlow;
+ if(this.actualSlow > (this.maxSlow * this.maxPercentajeSlow))
+ this.actualSlow = (this.maxSlow * this.maxPercentajeSlow);
+ this.maxSlow = this.agent.getMoveSpeed() * 10; //Update max slow
@@ -17,7 +17,7 @@
public class WanderBehaviour extends AbstractStrengthSteeringBehaviour {
@@ -49,7 +49,7 @@ public WanderBehaviour(Agent agent) {
velocity = new Vector3f();
timeInterval = 2f;
time = timeInterval;
- area = new Vector3f[2];
+ this.area = new Vector3f[] {Vector3f.ZERO, Vector3f.POSITIVE_INFINITY };
@@ -57,6 +57,9 @@ public WanderBehaviour(Agent agent) {
* @param agent to whom behaviour belongs
public WanderBehaviour(Agent agent, Spatial spatial) {
@@ -64,12 +67,7 @@ public WanderBehaviour(Agent agent, Spatial spatial) {
- changeTargetPosition(tpf);
@@ -80,10 +78,14 @@ protected void controlRender(RenderManager rm, ViewPort vp) {
* Calculate steering vector.
* @return steering vector
+ changeTargetPosition(this.getTPF());
Vector3f desiredVelocity = targetPosition.subtract(agent.getLocalTranslation()).normalize().mult(agent.getMoveSpeed());
+ desiredVelocity.subtract(velocity);
+ return desiredVelocity;
@@ -6,7 +6,7 @@
* Basic steering behaviour ai structure provided by Tihomir Radosavljević.
* Incorporate full steer behaviour project into MonkeyBrains by Jesús Martín Berlanga.
- * @version 1.5
+ * @version 1.6
* @author Jesús Martin Berlanga
@@ -1,3 +1,5 @@
package com.jme3.ai.agents.util;
import com.jme3.math.Quaternion;
@@ -17,11 +19,24 @@
* @see Game#addGameObject(com.jme3.ai.agents.util.GameObject)
- * @version 1.0
public abstract class GameObject extends AbstractControl {
+ * Container for the velocity of the game object
+ protected Vector3f velocity;
+ public void setVelocity(Vector3f velocity){ this.velocity = velocity; }
+ public Vector3f getVelocity() { return this.velocity; }
* Mass of GameObject.
protected float mass;
-user.properties.file=C:\\Users\\Tihomir\\AppData\\Roaming\\.jmonkeyplatform\\3.0\\build.properties
+user.properties.file=/root/.jmonkeyplatform/3.0/build.properties
-javadoc.author=false
+javadoc.author=true
-javadoc.version=false
+javadoc.version=true
- * @version 1.1
+ * @version 1.2
+
+
-
- */
-
- *
- *
- if(this.getAcceleration() == null)
+ if (this.getAcceleration() == null) {
+ return this.getLocalTranslation().add(this.getAcceleration());
+
- * @version 1.1
+ * @version 1.2
+
-
- Vector3f targetTrueLocation = this.getTarget().getLocalTranslation();
+ Vector3f aVelocity = this.agent.getVelocity();
- * @version 1.1
+ * @version 1.2
- * @version 1.1
+ * @version 1.2
- public SeparationBehaviour(Agent agent, List<Agent> initialObstacles, Spatial spatial) {
+ public SeparationBehaviour(Agent agent, Spatial spatial, List<Agent> initialObstacles) {
- * @version 1.1
+ * @version 1.2
- area = new Vector3f[2];
+ this.area = new Vector3f[] {Vector3f.ZERO, Vector3f.POSITIVE_INFINITY };
- * @version 1.5
+ * @version 1.6