Better conditional avoidance system

This commit is contained in:
Anuken
2025-07-06 01:20:57 -04:00
parent da402b85c6
commit b006a2a4f5
4 changed files with 42 additions and 5 deletions

View File

@@ -163,7 +163,7 @@ public class Pathfinder implements Runnable{
for(int dy = -r; dy <= r; dy++){ for(int dy = -r; dy <= r; dy++){
int x = dx + unit.tileX(), y = dy + unit.tileY(); int x = dx + unit.tileX(), y = dy + unit.tileY();
if(x >= 0 && y >= 0 && x < wwidth && y < wheight && (dx*dx + dy*dy) <= rad2){ if(x >= 0 && y >= 0 && x < wwidth && y < wheight && (dx*dx + dy*dy) <= rad2){
arr[x + y * wwidth] = Math.max(arr[x + y * wwidth], unit.id); arr[x + y * wwidth] = Math.max(arr[x + y * wwidth], Integer.MAX_VALUE - unit.id);
} }
} }
} }
@@ -441,7 +441,7 @@ public class Pathfinder implements Runnable{
if(other == null) continue; if(other == null) continue;
int packed = dx/res + dy/res * ww; int packed = dx/res + dy/res * ww;
int avoidance = avoid == null || unitId == 0 ? 0 : avoid[packed] > unitId ? 1 : 0; int avoidance = avoid == null || unitId == 0 ? 0 : avoid[packed] > Integer.MAX_VALUE - unitId ? 1 : 0;
int cost = values[packed] + avoidance; int cost = values[packed] + avoidance;
if(cost < value && avoidance == 0 && (current == null || cost < tl) && path.passable(packed) && if(cost < value && avoidance == 0 && (current == null || cost < tl) && path.passable(packed) &&

View File

@@ -1,7 +1,10 @@
package mindustry.ai.types; package mindustry.ai.types;
import arc.math.*; import arc.math.*;
import arc.util.*;
import mindustry.*;
import mindustry.ai.*; import mindustry.ai.*;
import mindustry.entities.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.world.*; import mindustry.world.*;
@@ -9,11 +12,16 @@ import mindustry.world.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class GroundAI extends AIController{ public class GroundAI extends AIController{
float stuckTime = 0f;
float stuckX = -999f, stuckY = -999f;
static final float stuckThreshold = 1.5f * 60f;
@Override @Override
public void updateMovement(){ public void updateMovement(){
Building core = unit.closestEnemyCore(); Building core = unit.closestEnemyCore();
boolean moved = false;
if(core != null && unit.within(core, unit.range() / 1.3f + core.block.size * tilesize / 2f)){ if(core != null && unit.within(core, unit.range() / 1.3f + core.block.size * tilesize / 2f)){
target = core; target = core;
@@ -38,7 +46,9 @@ public class GroundAI extends AIController{
move = false; move = false;
} }
if(move) pathfind(Pathfinder.fieldCore); moved = move;
if(move) pathfind(Pathfinder.fieldCore, true, stuckTime >= stuckThreshold);
} }
if(unit.type.canBoost && unit.elevation > 0.001f && !unit.onSolid()){ if(unit.type.canBoost && unit.elevation > 0.001f && !unit.onSolid()){
@@ -46,5 +56,28 @@ public class GroundAI extends AIController{
} }
faceTarget(); faceTarget();
if(moved){
if(unit.within(stuckX, stuckY, tilesize * 1.5f)){
stuckTime += Time.delta;
if(stuckTime - Time.delta < stuckThreshold && stuckTime >= stuckThreshold){
float radius = unit.hitSize * Vars.unitCollisionRadiusScale * 2f;
Units.nearby(unit.team, unit.x, unit.y, radius, other -> {
if(other != unit && other.controller() instanceof GroundAI ai && other.within(unit.x, unit.y, radius + other.hitSize * unitCollisionRadiusScale)){
ai.stuckX = other.x;
ai.stuckY = other.y;
ai.stuckTime = stuckThreshold + 1f;
}
});
}
}else{
stuckX = unit.x;
stuckY = unit.y;
stuckTime = 0f;
}
}else{
stuckTime = 0f;
}
} }
} }

View File

@@ -132,11 +132,15 @@ public class AIController implements UnitController{
} }
public void pathfind(int pathTarget, boolean stopAtTargetTile){ public void pathfind(int pathTarget, boolean stopAtTargetTile){
pathfind(pathTarget, stopAtTargetTile, false);
}
public void pathfind(int pathTarget, boolean stopAtTargetTile, boolean avoidance){
int costType = unit.type.flowfieldPathType; int costType = unit.type.flowfieldPathType;
Tile tile = unit.tileOn(); Tile tile = unit.tileOn();
if(tile == null) return; if(tile == null) return;
Tile targetTile = pathfinder.getField(unit.team, costType, pathTarget).getNextTile(tile, unit.collisionLayer(), unit.id); Tile targetTile = pathfinder.getField(unit.team, costType, pathTarget).getNextTile(tile, avoidance ? unit.collisionLayer() : -1, unit.id);
if((tile == targetTile && stopAtTargetTile) || !unit.canPass(targetTile.x, targetTile.y)) return; if((tile == targetTile && stopAtTargetTile) || !unit.canPass(targetTile.x, targetTile.y)) return;

View File

@@ -519,7 +519,7 @@ public class LExecutor{
if(obj instanceof Building b && (exec.privileged || (b.team == exec.team && exec.linkIds.contains(b.id)))){ if(obj instanceof Building b && (exec.privileged || (b.team == exec.team && exec.linkIds.contains(b.id)))){
if(type == LAccess.enabled){ if(type == LAccess.enabled){
if(p1.bool()) { if(p1.bool()){
b.noSleep(); b.noSleep();
}else{ }else{
b.lastDisabler = exec.build; b.lastDisabler = exec.build;