mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-02-22 04:28:27 +07:00
Unit system rewrite, new drone AI
This commit is contained in:
parent
12c746a4e4
commit
270dc351a1
@ -63,7 +63,7 @@ public class Vars{
|
||||
//whether turrets have infinite ammo (only with debug)
|
||||
public static boolean infiniteAmmo = true;
|
||||
//whether to show paths of enemies
|
||||
public static boolean showPaths = true;
|
||||
public static boolean showPaths = false;
|
||||
//if false, player is always hidden
|
||||
public static boolean showPlayer = true;
|
||||
//whether to hide ui, only on debug
|
||||
|
@ -11,8 +11,29 @@ public class UnitTypes implements ContentList {
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
drone = new Drone();
|
||||
scout = new Scout();
|
||||
vtol = new Vtol();
|
||||
drone = new UnitType("drone", team -> new Drone(drone, team)){{
|
||||
isFlying = true;
|
||||
drag = 0.01f;
|
||||
speed = 0.2f;
|
||||
maxVelocity = 0.8f;
|
||||
range = 50f;
|
||||
}};
|
||||
|
||||
scout = new UnitType("scout", team -> new Scout(scout, team)){{
|
||||
maxVelocity = 1.1f;
|
||||
speed = 0.1f;
|
||||
drag = 0.4f;
|
||||
range = 40f;
|
||||
setAmmo(AmmoTypes.bulletIron);
|
||||
}};
|
||||
|
||||
vtol = new UnitType("vtol", team -> new Vtol(vtol, team)){{
|
||||
speed = 0.3f;
|
||||
maxVelocity = 2f;
|
||||
drag = 0.01f;
|
||||
isFlying = true;
|
||||
reload = 7;
|
||||
setAmmo(AmmoTypes.bulletIron);
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public class Logic extends Module {
|
||||
|
||||
//TODO spawn enemies
|
||||
for(int i = 0; i < 10; i ++){
|
||||
BaseUnit unit = new BaseUnit(UnitTypes.vtol, Team.red);
|
||||
BaseUnit unit = UnitTypes.vtol.create(Team.red);
|
||||
Vector2 offset = new Vector2().setToRandomDirection().scl(world.width()/2f*tilesize).add(world.width()/2f*tilesize, world.height()/2f*tilesize);
|
||||
unit.inventory.addAmmo(AmmoTypes.bulletIron);
|
||||
unit.inventory.setInfiniteAmmo(true);
|
||||
|
@ -6,6 +6,7 @@ import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.content.fx.BlockFx;
|
||||
import io.anuke.mindustry.entities.effect.ItemTransfer;
|
||||
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
@ -14,6 +15,7 @@ import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.types.BuildBlock;
|
||||
import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Events;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Fill;
|
||||
@ -26,8 +28,7 @@ import io.anuke.ucore.util.Translator;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/**Interface for units that build, break or mine things.*/
|
||||
public interface BlockBuilder {
|
||||
@ -140,6 +141,9 @@ public interface BlockBuilder {
|
||||
if(Build.validPlace(unit.team, current.x, current.y, current.recipe.result, current.rotation)){
|
||||
//if it's valid, place it
|
||||
Build.placeBlock(unit.team, current.x, current.y, current.recipe, current.rotation);
|
||||
|
||||
//fire place event.
|
||||
threads.run(() -> Events.fire(BlockBuildEvent.class, unit.team, world.tile(current.x, current.y)));
|
||||
}else{
|
||||
//otherwise, skip it
|
||||
getPlaceQueue().removeFirst();
|
||||
|
@ -69,8 +69,7 @@ public class Player extends Unit implements BlockBuilder {
|
||||
public Player(){
|
||||
hitbox.setSize(5);
|
||||
hitboxTile.setSize(4f);
|
||||
|
||||
maxhealth = 200;
|
||||
|
||||
heal();
|
||||
}
|
||||
|
||||
@ -78,6 +77,10 @@ public class Player extends Unit implements BlockBuilder {
|
||||
|
||||
//region unit and event overrides, utility methods
|
||||
|
||||
@Override
|
||||
public float getMaxHealth() {
|
||||
return 200;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile getMineTile() {
|
||||
|
@ -41,7 +41,7 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
|
||||
|
||||
@Override
|
||||
public boolean collides(SolidEntity other){
|
||||
return other instanceof io.anuke.mindustry.entities.bullet.Bullet && state.teams.areEnemies((((Bullet) other).team), team);
|
||||
return other instanceof Bullet && state.teams.areEnemies((((Bullet) other).team), team);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,6 +22,10 @@ public class UnitInventory {
|
||||
this.ammoCapacity = ammoCapacity;
|
||||
}
|
||||
|
||||
public boolean isInfiniteAmmo() {
|
||||
return infiniteAmmo;
|
||||
}
|
||||
|
||||
public void setInfiniteAmmo(boolean infinite){
|
||||
infiniteAmmo = infinite;
|
||||
}
|
||||
@ -29,6 +33,7 @@ public class UnitInventory {
|
||||
public void write(DataOutputStream stream) throws IOException {
|
||||
stream.writeInt(item == null ? 0 : item.amount);
|
||||
stream.writeByte(item == null ? 0 : item.item.id);
|
||||
stream.writeBoolean(infiniteAmmo);
|
||||
stream.writeInt(totalAmmo);
|
||||
stream.writeByte(ammos.size);
|
||||
for(int i = 0; i < ammos.size; i ++){
|
||||
@ -40,6 +45,7 @@ public class UnitInventory {
|
||||
public void read(DataInputStream stream) throws IOException {
|
||||
int iamount = stream.readInt();
|
||||
byte iid = stream.readByte();
|
||||
infiniteAmmo = stream.readBoolean();
|
||||
this.totalAmmo = stream.readInt();
|
||||
byte ammoa = stream.readByte();
|
||||
for(int i = 0; i < ammoa; i ++){
|
||||
|
@ -1,16 +1,22 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
import io.anuke.mindustry.content.fx.ExplosionFx;
|
||||
import io.anuke.mindustry.entities.Targetable;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Timer;
|
||||
|
||||
@ -19,14 +25,19 @@ import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static io.anuke.mindustry.Vars.unitGroups;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class BaseUnit extends Unit{
|
||||
public UnitType type;
|
||||
public Timer timer = new Timer(5);
|
||||
public float walkTime = 0f;
|
||||
public StateMachine state = new StateMachine();
|
||||
public Targetable target;
|
||||
public abstract class BaseUnit extends Unit{
|
||||
private static int timerIndex = 0;
|
||||
|
||||
protected static final int timerTarget = timerIndex++;
|
||||
protected static final int timerBoost = timerIndex++;
|
||||
protected static final int timerReload = timerIndex++;
|
||||
|
||||
protected UnitType type;
|
||||
protected Timer timer = new Timer(5);
|
||||
protected StateMachine state = new StateMachine();
|
||||
protected Targetable target;
|
||||
|
||||
public BaseUnit(UnitType type, Team team){
|
||||
this.type = type;
|
||||
@ -52,15 +63,51 @@ public class BaseUnit extends Unit{
|
||||
}
|
||||
|
||||
public void setState(UnitState state){
|
||||
this.state.set(this, state);
|
||||
this.state.set(state);
|
||||
}
|
||||
|
||||
public void retarget(Runnable run){
|
||||
if(timer.get(UnitType.timerTarget, 20)){
|
||||
if(timer.get(timerTarget, 20)){
|
||||
run.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**Only runs when the unit has a target.*/
|
||||
public void behavior(){
|
||||
|
||||
}
|
||||
|
||||
public void updateTargeting(){
|
||||
if(target == null || (target instanceof Unit && (target.isDead() || ((Unit)target).team == team))
|
||||
|| (target instanceof TileEntity && ((TileEntity) target).tile.entity == null)){
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void shoot(AmmoType type, float rotation, float translation){
|
||||
Bullet.create(type.bullet, this,
|
||||
x + Angles.trnsx(rotation, translation),
|
||||
y + Angles.trnsy(rotation, translation), rotation);
|
||||
Effects.effect(type.shootEffect, x + Angles.trnsx(rotation, translation),
|
||||
y + Angles.trnsy(rotation, translation), rotation, this);
|
||||
Effects.effect(type.smokeEffect, x + Angles.trnsx(rotation, translation),
|
||||
y + Angles.trnsy(rotation, translation), rotation, this);
|
||||
}
|
||||
|
||||
public void targetClosestAllyFlag(BlockFlag flag){
|
||||
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, flag));
|
||||
if (target != null) this.target = target.entity;
|
||||
}
|
||||
|
||||
public UnitState getStartState(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxHealth() {
|
||||
return type.health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getArmor() {
|
||||
return type.armor;
|
||||
@ -99,22 +146,41 @@ public class BaseUnit extends Unit{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
type.update(this);
|
||||
if(hitTime > 0){
|
||||
hitTime -= Timers.delta();
|
||||
}
|
||||
|
||||
if(hitTime < 0) hitTime = 0;
|
||||
|
||||
if(Net.client()){
|
||||
interpolate();
|
||||
return;
|
||||
}
|
||||
|
||||
updateTargeting();
|
||||
|
||||
state.update();
|
||||
updateVelocityStatus(type.drag, type.maxVelocity);
|
||||
|
||||
if(target != null) behavior();
|
||||
|
||||
x = Mathf.clamp(x, 0, world.width() * tilesize);
|
||||
y = Mathf.clamp(y, 0, world.height() * tilesize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawSmooth(){
|
||||
type.draw(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(){
|
||||
type.drawUnder(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(){
|
||||
type.drawOver(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -130,27 +196,29 @@ public class BaseUnit extends Unit{
|
||||
@Override
|
||||
public void onDeath(){
|
||||
super.onDeath();
|
||||
type.onDeath(this);
|
||||
|
||||
Effects.effect(ExplosionFx.explosion, this);
|
||||
Effects.shake(2f, 2f, this);
|
||||
|
||||
remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteDeath(){
|
||||
type.onRemoteDeath(this);
|
||||
onDeath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
type.removed(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void added(){
|
||||
maxhealth = type.health;
|
||||
|
||||
hitbox.solid = !isFlying();
|
||||
hitbox.setSize(type.hitsize);
|
||||
hitboxTile.setSize(type.hitsizeTile);
|
||||
state.set(this, type.getStartState());
|
||||
state.set(getStartState());
|
||||
|
||||
heal();
|
||||
}
|
||||
|
168
core/src/io/anuke/mindustry/entities/units/FlyingUnit.java
Normal file
168
core/src/io/anuke/mindustry/entities/units/FlyingUnit.java
Normal file
@ -0,0 +1,168 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Trail;
|
||||
import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class FlyingUnit extends BaseUnit {
|
||||
protected static Translator vec = new Translator();
|
||||
protected static float maxAim = 30f;
|
||||
protected static float wobblyness = 0.6f;
|
||||
|
||||
protected Trail trail = new Trail(16);
|
||||
|
||||
public FlyingUnit(UnitType type, Team team) {
|
||||
super(type, team);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
|
||||
rotation = velocity.angle();
|
||||
trail.update(x + Angles.trnsx(rotation + 180f, 6f) + Mathf.range(wobblyness),
|
||||
y + Angles.trnsy(rotation + 180f, 6f) + Mathf.range(wobblyness));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawSmooth() {
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
|
||||
Draw.rect(type.name, x, y, rotation - 90);
|
||||
|
||||
Draw.alpha(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver() {
|
||||
trail.draw(Palette.lighterOrange, Palette.lightishOrange, 5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior() {
|
||||
if(health <= health * type.retreatPercent &&
|
||||
Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){
|
||||
setState(retreat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UnitState getStartState(){
|
||||
return attack;
|
||||
}
|
||||
|
||||
protected void circle(float circleLength){
|
||||
vec.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
if(vec.len() < circleLength){
|
||||
vec.rotate((circleLength-vec.len())/circleLength * 180f);
|
||||
}
|
||||
|
||||
vec.setLength(type.speed * Timers.delta());
|
||||
|
||||
velocity.add(vec);
|
||||
}
|
||||
|
||||
protected void attack(float circleLength){
|
||||
vec.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
float ang = angleTo(target);
|
||||
float diff = Angles.angleDist(ang, rotation);
|
||||
|
||||
if(diff > 100f && vec.len() < circleLength){
|
||||
vec.setAngle(velocity.angle());
|
||||
}else{
|
||||
vec.setAngle(Mathf.slerpDelta(velocity.angle(), vec.angle(), 0.44f));
|
||||
}
|
||||
|
||||
vec.setLength(type.speed*Timers.delta());
|
||||
|
||||
velocity.add(vec);
|
||||
}
|
||||
|
||||
public final UnitState
|
||||
|
||||
resupply = new UnitState(){
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
|
||||
state.set(attack);
|
||||
}else if(!targetHasFlag(BlockFlag.resupplyPoint)){
|
||||
retarget(() -> targetClosestAllyFlag(BlockFlag.resupplyPoint));
|
||||
}else{
|
||||
circle(20f);
|
||||
}
|
||||
}
|
||||
},
|
||||
attack = new UnitState(){
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(Units.invalidateTarget(target, team, x, y)){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(!inventory.hasAmmo()) {
|
||||
state.set(resupply);
|
||||
}else if (target == null){
|
||||
if(timer.get(timerTarget, 20)) {
|
||||
Unit closest = Units.getClosestEnemy(team, x, y,
|
||||
inventory.getAmmo().getRange(), other -> distanceTo(other) < 60f);
|
||||
if(closest != null){
|
||||
target = closest;
|
||||
}else {
|
||||
Tile target = Geometry.findClosest(x, y, world.indexer().getEnemy(team, BlockFlag.target));
|
||||
if (target != null) FlyingUnit.this.target = target.entity;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
attack(150f);
|
||||
|
||||
if (timer.get(timerReload, type.reload) && Mathf.angNear(angleTo(target), rotation, 13f)
|
||||
&& distanceTo(target) < inventory.getAmmo().getRange()) {
|
||||
AmmoType ammo = inventory.getAmmo();
|
||||
inventory.useAmmo();
|
||||
|
||||
shoot(ammo, Angles.moveToward(rotation, angleTo(target), maxAim), 4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new UnitState() {
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(health >= health){
|
||||
state.set(attack);
|
||||
}else if(!targetHasFlag(BlockFlag.repair)){
|
||||
retarget(() -> {
|
||||
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair));
|
||||
if (target != null) FlyingUnit.this.target = target.entity;
|
||||
});
|
||||
}else{
|
||||
circle(20f);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class FlyingUnitType extends UnitType {
|
||||
protected static Translator vec = new Translator();
|
||||
|
||||
protected float maxAim = 30f;
|
||||
|
||||
public FlyingUnitType(String name) {
|
||||
super(name);
|
||||
speed = 0.2f;
|
||||
maxVelocity = 2f;
|
||||
drag = 0.01f;
|
||||
isFlying = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(BaseUnit unit) {
|
||||
super.update(unit);
|
||||
|
||||
unit.rotation = unit.velocity.angle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(BaseUnit unit) {
|
||||
Draw.alpha(unit.hitTime / Unit.hitDuration);
|
||||
|
||||
Draw.rect(name, unit.x, unit.y, unit.rotation - 90);
|
||||
|
||||
Draw.alpha(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(BaseUnit unit) {
|
||||
if(unit.health <= health * retreatPercent &&
|
||||
Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair)) != null){
|
||||
unit.setState(retreat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UnitState getStartState(){
|
||||
return attack;
|
||||
}
|
||||
|
||||
protected void circle(BaseUnit unit, float circleLength){
|
||||
vec.set(unit.target.getX() - unit.x, unit.target.getY() - unit.y);
|
||||
|
||||
if(vec.len() < circleLength){
|
||||
vec.rotate((circleLength-vec.len())/circleLength * 180f);
|
||||
}
|
||||
|
||||
vec.setLength(speed * Timers.delta());
|
||||
|
||||
unit.velocity.add(vec);
|
||||
}
|
||||
|
||||
protected void attack(BaseUnit unit, float circleLength){
|
||||
vec.set(unit.target.getX() - unit.x, unit.target.getY() - unit.y);
|
||||
|
||||
float ang = unit.angleTo(unit.target);
|
||||
float diff = Angles.angleDist(ang, unit.rotation);
|
||||
|
||||
if(diff > 100f && vec.len() < circleLength){
|
||||
vec.setAngle(unit.velocity.angle());
|
||||
}else{
|
||||
vec.setAngle(Mathf.slerpDelta(unit.velocity.angle(), vec.angle(), 0.44f));
|
||||
}
|
||||
|
||||
vec.setLength(speed*Timers.delta());
|
||||
|
||||
unit.velocity.add(vec);
|
||||
}
|
||||
|
||||
public final UnitState
|
||||
|
||||
resupply = new UnitState(){
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
if(unit.inventory.totalAmmo() + 10 >= unit.inventory.ammoCapacity()){
|
||||
unit.state.set(unit, attack);
|
||||
}else if(!unit.targetHasFlag(BlockFlag.resupplyPoint)){
|
||||
unit.retarget(() -> targetClosestAllyFlag(unit, BlockFlag.resupplyPoint));
|
||||
}else{
|
||||
circle(unit, 20f);
|
||||
}
|
||||
}
|
||||
},
|
||||
attack = new UnitState(){
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
if(Units.invalidateTarget(unit.target, unit.team, unit.x, unit.y)){
|
||||
unit.target = null;
|
||||
}
|
||||
|
||||
if(!unit.inventory.hasAmmo()) {
|
||||
unit.state.set(unit, resupply);
|
||||
}else if (unit.target == null){
|
||||
if(unit.timer.get(timerTarget, 20)) {
|
||||
Unit closest = Units.getClosestEnemy(unit.team, unit.x, unit.y,
|
||||
unit.inventory.getAmmo().getRange(), other -> other.distanceTo(unit) < 60f);
|
||||
if(closest != null){
|
||||
unit.target = closest;
|
||||
}else {
|
||||
Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getEnemy(unit.team, BlockFlag.target));
|
||||
if (target != null) unit.target = target.entity;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
attack(unit, 150f);
|
||||
|
||||
if (unit.timer.get(timerReload, reload) && Mathf.angNear(unit.angleTo(unit.target), unit.rotation, 13f)
|
||||
&& unit.distanceTo(unit.target) < unit.inventory.getAmmo().getRange()) {
|
||||
AmmoType ammo = unit.inventory.getAmmo();
|
||||
unit.inventory.useAmmo();
|
||||
|
||||
shoot(unit, ammo, Angles.moveToward(unit.rotation, unit.angleTo(unit.target), maxAim), 4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new UnitState() {
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
if(unit.health >= health){
|
||||
unit.state.set(unit, attack);
|
||||
}else if(!unit.targetHasFlag(BlockFlag.repair)){
|
||||
if(unit.timer.get(timerTarget, 20)) {
|
||||
Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair));
|
||||
if (target != null) unit.target = target.entity;
|
||||
}
|
||||
}else{
|
||||
circle(unit, 20f);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@ -15,20 +17,16 @@ import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public abstract class GroundUnitType extends UnitType{
|
||||
public abstract class GroundUnitType extends BaseUnit {
|
||||
protected static Translator vec = new Translator();
|
||||
protected static float maxAim = 30f;
|
||||
|
||||
protected float maxAim = 30f;
|
||||
protected float walkTime;
|
||||
|
||||
public GroundUnitType(String name) {
|
||||
super(name);
|
||||
maxVelocity = 1.1f;
|
||||
speed = 0.1f;
|
||||
drag = 0.4f;
|
||||
range = 40f;
|
||||
public GroundUnitType(UnitType type, Team team) {
|
||||
super(type, team);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -37,158 +35,158 @@ public abstract class GroundUnitType extends UnitType{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(BaseUnit unit) {
|
||||
super.update(unit);
|
||||
public void update() {
|
||||
super.update();
|
||||
|
||||
if(!unit.velocity.isZero(0.0001f) && (unit.target == null
|
||||
|| (unit.inventory.hasAmmo() && unit.distanceTo(unit.target) > unit.inventory.getAmmo().getRange()))){
|
||||
unit.rotation = unit.velocity.angle();
|
||||
if(!velocity.isZero(0.0001f) && (target == null
|
||||
|| (inventory.hasAmmo() && distanceTo(target) > inventory.getAmmo().getRange()))){
|
||||
rotation = velocity.angle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(BaseUnit unit) {
|
||||
Draw.alpha(unit.hitTime / Unit.hitDuration);
|
||||
public void drawSmooth() {
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
|
||||
float walktime = unit.walkTime;
|
||||
float walktime = walkTime;
|
||||
|
||||
float ft = Mathf.sin(walktime, 6f, 2f);
|
||||
|
||||
Floor floor = unit.getFloorOn();
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
if(floor.liquid){
|
||||
Draw.tint(Hue.mix(Color.WHITE, floor.liquidColor, 0.5f));
|
||||
}
|
||||
|
||||
for (int i : Mathf.signs) {
|
||||
Draw.rect(name + "-leg",
|
||||
unit.x + Angles.trnsx(unit.baseRotation, ft * i),
|
||||
unit.y + Angles.trnsy(unit.baseRotation, ft * i),
|
||||
12f * i, 12f - Mathf.clamp(ft * i, 0, 2), unit.baseRotation - 90);
|
||||
Draw.rect(type.name + "-leg",
|
||||
x + Angles.trnsx(baseRotation, ft * i),
|
||||
y + Angles.trnsy(baseRotation, ft * i),
|
||||
12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90);
|
||||
}
|
||||
|
||||
if(floor.liquid) {
|
||||
Draw.tint(Color.WHITE, floor.liquidColor, unit.drownTime * 0.4f);
|
||||
Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f);
|
||||
}else {
|
||||
Draw.tint(Color.WHITE);
|
||||
}
|
||||
|
||||
Draw.rect(name + "-base", unit.x, unit.y, unit.baseRotation- 90);
|
||||
Draw.rect(type.name + "-base", x, y, baseRotation- 90);
|
||||
|
||||
Draw.rect(name, unit.x, unit.y, unit.rotation -90);
|
||||
Draw.rect(type.name, x, y, rotation -90);
|
||||
|
||||
Draw.alpha(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(BaseUnit unit) {
|
||||
if(unit.health <= health * retreatPercent){
|
||||
unit.setState(retreat);
|
||||
public void behavior() {
|
||||
if(health <= health * type.retreatPercent && !inventory.isInfiniteAmmo()){
|
||||
setState(retreat);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTargeting(BaseUnit unit) {
|
||||
super.updateTargeting(unit);
|
||||
public void updateTargeting() {
|
||||
super.updateTargeting();
|
||||
|
||||
if(Units.invalidateTarget(unit.target, unit)){
|
||||
unit.target = null;
|
||||
if(Units.invalidateTarget(target, this)){
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void moveToCore(BaseUnit unit){
|
||||
Tile tile = world.tileWorld(unit.x, unit.y);
|
||||
Tile targetTile = world.pathfinder().getTargetTile(unit.team, tile);
|
||||
protected void moveToCore(){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
Tile targetTile = world.pathfinder().getTargetTile(team, tile);
|
||||
|
||||
if(tile == targetTile) return;
|
||||
|
||||
vec.trns(unit.baseRotation, speed);
|
||||
vec.trns(baseRotation, type.speed);
|
||||
|
||||
unit.baseRotation = Mathf.slerpDelta(unit.baseRotation, unit.angleTo(targetTile), 0.05f);
|
||||
unit.walkTime += Timers.delta();
|
||||
unit.velocity.add(vec);
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, angleTo(targetTile), 0.05f);
|
||||
walkTime += Timers.delta();
|
||||
velocity.add(vec);
|
||||
}
|
||||
|
||||
protected void moveAwayFromCore(BaseUnit unit){
|
||||
Tile tile = world.tileWorld(unit.x, unit.y);
|
||||
Tile targetTile = world.pathfinder().getTargetTile(state.teams.enemiesOf(unit.team).first(), tile);
|
||||
protected void moveAwayFromCore(){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
Tile targetTile = world.pathfinder().getTargetTile(Vars.state.teams.enemiesOf(team).first(), tile);
|
||||
|
||||
if(tile == targetTile) return;
|
||||
|
||||
vec.trns(unit.baseRotation, speed);
|
||||
vec.trns(baseRotation, type.speed);
|
||||
|
||||
unit.baseRotation = Mathf.slerpDelta(unit.baseRotation, unit.angleTo(targetTile), 0.05f);
|
||||
unit.walkTime += Timers.delta();
|
||||
unit.velocity.add(vec);
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, angleTo(targetTile), 0.05f);
|
||||
walkTime += Timers.delta();
|
||||
velocity.add(vec);
|
||||
}
|
||||
|
||||
public final UnitState
|
||||
|
||||
resupply = new UnitState(){
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
Tile tile = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.resupplyPoint));
|
||||
public void update() {
|
||||
Tile tile = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.resupplyPoint));
|
||||
|
||||
if (tile != null && unit.distanceTo(tile) > 40) {
|
||||
moveAwayFromCore(unit);
|
||||
if (tile != null && distanceTo(tile) > 40) {
|
||||
moveAwayFromCore();
|
||||
}
|
||||
|
||||
//TODO move toward resupply point
|
||||
if(unit.inventory.totalAmmo() + 10 >= unit.inventory.ammoCapacity()){
|
||||
unit.state.set(unit, attack);
|
||||
if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
|
||||
state.set(attack);
|
||||
}
|
||||
}
|
||||
},
|
||||
attack = new UnitState(){
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
unit.retarget(() -> {
|
||||
Unit closest = Units.getClosestEnemy(unit.team, unit.x, unit.y, unit.inventory.getAmmo().getRange(), other -> true);
|
||||
public void update() {
|
||||
retarget(() -> {
|
||||
Unit closest = Units.getClosestEnemy(team, x, y, inventory.getAmmo().getRange(), other -> true);
|
||||
if(closest != null){
|
||||
unit.target = closest;
|
||||
target = closest;
|
||||
}else {
|
||||
Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getEnemy(unit.team, BlockFlag.target));
|
||||
if (target != null) unit.target = target.entity;
|
||||
Tile target = Geometry.findClosest(x, y, world.indexer().getEnemy(team, BlockFlag.target));
|
||||
if (target != null) GroundUnitType.this.target = target.entity;
|
||||
}
|
||||
});
|
||||
|
||||
if(!unit.inventory.hasAmmo()) {
|
||||
unit.state.set(unit, resupply);
|
||||
if(!inventory.hasAmmo()) {
|
||||
state.set(resupply);
|
||||
}else{
|
||||
if(unit.distanceTo(unit.target) > unit.inventory.getAmmo().getRange() * 0.7f){
|
||||
moveToCore(unit);
|
||||
if(distanceTo(target) > inventory.getAmmo().getRange() * 0.7f){
|
||||
moveToCore();
|
||||
}else{
|
||||
unit.rotate(unit.angleTo(unit.target));
|
||||
rotate(angleTo(target));
|
||||
}
|
||||
|
||||
if (unit.timer.get(timerReload, reload) && Mathf.angNear(unit.angleTo(unit.target), unit.rotation, 13f)
|
||||
&& unit.distanceTo(unit.target) < unit.inventory.getAmmo().getRange()) {
|
||||
AmmoType ammo = unit.inventory.getAmmo();
|
||||
unit.inventory.useAmmo();
|
||||
unit.rotate(unit.angleTo(unit.target));
|
||||
if (timer.get(timerReload, type.reload) && Mathf.angNear(angleTo(target), rotation, 13f)
|
||||
&& distanceTo(target) < inventory.getAmmo().getRange()) {
|
||||
AmmoType ammo = inventory.getAmmo();
|
||||
inventory.useAmmo();
|
||||
rotate(angleTo(target));
|
||||
|
||||
shoot(unit, ammo, Angles.moveToward(unit.rotation, unit.angleTo(unit.target), maxAim), 4f);
|
||||
shoot(ammo, Angles.moveToward(rotation, angleTo(target), maxAim), 4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new UnitState() {
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
if(unit.health >= health){
|
||||
unit.state.set(unit, attack);
|
||||
public void update() {
|
||||
if(health >= health){
|
||||
state.set(attack);
|
||||
}
|
||||
|
||||
moveAwayFromCore(unit);
|
||||
moveAwayFromCore();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -3,15 +3,15 @@ package io.anuke.mindustry.entities.units;
|
||||
public class StateMachine {
|
||||
private UnitState state;
|
||||
|
||||
public void update(BaseUnit unit){
|
||||
if(state != null) state.update(unit);
|
||||
public void update(){
|
||||
if(state != null) state.update();
|
||||
}
|
||||
|
||||
public void set(BaseUnit unit, UnitState next){
|
||||
public void set( UnitState next){
|
||||
if(next == state) return;
|
||||
if(state != null) state.exited(unit);
|
||||
if(state != null) state.exited();
|
||||
this.state = next;
|
||||
if(next != null) next.entered(unit);
|
||||
if(next != null) next.entered();
|
||||
}
|
||||
|
||||
public boolean is(UnitState state){
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
public interface UnitState {
|
||||
default void entered(BaseUnit unit){}
|
||||
default void exited(BaseUnit unit){}
|
||||
default void update(BaseUnit unit){}
|
||||
default void entered(){}
|
||||
default void exited(){}
|
||||
default void update(){}
|
||||
}
|
||||
|
@ -2,146 +2,55 @@ package io.anuke.mindustry.entities.units;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import io.anuke.mindustry.content.fx.ExplosionFx;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public abstract class UnitType {
|
||||
public class UnitType {
|
||||
private static byte lastid = 0;
|
||||
private static Array<UnitType> types = new Array<>();
|
||||
|
||||
private static int timerIndex = 0;
|
||||
|
||||
protected static final int timerTarget = timerIndex++;
|
||||
protected static final int timerBoost = timerIndex++;
|
||||
protected static final int timerReload = timerIndex++;
|
||||
protected final UnitCreator creator;
|
||||
|
||||
public final String name;
|
||||
public final byte id;
|
||||
|
||||
protected float health = 60;
|
||||
protected float hitsize = 5f;
|
||||
protected float hitsizeTile = 4f;
|
||||
protected float speed = 0.4f;
|
||||
protected float range = 160;
|
||||
protected float rotatespeed = 0.1f;
|
||||
protected float baseRotateSpeed = 0.1f;
|
||||
protected float mass = 1f;
|
||||
protected boolean isFlying;
|
||||
protected float drag = 0.1f;
|
||||
protected float maxVelocity = 5f;
|
||||
protected float reload = 40f;
|
||||
protected float retreatPercent = 0.2f;
|
||||
protected float armor = 0f;
|
||||
protected ObjectMap<Item, AmmoType> ammo = new ObjectMap<>();
|
||||
public float health = 60;
|
||||
public float hitsize = 5f;
|
||||
public float hitsizeTile = 4f;
|
||||
public float speed = 0.4f;
|
||||
public float range = 160;
|
||||
public float rotatespeed = 0.1f;
|
||||
public float baseRotateSpeed = 0.1f;
|
||||
public float mass = 1f;
|
||||
public boolean isFlying;
|
||||
public float drag = 0.1f;
|
||||
public float maxVelocity = 5f;
|
||||
public float reload = 40f;
|
||||
public float retreatPercent = 0.2f;
|
||||
public float armor = 0f;
|
||||
public ObjectMap<Item, AmmoType> ammo = new ObjectMap<>();
|
||||
|
||||
public UnitType(String name){
|
||||
public UnitType(String name, UnitCreator creator){
|
||||
this.id = lastid++;
|
||||
this.name = name;
|
||||
this.creator = creator;
|
||||
|
||||
types.add(this);
|
||||
}
|
||||
|
||||
public BaseUnit create(Team team){
|
||||
return creator.create(team);
|
||||
}
|
||||
|
||||
protected void setAmmo(AmmoType... types){
|
||||
for(AmmoType type : types){
|
||||
ammo.put(type.item, type);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void draw(BaseUnit unit);
|
||||
|
||||
public void drawUnder(BaseUnit unit){}
|
||||
|
||||
public void drawOver(BaseUnit unit){}
|
||||
|
||||
public UnitState getStartState(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isFlying(){
|
||||
return isFlying;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit){
|
||||
if(unit.hitTime > 0){
|
||||
unit.hitTime -= Timers.delta();
|
||||
}
|
||||
|
||||
if(unit.hitTime < 0) unit.hitTime = 0;
|
||||
|
||||
if(Net.client()){
|
||||
unit.interpolate();
|
||||
return;
|
||||
}
|
||||
|
||||
updateTargeting(unit);
|
||||
|
||||
unit.state.update(unit);
|
||||
unit.updateVelocityStatus(drag, maxVelocity);
|
||||
|
||||
if(unit.target != null) behavior(unit);
|
||||
|
||||
unit.x = Mathf.clamp(unit.x, 0, world.width() * tilesize);
|
||||
unit.y = Mathf.clamp(unit.y, 0, world.height() * tilesize);
|
||||
}
|
||||
|
||||
/**Only runs when the unit has a target.*/
|
||||
public abstract void behavior(BaseUnit unit);
|
||||
|
||||
public void updateTargeting(BaseUnit unit){
|
||||
if(unit.target == null || (unit.target instanceof Unit && (unit.target.isDead() || ((Unit)unit.target).team == unit.team))
|
||||
|| (unit.target instanceof TileEntity && ((TileEntity) unit.target).tile.entity == null)){
|
||||
unit.target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void shoot(BaseUnit unit, AmmoType type, float rotation, float translation){
|
||||
Bullet.create(type.bullet, unit,
|
||||
unit.x + Angles.trnsx(rotation, translation),
|
||||
unit.y + Angles.trnsy(rotation, translation), rotation);
|
||||
Effects.effect(type.shootEffect, unit.x + Angles.trnsx(rotation, translation),
|
||||
unit.y + Angles.trnsy(rotation, translation), rotation, unit);
|
||||
Effects.effect(type.smokeEffect, unit.x + Angles.trnsx(rotation, translation),
|
||||
unit.y + Angles.trnsy(rotation, translation), rotation, unit);
|
||||
}
|
||||
|
||||
public void targetClosestAllyFlag(BaseUnit unit, BlockFlag flag){
|
||||
Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, flag));
|
||||
if (target != null) unit.target = target.entity;
|
||||
}
|
||||
|
||||
public void onDeath(BaseUnit unit){
|
||||
//TODO other things, such as enemies?
|
||||
Effects.effect(ExplosionFx.explosion, unit);
|
||||
Effects.shake(2f, 2f, unit);
|
||||
|
||||
if(Net.server()){
|
||||
NetEvents.handleUnitDeath(unit);
|
||||
}
|
||||
|
||||
unit.remove();
|
||||
}
|
||||
|
||||
public void onRemoteDeath(BaseUnit unit){
|
||||
onDeath(unit);
|
||||
}
|
||||
|
||||
public void removed(BaseUnit unit){
|
||||
//TODO
|
||||
public interface UnitCreator{
|
||||
BaseUnit create(Team team);
|
||||
}
|
||||
|
||||
public static UnitType getByID(byte id){
|
||||
|
@ -1,13 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
import io.anuke.mindustry.content.AmmoTypes;
|
||||
import io.anuke.mindustry.entities.units.GroundUnitType;
|
||||
|
||||
public class Brute extends GroundUnitType {
|
||||
|
||||
public Brute(String name) {
|
||||
super(name);
|
||||
setAmmo(AmmoTypes.bulletIron);
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
import io.anuke.mindustry.content.AmmoTypes;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnitType;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class Cruiser extends FlyingUnitType {
|
||||
|
||||
|
||||
public Cruiser(){
|
||||
super("vtol");
|
||||
setAmmo(AmmoTypes.bulletIron);
|
||||
speed = 0.2f;
|
||||
maxVelocity = 1.4f;
|
||||
health = 300f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(BaseUnit unit) {
|
||||
float rotation = unit.rotation - 90;
|
||||
float scl = 0.6f + Mathf.absin(Timers.time(), 1f, 0.3f);
|
||||
float dy = -6f*scl;
|
||||
|
||||
Draw.color(Palette.lighterOrange, Palette.lightFlame, Mathf.absin(Timers.time(), 3f, 0.7f));
|
||||
|
||||
Draw.rect("vtol-flame",
|
||||
unit.x + Angles.trnsx(rotation, 0, dy),
|
||||
unit.y + Angles.trnsy(rotation, 0, dy), Mathf.atan2(0, dy) + rotation);
|
||||
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(BaseUnit unit) {
|
||||
Draw.alpha(unit.hitTime / Unit.hitDuration);
|
||||
|
||||
Draw.rect(name, unit.x, unit.y, unit.rotation - 90);
|
||||
|
||||
Draw.alpha(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(BaseUnit unit) {
|
||||
super.update(unit);
|
||||
|
||||
unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.06f);
|
||||
unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.06f);
|
||||
|
||||
if(unit.velocity.len() <= 0.2f){
|
||||
unit.rotation += Mathf.sin(Timers.time() + unit.id * 99, 10f, 8f);
|
||||
}
|
||||
|
||||
if(unit.timer.get(timerBoost, 2)){
|
||||
// unit.effectAt(UnitFx.vtolHover, unit.rotation + 180f, 4f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitState getStartState(){
|
||||
return resupply;
|
||||
}
|
||||
}
|
@ -1,58 +1,117 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import io.anuke.mindustry.entities.BlockBuilder;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnitType;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnit;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.entities.units.UnitType;
|
||||
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.types.BuildBlock;
|
||||
import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity;
|
||||
import io.anuke.ucore.core.Events;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Shapes;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.unitGroups;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Drone extends FlyingUnitType {
|
||||
protected float healSpeed = 0.1f;
|
||||
protected float discoverRange = 120f;
|
||||
public class Drone extends FlyingUnit implements BlockBuilder{
|
||||
protected static float healSpeed = 0.1f;
|
||||
protected static float discoverRange = 120f;
|
||||
protected static boolean initialized;
|
||||
|
||||
public Drone() {
|
||||
super("drone");
|
||||
speed = 0.2f;
|
||||
maxVelocity = 0.8f;
|
||||
range = 50f;
|
||||
protected Tile mineTile;
|
||||
protected Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
|
||||
private static void initEvents(){
|
||||
Events.on(BlockBuildEvent.class, (team, tile) -> {
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
|
||||
if(!(tile.entity instanceof BuildEntity)) return;
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
for(BaseUnit unit : group.all()){
|
||||
if(unit instanceof Drone){
|
||||
((Drone) unit).notifyPlaced(entity);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Drone(UnitType type, Team team) {
|
||||
super(type, team);
|
||||
|
||||
if(!initialized){
|
||||
initEvents();
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyPlaced(BuildEntity entity){
|
||||
float timeToBuild = entity.recipe.cost;
|
||||
float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0);
|
||||
|
||||
if(dist / type.maxVelocity < timeToBuild * 0.9f){
|
||||
target = entity;
|
||||
setState(build);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(BaseUnit unit) {
|
||||
float rot = unit.rotation;
|
||||
super.update(unit);
|
||||
unit.rotation = rot;
|
||||
public Queue<BuildRequest> getPlaceQueue() {
|
||||
return placeQueue;
|
||||
}
|
||||
|
||||
if(unit.target != null && unit.state.is(repair)){
|
||||
unit.rotation = Mathf.slerpDelta(rot, unit.angleTo(unit.target), 0.3f);
|
||||
@Override
|
||||
public Tile getMineTile() {
|
||||
return mineTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMineTile(Tile tile) {
|
||||
this.mineTile = tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
float rot = rotation;
|
||||
super.update();
|
||||
rotation = rot;
|
||||
|
||||
if(target != null && state.is(repair)){
|
||||
rotation = Mathf.slerpDelta(rot, angleTo(target), 0.3f);
|
||||
}else{
|
||||
unit.rotation = Mathf.slerpDelta(rot, unit.velocity.angle(), 0.3f);
|
||||
rotation = Mathf.slerpDelta(rot, velocity.angle(), 0.3f);
|
||||
}
|
||||
|
||||
unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.07f);
|
||||
unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.07f);
|
||||
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
|
||||
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
|
||||
|
||||
if(unit.velocity.len() <= 0.2f && !(unit.state.is(repair) && unit.target != null)){
|
||||
unit.rotation += Mathf.sin(Timers.time() + unit.id * 99, 10f, 5f);
|
||||
if(velocity.len() <= 0.2f && !(state.is(repair) && target != null)){
|
||||
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 5f);
|
||||
}
|
||||
|
||||
updateBuilding(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(BaseUnit unit) {
|
||||
if(unit.health <= health * retreatPercent &&
|
||||
Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair)) != null){
|
||||
unit.setState(retreat);
|
||||
public void behavior() {
|
||||
if(health <= health * type.retreatPercent &&
|
||||
Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){
|
||||
setState(retreat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,60 +121,86 @@ public class Drone extends FlyingUnitType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(BaseUnit unit) {
|
||||
if(unit.target instanceof TileEntity && unit.state.is(repair)){
|
||||
public void drawOver() {
|
||||
trail.draw(Palette.lighterOrange, Palette.lightishOrange, 3f);
|
||||
|
||||
if(target instanceof TileEntity && state.is(repair)){
|
||||
float len = 5f;
|
||||
Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f));
|
||||
Shapes.laser("beam", "beam-end",
|
||||
unit.x + Angles.trnsx(unit.rotation, len),
|
||||
unit.y + Angles.trnsy(unit.rotation, len),
|
||||
unit.target.getX(), unit.target.getY());
|
||||
x + Angles.trnsx(rotation, len),
|
||||
y + Angles.trnsy(rotation, len),
|
||||
target.getX(), target.getY());
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
drawBuilding(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize() {
|
||||
return isBuilding() ? placeDistance*2f : 30f;
|
||||
}
|
||||
|
||||
public final UnitState
|
||||
|
||||
build = new UnitState(){
|
||||
|
||||
public void update() {
|
||||
BuildEntity entity = (BuildEntity)target;
|
||||
|
||||
if(entity.progress() < 1f && entity.tile.block() instanceof BuildBlock){ //building is valid
|
||||
if(!isBuilding() && distanceTo(target) < placeDistance * 0.9f){ //within distance, begin placing
|
||||
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.recipe));
|
||||
}
|
||||
|
||||
circle(placeDistance * 0.7f);
|
||||
}else{ //building isn't valid
|
||||
setState(repair);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
repair = new UnitState(){
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
if(unit.target != null && (((TileEntity)unit.target).health >= ((TileEntity)unit.target).tile.block().health
|
||||
|| unit.target.distanceTo(unit) > discoverRange)){
|
||||
unit.target = null;
|
||||
public void update() {
|
||||
if(target != null && (((TileEntity)target).health >= ((TileEntity)target).tile.block().health
|
||||
|| target.distanceTo(Drone.this) > discoverRange)){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if (unit.target == null) {
|
||||
if (unit.timer.get(timerTarget, 20)) {
|
||||
unit.target = Units.findAllyTile(unit.team, unit.x, unit.y, discoverRange,
|
||||
tile -> tile.entity != null && tile.entity.health + 0.0001f < tile.block().health);
|
||||
}
|
||||
}else if(unit.target.distanceTo(unit) > range){
|
||||
circle(unit, range);
|
||||
if (target == null) {
|
||||
retarget(() -> {
|
||||
target = Units.findAllyTile(team, x, y, discoverRange,
|
||||
tile -> tile.entity != null && tile.entity.health + 0.0001f < tile.block().health);
|
||||
});
|
||||
}else if(target.distanceTo(Drone.this) > type.range){
|
||||
circle(type.range);
|
||||
}else{
|
||||
TileEntity entity = (TileEntity) unit.target;
|
||||
TileEntity entity = (TileEntity) target;
|
||||
entity.health += healSpeed * Timers.delta();
|
||||
entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health);
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new UnitState() {
|
||||
public void entered(BaseUnit unit) {
|
||||
unit.target = null;
|
||||
public void entered() {
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(BaseUnit unit) {
|
||||
if(unit.health >= health){
|
||||
unit.state.set(unit, attack);
|
||||
}else if(!unit.targetHasFlag(BlockFlag.repair)){
|
||||
if(unit.timer.get(timerTarget, 20)) {
|
||||
Tile target = Geometry.findClosest(unit.x, unit.y, world.indexer().getAllied(unit.team, BlockFlag.repair));
|
||||
if (target != null) unit.target = target.entity;
|
||||
public void update() {
|
||||
if(health >= health){
|
||||
state.set(attack);
|
||||
}else if(!targetHasFlag(BlockFlag.repair)){
|
||||
if(timer.get(timerTarget, 20)) {
|
||||
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair));
|
||||
if (target != null) Drone.this.target = target.entity;
|
||||
}
|
||||
}else{
|
||||
circle(unit, 40f);
|
||||
circle(40f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
public class Eradicator {
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
import io.anuke.mindustry.entities.units.FlyingUnitType;
|
||||
|
||||
public class Reaper extends FlyingUnitType {
|
||||
|
||||
public Reaper(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
import io.anuke.mindustry.content.AmmoTypes;
|
||||
import io.anuke.mindustry.entities.units.GroundUnitType;
|
||||
import io.anuke.mindustry.entities.units.UnitType;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
|
||||
public class Scout extends GroundUnitType {
|
||||
|
||||
public Scout(){
|
||||
super("scout");
|
||||
setAmmo(AmmoTypes.bulletIron);
|
||||
public Scout(UnitType type, Team team) {
|
||||
super(type, team);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
public class Sheller {
|
||||
}
|
@ -1,67 +1,62 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
|
||||
import io.anuke.mindustry.content.AmmoTypes;
|
||||
import io.anuke.mindustry.content.fx.UnitFx;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnitType;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnit;
|
||||
import io.anuke.mindustry.entities.units.UnitType;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class Vtol extends FlyingUnitType {
|
||||
public class Vtol extends FlyingUnit {
|
||||
|
||||
public Vtol(){
|
||||
super("vtol");
|
||||
setAmmo(AmmoTypes.bulletIron);
|
||||
speed = 0.3f;
|
||||
maxVelocity = 2f;
|
||||
reload = 7;
|
||||
public Vtol(UnitType type, Team team) {
|
||||
super(type, team);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(BaseUnit unit) {
|
||||
float rotation = unit.rotation - 90;
|
||||
public void drawUnder() {
|
||||
float rotation = this.rotation - 90;
|
||||
float scl = 0.6f + Mathf.absin(Timers.time(), 1f, 0.3f);
|
||||
float dy = -6f*scl;
|
||||
|
||||
Draw.color(Palette.lighterOrange, Palette.lightFlame, Mathf.absin(Timers.time(), 3f, 0.7f));
|
||||
|
||||
Draw.rect("vtol-flame",
|
||||
unit.x + Angles.trnsx(rotation, 0, dy),
|
||||
unit.y + Angles.trnsy(rotation, 0, dy), Mathf.atan2(0, dy) + rotation);
|
||||
x + Angles.trnsx(rotation, 0, dy),
|
||||
y + Angles.trnsy(rotation, 0, dy), Mathf.atan2(0, dy) + rotation);
|
||||
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(BaseUnit unit) {
|
||||
Draw.alpha(unit.hitTime / Unit.hitDuration);
|
||||
public void drawSmooth() {
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
|
||||
Draw.rect(name, unit.x, unit.y, unit.rotation - 90);
|
||||
Draw.rect(type.name, x, y, rotation - 90);
|
||||
for(int i : Mathf.signs){
|
||||
Draw.rect(name + "-booster-1", unit.x, unit.y, 12*i, 12, unit.rotation - 90);
|
||||
Draw.rect(name + "-booster-2", unit.x, unit.y, 12*i, 12, unit.rotation - 90);
|
||||
Draw.rect(type.name + "-booster-1", x, y, 12*i, 12, rotation - 90);
|
||||
Draw.rect(type.name + "-booster-2", x, y, 12*i, 12, rotation - 90);
|
||||
}
|
||||
|
||||
Draw.alpha(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(BaseUnit unit) {
|
||||
super.update(unit);
|
||||
public void update() {
|
||||
super.update();
|
||||
|
||||
unit.x += Mathf.sin(Timers.time() + unit.id * 999, 25f, 0.07f);
|
||||
unit.y += Mathf.cos(Timers.time() + unit.id * 999, 25f, 0.07f);
|
||||
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
|
||||
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
|
||||
|
||||
if(unit.velocity.len() <= 0.2f){
|
||||
unit.rotation += Mathf.sin(Timers.time() + unit.id * 99, 10f, 8f);
|
||||
if(velocity.len() <= 0.2f){
|
||||
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 8f);
|
||||
}
|
||||
|
||||
if(unit.timer.get(timerBoost, 2)){
|
||||
unit.effectAt(UnitFx.vtolHover, unit.rotation + 180f, 4f, 0);
|
||||
if(timer.get(timerBoost, 2)){
|
||||
effectAt(UnitFx.vtolHover, rotation + 180f, 4f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,5 +50,9 @@ public class EventType {
|
||||
public interface UnlockEvent extends Event{
|
||||
void handle(Content content);
|
||||
}
|
||||
|
||||
public interface BlockBuildEvent extends Event{
|
||||
void handle(Team team, Tile tile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ public class OverlayRenderer {
|
||||
}
|
||||
|
||||
drawEncloser(x, y - 8f, 2f);
|
||||
drawBar(Color.SCARLET, x, y - 8f, unit.health / unit.maxhealth);
|
||||
drawBar(Color.SCARLET, x, y - 8f, unit.healthfrac());
|
||||
drawBar(Color.valueOf("32cf6d"), x, y - 9f, unit.inventory.totalAmmo() / (float) unit.inventory.ammoCapacity());
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ public class Item implements Comparable<Item>, Content{
|
||||
public Color flameColor = Palette.darkFlame.cpy();
|
||||
/**base material cost of this item, used for calculating place times
|
||||
* 1 cost = 1 tick added to build time*/
|
||||
public float cost = 1f;
|
||||
public float cost = 3f;
|
||||
|
||||
public Item(String name, Color color) {
|
||||
this.id = items.size;
|
||||
|
@ -4,10 +4,9 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import io.anuke.mindustry.content.UnitTypes;
|
||||
import io.anuke.mindustry.content.bullets.TurretBullets;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
@ -70,9 +69,9 @@ public class DebugFragment implements Fragment {
|
||||
row();
|
||||
new button("death", () -> player.damage(99999, false));
|
||||
row();
|
||||
new button("spawnf", () -> new BaseUnit(UnitTypes.drone, player.team).set(player.x, player.y).add());
|
||||
new button("spawnf", () -> UnitTypes.drone.create(player.team).set(player.x, player.y).add());
|
||||
row();
|
||||
new button("spawng", () -> new BaseUnit(UnitTypes.scout, player.team).set(player.x, player.y).add());
|
||||
new button("spawng", () -> UnitTypes.scout.create(player.team).set(player.x, player.y).add());
|
||||
row();
|
||||
}}.end();
|
||||
|
||||
|
@ -47,6 +47,7 @@ public class NuclearReactor extends LiquidBurnerGenerator {
|
||||
itemCapacity = 30;
|
||||
liquidCapacity = 50;
|
||||
powerCapacity = 80f;
|
||||
hasItems = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,7 +75,7 @@ public class RepairPoint extends Block{
|
||||
RepairPointEntity entity = tile.entity();
|
||||
|
||||
if(entity.target != null && (entity.target.isDead() || entity.target.distanceTo(tile) > repairRadius ||
|
||||
entity.target.health >= entity.target.maxhealth)){
|
||||
entity.target.health >= entity.target.getMaxHealth())){
|
||||
entity.target = null;
|
||||
}else if(entity.target != null){
|
||||
entity.target.health += repairSpeed * Timers.delta() * entity.strength;
|
||||
@ -95,7 +95,7 @@ public class RepairPoint extends Block{
|
||||
if(entity.timer.get(timerTarget, 20)) {
|
||||
rect.setSize(repairRadius * 2).setCenter(tile.drawx(), tile.drawy());
|
||||
entity.target = Units.getClosest(tile.getTeam(), tile.drawx(), tile.drawy(), repairRadius,
|
||||
unit -> unit.health < unit.maxhealth);
|
||||
unit -> unit.health < unit.getMaxHealth());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class UnitFactory extends Block {
|
||||
@Override
|
||||
public boolean isSolidFor(Tile tile) {
|
||||
UnitFactoryEntity entity = tile.entity();
|
||||
return type.isFlying() || !entity.open;
|
||||
return type.isFlying || !entity.open;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -114,7 +114,7 @@ public class UnitFactory extends Block {
|
||||
if(entity.openCountdown > Timers.delta()){
|
||||
entity.openCountdown -= Timers.delta();
|
||||
}else{
|
||||
if(type.isFlying() || !anyEntities(tile)) {
|
||||
if(type.isFlying || !anyEntities(tile)) {
|
||||
entity.open = false;
|
||||
entity.openCountdown = -1;
|
||||
}else{
|
||||
@ -141,7 +141,7 @@ public class UnitFactory extends Block {
|
||||
Effects.shake(2f, 3f, entity);
|
||||
Effects.effect(BlockFx.producesmoke, tile.drawx(), tile.drawy());
|
||||
|
||||
BaseUnit unit = new BaseUnit(type, tile.getTeam());
|
||||
BaseUnit unit = type.create(tile.getTeam());
|
||||
unit.set(tile.drawx(), tile.drawy()).add();
|
||||
unit.velocity.y = launchVelocity;
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user