//Copyright (c) 2014, Jesús Martín Berlanga. All rights reserved.
//Distributed under the BSD licence. Read "com/jme3/ai/license.txt".
package steeringDemos.demos;
import com.jme3.ai.agents.Agent;
import com.jme3.ai.agents.behaviors.npc.SimpleMainBehavior;
import com.jme3.ai.agents.behaviors.npc.steering.CompoundSteeringBehavior;
import com.jme3.ai.agents.behaviors.npc.steering.PursuitBehavior;
import com.jme3.ai.agents.behaviors.npc.steering.SeekBehavior;
import com.jme3.ai.agents.behaviors.npc.steering.SeparationBehavior;
import com.jme3.ai.agents.util.GameEntity;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import java.util.ArrayList;
import steeringDemos.BasicDemo;
import steeringDemos.control.CustomSteerControl;
/**
* Priority Demo
*
* @author Jesús Martín Berlanga
* @version 1.0.0
*/
public class PriorityDemo extends BasicDemo {
private final String HUD_LAYER_TEXT = "Current priority layer: ";
private BitmapText hudText;
//The purpose of this class is to save the active layer inside the activeLayer variable
private class DebugCompoundSteeringBehavior extends CompoundSteeringBehavior {
private DebugCompoundSteeringBehavior(Agent agent) {
super(agent);
}
private int activeLayer = Integer.MAX_VALUE; //We can see which is the active layer
@Override
protected Vector3f calculateRawSteering() {
Vector3f totalForce = new Vector3f();
float totalBraking = 1;
this.behaviors.moveAtBeginning();
if (!this.behaviors.nullPointer()) {
int currentLayer = this.behaviors.getLayer();
int inLayerCounter = 0;
int validCounter = 0;
while (!this.behaviors.nullPointer()) {
if (this.behaviors.getLayer() != currentLayer) //We have finished the last layer, check If it was a valid layer
{
if (inLayerCounter == validCounter) {
break; //If we have a valid layer, return the force
} else {
totalForce = new Vector3f(); //If not, reset the total force
totalBraking = 1; //and braking
}
currentLayer = this.behaviors.getLayer();
inLayerCounter = 0;
validCounter = 0;
}
Vector3f force = this.calculatePartialForce(this.behaviors.getBehavior());
if (force.length() > this.behaviors.getMinLengthToInvalidSteer()) {
validCounter++;
}
totalForce = totalForce.add(force);
totalBraking *= this.behaviors.getBehavior().getBrakingFactor();
this.activeLayer = this.behaviors.getLayer();
inLayerCounter++;
this.behaviors.moveNext();
}
}
this.setBrakingFactor(totalBraking);
return totalForce;
}
}
private Agent target;
private Agent seeker;
private SeekBehavior targetMove;
private DebugCompoundSteeringBehavior targetSteer;
Vector3f[] locations = new Vector3f[]{
new Vector3f(7, 0, 0),
new Vector3f(0, 7, 0),
new Vector3f(0, 0, 7)
};
private int currentFocus = -1;
public static void main(String[] args) {
PriorityDemo app = new PriorityDemo();
app.start();
}
@Override
public void simpleInitApp() {
this.steerControl = new CustomSteerControl(9, 1);
this.steerControl.setCameraSettings(getCamera());
this.steerControl.setFlyCameraSettings(getFlyByCamera());
//defining rootNode for brainsAppState processing
brainsAppState.setApp(this);
brainsAppState.setGameControl(new CustomSteerControl(5f));
target = this.createBoid("Target", this.targetColor, 0.11f);
for (Vector3f loc : this.locations) {
this.createSphereHelper("Sphere " + loc.toString(), ColorRGBA.Yellow, 0.05f, loc);
}
brainsAppState.addAgent(target); //Add the target to the brainsAppState
brainsAppState.getGameControl().spawn(target, Vector3f.ZERO);
this.setStats(
target,
this.targetMoveSpeed,
this.targetRotationSpeed,
this.targetMass,
this.targetMaxForce);
seeker = this.createBoid("Target", this.neighboursColor, 0.11f);
this.neighboursMoveSpeed = 3f;
brainsAppState.addAgent(seeker); //Add the target to the brainsAppState
brainsAppState.getGameControl().spawn(seeker, new Vector3f(10, 10, 10));
this.setStats(
seeker,
this.neighboursMoveSpeed,
this.neighboursRotationSpeed,
this.neighboursMass,
this.neighboursMaxForce);
SimpleMainBehavior seekerMainBehavior = new SimpleMainBehavior(seeker);
PursuitBehavior pursuit = new PursuitBehavior(seeker, target);
pursuit.setupStrengthControl(5f);
seekerMainBehavior.addBehavior(pursuit);
seeker.setMainBehavior(seekerMainBehavior);
SimpleMainBehavior targetMainBehavior = new SimpleMainBehavior(target);
this.targetMove = new SeekBehavior(target, this.locations[0]);
this.currentFocus = 0;
ArrayList separationObstacle = new ArrayList();
separationObstacle.add(seeker);
SeparationBehavior separation = new SeparationBehavior(target, separationObstacle);
targetSteer = new DebugCompoundSteeringBehavior(target);
targetSteer.addSteerBehavior(targetMove);
targetSteer.addSteerBehavior(separation, 1, 0.1f);
targetMainBehavior.addBehavior(this.targetSteer);
target.setMainBehavior(targetMainBehavior);
hudText = new BitmapText(guiFont, false);
hudText.setSize(guiFont.getCharSet().getRenderedSize() * 1.25f); // font size
hudText.setColor(ColorRGBA.Red); // font color
hudText.setText(""); // the text
hudText.setLocalTranslation(0, 475, 0); // position
guiNode.attachChild(hudText);
brainsAppState.start();
}
@Override
public void simpleUpdate(float tpf) {
brainsAppState.update(tpf);
if (this.target.distanceFromPosition(this.locations[this.currentFocus]) < 0.01f) {
this.currentFocus++;
if (this.currentFocus > this.locations.length - 1) {
this.currentFocus = 0;
}
this.targetMove.setSeekingPosition(this.locations[this.currentFocus]);
}
this.hudText.setText(this.HUD_LAYER_TEXT + this.targetSteer.activeLayer);
if (this.seeker.distanceRelativeToGameEntity(this.target) < 0.25f) {
this.seeker.setLocalTranslation(
(FastMath.nextRandomFloat() - 0.5f) * 10,
(FastMath.nextRandomFloat() - 0.5f) * 10,
(FastMath.nextRandomFloat() - 0.5f) * 10);
}
}
}