Minor command AI improvements
This commit is contained in:
@@ -11,14 +11,16 @@ import mindustry.gen.*;
|
|||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
|
|
||||||
public class CommandAI extends AIController{
|
public class CommandAI extends AIController{
|
||||||
private static final float localInterval = 30f;
|
private static final float localInterval = 40f;
|
||||||
private static final Vec2 vecOut = new Vec2();
|
private static final Vec2 vecOut = new Vec2(), flockVec = new Vec2(), separation = new Vec2(), cohesion = new Vec2(), massCenter = new Vec2();
|
||||||
|
|
||||||
public @Nullable Vec2 targetPos;
|
public @Nullable Vec2 targetPos;
|
||||||
public @Nullable Teamc attackTarget;
|
public @Nullable Teamc attackTarget;
|
||||||
|
|
||||||
|
private Vec2 lastTargetPos;
|
||||||
private int pathId = -1;
|
private int pathId = -1;
|
||||||
private Seq<Unit> local = new Seq<>(false);
|
private Seq<Unit> local = new Seq<>(false);
|
||||||
|
private boolean flocked;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateUnit(){
|
public void updateUnit(){
|
||||||
@@ -31,18 +33,28 @@ public class CommandAI extends AIController{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(targetPos != null){
|
if(targetPos != null){
|
||||||
if(timer.get(timerTarget3, localInterval)){
|
if(timer.get(timerTarget3, localInterval) || !flocked){
|
||||||
|
if(!flocked){
|
||||||
|
//make sure updates are staggered randomly
|
||||||
|
timer.reset(timerTarget3, Mathf.random(localInterval));
|
||||||
|
}
|
||||||
|
|
||||||
local.clear();
|
local.clear();
|
||||||
|
//TODO experiment with 2/3/4
|
||||||
float size = unit.hitSize * 3f;
|
float size = unit.hitSize * 3f;
|
||||||
unit.team.data().tree().intersect(unit.x - size / 2f, unit.y - size/2f, size, size, local);
|
unit.team.data().tree().intersect(unit.x - size / 2f, unit.y - size/2f, size, size, local);
|
||||||
|
local.remove(unit);
|
||||||
|
flocked = true;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
//make sure updates are staggered randomly
|
flocked = false;
|
||||||
timer.reset(timerTarget3, Mathf.random(localInterval));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attackTarget != null){
|
if(attackTarget != null){
|
||||||
if(targetPos == null) targetPos = new Vec2();
|
if(targetPos == null){
|
||||||
|
targetPos = new Vec2();
|
||||||
|
lastTargetPos = targetPos;
|
||||||
|
}
|
||||||
targetPos.set(attackTarget);
|
targetPos.set(attackTarget);
|
||||||
|
|
||||||
if(unit.isGrounded() && attackTarget instanceof Building build && build.tile.solid() && unit.pathType() != Pathfinder.costLegs){
|
if(unit.isGrounded() && attackTarget instanceof Building build && build.tile.solid() && unit.pathType() != Pathfinder.costLegs){
|
||||||
@@ -68,7 +80,9 @@ public class CommandAI extends AIController{
|
|||||||
attackTarget != null && unit.within(attackTarget, engageRange) ? engageRange :
|
attackTarget != null && unit.within(attackTarget, engageRange) ? engageRange :
|
||||||
unit.isGrounded() ? 0f :
|
unit.isGrounded() ? 0f :
|
||||||
attackTarget != null ? engageRange :
|
attackTarget != null ? engageRange :
|
||||||
0f, 100f, false);
|
0f, 100f, false, null);
|
||||||
|
|
||||||
|
//calculateFlock().limit(unit.speed() * flockMult)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(unit.isFlying()){
|
if(unit.isFlying()){
|
||||||
@@ -77,14 +91,75 @@ public class CommandAI extends AIController{
|
|||||||
faceTarget();
|
faceTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attackTarget == null && unit.within(targetPos, Math.max(5f, unit.hitSize / 2.5f))){
|
if(attackTarget == null){
|
||||||
targetPos = null;
|
if(unit.within(targetPos, Math.max(5f, unit.hitSize / 2f))){
|
||||||
|
targetPos = null;
|
||||||
|
}else if(local.size > 1){
|
||||||
|
int count = 0;
|
||||||
|
for(var near : local){
|
||||||
|
//has arrived
|
||||||
|
if(near.isCommandable() && !near.command().hasCommand() && targetPos.equals(near.command().lastTargetPos)){
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//others have arrived at destination, so this one will too
|
||||||
|
if(count >= Math.max(2, local.size / 3)){
|
||||||
|
targetPos = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if(target != null){
|
}else if(target != null){
|
||||||
faceTarget();
|
faceTarget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float cohesionScl = 0.3f;
|
||||||
|
public static float cohesionRad = 3f, separationRad = 1.1f, separationScl = 1f, flockMult = 0.5f;
|
||||||
|
|
||||||
|
//TODO ひどい
|
||||||
|
Vec2 calculateFlock(){
|
||||||
|
if(local.isEmpty()) return flockVec.setZero();
|
||||||
|
|
||||||
|
flockVec.setZero();
|
||||||
|
separation.setZero();
|
||||||
|
cohesion.setZero();
|
||||||
|
massCenter.set(unit);
|
||||||
|
|
||||||
|
float rad = unit.hitSize;
|
||||||
|
float sepDst = rad * separationRad, cohDst = rad * cohesionRad;
|
||||||
|
|
||||||
|
//"cohesed" isn't even a word smh
|
||||||
|
int separated = 0, cohesed = 1;
|
||||||
|
|
||||||
|
for(var other : local){
|
||||||
|
float dst = other.dst(unit);
|
||||||
|
if(dst < sepDst){
|
||||||
|
separation.add(Tmp.v1.set(unit).sub(other).scl(1f / sepDst));
|
||||||
|
separated ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dst < cohDst){
|
||||||
|
massCenter.add(other);
|
||||||
|
cohesed ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(separated > 0){
|
||||||
|
separation.scl(1f / separated);
|
||||||
|
flockVec.add(separation.scl(separationScl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cohesed > 1){
|
||||||
|
massCenter.scl(1f / cohesed);
|
||||||
|
flockVec.add(Tmp.v1.set(massCenter).sub(unit).limit(cohesionScl * unit.type.speed));
|
||||||
|
//seek mass center?
|
||||||
|
}
|
||||||
|
|
||||||
|
return flockVec;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keepState(){
|
public boolean keepState(){
|
||||||
return true;
|
return true;
|
||||||
@@ -107,6 +182,7 @@ public class CommandAI extends AIController{
|
|||||||
|
|
||||||
public void commandPosition(Vec2 pos){
|
public void commandPosition(Vec2 pos){
|
||||||
targetPos = pos;
|
targetPos = pos;
|
||||||
|
lastTargetPos = pos;
|
||||||
attackTarget = null;
|
attackTarget = null;
|
||||||
pathId = Vars.controlPath.nextTargetId();
|
pathId = Vars.controlPath.nextTargetId();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,10 +256,10 @@ public class AIController implements UnitController{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void moveTo(Position target, float circleLength, float smooth){
|
public void moveTo(Position target, float circleLength, float smooth){
|
||||||
moveTo(target, circleLength, smooth, unit.isFlying());
|
moveTo(target, circleLength, smooth, unit.isFlying(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveTo(Position target, float circleLength, float smooth, boolean keepDistance){
|
public void moveTo(Position target, float circleLength, float smooth, boolean keepDistance, @Nullable Vec2 offset){
|
||||||
if(target == null) return;
|
if(target == null) return;
|
||||||
|
|
||||||
vec.set(target).sub(unit);
|
vec.set(target).sub(unit);
|
||||||
@@ -267,6 +267,7 @@ public class AIController implements UnitController{
|
|||||||
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / smooth, -1f, 1f);
|
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / smooth, -1f, 1f);
|
||||||
|
|
||||||
vec.setLength(unit.speed() * length);
|
vec.setLength(unit.speed() * length);
|
||||||
|
|
||||||
if(length < -0.5f){
|
if(length < -0.5f){
|
||||||
if(keepDistance){
|
if(keepDistance){
|
||||||
vec.rotate(180f);
|
vec.rotate(180f);
|
||||||
@@ -277,6 +278,11 @@ public class AIController implements UnitController{
|
|||||||
vec.setZero();
|
vec.setZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(offset != null){
|
||||||
|
vec.add(offset);
|
||||||
|
vec.setLength(unit.speed() * length);
|
||||||
|
}
|
||||||
|
|
||||||
//do not move when infinite vectors are used.
|
//do not move when infinite vectors are used.
|
||||||
if(vec.isNaN() || vec.isInfinite()) return;
|
if(vec.isNaN() || vec.isInfinite()) return;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -24,4 +24,4 @@ android.useAndroidX=true
|
|||||||
#used for slow jitpack builds; TODO see if this actually works
|
#used for slow jitpack builds; TODO see if this actually works
|
||||||
org.gradle.internal.http.socketTimeout=100000
|
org.gradle.internal.http.socketTimeout=100000
|
||||||
org.gradle.internal.http.connectionTimeout=100000
|
org.gradle.internal.http.connectionTimeout=100000
|
||||||
archash=6f8e68b7db
|
archash=ab33b65395
|
||||||
|
|||||||
Reference in New Issue
Block a user