Simple mining AI

This commit is contained in:
Anuken
2020-08-12 00:08:23 -04:00
parent 8810cf037e
commit 925b1e3057
11 changed files with 150 additions and 68 deletions

View File

@@ -1,9 +1,6 @@
package mindustry.ai.types;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.entities.units.*;
import mindustry.game.Teams.*;
import mindustry.gen.*;
@@ -63,19 +60,4 @@ public class BuilderAI extends AIController{
}
}
}
protected void moveTo(Position target, float circleLength){
vec.set(target).sub(unit);
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f);
vec.setLength(unit.type().speed * Time.delta * length);
if(length < -0.5f){
vec.rotate(180f);
}else if(length < 0){
vec.setZero();
}
unit.moveAt(vec);
}
}

View File

@@ -20,7 +20,7 @@ public class FlyingAI extends AIController{
if(target != null && unit.hasWeapons()){
if(unit.type().weapons.first().rotate){
moveTo(unit.range() * 0.8f);
moveTo(target, unit.range() * 0.8f);
unit.lookAt(target);
}else{
attack(80f);
@@ -44,41 +44,6 @@ public class FlyingAI extends AIController{
//TODO clean up
protected void circle(float circleLength){
circle(circleLength, unit.type().speed);
}
protected void circle(float circleLength, float speed){
if(target == null) return;
vec.set(target).sub(unit);
if(vec.len() < circleLength){
vec.rotate((circleLength - vec.len()) / circleLength * 180f);
}
vec.setLength(speed * Time.delta);
unit.moveAt(vec);
}
protected void moveTo(float circleLength){
if(target == null) return;
vec.set(target).sub(unit);
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f);
vec.setLength(unit.type().speed * Time.delta * length);
if(length < -0.5f){
vec.rotate(180f);
}else if(length < 0){
vec.setZero();
}
unit.moveAt(vec);
}
protected void attack(float circleLength){
vec.set(target).sub(unit);

View File

@@ -0,0 +1,93 @@
package mindustry.ai.types;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
import static mindustry.Vars.*;
public class MinerAI extends AIController{
//miners are limited to copper and lead until further notice
Seq<Item> targets = Seq.with(Items.copper, Items.lead);
boolean mining = true;
Item targetItem;
Tile ore;
@Override
protected void updateMovement(){
if(unit.moving()){
unit.lookAt(unit.vel.angle());
}
if(unit.isFlying()){
unit.wobble();
}
Building core = unit.closestCore();
if(!(unit instanceof Minerc) || core == null) return;
Minerc miner = (Minerc)unit;
if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type().range)){
miner.mineTile(null);
}
if(mining){
targetItem = Structs.findMin(targets, indexer::hasOre, Structs.comparingInt(i -> -core.items.get(i)));
//core full of the target item, do nothing
if(targetItem != null && core.acceptStack(targetItem, 1, unit) == 0){
unit.clearItem();
return;
}
//if inventory is full, drop it off.
if(unit.stack.amount >= unit.type().itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){
mining = false;
}else{
if(retarget() && targetItem != null){
ore = indexer.findClosestOre(unit.x, unit.y, targetItem);
}
if(ore != null){
moveTo(ore, unit.type().range / 1.5f);
if(unit.within(ore, unit.type().range)){
miner.mineTile(ore);
}
if(ore.block() != Blocks.air){
mining = false;
}
}
}
}else{
if(unit.stack.amount == 0){
mining = true;
return;
}
if(unit.within(core, unit.type().range)){
if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){
Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core);
}
unit.clearItem();
mining = true;
}
circle(core, unit.type().range / 1.8f);
}
}
@Override
protected void updateTargeting(){
}
}

View File

@@ -102,7 +102,7 @@ public class Fx{
Tmp.v1.set(e.x, e.y).interpolate(Tmp.v2.set(to), e.fin(), Interp.pow3)
.add(Tmp.v2.sub(e.x, e.y).nor().rotate90(1).scl(Mathf.randomSeedRange(e.id, 1f) * e.fslope() * 10f));
float x = Tmp.v1.x, y = Tmp.v1.y;
float size = Math.min(0.8f + e.rotation / 5f, 2);
float size = 1f;
stroke(e.fslope() * 2f * size, Pal.accent);
Lines.circle(x, y, e.fslope() * 2f * size);

View File

@@ -687,13 +687,17 @@ public class UnitTypes implements ContentList{
//region air support
mono = new UnitType("mono"){{
defaultController = MinerAI::new;
flying = true;
drag = 0.05f;
accel = 0.15f;
speed = 2f;
drag = 0.06f;
accel = 0.12f;
speed = 1.1f;
health = 100;
engineSize = 1.8f;
engineOffset = 5.7f;
itemCapacity = 30;
range = 50f;
mineTier = 1;
mineSpeed = 2.5f;
@@ -704,7 +708,7 @@ public class UnitTypes implements ContentList{
flying = true;
drag = 0.05f;
speed = 2f;
speed = 1.9f;
rotateSpeed = 15f;
accel = 0.1f;
range = 70f;

View File

@@ -45,7 +45,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
if(accepted > 0){
Call.transferItemTo(item(), accepted,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile());
mineTile.worldy() + Mathf.range(tilesize / 2f), core);
clearItem();
}
}
@@ -66,7 +66,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
if(within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){
Call.transferItemTo(item, 1,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile());
mineTile.worldy() + Mathf.range(tilesize / 2f), core);
}else if(acceptsItem(item)){
//this is clientside, since items are synced anyway
InputHandler.transferItemToUnit(item,

View File

@@ -115,6 +115,41 @@ public class AIController implements UnitController{
}
protected void circle(Position target, float circleLength){
circle(target, circleLength, unit.type().speed);
}
protected void circle(Position target, float circleLength, float speed){
if(target == null) return;
vec.set(target).sub(unit);
if(vec.len() < circleLength){
vec.rotate((circleLength - vec.len()) / circleLength * 180f);
}
vec.setLength(speed * Time.delta);
unit.moveAt(vec);
}
protected void moveTo(Position target, float circleLength){
if(target == null) return;
vec.set(target).sub(unit);
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f);
vec.setLength(unit.type().speed * Time.delta * length);
if(length < -0.5f){
vec.rotate(180f);
}else if(length < 0){
vec.setZero();
}
unit.moveAt(vec);
}
@Override
public void unit(Unit unit){
if(this.unit == unit) return;

View File

@@ -86,12 +86,12 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
}
@Remote(called = Loc.server, unreliable = true)
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
if(tile == null || tile.build == null || tile.build.items == null) return;
public static void transferItemTo(Item item, int amount, float x, float y, Building build){
if(build == null || build.items == null) return;
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, tile, () -> {}));
Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, build, () -> {}));
}
tile.build.items.add(item, amount);
build.items.add(item, amount);
}
public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){

View File

@@ -99,6 +99,7 @@ public class LCanvas extends Table{
void load(String asm){
Seq<LStatement> statements = LAssembler.read(asm);
statements.truncate(LogicBlock.maxInstructions);
this.statements.clearChildren();
for(LStatement st : statements){
add(st);
@@ -119,8 +120,8 @@ public class LCanvas extends Table{
}
public class DragLayout extends WidgetGroup{
float margin = 4f;
float space = 10f, prefWidth, prefHeight;
float margin = Scl.scl(4f);
float space = Scl.scl(10f), prefWidth, prefHeight;
Seq<Element> seq = new Seq<>();
int insertPosition = 0;
@@ -136,7 +137,7 @@ public class LCanvas extends Table{
float totalHeight = getChildren().sumf(e -> e.getHeight() + space) + margin*2f;
height = prefHeight = totalHeight;
width = prefWidth = 400f;
width = prefWidth = Scl.scl(400f);
//layout everything normally
for(int i = 0; i < getChildren().size; i++){

View File

@@ -175,6 +175,7 @@ public abstract class Turret extends Block{
@Override
public double sense(LAccess sensor){
if(sensor == LAccess.rotation) return rotation;
if(sensor == LAccess.shootX) return targetPos.x;
if(sensor == LAccess.shootY) return targetPos.y;
if(sensor == LAccess.shooting) return (isControlled() ? unit.isShooting() : logicControlled() ? logicShooting : validateTarget()) ? 1 : 0;

View File

@@ -76,6 +76,7 @@ public class LogicBlock extends Block{
public void updateCodeVars(String str, Cons<LAssembler> assemble){
if(str != null){
if(str.length() >= Short.MAX_VALUE) str = str.substring(0, Short.MAX_VALUE - 1);
code = str;
try{