Simple mining AI
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
93
core/src/mindustry/ai/types/MinerAI.java
Normal file
93
core/src/mindustry/ai/types/MinerAI.java
Normal 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(){
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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++){
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user