Minor command AI improvements

This commit is contained in:
Anuken
2022-02-18 16:35:29 -05:00
parent 9c1cb64c77
commit bc8842d0d7
3 changed files with 94 additions and 12 deletions
+85 -9
View File
@@ -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
View File
@@ -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