Fixed RTS AI targeting unreachable things

This commit is contained in:
Anuken
2022-10-06 14:03:57 -04:00
parent 718cf72912
commit 4ac3eb1c9a
4 changed files with 45 additions and 6 deletions

View File

@@ -164,6 +164,19 @@ public class ControlPathfinder{
* @param pathId a unique ID for this location query, which should change every time the 'destination' vector is modified.
* */
public boolean getPathPosition(Unit unit, int pathId, Vec2 destination, Vec2 out){
return getPathPosition(unit, pathId, destination, out, null);
}
/**
* @return whether a path is ready.
* @param pathId a unique ID for this location query, which should change every time the 'destination' vector is modified.
* @param noResultFound extra return value for storing whether no valid path to the destination exists (thanks java!)
* */
public boolean getPathPosition(Unit unit, int pathId, Vec2 destination, Vec2 out, @Nullable boolean[] noResultFound){
if(noResultFound != null){
noResultFound[0] = false;
}
//uninitialized
if(threads == null || !world.tiles.in(World.toTile(destination.x), World.toTile(destination.y))) return false;
@@ -272,6 +285,10 @@ public class ControlPathfinder{
out.set(unit);
//end of path, we're done here? reset path? what???
}
if(noResultFound != null){
noResultFound[0] = !req.foundEnd;
}
}
return req.done;

View File

@@ -7,6 +7,7 @@ import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.ai.types.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
@@ -25,7 +26,7 @@ public class RtsAI{
static final Seq<Building> targets = new Seq<>();
static final Seq<Unit> squad = new Seq<>(false);
static final IntSet used = new IntSet();
static final IntSet assignedTargets = new IntSet();
static final IntSet assignedTargets = new IntSet(), invalidTarget = new IntSet();
static final float squadRadius = 140f;
static final int timeUpdate = 0, timerSpawn = 1, maxTargetsChecked = 15;
@@ -233,6 +234,14 @@ public class RtsAI{
boolean anyDefend = defendPos != null || defendTarget != null;
invalidTarget.clear();
for(var unit : squad){
if(unit.controller() instanceof CommandAI ai){
invalidTarget.addAll(ai.unreachableBuildings);
}
}
var build = anyDefend ? null : findTarget(ax, ay, units.size, dps, health, units.first().flag == 0);
if(build != null || anyDefend){
@@ -267,7 +276,7 @@ public class RtsAI{
for(var flag : flags){
targets.addAll(Vars.indexer.getEnemy(data.team, flag));
}
targets.removeAll(b -> assignedTargets.contains(b.id));
targets.removeAll(b -> assignedTargets.contains(b.id) || invalidTarget.contains(b.pos()));
if(targets.size == 0) return null;
@@ -327,9 +336,9 @@ public class RtsAI{
float timeDestroySelf = Mathf.zero(dp) ? Float.POSITIVE_INFINITY : selfHealth / dp;
//other can never be destroyed | other destroys self instantly
if(Float.isInfinite(timeDestroyOther) | Mathf.zero(timeDestroySelf)) return 0f;
if(Float.isInfinite(timeDestroyOther) || Mathf.zero(timeDestroySelf)) return 0f;
//self can never be destroyed | self destroys other instantly
if(Float.isInfinite(timeDestroySelf) | Mathf.zero(timeDestroyOther)) return 1f;
if(Float.isInfinite(timeDestroySelf) || Mathf.zero(timeDestroyOther)) return 1f;
//examples:
// self 10 sec / other 10 sec -> can destroy target with 100 % losses -> returns 1

View File

@@ -14,9 +14,12 @@ import mindustry.world.*;
public class CommandAI extends AIController{
protected static final float localInterval = 40f;
protected static final Vec2 vecOut = new Vec2(), flockVec = new Vec2(), separation = new Vec2(), cohesion = new Vec2(), massCenter = new Vec2();
protected static final boolean[] noFound = {false};
public @Nullable Vec2 targetPos;
public @Nullable Teamc attackTarget;
/** All encountered unreachable buildings of this AI. Why a sequence? Because contains() is very rarely called on it. */
public IntSeq unreachableBuildings = new IntSeq(8);
protected boolean stopAtTarget;
protected Vec2 lastTargetPos;
@@ -133,7 +136,17 @@ public class CommandAI extends AIController{
vecOut.set(targetPos);
if(unit.isGrounded()){
move = Vars.controlPath.getPathPosition(unit, pathId, targetPos, vecOut);
move = Vars.controlPath.getPathPosition(unit, pathId, targetPos, vecOut, noFound);
//if the path is invalid, stop trying and record the end as unreachable
if(unit.team.isAI() && noFound[0]){
if(attackTarget instanceof Building build){
unreachableBuildings.addUnique(build.pos());
}
attackTarget = null;
targetPos = null;
return;
}
}
float engageRange = unit.type.range - 10f;