This commit is contained in:
Anuken
2020-05-02 14:54:01 -04:00
parent b9aa8edf78
commit 3e87fff9db
42 changed files with 102 additions and 1904 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ public class Formation{
this.motionModerator = motionModerator; this.motionModerator = motionModerator;
this.slotAssignments = new Array<>(); this.slotAssignments = new Array<>();
this.driftOffset = anchor.newLocation(); this.driftOffset = new VecLocation();
this.positionOffset = anchor.getPosition().cpy(); this.positionOffset = anchor.getPosition().cpy();
} }
@@ -35,7 +35,7 @@ public abstract class FormationMotionModerator{
float centerOfMassOrientation = 0; float centerOfMassOrientation = 0;
// Make sure tempLocation is instantiated // Make sure tempLocation is instantiated
if(tempLocation == null) tempLocation = centerOfMass.newLocation(); if(tempLocation == null) tempLocation = new VecLocation();
Vec2 centerOfMassPos = centerOfMass.getPosition(); Vec2 centerOfMassPos = centerOfMass.getPosition();
Vec2 tempLocationPos = tempLocation.getPosition(); Vec2 tempLocationPos = tempLocation.getPosition();
@@ -9,7 +9,6 @@ import mindustry.ai.ai.steer.Proximity.*;
* @author davebaol * @author davebaol
*/ */
public abstract class GroupBehavior extends SteeringBehavior{ public abstract class GroupBehavior extends SteeringBehavior{
/** The proximity decides which agents are considered neighbors. */ /** The proximity decides which agents are considered neighbors. */
protected Proximity proximity; protected Proximity proximity;
+15 -23
View File
@@ -10,35 +10,27 @@ public interface Limiter{
* Returns the threshold below which the linear speed can be considered zero. It must be a small positive value near to zero. * Returns the threshold below which the linear speed can be considered zero. It must be a small positive value near to zero.
* Usually it is used to avoid updating the orientation when the velocity vector has a negligible length. * Usually it is used to avoid updating the orientation when the velocity vector has a negligible length.
*/ */
float getZeroLinearSpeedThreshold(); default float getZeroLinearSpeedThreshold(){
return 0.001f;
/** }
* Sets the threshold below which the linear speed can be considered zero. It must be a small positive value near to zero.
* Usually it is used to avoid updating the orientation when the velocity vector has a negligible length.
*/
void setZeroLinearSpeedThreshold(float value);
/** Returns the maximum linear speed. */ /** Returns the maximum linear speed. */
float getMaxLinearSpeed(); default float getMaxLinearSpeed(){
return Float.MAX_VALUE;
/** Sets the maximum linear speed. */ }
void setMaxLinearSpeed(float maxLinearSpeed);
/** Returns the maximum linear acceleration. */ /** Returns the maximum linear acceleration. */
float getMaxLinearAcceleration(); default float getMaxLinearAcceleration(){
return Float.MAX_VALUE;
/** Sets the maximum linear acceleration. */ }
void setMaxLinearAcceleration(float maxLinearAcceleration);
/** Returns the maximum angular speed. */ /** Returns the maximum angular speed. */
float getMaxAngularSpeed(); default float getMaxAngularSpeed(){
return Float.MAX_VALUE;
/** Sets the maximum angular speed. */ }
void setMaxAngularSpeed(float maxAngularSpeed);
/** Returns the maximum angular acceleration. */ /** Returns the maximum angular acceleration. */
float getMaxAngularAcceleration(); default float getMaxAngularAcceleration(){
return Float.MAX_VALUE;
/** Sets the maximum angular acceleration. */ }
void setMaxAngularAcceleration(float maxAngularAcceleration);
} }
@@ -36,7 +36,7 @@ import mindustry.ai.ai.utils.Timepiece;
* </li> * </li>
* <li>If you want to make sure a Proximity doesn't use as a neighbor a given agent from the list, for example the evader or the * <li>If you want to make sure a Proximity doesn't use as a neighbor a given agent from the list, for example the evader or the
* owner itself, you have to implement a callback that prevents it from being considered by returning {@code false} from the method * owner itself, you have to implement a callback that prevents it from being considered by returning {@code false} from the method
* {@link ProximityCallback#reportNeighbor(Steerable) reportNeighbor}.</li> * {@link ProximityCallback#report(Steerable) reportNeighbor}.</li>
* <li>If there is some efficient way of pruning potential neighbors before they are processed, the overall performance in time * <li>If there is some efficient way of pruning potential neighbors before they are processed, the overall performance in time
* will improve. Spatial data structures such as multi-resolution maps, quad-trees, oct-trees, and binary space partition (BSP) * will improve. Spatial data structures such as multi-resolution maps, quad-trees, oct-trees, and binary space partition (BSP)
* trees can be used to get potential neighbors more efficiently. Spatial partitioning techniques are crucial when you have to * trees can be used to get potential neighbors more efficiently. Spatial partitioning techniques are crucial when you have to
@@ -55,7 +55,7 @@ public interface Proximity{
/** /**
* Finds the agents that are within the immediate area of the owner. Each of those agents is passed to the * Finds the agents that are within the immediate area of the owner. Each of those agents is passed to the
* {@link ProximityCallback#reportNeighbor(Steerable) reportNeighbor} method of the specified callback. * {@link ProximityCallback#report(Steerable) reportNeighbor} method of the specified callback.
* @return the number of neighbors found. * @return the number of neighbors found.
*/ */
int findNeighbors(ProximityCallback callback); int findNeighbors(ProximityCallback callback);
@@ -71,7 +71,7 @@ public interface Proximity{
* @param neighbor the reported neighbor. * @param neighbor the reported neighbor.
* @return {@code true} if the given neighbor is valid; {@code false} otherwise. * @return {@code true} if the given neighbor is valid; {@code false} otherwise.
*/ */
boolean reportNeighbor(Steerable neighbor); boolean report(Steerable neighbor);
} }
} }
@@ -1,7 +1,6 @@
package mindustry.ai.ai.steer; package mindustry.ai.ai.steer;
import arc.math.geom.*; import arc.math.geom.*;
import mindustry.ai.ai.utils.*;
/** /**
* An adapter class for {@link Steerable}. You can derive from this and only override what you are interested in. For example, * An adapter class for {@link Steerable}. You can derive from this and only override what you are interested in. For example,
@@ -10,15 +9,6 @@ import mindustry.ai.ai.utils.*;
*/ */
public class SteerableAdapter implements Steerable{ public class SteerableAdapter implements Steerable{
@Override
public float getZeroLinearSpeedThreshold(){
return 0.001f;
}
@Override
public void setZeroLinearSpeedThreshold(float value){
}
@Override @Override
public float getMaxLinearSpeed(){ public float getMaxLinearSpeed(){
return 0; return 0;
@@ -93,19 +83,4 @@ public class SteerableAdapter implements Steerable{
public void setTagged(boolean tagged){ public void setTagged(boolean tagged){
} }
@Override
public Location newLocation(){
return null;
}
@Override
public float vectorToAngle(Vec2 vector){
return 0;
}
@Override
public Vec2 angleToVector(Vec2 outVector, float angle){
return null;
}
} }
@@ -15,7 +15,6 @@ import mindustry.ai.ai.steer.Proximity.*;
* @author davebaol * @author davebaol
*/ */
public class Alignment extends GroupBehavior implements ProximityCallback{ public class Alignment extends GroupBehavior implements ProximityCallback{
private Vec2 averageVelocity; private Vec2 averageVelocity;
/** /**
@@ -48,36 +47,9 @@ public class Alignment extends GroupBehavior implements ProximityCallback{
} }
@Override @Override
public boolean reportNeighbor(Steerable neighbor){ public boolean report(Steerable neighbor){
// Accumulate neighbor velocity // Accumulate neighbor velocity
averageVelocity.add(neighbor.getLinearVelocity()); averageVelocity.add(neighbor.getLinearVelocity());
return true; return true;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Alignment setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Alignment setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Alignment setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -22,21 +22,17 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class Arrive extends SteeringBehavior{ public class Arrive extends SteeringBehavior{
/** The target to arrive to. */ /** The target to arrive to. */
protected Location target; public Location target;
/** /**
* The tolerance for arriving at the target. It lets the owner get near enough to the target without letting small errors keep * The tolerance for arriving at the target. It lets the owner get near enough to the target without letting small errors keep
* it in motion. * it in motion.
*/ */
protected float arrivalTolerance; public float arrivalTolerance;
/** The radius for beginning to slow down */ /** The radius for beginning to slow down */
protected float decelerationRadius; public float decelerationRadius;
/** The time over which to achieve target speed */ /** The time over which to achieve target speed */
protected float timeToTarget = 0.1f; public float timeToTarget = 0.1f;
/** /**
* Creates an {@code Arrive} behavior for the specified owner. * Creates an {@code Arrive} behavior for the specified owner.
@@ -89,92 +85,4 @@ public class Arrive extends SteeringBehavior{
// Output the steering // Output the steering
return steering; return steering;
} }
/** Returns the target to arrive to. */
public Location getTarget(){
return target;
}
/**
* Sets the target to arrive to.
* @return this behavior for chaining.
*/
public Arrive setTarget(Location target){
this.target = target;
return this;
}
/**
* Returns the tolerance for arriving at the target. It lets the owner get near enough to the target without letting small
* errors keep it in motion.
*/
public float getArrivalTolerance(){
return arrivalTolerance;
}
/**
* Sets the tolerance for arriving at the target. It lets the owner get near enough to the target without letting small errors
* keep it in motion.
* @return this behavior for chaining.
*/
public Arrive setArrivalTolerance(float arrivalTolerance){
this.arrivalTolerance = arrivalTolerance;
return this;
}
/** Returns the radius for beginning to slow down. */
public float getDecelerationRadius(){
return decelerationRadius;
}
/**
* Sets the radius for beginning to slow down.
* @return this behavior for chaining.
*/
public Arrive setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
/** Returns the time over which to achieve target speed. */
public float getTimeToTarget(){
return timeToTarget;
}
/**
* Sets the time over which to achieve target speed.
* @return this behavior for chaining.
*/
public Arrive setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Arrive setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Arrive setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear speed and
* acceleration.
* @return this behavior for chaining.
*/
@Override
public Arrive setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -2,7 +2,6 @@ package mindustry.ai.ai.steer.behaviors;
import arc.struct.*; import arc.struct.*;
import mindustry.ai.ai.steer.*; import mindustry.ai.ai.steer.*;
import mindustry.ai.ai.steer.limiters.*;
/** /**
* This combination behavior simply sums up all the behaviors, applies their weights, and truncates the result before returning. * This combination behavior simply sums up all the behaviors, applies their weights, and truncates the result before returning.
@@ -27,7 +26,7 @@ import mindustry.ai.ai.steer.limiters.*;
public class BlendedSteering extends SteeringBehavior{ public class BlendedSteering extends SteeringBehavior{
/** The list of behaviors and their corresponding blending weights. */ /** The list of behaviors and their corresponding blending weights. */
protected Array<BehaviorAndWeight> list; protected Array<BehaviorAndWeight> list = new Array<>();
private SteeringAcceleration steering; private SteeringAcceleration steering;
@@ -120,33 +119,6 @@ public class BlendedSteering extends SteeringBehavior{
return blendedSteering; return blendedSteering;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public BlendedSteering setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public BlendedSteering setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear and angular
* accelerations. You can use {@link NullLimiter#NEUTRAL_LIMITER} to avoid all truncations.
* @return this behavior for chaining.
*/
@Override
public BlendedSteering setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
// //
// Nested classes // Nested classes
// //
@@ -48,35 +48,9 @@ public class Cohesion extends GroupBehavior implements ProximityCallback{
} }
@Override @Override
public boolean reportNeighbor(Steerable neighbor){ public boolean report(Steerable neighbor){
// Accumulate neighbor position // Accumulate neighbor position
centerOfMass.add(neighbor.getPosition()); centerOfMass.add(neighbor.getPosition());
return true; return true;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Cohesion setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Cohesion setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Cohesion setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -19,7 +19,6 @@ import mindustry.ai.ai.steer.Proximity.*;
* @author davebaol * @author davebaol
*/ */
public class CollisionAvoidance extends GroupBehavior implements ProximityCallback{ public class CollisionAvoidance extends GroupBehavior implements ProximityCallback{
private float shortestTime; private float shortestTime;
private Steerable firstNeighbor; private Steerable firstNeighbor;
private float firstMinSeparation; private float firstMinSeparation;
@@ -83,7 +82,7 @@ public class CollisionAvoidance extends GroupBehavior implements ProximityCallba
} }
@Override @Override
public boolean reportNeighbor(Steerable neighbor){ public boolean report(Steerable neighbor){
// Calculate the time to collision // Calculate the time to collision
relativePosition.set(neighbor.getPosition()).sub(owner.getPosition()); relativePosition.set(neighbor.getPosition()).sub(owner.getPosition());
relativeVelocity.set(neighbor.getLinearVelocity()).sub(owner.getLinearVelocity()); relativeVelocity.set(neighbor.getLinearVelocity()).sub(owner.getLinearVelocity());
@@ -117,30 +116,4 @@ public class CollisionAvoidance extends GroupBehavior implements ProximityCallba
return true; return true;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public CollisionAvoidance setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public CollisionAvoidance setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public CollisionAvoidance setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -35,36 +35,4 @@ public class Evade extends Pursue{
return -getActualLimiter().getMaxLinearAcceleration(); return -getActualLimiter().getMaxLinearAcceleration();
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Evade setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Evade setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Evade setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
@Override
public Evade setTarget(Steerable target){
this.target = target;
return this;
}
} }
@@ -46,56 +46,4 @@ public class Face extends ReachOrientation{
// Delegate to ReachOrientation // Delegate to ReachOrientation
return reachOrientation(steering, orientation); return reachOrientation(steering, orientation);
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Face setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Face setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum angular speed and
* acceleration.
* @return this behavior for chaining.
*/
@Override
public Face setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
@Override
public Face setTarget(Location target){
this.target = target;
return this;
}
@Override
public Face setAlignTolerance(float alignTolerance){
this.alignTolerance = alignTolerance;
return this;
}
@Override
public Face setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
@Override
public Face setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
} }
@@ -40,36 +40,4 @@ public class Flee extends Seek{
return steering; return steering;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Flee setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Flee setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Flee setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
@Override
public Flee setTarget(Location target){
this.target = target;
return this;
}
} }
@@ -16,12 +16,10 @@ import mindustry.ai.ai.steer.*;
* @author davebaol * @author davebaol
*/ */
public class FollowFlowField extends SteeringBehavior{ public class FollowFlowField extends SteeringBehavior{
/** The flow field to follow. */ /** The flow field to follow. */
protected FlowField flowField; public FlowField flowField;
/** The time in the future to predict the owner's position. Set it to 0 for non-predictive flow field following. */ /** The time in the future to predict the owner's position. Set it to 0 for non-predictive flow field following. */
protected float predictionTime; public float predictionTime;
/** /**
* Creates a non-predictive {@code FollowFlowField} for the specified owner. * Creates a non-predictive {@code FollowFlowField} for the specified owner.
@@ -81,63 +79,6 @@ public class FollowFlowField extends SteeringBehavior{
return steering; return steering;
} }
/** Returns the flow field of this behavior */
public FlowField getFlowField(){
return flowField;
}
/**
* Sets the flow field of this behavior
* @param flowField the flow field to set
* @return this behavior for chaining
*/
public FollowFlowField setFlowField(FlowField flowField){
this.flowField = flowField;
return this;
}
/** Returns the prediction time. */
public float getPredictionTime(){
return predictionTime;
}
/**
* Sets the prediction time. Set it to 0 for non-predictive flow field following.
* @param predictionTime the predictionTime to set
* @return this behavior for chaining.
*/
public FollowFlowField setPredictionTime(float predictionTime){
this.predictionTime = predictionTime;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public FollowFlowField setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public FollowFlowField setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear speed and
* acceleration.
* @return this behavior for chaining.
*/
@Override
public FollowFlowField setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
/** /**
* A {@code FlowField} defines a mapping from a location in space to a flow vector. Typically flow fields are implemented as a * A {@code FlowField} defines a mapping from a location in space to a flow vector. Typically flow fields are implemented as a
* multidimensional array representing a grid of cells. In each cell of the grid lives a flow vector. * multidimensional array representing a grid of cells. In each cell of the grid lives a flow vector.
@@ -4,7 +4,6 @@ import arc.math.geom.*;
import mindustry.ai.ai.steer.*; import mindustry.ai.ai.steer.*;
import mindustry.ai.ai.steer.utils.Path; import mindustry.ai.ai.steer.utils.Path;
import mindustry.ai.ai.steer.utils.Path.*; import mindustry.ai.ai.steer.utils.Path.*;
import mindustry.ai.ai.utils.*;
/** /**
* {@code FollowPath} behavior produces a linear acceleration that moves the agent along the given path. First it calculates the * {@code FollowPath} behavior produces a linear acceleration that moves the agent along the given path. First it calculates the
@@ -22,21 +21,16 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class FollowPath<P extends PathParam> extends Arrive{ public class FollowPath<P extends PathParam> extends Arrive{
/** The path to follow */ /** The path to follow */
protected Path<P> path; public Path<P> path;
/** The distance along the path to generate the target. Can be negative if the owner has to move along the reverse direction. */ /** The distance along the path to generate the target. Can be negative if the owner has to move along the reverse direction. */
protected float pathOffset; public float pathOffset;
/** The current position on the path */ /** The current position on the path */
protected P pathParam; public P pathParam;
/** The flag indicating whether to use {@link Arrive} behavior to approach the end of an open path. It defaults to {@code true}. */ /** The flag indicating whether to use {@link Arrive} behavior to approach the end of an open path. It defaults to {@code true}. */
protected boolean arriveEnabled; public boolean arriveEnabled;
/** The time in the future to predict the owner's position. Set it to 0 for non-predictive path following. */ /** The time in the future to predict the owner's position. Set it to 0 for non-predictive path following. */
protected float predictionTime; public float predictionTime;
private Vec2 internalTargetPosition; private Vec2 internalTargetPosition;
@@ -122,126 +116,9 @@ public class FollowPath<P extends PathParam> extends Arrive{
return steering; return steering;
} }
/** Returns the path to follow */
public Path<P> getPath(){
return path;
}
/**
* Sets the path followed by this behavior.
* @param path the path to set
* @return this behavior for chaining.
*/
public FollowPath<P> setPath(Path<P> path){
this.path = path;
return this;
}
/** Returns the path offset. */
public float getPathOffset(){
return pathOffset;
}
/** Returns the flag indicating whether to use {@link Arrive} behavior to approach the end of an open path. */
public boolean isArriveEnabled(){
return arriveEnabled;
}
/** Returns the prediction time. */
public float getPredictionTime(){
return predictionTime;
}
/**
* Sets the prediction time. Set it to 0 for non-predictive path following.
* @param predictionTime the predictionTime to set
* @return this behavior for chaining.
*/
public FollowPath<P> setPredictionTime(float predictionTime){
this.predictionTime = predictionTime;
return this;
}
/**
* Sets the flag indicating whether to use {@link Arrive} behavior to approach the end of an open path. It defaults to
* {@code true}.
* @param arriveEnabled the flag value to set
* @return this behavior for chaining.
*/
public FollowPath<P> setArriveEnabled(boolean arriveEnabled){
this.arriveEnabled = arriveEnabled;
return this;
}
/**
* Sets the path offset to generate the target. Can be negative if the owner has to move along the reverse direction.
* @param pathOffset the pathOffset to set
* @return this behavior for chaining.
*/
public FollowPath<P> setPathOffset(float pathOffset){
this.pathOffset = pathOffset;
return this;
}
/** Returns the current path parameter. */
public P getPathParam(){
return pathParam;
}
/** Returns the current position of the internal target. This method is useful for debug purpose. */ /** Returns the current position of the internal target. This method is useful for debug purpose. */
public Vec2 getInternalTargetPosition(){ public Vec2 getInternalTargetPosition(){
return internalTargetPosition; return internalTargetPosition;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public FollowPath<P> setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public FollowPath<P> setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear speed and
* acceleration. However the maximum linear speed is not required for a closed path.
* @return this behavior for chaining.
*/
@Override
public FollowPath<P> setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
@Override
public FollowPath<P> setTarget(Location target){
this.target = target;
return this;
}
@Override
public FollowPath<P> setArrivalTolerance(float arrivalTolerance){
this.arrivalTolerance = arrivalTolerance;
return this;
}
@Override
public FollowPath<P> setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
@Override
public FollowPath<P> setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
} }
@@ -38,12 +38,10 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class Hide extends Arrive implements ProximityCallback{ public class Hide extends Arrive implements ProximityCallback{
/** The proximity to find nearby obstacles. */ /** The proximity to find nearby obstacles. */
protected Proximity proximity; public Proximity proximity;
/** The distance from the boundary of the obstacle behind which to hide. */ /** The distance from the boundary of the obstacle behind which to hide. */
protected float distanceFromBoundary; public float distanceFromBoundary;
private Vec2 toObstacle; private Vec2 toObstacle;
private Vec2 bestHidingSpot; private Vec2 bestHidingSpot;
@@ -94,7 +92,7 @@ public class Hide extends Arrive implements ProximityCallback{
} }
@Override @Override
public boolean reportNeighbor(Steerable neighbor){ public boolean report(Steerable neighbor){
// Calculate the position of the hiding spot for this obstacle // Calculate the position of the hiding spot for this obstacle
Vec2 hidingSpot = getHidingPosition(neighbor.getPosition(), neighbor.getBoundingRadius(), target.getPosition()); Vec2 hidingSpot = getHidingPosition(neighbor.getPosition(), neighbor.getBoundingRadius(), target.getPosition());
@@ -110,36 +108,6 @@ public class Hide extends Arrive implements ProximityCallback{
return false; return false;
} }
/** Returns the proximity used to find nearby obstacles. */
public Proximity getProximity(){
return proximity;
}
/**
* Sets the proximity used to find nearby obstacles.
* @param proximity the proximity to set
* @return this behavior for chaining.
*/
public Hide setProximity(Proximity proximity){
this.proximity = proximity;
return this;
}
/** Returns the distance from the boundary of the obstacle behind which to hide. */
public float getDistanceFromBoundary(){
return distanceFromBoundary;
}
/**
* Sets the distance from the boundary of the obstacle behind which to hide.
* @param distanceFromBoundary the distance to set
* @return this behavior for chaining.
*/
public Hide setDistanceFromBoundary(float distanceFromBoundary){
this.distanceFromBoundary = distanceFromBoundary;
return this;
}
/** /**
* Given the position of a target and the position and radius of an obstacle, this method calculates a position * Given the position of a target and the position and radius of an obstacle, this method calculates a position
* {@code distanceFromBoundary} away from the object's bounding radius and directly opposite the target. It does this by scaling * {@code distanceFromBoundary} away from the object's bounding radius and directly opposite the target. It does this by scaling
@@ -160,50 +128,4 @@ public class Hide extends Arrive implements ProximityCallback{
return toObstacle.scl(distanceAway).add(obstaclePosition); return toObstacle.scl(distanceAway).add(obstaclePosition);
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Hide setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Hide setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
@Override
public Hide setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
@Override
public Hide setTarget(Location target){
this.target = target;
return this;
}
@Override
public Hide setArrivalTolerance(float arrivalTolerance){
this.arrivalTolerance = arrivalTolerance;
return this;
}
@Override
public Hide setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
@Override
public Hide setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
} }
@@ -2,7 +2,6 @@ package mindustry.ai.ai.steer.behaviors;
import arc.math.geom.*; import arc.math.geom.*;
import mindustry.ai.ai.steer.*; import mindustry.ai.ai.steer.*;
import mindustry.ai.ai.utils.*;
/** /**
* {@code Interpose} behavior produces a steering force that moves the owner to a point along the imaginary line connecting two * {@code Interpose} behavior produces a steering force that moves the owner to a point along the imaginary line connecting two
@@ -24,10 +23,9 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class Interpose extends Arrive{ public class Interpose extends Arrive{
public Steerable agentA;
protected Steerable agentA; public Steerable agentB;
protected Steerable agentB; public float interpositionRatio;
protected float interpositionRatio;
private Vec2 internalTargetPosition; private Vec2 internalTargetPosition;
@@ -58,50 +56,6 @@ public class Interpose extends Arrive{
this.internalTargetPosition = newVector(owner); this.internalTargetPosition = newVector(owner);
} }
/** Returns the first agent. */
public Steerable getAgentA(){
return agentA;
}
/**
* Sets the first agent.
* @return this behavior for chaining.
*/
public Interpose setAgentA(Steerable agentA){
this.agentA = agentA;
return this;
}
/** Returns the second agent. */
public Steerable getAgentB(){
return agentB;
}
/**
* Sets the second agent.
* @return this behavior for chaining.
*/
public Interpose setAgentB(Steerable agentB){
this.agentB = agentB;
return this;
}
/** Returns the interposition ratio. */
public float getInterpositionRatio(){
return interpositionRatio;
}
/**
* Sets the interposition ratio.
* @param interpositionRatio a number between 0 and 1 indicating the percentage of the distance between the 2 agents that the
* owner should reach. Especially, 0 is the position of agentA and 1 is the position of agentB.
* @return this behavior for chaining.
*/
public Interpose setInterpositionRatio(float interpositionRatio){
this.interpositionRatio = interpositionRatio;
return this;
}
@Override @Override
protected SteeringAcceleration calculateRealSteering(SteeringAcceleration steering){ protected SteeringAcceleration calculateRealSteering(SteeringAcceleration steering){
// First we need to figure out where the two agents are going to be at // First we need to figure out where the two agents are going to be at
@@ -132,51 +86,4 @@ public class Interpose extends Arrive{
public Vec2 getInternalTargetPosition(){ public Vec2 getInternalTargetPosition(){
return internalTargetPosition; return internalTargetPosition;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Interpose setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Interpose setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
@Override
public Interpose setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
@Override
public Interpose setTarget(Location target){
this.target = target;
return this;
}
@Override
public Interpose setArrivalTolerance(float arrivalTolerance){
this.arrivalTolerance = arrivalTolerance;
return this;
}
@Override
public Interpose setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
@Override
public Interpose setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
} }
@@ -233,55 +233,6 @@ public class Jump extends MatchVelocity{
return this; return this;
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Jump setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Jump setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration and
* speed.
* @return this behavior for chaining.
*/
@Override
public Jump setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
/**
* Sets the target whose velocity should be matched. Notice that this method is inherited from {@link MatchVelocity}. Usually
* with {@code Jump} you should never call it because a specialized internal target has already been created implicitly.
* @param target the target to set
* @return this behavior for chaining.
*/
@Override
public Jump setTarget(Steerable target){
this.target = target;
return this;
}
@Override
public Jump setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
//
// Nested classes and interfaces
//
private static class JumpTarget extends SteerableAdapter{ private static class JumpTarget extends SteerableAdapter{
Vec2 position; Vec2 position;
@@ -1,7 +1,6 @@
package mindustry.ai.ai.steer.behaviors; package mindustry.ai.ai.steer.behaviors;
import mindustry.ai.ai.steer.*; import mindustry.ai.ai.steer.*;
import mindustry.ai.ai.utils.*;
/** /**
* The entire steering framework assumes that the direction a character is facing does not have to be its direction of motion. In * The entire steering framework assumes that the direction a character is facing does not have to be its direction of motion. In
@@ -40,60 +39,4 @@ public class LookWhereYouAreGoing extends ReachOrientation{
return reachOrientation(steering, orientation); return reachOrientation(steering, orientation);
} }
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public LookWhereYouAreGoing setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public LookWhereYouAreGoing setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum angular speed and
* acceleration.
* @return this behavior for chaining.
*/
@Override
public LookWhereYouAreGoing setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
/**
* Sets the target to align to. Notice that this method is inherited from {@link ReachOrientation}, but is completely useless
* for {@code LookWhereYouAreGoing} because the target orientation is determined by the velocity of the owner itself.
* @return this behavior for chaining.
*/
@Override
public LookWhereYouAreGoing setTarget(Location target){
this.target = target;
return this;
}
@Override
public LookWhereYouAreGoing setAlignTolerance(float alignTolerance){
this.alignTolerance = alignTolerance;
return this;
}
@Override
public LookWhereYouAreGoing setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
@Override
public LookWhereYouAreGoing setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
} }
@@ -8,12 +8,10 @@ import mindustry.ai.ai.steer.*;
* @author davebaol * @author davebaol
*/ */
public class MatchVelocity extends SteeringBehavior{ public class MatchVelocity extends SteeringBehavior{
/** The target of this behavior */ /** The target of this behavior */
protected Steerable target; public Steerable target;
/** The time over which to achieve target speed */ /** The time over which to achieve target speed */
protected float timeToTarget; public float timeToTarget;
/** /**
* Creates a {@code MatchVelocity} behavior for the given owner. No target is set. The maxLinearAcceleration is set to 100. The * Creates a {@code MatchVelocity} behavior for the given owner. No target is set. The maxLinearAcceleration is set to 100. The
@@ -57,61 +55,4 @@ public class MatchVelocity extends SteeringBehavior{
// Output steering acceleration // Output steering acceleration
return steering; return steering;
} }
/** Returns the target whose velocity should be matched. */
public Steerable getTarget(){
return target;
}
/**
* Sets the target whose velocity should be matched.
* @param target the target to set
* @return this behavior for chaining.
*/
public MatchVelocity setTarget(Steerable target){
this.target = target;
return this;
}
/** Returns the time over which to achieve target speed. */
public float getTimeToTarget(){
return timeToTarget;
}
/**
* Sets the time over which to achieve target speed.
* @param timeToTarget the time to set
* @return this behavior for chaining.
*/
public MatchVelocity setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public MatchVelocity setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public MatchVelocity setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public MatchVelocity setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -39,18 +39,15 @@ import mindustry.ai.ai.steer.*;
* @author davebaol * @author davebaol
*/ */
public class PrioritySteering extends SteeringBehavior{ public class PrioritySteering extends SteeringBehavior{
/** The threshold of the steering acceleration magnitude below which a steering behavior is considered to have given no output. */ /** The threshold of the steering acceleration magnitude below which a steering behavior is considered to have given no output. */
protected float epsilon; public float epsilon;
/** /**
* The list of steering behaviors in priority order. The first item in the list is tried first, the subsequent entries are only * The list of steering behaviors in priority order. The first item in the list is tried first, the subsequent entries are only
* considered if the first one does not return a result. * considered if the first one does not return a result.
*/ */
protected Array<SteeringBehavior> behaviors = new Array<>(); public Array<SteeringBehavior> behaviors = new Array<>();
/** The index of the behavior whose acceleration has been returned by the last evaluation of this priority steering. */ /** The index of the behavior whose acceleration has been returned by the last evaluation of this priority steering. */
protected int selectedBehaviorIndex; public int selectedBehaviorIndex;
/** /**
* Creates a {@code PrioritySteering} behavior for the specified owner. The threshold is set to 0.001. * Creates a {@code PrioritySteering} behavior for the specified owner. The threshold is set to 0.001.
@@ -107,57 +104,4 @@ public class PrioritySteering extends SteeringBehavior{
return n > 0 ? steering : steering.setZero(); return n > 0 ? steering : steering.setZero();
} }
/**
* Returns the index of the behavior whose acceleration has been returned by the last evaluation of this priority steering; -1
* otherwise.
*/
public int getSelectedBehaviorIndex(){
return selectedBehaviorIndex;
}
/**
* Returns the threshold of the steering acceleration magnitude below which a steering behavior is considered to have given no
* output.
*/
public float getEpsilon(){
return epsilon;
}
/**
* Sets the threshold of the steering acceleration magnitude below which a steering behavior is considered to have given no
* output.
* @param epsilon the epsilon to set
* @return this behavior for chaining.
*/
public PrioritySteering setEpsilon(float epsilon){
this.epsilon = epsilon;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public PrioritySteering setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public PrioritySteering setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. However, {@code PrioritySteering} needs no limiter at all as it simply returns
* the first non zero steering acceleration.
* @return this behavior for chaining.
*/
@Override
public PrioritySteering setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -20,12 +20,10 @@ import mindustry.ai.ai.steer.*;
* @author davebaol * @author davebaol
*/ */
public class Pursue extends SteeringBehavior{ public class Pursue extends SteeringBehavior{
/** The target */ /** The target */
protected Steerable target; public Steerable target;
/** The maximum prediction time */ /** The maximum prediction time */
protected float maxPredictionTime; public float maxPredictionTime;
/** /**
* Creates a {@code Pursue} behavior for the specified owner and target. Maximum prediction time defaults to 1 second. * Creates a {@code Pursue} behavior for the specified owner and target. Maximum prediction time defaults to 1 second.
@@ -87,58 +85,4 @@ public class Pursue extends SteeringBehavior{
return steering; return steering;
} }
/** Returns the target. */
public Steerable getTarget(){
return target;
}
/**
* Sets the target.
* @return this behavior for chaining.
*/
public Pursue setTarget(Steerable target){
this.target = target;
return this;
}
/** Returns the maximum prediction time. */
public float getMaxPredictionTime(){
return maxPredictionTime;
}
/**
* Sets the maximum prediction time.
* @return this behavior for chaining.
*/
public Pursue setMaxPredictionTime(float maxPredictionTime){
this.maxPredictionTime = maxPredictionTime;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Pursue setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Pursue setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Pursue setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -48,15 +48,12 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class RaycastObstacleAvoidance extends SteeringBehavior{ public class RaycastObstacleAvoidance extends SteeringBehavior{
/** The inputRay configuration */ /** The inputRay configuration */
protected RayConfiguration rayConfiguration; public RayConfiguration rayConfiguration;
/** The collision detector */ /** The collision detector */
protected RaycastCollisionDetector raycastCollisionDetector; public RaycastCollisionDetector raycastCollisionDetector;
/** The minimum distance to a wall, i.e. how far to avoid collision. */ /** The minimum distance to a wall, i.e. how far to avoid collision. */
protected float distanceFromBoundary; public float distanceFromBoundary;
private Collision outputCollision; private Collision outputCollision;
private Collision minOutputCollision; private Collision minOutputCollision;
@@ -147,75 +144,4 @@ public class RaycastObstacleAvoidance extends SteeringBehavior{
return steering; return steering;
} }
/** Returns the ray configuration of this behavior. */
public RayConfiguration getRayConfiguration(){
return rayConfiguration;
}
/**
* Sets the ray configuration of this behavior.
* @param rayConfiguration the ray configuration to set
* @return this behavior for chaining.
*/
public RaycastObstacleAvoidance setRayConfiguration(RayConfiguration rayConfiguration){
this.rayConfiguration = rayConfiguration;
return this;
}
/** Returns the raycast collision detector of this behavior. */
public RaycastCollisionDetector getRaycastCollisionDetector(){
return raycastCollisionDetector;
}
/**
* Sets the raycast collision detector of this behavior.
* @param raycastCollisionDetector the raycast collision detector to set
* @return this behavior for chaining.
*/
public RaycastObstacleAvoidance setRaycastCollisionDetector(RaycastCollisionDetector raycastCollisionDetector){
this.raycastCollisionDetector = raycastCollisionDetector;
return this;
}
/** Returns the distance from boundary, i.e. the minimum distance to an obstacle. */
public float getDistanceFromBoundary(){
return distanceFromBoundary;
}
/**
* Sets the distance from boundary, i.e. the minimum distance to an obstacle.
* @param distanceFromBoundary the distanceFromBoundary to set
* @return this behavior for chaining.
*/
public RaycastObstacleAvoidance setDistanceFromBoundary(float distanceFromBoundary){
this.distanceFromBoundary = distanceFromBoundary;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public RaycastObstacleAvoidance setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public RaycastObstacleAvoidance setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public RaycastObstacleAvoidance setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -17,18 +17,14 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class ReachOrientation extends SteeringBehavior{ public class ReachOrientation extends SteeringBehavior{
/** The target to align to. */ /** The target to align to. */
protected Location target; public Location target;
/** The tolerance for aligning to the target without letting small errors keep the owner swinging. */ /** The tolerance for aligning to the target without letting small errors keep the owner swinging. */
protected float alignTolerance; public float alignTolerance;
/** The radius for beginning to slow down */ /** The radius for beginning to slow down */
protected float decelerationRadius; public float decelerationRadius;
/** The time over which to achieve target rotation speed */ /** The time over which to achieve target rotation speed */
protected float timeToTarget = 0.1f; public float timeToTarget = 0.1f;
/** /**
* Creates a {@code ReachOrientation} behavior for the specified owner. * Creates a {@code ReachOrientation} behavior for the specified owner.
@@ -97,87 +93,4 @@ public class ReachOrientation extends SteeringBehavior{
return steering; return steering;
} }
/** Returns the target to align to. */
public Location getTarget(){
return target;
}
/**
* Sets the target to align to.
* @return this behavior for chaining.
*/
public ReachOrientation setTarget(Location target){
this.target = target;
return this;
}
/** Returns the tolerance for aligning to the target without letting small errors keep the owner swinging. */
public float getAlignTolerance(){
return alignTolerance;
}
/**
* Sets the tolerance for aligning to the target without letting small errors keep the owner swinging.
* @return this behavior for chaining.
*/
public ReachOrientation setAlignTolerance(float alignTolerance){
this.alignTolerance = alignTolerance;
return this;
}
/** Returns the radius for beginning to slow down */
public float getDecelerationRadius(){
return decelerationRadius;
}
/**
* Sets the radius for beginning to slow down
* @return this behavior for chaining.
*/
public ReachOrientation setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
/** Returns the time over which to achieve target rotation speed */
public float getTimeToTarget(){
return timeToTarget;
}
/**
* Sets the time over which to achieve target rotation speed
* @return this behavior for chaining.
*/
public ReachOrientation setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public ReachOrientation setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public ReachOrientation setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum angular speed and
* acceleration.
* @return this behavior for chaining.
*/
@Override
public ReachOrientation setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -9,9 +9,8 @@ import mindustry.ai.ai.utils.*;
* @author davebaol * @author davebaol
*/ */
public class Seek extends SteeringBehavior{ public class Seek extends SteeringBehavior{
/** The target to seek */ /** The target to seek */
protected Location target; public Location target;
/** /**
* Creates a {@code Seek} behavior for the specified owner. * Creates a {@code Seek} behavior for the specified owner.
@@ -43,45 +42,4 @@ public class Seek extends SteeringBehavior{
// Output steering acceleration // Output steering acceleration
return steering; return steering;
} }
/** Returns the target to seek. */
public Location getTarget(){
return target;
}
/**
* Sets the target to seek.
* @return this behavior for chaining.
*/
public Seek setTarget(Location target){
this.target = target;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Seek setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Seek setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Seek setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -12,12 +12,11 @@ import mindustry.ai.ai.steer.Proximity.*;
* @author davebaol * @author davebaol
*/ */
public class Separation extends GroupBehavior implements ProximityCallback{ public class Separation extends GroupBehavior implements ProximityCallback{
/** /**
* The constant coefficient of decay for the inverse square law force. It controls how fast the separation strength decays with * The constant coefficient of decay for the inverse square law force. It controls how fast the separation strength decays with
* distance. * distance.
*/ */
float decayCoefficient = 1f; public float decayCoefficient = 1f;
private Vec2 toAgent; private Vec2 toAgent;
private Vec2 linear; private Vec2 linear;
@@ -45,7 +44,7 @@ public class Separation extends GroupBehavior implements ProximityCallback{
} }
@Override @Override
public boolean reportNeighbor(Steerable neighbor){ public boolean report(Steerable neighbor){
toAgent.set(owner.getPosition()).sub(neighbor.getPosition()); toAgent.set(owner.getPosition()).sub(neighbor.getPosition());
float distanceSqr = toAgent.len2(); float distanceSqr = toAgent.len2();
@@ -55,7 +54,7 @@ public class Separation extends GroupBehavior implements ProximityCallback{
float maxAcceleration = getActualLimiter().getMaxLinearAcceleration(); float maxAcceleration = getActualLimiter().getMaxLinearAcceleration();
// Calculate the strength of repulsion through inverse square law decay // Calculate the strength of repulsion through inverse square law decay
float strength = getDecayCoefficient() / distanceSqr; float strength = decayCoefficient / distanceSqr;
if(strength > maxAcceleration) strength = maxAcceleration; if(strength > maxAcceleration) strength = maxAcceleration;
// Add the acceleration // Add the acceleration
@@ -64,45 +63,4 @@ public class Separation extends GroupBehavior implements ProximityCallback{
return true; return true;
} }
/** Returns the coefficient of decay for the inverse square law force. */
public float getDecayCoefficient(){
return decayCoefficient;
}
/**
* Sets the coefficient of decay for the inverse square law force. It controls how fast the separation strength decays with
* distance.
* @param decayCoefficient the coefficient of decay to set
*/
public Separation setDecayCoefficient(float decayCoefficient){
this.decayCoefficient = decayCoefficient;
return this;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Separation setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Separation setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration.
* @return this behavior for chaining.
*/
@Override
public Separation setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
} }
@@ -4,7 +4,6 @@ import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import mindustry.ai.ai.steer.*; import mindustry.ai.ai.steer.*;
import mindustry.ai.ai.utils.*; import mindustry.ai.ai.utils.*;
import mindustry.ai.ai.utils.Timepiece;
/** /**
* {@code Wander} behavior is designed to produce a steering acceleration that will give the impression of a random walk through * {@code Wander} behavior is designed to produce a steering acceleration that will give the impression of a random walk through
@@ -42,27 +41,21 @@ import mindustry.ai.ai.utils.Timepiece;
* @author davebaol * @author davebaol
*/ */
public class Wander extends Face{ public class Wander extends Face{
/** The forward offset of the wander circle */ /** The forward offset of the wander circle */
protected float wanderOffset; public float wanderOffset;
/** The radius of the wander circle */ /** The radius of the wander circle */
protected float wanderRadius; public float wanderRadius;
/** The rate, expressed in radian per second, at which the wander orientation can change */ /** The rate, expressed in radian per second, at which the wander orientation can change */
protected float wanderRate; public float wanderRate;
/** The last time the orientation of the wander target has been updated */ /** The last time the orientation of the wander target has been updated */
protected float lastTime; public float lastTime;
/** The current orientation of the wander target */ /** The current orientation of the wander target */
protected float wanderOrientation; public float wanderOrientation;
/** /**
* The flag indicating whether to use {@link Face} behavior or not. This should be set to {@code true} when independent facing * The flag indicating whether to use {@link Face} behavior or not. This should be set to {@code true} when independent facing
* is used. * is used.
*/ */
protected boolean faceEnabled; public boolean faceEnabled;
private Vec2 internalTargetPosition; private Vec2 internalTargetPosition;
private Vec2 wanderCenter; private Vec2 wanderCenter;
@@ -118,142 +111,4 @@ public class Wander extends Face{
return steering; return steering;
} }
/** Returns the forward offset of the wander circle. */
public float getWanderOffset(){
return wanderOffset;
}
/**
* Sets the forward offset of the wander circle.
* @return this behavior for chaining.
*/
public Wander setWanderOffset(float wanderOffset){
this.wanderOffset = wanderOffset;
return this;
}
/** Returns the radius of the wander circle. */
public float getWanderRadius(){
return wanderRadius;
}
/**
* Sets the radius of the wander circle.
* @return this behavior for chaining.
*/
public Wander setWanderRadius(float wanderRadius){
this.wanderRadius = wanderRadius;
return this;
}
/** Returns the rate, expressed in radian per second, at which the wander orientation can change. */
public float getWanderRate(){
return wanderRate;
}
/**
* Sets the rate, expressed in radian per second, at which the wander orientation can change.
* @return this behavior for chaining.
*/
public Wander setWanderRate(float wanderRate){
this.wanderRate = wanderRate;
return this;
}
/** Returns the current orientation of the wander target. */
public float getWanderOrientation(){
return wanderOrientation;
}
/**
* Sets the current orientation of the wander target.
* @return this behavior for chaining.
*/
public Wander setWanderOrientation(float wanderOrientation){
this.wanderOrientation = wanderOrientation;
return this;
}
/** Returns the flag indicating whether to use {@link Face} behavior or not. */
public boolean isFaceEnabled(){
return faceEnabled;
}
/**
* Sets the flag indicating whether to use {@link Face} behavior or not. This should be set to {@code true} when independent
* facing is used.
* @return this behavior for chaining.
*/
public Wander setFaceEnabled(boolean faceEnabled){
this.faceEnabled = faceEnabled;
return this;
}
/** Returns the current position of the wander target. This method is useful for debug purpose. */
public Vec2 getInternalTargetPosition(){
return internalTargetPosition;
}
/** Returns the current center of the wander circle. This method is useful for debug purpose. */
public Vec2 getWanderCenter(){
return wanderCenter;
}
//
// Setters overridden in order to fix the correct return type for chaining
//
@Override
public Wander setOwner(Steerable owner){
this.owner = owner;
return this;
}
@Override
public Wander setEnabled(boolean enabled){
this.enabled = enabled;
return this;
}
/**
* Sets the limiter of this steering behavior. The given limiter must at least take care of the maximum linear acceleration;
* additionally, if the flag {@code faceEnabled} is true, it must take care of the maximum angular speed and acceleration.
* @return this behavior for chaining.
*/
@Override
public Wander setLimiter(Limiter limiter){
this.limiter = limiter;
return this;
}
/**
* Sets the target to align to. Notice that this method is inherited from {@link ReachOrientation}, but is completely useless
* for {@code Wander} because owner's orientation is determined by the internal target, which is moving on the wander circle.
* @return this behavior for chaining.
*/
@Override
public Wander setTarget(Location target){
this.target = target;
return this;
}
@Override
public Wander setAlignTolerance(float alignTolerance){
this.alignTolerance = alignTolerance;
return this;
}
@Override
public Wander setDecelerationRadius(float decelerationRadius){
this.decelerationRadius = decelerationRadius;
return this;
}
@Override
public Wander setTimeToTarget(float timeToTarget){
this.timeToTarget = timeToTarget;
return this;
}
} }
@@ -1,32 +0,0 @@
package mindustry.ai.ai.steer.limiters;
/**
* An {@code AngularAccelerationLimiter} provides the maximum magnitude of angular acceleration. All other methods throw an
* {@link UnsupportedOperationException}.
* @author davebaol
*/
public class AngularAccelerationLimiter extends NullLimiter{
private float maxAngularAcceleration;
/**
* Creates an {@code AngularAccelerationLimiter}.
* @param maxAngularAcceleration the maximum angular acceleration
*/
public AngularAccelerationLimiter(float maxAngularAcceleration){
this.maxAngularAcceleration = maxAngularAcceleration;
}
/** Returns the maximum angular acceleration. */
@Override
public float getMaxAngularAcceleration(){
return maxAngularAcceleration;
}
/** Sets the maximum angular acceleration. */
@Override
public void setMaxAngularAcceleration(float maxAngularAcceleration){
this.maxAngularAcceleration = maxAngularAcceleration;
}
}
@@ -1,47 +0,0 @@
package mindustry.ai.ai.steer.limiters;
/**
* An {@code AngularLimiter} provides the maximum magnitudes of angular speed and angular acceleration. Linear methods throw an
* {@link UnsupportedOperationException}.
* @author davebaol
*/
public class AngularLimiter extends NullLimiter{
private float maxAngularAcceleration;
private float maxAngularSpeed;
/**
* Creates an {@code AngularLimiter}.
* @param maxAngularAcceleration the maximum angular acceleration
* @param maxAngularSpeed the maximum angular speed
*/
public AngularLimiter(float maxAngularAcceleration, float maxAngularSpeed){
this.maxAngularAcceleration = maxAngularAcceleration;
this.maxAngularSpeed = maxAngularSpeed;
}
/** Returns the maximum angular speed. */
@Override
public float getMaxAngularSpeed(){
return maxAngularSpeed;
}
/** Sets the maximum angular speed. */
@Override
public void setMaxAngularSpeed(float maxAngularSpeed){
this.maxAngularSpeed = maxAngularSpeed;
}
/** Returns the maximum angular acceleration. */
@Override
public float getMaxAngularAcceleration(){
return maxAngularAcceleration;
}
/** Sets the maximum angular acceleration. */
@Override
public void setMaxAngularAcceleration(float maxAngularAcceleration){
this.maxAngularAcceleration = maxAngularAcceleration;
}
}
@@ -1,32 +0,0 @@
package mindustry.ai.ai.steer.limiters;
/**
* An {@code AngularSpeedLimiter} provides the maximum magnitudes of angular speed. All other methods throw an
* {@link UnsupportedOperationException}.
* @author davebaol
*/
public class AngularSpeedLimiter extends NullLimiter{
private float maxAngularSpeed;
/**
* Creates an {@code AngularSpeedLimiter}.
* @param maxAngularSpeed the maximum angular speed
*/
public AngularSpeedLimiter(float maxAngularSpeed){
this.maxAngularSpeed = maxAngularSpeed;
}
/** Returns the maximum angular speed. */
@Override
public float getMaxAngularSpeed(){
return maxAngularSpeed;
}
/** Sets the maximum angular speed. */
@Override
public void setMaxAngularSpeed(float maxAngularSpeed){
this.maxAngularSpeed = maxAngularSpeed;
}
}
@@ -1,80 +0,0 @@
package mindustry.ai.ai.steer.limiters;
import mindustry.ai.ai.steer.*;
/**
* A {@code FullLimiter} provides the maximum magnitudes of speed and acceleration for both linear and angular components.
* @author davebaol
*/
public class FullLimiter implements Limiter{
private float maxLinearAcceleration;
private float maxLinearSpeed;
private float maxAngularAcceleration;
private float maxAngularSpeed;
private float zeroLinearSpeedThreshold;
/**
* Creates a {@code FullLimiter}.
* @param maxLinearAcceleration the maximum linear acceleration
* @param maxLinearSpeed the maximum linear speed
* @param maxAngularAcceleration the maximum angular acceleration
* @param maxAngularSpeed the maximum angular speed
*/
public FullLimiter(float maxLinearAcceleration, float maxLinearSpeed, float maxAngularAcceleration, float maxAngularSpeed){
this.maxLinearAcceleration = maxLinearAcceleration;
this.maxLinearSpeed = maxLinearSpeed;
this.maxAngularAcceleration = maxAngularAcceleration;
this.maxAngularSpeed = maxAngularSpeed;
}
@Override
public float getMaxLinearSpeed(){
return maxLinearSpeed;
}
@Override
public void setMaxLinearSpeed(float maxLinearSpeed){
this.maxLinearSpeed = maxLinearSpeed;
}
@Override
public float getMaxLinearAcceleration(){
return maxLinearAcceleration;
}
@Override
public void setMaxLinearAcceleration(float maxLinearAcceleration){
this.maxLinearAcceleration = maxLinearAcceleration;
}
@Override
public float getMaxAngularSpeed(){
return maxAngularSpeed;
}
@Override
public void setMaxAngularSpeed(float maxAngularSpeed){
this.maxAngularSpeed = maxAngularSpeed;
}
@Override
public float getMaxAngularAcceleration(){
return maxAngularAcceleration;
}
@Override
public void setMaxAngularAcceleration(float maxAngularAcceleration){
this.maxAngularAcceleration = maxAngularAcceleration;
}
@Override
public float getZeroLinearSpeedThreshold(){
return zeroLinearSpeedThreshold;
}
@Override
public void setZeroLinearSpeedThreshold(float zeroLinearSpeedThreshold){
this.zeroLinearSpeedThreshold = zeroLinearSpeedThreshold;
}
}
@@ -1,32 +0,0 @@
package mindustry.ai.ai.steer.limiters;
/**
* A {@code LinearAccelerationLimiter} provides the maximum magnitude of linear acceleration. All other methods throw an
* {@link UnsupportedOperationException}.
* @author davebaol
*/
public class LinearAccelerationLimiter extends NullLimiter{
private float maxLinearAcceleration;
/**
* Creates a {@code LinearAccelerationLimiter}.
* @param maxLinearAcceleration the maximum linear acceleration
*/
public LinearAccelerationLimiter(float maxLinearAcceleration){
this.maxLinearAcceleration = maxLinearAcceleration;
}
/** Returns the maximum linear acceleration. */
@Override
public float getMaxLinearAcceleration(){
return maxLinearAcceleration;
}
/** Sets the maximum linear acceleration. */
@Override
public void setMaxLinearAcceleration(float maxLinearAcceleration){
this.maxLinearAcceleration = maxLinearAcceleration;
}
}
@@ -1,47 +0,0 @@
package mindustry.ai.ai.steer.limiters;
/**
* A {@code LinearLimiter} provides the maximum magnitudes of linear speed and linear acceleration. Angular methods throw an
* {@link UnsupportedOperationException}.
* @author davebaol
*/
public class LinearLimiter extends NullLimiter{
private float maxLinearAcceleration;
private float maxLinearSpeed;
/**
* Creates a {@code LinearLimiter}.
* @param maxLinearAcceleration the maximum linear acceleration
* @param maxLinearSpeed the maximum linear speed
*/
public LinearLimiter(float maxLinearAcceleration, float maxLinearSpeed){
this.maxLinearAcceleration = maxLinearAcceleration;
this.maxLinearSpeed = maxLinearSpeed;
}
/** Returns the maximum linear speed. */
@Override
public float getMaxLinearSpeed(){
return maxLinearSpeed;
}
/** Sets the maximum linear speed. */
@Override
public void setMaxLinearSpeed(float maxLinearSpeed){
this.maxLinearSpeed = maxLinearSpeed;
}
/** Returns the maximum linear acceleration. */
@Override
public float getMaxLinearAcceleration(){
return maxLinearAcceleration;
}
/** Sets the maximum linear acceleration. */
@Override
public void setMaxLinearAcceleration(float maxLinearAcceleration){
this.maxLinearAcceleration = maxLinearAcceleration;
}
}
@@ -1,32 +0,0 @@
package mindustry.ai.ai.steer.limiters;
/**
* A {@code LinearSpeedLimiter} provides the maximum magnitudes of linear speed. All other methods throw an
* {@link UnsupportedOperationException}.
* @author davebaol
*/
public class LinearSpeedLimiter extends NullLimiter{
private float maxLinearSpeed;
/**
* Creates a {@code LinearSpeedLimiter}.
* @param maxLinearSpeed the maximum linear speed
*/
public LinearSpeedLimiter(float maxLinearSpeed){
this.maxLinearSpeed = maxLinearSpeed;
}
/** Returns the maximum linear speed. */
@Override
public float getMaxLinearSpeed(){
return maxLinearSpeed;
}
/** Sets the maximum linear speed. */
@Override
public void setMaxLinearSpeed(float maxLinearSpeed){
this.maxLinearSpeed = maxLinearSpeed;
}
}
@@ -1,129 +0,0 @@
package mindustry.ai.ai.steer.limiters;
import mindustry.ai.ai.steer.*;
/**
* A {@code NullLimiter} always throws {@link UnsupportedOperationException}. Typically it's used as the base class of partial or
* immutable limiters.
* @author davebaol
*/
public class NullLimiter implements Limiter{
/**
* An immutable limiter whose getters return {@link Float#POSITIVE_INFINITY} and setters throw
* {@link UnsupportedOperationException}.
*/
public static final NullLimiter NEUTRAL_LIMITER = new NullLimiter(){
@Override
public float getMaxLinearSpeed(){
return Float.POSITIVE_INFINITY;
}
@Override
public float getMaxLinearAcceleration(){
return Float.POSITIVE_INFINITY;
}
@Override
public float getMaxAngularSpeed(){
return Float.POSITIVE_INFINITY;
}
@Override
public float getMaxAngularAcceleration(){
return Float.POSITIVE_INFINITY;
}
};
/** Creates a {@code NullLimiter}. */
public NullLimiter(){
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public float getMaxLinearSpeed(){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public void setMaxLinearSpeed(float maxLinearSpeed){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public float getMaxLinearAcceleration(){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public void setMaxLinearAcceleration(float maxLinearAcceleration){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public float getMaxAngularSpeed(){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public void setMaxAngularSpeed(float maxAngularSpeed){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public float getMaxAngularAcceleration(){
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public void setMaxAngularAcceleration(float maxAngularAcceleration){
throw new UnsupportedOperationException();
}
@Override
public float getZeroLinearSpeedThreshold(){
return 0.001f;
}
/**
* Guaranteed to throw UnsupportedOperationException.
* @throws UnsupportedOperationException always
*/
@Override
public void setZeroLinearSpeedThreshold(float zeroLinearSpeedThreshold){
throw new UnsupportedOperationException();
}
}
@@ -108,7 +108,7 @@ public class FieldOfViewProximity extends ProximityBase{
// If the current agent is within the field of view of the owner, // If the current agent is within the field of view of the owner,
// report it to the callback and tag it for further consideration. // report it to the callback and tag it for further consideration.
if(ownerOrientation.dot(toAgent) > coneThreshold){ if(ownerOrientation.dot(toAgent) > coneThreshold){
if(callback.reportNeighbor(currentAgent)){ if(callback.report(currentAgent)){
currentAgent.setTagged(true); currentAgent.setTagged(true);
neighborCount++; neighborCount++;
continue; continue;
@@ -128,7 +128,7 @@ public class FieldOfViewProximity extends ProximityBase{
// it's tagged. // it's tagged.
if(currentAgent != owner && currentAgent.isTagged()){ if(currentAgent != owner && currentAgent.isTagged()){
if(callback.reportNeighbor(currentAgent)){ if(callback.report(currentAgent)){
neighborCount++; neighborCount++;
} }
} }
@@ -24,7 +24,7 @@ public class InfiniteProximity extends ProximityBase{
for(Steerable currentAgent : agents){ for(Steerable currentAgent : agents){
// Make sure the agent being examined isn't the owner // Make sure the agent being examined isn't the owner
if(currentAgent != owner){ if(currentAgent != owner){
if(callback.reportNeighbor(currentAgent)){ if(callback.report(currentAgent)){
neighborCount++; neighborCount++;
} }
} }
@@ -7,17 +7,10 @@ import mindustry.ai.ai.steer.*;
* @author davebaol * @author davebaol
*/ */
public abstract class ProximityBase implements Proximity{ public abstract class ProximityBase implements Proximity{
/** The owner of this proximity. */ /** The owner of this proximity. */
protected Steerable owner; protected Steerable owner;
/** The collection of the agents handled by this proximity. */
/** public Iterable<? extends Steerable> agents;
* The collection of the agents handled by this proximity.
* <p>
* Note that, being this field of type {@code Iterable}, you can either use java or libgdx collections. See
* https://github.com/libgdx/gdx-ai/issues/65
*/
protected Iterable<? extends Steerable> agents;
/** /**
* Creates a {@code ProximityBase} for the specified owner and list of agents. * Creates a {@code ProximityBase} for the specified owner and list of agents.
@@ -38,15 +31,4 @@ public abstract class ProximityBase implements Proximity{
public void setOwner(Steerable owner){ public void setOwner(Steerable owner){
this.owner = owner; this.owner = owner;
} }
/** Returns the the agents that represent potential neighbors. */
public Iterable<? extends Steerable> getAgents(){
return agents;
}
/** Sets the agents that represent potential neighbors. */
public void setAgents(Iterable<Steerable> agents){
this.agents = agents;
}
} }
@@ -19,7 +19,6 @@ import mindustry.ai.ai.utils.Timepiece;
* @author davebaol * @author davebaol
*/ */
public class RadiusProximity extends ProximityBase{ public class RadiusProximity extends ProximityBase{
/** The radius of this proximity. */ /** The radius of this proximity. */
protected float radius; protected float radius;
@@ -73,7 +72,7 @@ public class RadiusProximity extends ProximityBase{
// If the current agent is within the range, report it to the callback // If the current agent is within the range, report it to the callback
// and tag it for further consideration. // and tag it for further consideration.
if(squareDistance < range * range){ if(squareDistance < range * range){
if(callback.reportNeighbor(currentAgent)){ if(callback.report(currentAgent)){
currentAgent.setTagged(true); currentAgent.setTagged(true);
neighborCount++; neighborCount++;
continue; continue;
@@ -91,7 +90,7 @@ public class RadiusProximity extends ProximityBase{
// it's tagged. // it's tagged.
if(currentAgent != owner && currentAgent.isTagged()){ if(currentAgent != owner && currentAgent.isTagged()){
if(callback.reportNeighbor(currentAgent)){ if(callback.report(currentAgent)){
neighborCount++; neighborCount++;
} }
} }
+7 -11
View File
@@ -1,6 +1,7 @@
package mindustry.ai.ai.utils; package mindustry.ai.ai.utils;
import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
/** /**
@@ -28,7 +29,9 @@ public interface Location{
* Returns the angle in radians pointing along the specified vector. * Returns the angle in radians pointing along the specified vector.
* @param vector the vector * @param vector the vector
*/ */
float vectorToAngle(Vec2 vector); default float vectorToAngle(Vec2 vector){
return Mathf.atan2(-vector.x, vector.y);
}
/** /**
* Returns the unit vector in the direction of the specified angle expressed in radians. * Returns the unit vector in the direction of the specified angle expressed in radians.
@@ -36,14 +39,7 @@ public interface Location{
* @param angle the angle in radians. * @param angle the angle in radians.
* @return the output vector for chaining. * @return the output vector for chaining.
*/ */
Vec2 angleToVector(Vec2 outVector, float angle); default Vec2 angleToVector(Vec2 outVector, float angle){
return outVector.set(-Mathf.sin(angle), Mathf.cos(angle));
/** }
* Creates a new location.
* <p>
* This method is used internally to instantiate locations of the correct type parameter {@code T}. This technique keeps the API
* simple and makes the API easier to use with the GWVec2 backend because avoids the use of reflection.
* @return the newly created location.
*/
Location newLocation();
} }
@@ -0,0 +1,23 @@
package mindustry.ai.ai.utils;
import arc.math.geom.*;
public class VecLocation implements Location{
float orientation;
Vec2 position = new Vec2();
@Override
public Vec2 getPosition(){
return position;
}
@Override
public float getOrientation(){
return orientation;
}
@Override
public void setOrientation(float orientation){
this.orientation = orientation;
}
}