Changed too many things to fit in commit log

This commit is contained in:
Anuken
2018-06-04 12:47:08 -04:00
parent 3202d62a92
commit 01f4a9b23b
73 changed files with 683 additions and 1962 deletions
@@ -10,24 +10,26 @@ import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.Weapons;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.entities.effect.DamageArea;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Trail;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.mindustry.world.blocks.types.storage.CoreBlock.CoreEntity;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.*;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -36,7 +38,7 @@ import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.*;
public class Player extends Unit implements BlockBuilder {
public class Player extends Unit implements BuilderTrait {
private static final float walkSpeed = 1.1f;
private static final float flySpeed = 0.4f;
private static final float flyMaxSpeed = 3f;
@@ -45,6 +47,8 @@ public class Player extends Unit implements BlockBuilder {
//region instance variables, constructor
public float baseRotation;
public String name = "name";
public String uuid;
public boolean isAdmin;
@@ -58,7 +62,7 @@ public class Player extends Unit implements BlockBuilder {
public int playerIndex = 0;
public boolean isLocal = false;
public Timer timer = new Timer(4);
public Targetable target;
public TargetTrait target;
private boolean respawning;
private float walktime;
@@ -84,7 +88,7 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public float getMaxHealth() {
public float maxHealth() {
return 200;
}
@@ -113,12 +117,6 @@ public class Player extends Unit implements BlockBuilder {
inventory.addAmmo(weapon.getAmmoType(item));
}
@Override
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
Weapon weapon = Upgrade.getByID(Bits.getLeftByte(data));
weapon.shoot(this, x, y, rotation, Bits.getRightByte(data) == 1);
}
@Override
public float getMass(){
return mech.mass;
@@ -147,7 +145,7 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public boolean collides(SolidEntity other){
public boolean collides(SolidTrait other){
return !isDead() && super.collides(other) && !mech.flying;
}
@@ -156,9 +154,6 @@ public class Player extends Unit implements BlockBuilder {
dead = true;
respawning = false;
placeQueue.clear();
if(Net.active()){
NetEvents.handleUnitDeath(this);
}
float explosiveness = 2f + (inventory.hasItem() ? inventory.getItem().item.explosiveness * inventory.getItem().amount : 0f);
float flammability = (inventory.hasItem() ? inventory.getItem().item.flammability * inventory.getItem().amount : 0f);
@@ -168,35 +163,35 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public void onRemoteDeath() {
dead = true;
respawning = false;
Effects.effect(ExplosionFx.explosion, this);
Effects.shake(4f, 5f, this);
Effects.sound("die", this);
}
@Override
public Player set(float x, float y){
public void set(float x, float y){
this.x = x;
this.y = y;
if(isFlying() && isLocal){
Core.camera.position.set(x, y, 0f);
}
return this;
}
@Override
public Player add(){
return add(playerGroup);
public EntityGroup targetGroup() {
return playerGroup;
}
public void toggleTeam(){
team = (team == Team.blue ? Team.red : Team.blue);
}
//endregion
//region draw methods
@Override
public void drawSmooth(){
public float drawSize() {
return 40;
}
@Override
public void draw(){
if((debug && (!showPlayer || !showUI)) || dead) return;
boolean snap = snapCamera && isLocal;
@@ -287,15 +282,15 @@ public class Player extends Unit implements BlockBuilder {
Draw.tscl(0.25f/2);
layout.setText(Core.font, name);
Draw.color(0f, 0f, 0f, 0.3f);
Draw.rect("blank", getDrawPosition().x, getDrawPosition().y + 8 - layout.height/2, layout.width + 2, layout.height + 2);
Draw.rect("blank", x, y + 8 - layout.height/2, layout.width + 2, layout.height + 2);
Draw.color();
Draw.tcolor(color);
Draw.text(name, getDrawPosition().x, getDrawPosition().y + 8);
Draw.text(name, x, y + 8);
if(isAdmin){
Draw.color(color);
float s = 3f;
Draw.rect("icon-admin-small", getDrawPosition().x + layout.width/2f + 2 + 1, getDrawPosition().y + 7f, s, s);
Draw.rect("icon-admin-small", x + layout.width/2f + 2 + 1, y + 7f, s, s);
}
Draw.reset();
@@ -574,56 +569,13 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public void writeSpawn(ByteBuffer buffer) {
IOUtils.writeString(buffer, name);
buffer.put(weapon.id);
buffer.put(mech.id);
buffer.put(isAdmin ? 1 : (byte)0);
buffer.putInt(Color.rgba8888(color));
buffer.putFloat(x);
buffer.putFloat(y);
buffer.put((byte)team.ordinal());
public void write(ByteBuffer buffer) {
//todo
}
@Override
public void readSpawn(ByteBuffer buffer) {
name = IOUtils.readString(buffer);
weapon = Upgrade.getByID(buffer.get());
mech = Upgrade.getByID(buffer.get());
isAdmin = buffer.get() == 1;
color.set(buffer.getInt());
x = buffer.getFloat();
y = buffer.getFloat();
team = Team.values()[buffer.get()];
setNet(x, y);
}
@Override
public void write(ByteBuffer data) {
if(Net.client() || isLocal) {
data.putFloat(x);
data.putFloat(y);
}else{
data.putFloat(interpolator.target.x);
data.putFloat(interpolator.target.y);
}
data.putFloat(rotation);
data.putFloat(baseRotation);
data.putShort((short)health);
}
@Override
public void read(ByteBuffer data, long time) {
float x = data.getFloat();
float y = data.getFloat();
float rot = data.getFloat();
float baseRot = data.getFloat();
short health = data.getShort();
byte dashing = data.get();
this.health = health;
interpolator.read(this.x, this.y, x, y, rot, baseRot, time);
public void read(ByteBuffer buffer, long time) {
//todo
}
//endregion
@@ -1,6 +1,7 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.ucore.util.Mathf;
/**Class for predicting shoot angles based on velocities of targets.*/
@@ -43,6 +44,11 @@ public class Predict {
return sol;
}
/**See {@link #intercept(float, float, float, float, float, float, float)}.*/
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v) {
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getVelocity().x - src.getVelocity().x, dst.getVelocity().x - src.getVelocity().y, v);
}
private static Vector2 quad(float a, float b, float c) {
Vector2 sol = null;
if (Math.abs(a) < 1e-6) {
@@ -1,137 +0,0 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.DestructibleEntity;
import io.anuke.ucore.util.Mathf;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.threads;
/**Base class for any entity that needs to be synced across clients.*/
public abstract class SyncEntity extends DestructibleEntity{
/**Interpolator, used for smoothing position.*/
protected Interpolator interpolator = new Interpolator();
/**smoothed position and rotation*/
private Vector3 spos = new Vector3();
/**rotation of the top, usually used as the 'shoot' direction.*/
public float rotation = 90;
/**rotation of the base, usually leg rotation for mechs.*/
public float baseRotation = 90;
/**Called when a death event is recieved remotely.*/
public abstract void onRemoteDeath();
/**Called when a shoot event is recieved remotely.*/
public abstract void onRemoteShoot(BulletType type, float x, float y, float rotation, short data);
//Read and write spawn data, which is sent when the entity is requested
public abstract void writeSpawn(ByteBuffer data);
public abstract void readSpawn(ByteBuffer data);
//Read and write sync data, usually position
public abstract void write(ByteBuffer data);
public abstract void read(ByteBuffer data, long time);
/**Interpolate everything needed. Should be called in update() for non-local entities.*/
public void interpolate(){
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.rotation;
baseRotation = interpolator.baseRotation;
}
/**Same as draw, but for interpolated drawing at low tick speeds.*/
public abstract void drawSmooth();
/**Do not override, use drawSmooth instead.*/
@Override
public final void draw(){
final float x = this.x, y = this.y, rotation = this.rotation;
//interpolates data at low tick speeds.
if(isSmoothing()){
if(Vector2.dst(spos.x, spos.y, x, y) > 128){
spos.set(x, y, rotation);
}
this.x = spos.x = Mathf.lerpDelta(spos.x, x, 0.2f);
this.y = spos.y = Mathf.lerpDelta(spos.y, y, 0.2f);
this.rotation = spos.z = Mathf.slerpDelta(spos.z, rotation, 0.3f);
}
drawSmooth();
this.x = x;
this.y = y;
this.rotation = rotation;
}
/**Returns smoothed position. x = x, y = y, z = rotation.*/
public Vector3 getDrawPosition(){
return isSmoothing() ? spos : spos.set(x, y, rotation);
}
/**Set position and interpolator position.*/
public <T extends SyncEntity> T setNet(float x, float y){
set(x, y);
interpolator.target.set(x, y);
interpolator.last.set(x, y);
interpolator.spacing = 1f;
interpolator.time = 0f;
return (T)this;
}
public static boolean isSmoothing(){
return threads.isEnabled() && threads.getFPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
}
public static class Interpolator {
//used for movement
public Vector2 target = new Vector2();
public Vector2 last = new Vector2();
public float targetrot, targetBaseRot;
public float spacing = 1f;
public float time;
//current state
public Vector2 pos = new Vector2();
public float rotation, baseRotation;
public void read(float cx, float cy, float x, float y, float rotation, float baseRotation, long sent){
targetrot = rotation;
targetBaseRot = baseRotation;
time = 0f;
last.set(cx, cy);
target.set(x, y);
spacing = Math.min(Math.max(((TimeUtils.timeSinceMillis(sent) / 1000f) * 60f), 4f), 10);
}
public void update(){
time += 1f / spacing * Math.min(Timers.delta(), 1f);
time = Mathf.clamp(time, 0, 2f);
Mathf.lerp2(pos.set(last), target, time);
rotation = Mathf.slerpDelta(rotation, targetrot, 0.6f);
baseRotation = Mathf.slerpDelta(baseRotation, targetBaseRot, 0.6f);
if(target.dst(pos) > 128){
pos.set(target);
last.set(target);
time = 0f;
}
}
}
}
@@ -3,9 +3,8 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Wall;
@@ -14,7 +13,8 @@ import io.anuke.mindustry.world.blocks.types.modules.LiquidModule;
import io.anuke.mindustry.world.blocks.types.modules.PowerModule;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
@@ -25,7 +25,7 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.tileGroup;
import static io.anuke.mindustry.Vars.world;
public class TileEntity extends Entity implements Targetable{
public class TileEntity extends BaseEntity implements TargetTrait {
public static final float timeToSleep = 60f*4; //4 seconds to fall asleep
public static int sleepingEntities = 0;
@@ -79,7 +79,7 @@ public class TileEntity extends Entity implements Targetable{
public void wakeUp(){
sleepTime = 0f;
if(sleeping){
add(tileGroup);
add();
sleeping = false;
sleepingEntities --;
}
@@ -91,31 +91,21 @@ public class TileEntity extends Entity implements Targetable{
public void write(DataOutputStream stream) throws IOException{}
public void read(DataInputStream stream) throws IOException{}
public void onDeath(){
onDeath(false);
}
if(!dead) {
dead = true;
Block block = tile.block();
public void onDeath(boolean force){
if(Net.server()){
NetEvents.handleBlockDestroyed(this);
block.onDestroyed(tile);
world.removeBlock(tile);
block.afterDestroyed(tile, this);
remove();
}
if(!Net.active() || Net.server() || force){
if(!dead) {
dead = true;
Block block = tile.block();
block.onDestroyed(tile);
world.removeBlock(tile);
block.afterDestroyed(tile, this);
remove();
}
}
}
public boolean collide(io.anuke.mindustry.entities.bullet.Bullet other){
public boolean collide(Bullet other){
return true;
}
@@ -129,10 +119,6 @@ public class TileEntity extends Entity implements Targetable{
float amount = tile.block().handleDamage(tile, damage);
health -= amount;
if(health <= 0) onDeath();
if(Net.server()){
NetEvents.handleBlockDamaged(this);
}
}
@Override
@@ -162,9 +148,9 @@ public class TileEntity extends Entity implements Targetable{
tile.block().update(tile);
}
}
@Override
public TileEntity add(){
return add(tileGroup);
public EntityGroup targetGroup() {
return tileGroup;
}
}
+46 -17
View File
@@ -3,14 +3,21 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.traits.TeamTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.TeamInfo.TeamData;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.entities.impl.DestructibleEntity;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@@ -21,17 +28,39 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.world;
public abstract class Unit extends SyncEntity implements SerializableEntity, Targetable {
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait {
/**total duration of hit flash effect*/
public static final float hitDuration = 9f;
public StatusController status = new StatusController();
public UnitInventory inventory = new UnitInventory(100, 100);
public Team team = Team.blue;
public float rotation;
public Vector2 velocity = new Vector2(0f, 0.0001f);
public float hitTime;
public float drownTime;
protected Interpolator interpolator = new Interpolator();
protected StatusController status = new StatusController();
protected Team team = Team.blue;
protected Vector2 velocity = new Vector2(0f, 0.0001f);
protected float hitTime;
protected float drownTime;
@Override
public Team getTeam(){
return team;
}
@Override
public void interpolate() {
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.values[0];
}
@Override
public Interpolator getInterpolator() {
return interpolator;
}
@Override
public void damage(float amount){
@@ -40,7 +69,7 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
}
@Override
public boolean collides(SolidEntity other){
public boolean collides(SolidTrait other){
return other instanceof Bullet && state.teams.areEnemies((((Bullet) other).team), team);
}
@@ -51,6 +80,11 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
status.clear();
}
@Override
public Vector2 getVelocity() {
return velocity;
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeByte(team.ordinal());
@@ -79,6 +113,10 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
this.status.set(StatusEffect.getByID(effect), etime);
}
public StatusEffect getStatus(){
return status.current();
}
public TileEntity getClosestCore(){
if(state.teams.has(team)){
TeamData data = state.teams.get(team);
@@ -99,10 +137,6 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
return (Floor)(tile == null || (tile.floor() == null) ? Blocks.defaultFloor : tile.floor());
}
public Team getTeam(){
return team;
}
public void updateVelocityStatus(float drag, float maxVelocity){
Floor floor = getFloorOn();
Tile tile = world.tileWorld(x, y);
@@ -175,11 +209,6 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
}
}
@Override
public Vector2 getVelocity() {
return velocity;
}
public void drawUnder(){}
public void drawOver(){}
+23 -17
View File
@@ -3,13 +3,14 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.ObjectSet;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.Mathf;
@@ -19,6 +20,7 @@ import static io.anuke.mindustry.Vars.*;
/**Utility class for unit and team interactions.*/
public class Units {
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle();
/**Validates a target.
* @param target The target to validate
@@ -28,18 +30,18 @@ public class Units {
* @param range The maximum distance from the target X/Y the targeter can be for it to be valid
* @return whether the target is invalid
*/
public static boolean invalidateTarget(Targetable target, Team team, float x, float y, float range) {
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range) {
return target == null || (range != Float.MAX_VALUE && target.distanceTo(x, y) > range) || target.getTeam() == team || !target.isValid();
}
/**See {@link #invalidateTarget(Targetable, Team, float, float, float)}*/
public static boolean invalidateTarget(Targetable target, Team team, float x, float y){
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){
return invalidateTarget(target, team, x, y, Float.MAX_VALUE);
}
/**See {@link #invalidateTarget(Targetable, Team, float, float, float)}*/
public static boolean invalidateTarget(Targetable target, Unit targeter){
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
public static boolean invalidateTarget(TargetTrait target, Unit targeter){
return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.inventory.getAmmoRange());
}
@@ -53,8 +55,12 @@ public class Units {
Units.getNearby(rect, unit -> {
if(value[0]) return;
if(!unit.isFlying() && unit.hitbox.getRect(unit.x, unit.y).overlaps(rect)){
value[0] = true;
if(!unit.isFlying()){
unit.getHitbox(hitrect);
if(hitrect.overlaps(rect)) {
value[0] = true;
}
}
});
@@ -73,7 +79,7 @@ public class Units {
/**Returns the neareset tile entity in a range.*/
public static TileEntity findTile(float x, float y, float range, Predicate<Tile> pred){
Entity closest = null;
BaseEntity closest = null;
float dst = 0;
int rad = (int)(range/tilesize)+1;
@@ -119,7 +125,7 @@ public class Units {
}
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
public static Targetable getClosestTarget(Team team, float x, float y, float range){
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){
Unit unit = getClosestEnemy(team, x, y, range, u -> true);
if(unit != null){
return unit;
@@ -179,11 +185,11 @@ public class Units {
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
//now check all ally players
Entities.getNearby(playerGroup, rect, player -> {
EntityPhysics.getNearby(playerGroup, rect, player -> {
if(((Unit)player).team == team) cons.accept((Unit)player);
});
}
@@ -194,12 +200,12 @@ public class Units {
for(Team team : Team.values()){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
}
//now check all enemy players
Entities.getNearby(playerGroup, rect, player -> cons.accept((Unit)player));
EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit)player));
}
/**Iterates over all units that are enemies of this team.*/
@@ -209,12 +215,12 @@ public class Units {
for(Team other : targets){
EntityGroup<BaseUnit> group = unitGroups[other.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
}
//now check all enemy players
Entities.getNearby(playerGroup, rect, player -> {
EntityPhysics.getNearby(playerGroup, rect, player -> {
if(targets.contains(((Player)player).team)){
cons.accept((Unit)player);
}
@@ -42,7 +42,7 @@ public class BasicBulletType extends BulletType {
float a = Mathf.random(360f);
Bullet bullet = Bullet.create(fragBullet, b,
x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a);
bullet.velocity.scl(Mathf.random(fragVelocityMin, fragVelocityMax));
bullet.getVelocity().scl(Mathf.random(fragVelocityMin, fragVelocityMax));
}
}
}
@@ -2,16 +2,19 @@ package io.anuke.mindustry.entities.bullet;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.traits.TeamTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.Entity;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.entities.component.VelocityTrait;
import io.anuke.ucore.entities.impl.BulletEntity;
import io.anuke.ucore.util.Timer;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.world;
public class Bullet extends BulletEntity<BulletType>{
private static Vector2 vector = new Vector2();
@@ -19,8 +22,8 @@ public class Bullet extends BulletEntity<BulletType>{
public Timer timer = new Timer(3);
public Team team;
public static Bullet create(BulletType type, Unit owner, float x, float y, float angle){
return create(type, owner, owner.team, x, y, angle);
public static Bullet create(BulletType type, TeamTrait owner, float x, float y, float angle){
return create(type, owner, owner.getTeam(), x, y, angle);
}
public static Bullet create (BulletType type, Entity owner, Team team, float x, float y, float angle){
@@ -29,13 +32,14 @@ public class Bullet extends BulletEntity<BulletType>{
bullet.owner = owner;
bullet.velocity.set(0, type.speed).setAngle(angle);
bullet.velocity.add(owner instanceof Unit ? ((Unit)owner).velocity : Vector2.Zero);
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero);
bullet.hitbox.setSize(type.hitsize);
bullet.team = team;
bullet.type = type;
bullet.set(x, y);
return bullet.add();
bullet.add();
return bullet;
}
public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle){
@@ -43,20 +47,14 @@ public class Bullet extends BulletEntity<BulletType>{
}
private Bullet(){}
public boolean collidesTiles(){
return true; //TODO make artillery and such not do this
}
@Override
public void draw(){
//interpolate position linearly at low tick speeds
if(SyncEntity.isSmoothing()){
x += threads.getFramesSinceUpdate() * velocity.x;
y += threads.getFramesSinceUpdate() * velocity.y;
type.draw(this);
x -= threads.getFramesSinceUpdate() * velocity.x;
y -= threads.getFramesSinceUpdate() * velocity.y;
}else{
type.draw(this);
}
type.draw(this);
}
@Override
@@ -64,22 +62,18 @@ public class Bullet extends BulletEntity<BulletType>{
return 8;
}
public boolean collidesTiles(){
return true;
}
@Override
public boolean collides(SolidEntity other){
public boolean collides(SolidTrait other){
return super.collides(other);
}
@Override
public void collision(SolidEntity other, float x, float y){
public void collision(SolidTrait other, float x, float y){
super.collision(other, x, y);
if(other instanceof Unit){
Unit unit = (Unit)other;
unit.velocity.add(vector.set(other.x, other.y).sub(x, y).setLength(type.knockback / unit.getMass()));
unit.getVelocity().add(vector.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass()));
unit.applyEffect(type.status, type.statusIntensity);
}
}
@@ -89,7 +83,7 @@ public class Bullet extends BulletEntity<BulletType>{
super.update();
if (type.hitTiles && collidesTiles()) {
world.raycastEach(world.toTile(lastX), world.toTile(lastY), world.toTile(x), world.toTile(y), (x, y) -> {
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
Tile tile = world.tile(x, y);
if (tile == null) return false;
@@ -108,11 +102,6 @@ public class Bullet extends BulletEntity<BulletType>{
}
}
@Override
public float getDamage(){
return damage == -1 ? type.damage : damage;
}
@Override
public void reset() {
super.reset();
@@ -126,7 +115,7 @@ public class Bullet extends BulletEntity<BulletType>{
}
@Override
public Bullet add(){
return super.add(bulletGroup);
public EntityGroup targetGroup() {
return bulletGroup;
}
}
@@ -5,7 +5,7 @@ import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.BulletFx;
import io.anuke.mindustry.entities.StatusEffect;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.entities.BaseBulletType;
import io.anuke.ucore.entities.impl.BaseBulletType;
public abstract class BulletType extends BaseBulletType<Bullet>{
private static int lastid = 0;
@@ -15,7 +15,7 @@ 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.entities.SolidEntity;
import io.anuke.ucore.entities.impl.SolidEntity;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Physics;
@@ -26,6 +26,7 @@ import static io.anuke.mindustry.Vars.*;
/**Utility class for damaging in an area.*/
public class DamageArea{
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle();
private static Translator tr = new Translator();
/**Creates a dynamic explosion based on specified parameters.*/
@@ -90,7 +91,8 @@ public class DamageArea{
rect.height += expand*2;
Consumer<Unit> cons = e -> {
Rectangle other = e.hitbox.getRect(e.x, e.y);
e.getHitbox(hitrect);
Rectangle other = hitrect;
other.y -= expand;
other.x -= expand;
other.width += expand * 2;
@@ -111,7 +113,8 @@ public class DamageArea{
/**Damages all entities and blocks in a radius that are enemies of the team.*/
public static void damageUnits(Team team, float x, float y, float size, float damage, Consumer<Unit> acceptor) {
Consumer<Unit> cons = entity -> {
if (!entity.hitbox.getRect(entity.x, entity.y).overlaps(rect)) {
entity.getHitbox(hitrect);
if (!hitrect.overlaps(rect)) {
return;
}
entity.damage(damage);
@@ -140,7 +143,7 @@ public class DamageArea{
float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage);
entity.damage(amount);
//TODO better velocity displacement
entity.velocity.add(tr.set(entity.x - x, entity.y - y).setLength(damage*2f));
entity.getVelocity().add(tr.set(entity.x - x, entity.y - y).setLength(damage*2f));
};
rect.setSize(radius *2).setCenter(x, y);
@@ -6,13 +6,15 @@ import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.SerializableEntity;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@@ -22,7 +24,7 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Fire extends TimedEntity implements SerializableEntity, Poolable{
public class Fire extends TimedEntity implements SaveTrait, Poolable, DrawTrait {
private static final IntMap<Fire> map = new IntMap<>();
private static final float baseLifetime = 1000f;
@@ -39,7 +41,8 @@ public class Fire extends TimedEntity implements SerializableEntity, Poolable{
fire = Pools.obtain(Fire.class);
fire.tile = tile;
fire.lifetime = baseLifetime;
map.put(tile.packedPosition(), fire.add());
fire.add();
map.put(tile.packedPosition(), fire);
}else{
fire.lifetime = baseLifetime;
fire.time = 0f;
@@ -105,6 +108,11 @@ public class Fire extends TimedEntity implements SerializableEntity, Poolable{
}
}
@Override
public float drawSize() {
return 10;
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeInt(tile.packedPosition());
@@ -144,7 +152,7 @@ public class Fire extends TimedEntity implements SerializableEntity, Poolable{
}
@Override
public Fire add(){
return add(airItemGroup);
public EntityGroup targetGroup() {
return airItemGroup;
}
}
@@ -5,7 +5,7 @@ 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.entities.EffectEntity;
import io.anuke.ucore.entities.impl.EffectEntity;
import io.anuke.ucore.function.EffectRenderer;
import io.anuke.ucore.util.Mathf;
@@ -0,0 +1,57 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.mindustry.type.Item;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.SolidEntity;
import java.nio.ByteBuffer;
public class ItemDrop extends SolidEntity implements SyncTrait, DrawTrait {
private Interpolator interpolator = new Interpolator();
private Item item;
public static ItemDrop create(Item item, float x, float y){
ItemDrop drop = Pools.obtain(ItemDrop.class);
drop.item = item;
drop.set(x, y);
return drop;
}
/**Internal use only!*/
public ItemDrop(){}
@Override
public void removed() {
Pools.free(this);
}
@Override
public void draw() {
}
@Override
public Interpolator getInterpolator() {
return interpolator;
}
@Override
public float drawSize() {
return 10;
}
@Override
public void write(ByteBuffer data) {
data.putFloat(x);
data.putFloat(y);
}
@Override
public void read(ByteBuffer data, long time) {
}
}
@@ -3,11 +3,10 @@ package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Item;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
@@ -15,6 +14,8 @@ import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Position;
import static io.anuke.mindustry.Vars.effectGroup;
public class ItemTransfer extends TimedEntity{
private Vector2 from = new Vector2();
private Vector2 current = new Vector2();
@@ -80,7 +81,7 @@ public class ItemTransfer extends TimedEntity{
}
@Override
public <T extends Entity> T add() {
return super.add(Vars.effectGroup);
public EntityGroup targetGroup() {
return effectGroup;
}
}
@@ -6,24 +6,26 @@ import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.bulletGroup;
public class Lightning extends TimedEntity implements Poolable{
private static Array<SolidEntity> entities = new Array<>();
private static Array<SolidTrait> entities = new Array<>();
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle();
private static float angle;
private static float wetDamageMultiplier = 2;
@@ -66,12 +68,16 @@ public class Lightning extends TimedEntity implements Poolable{
angle = Mathf.slerp(angle, Angles.angle(x2, y2, entity.x, entity.y), (attractRange - dst) / attractRange / 4f);
}
Rectangle hitbox = entity.hitbox.getRect(entity.x, entity.y, range);
entity.getHitbox(hitrect);
hitrect.x -= range/2f;
hitrect.y -= range/2f;
hitrect.width += range/2f;
hitrect.height += range/2f;
if(hitbox.contains(x2, y2) || hitbox.contains(fx, fy)){
if(hitrect.contains(x2, y2) || hitrect.contains(fx, fy)){
float result = damage;
if(entity.status.current() == StatusEffects.wet)
if(entity.getStatus() == StatusEffects.wet)
result = (result * wetDamageMultiplier);
entity.damage(result);
@@ -115,7 +121,7 @@ public class Lightning extends TimedEntity implements Poolable{
}
@Override
public <T extends Entity> T add() {
return super.add(Vars.bulletGroup);
public EntityGroup targetGroup() {
return bulletGroup;
}
}
@@ -12,14 +12,16 @@ import io.anuke.mindustry.content.bullets.TurretBullets;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.SerializableEntity;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Hue;
@@ -34,12 +36,13 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.puddleGroup;
import static io.anuke.mindustry.Vars.world;
public class Puddle extends Entity implements SerializableEntity, Poolable{
public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait {
private static final IntMap<Puddle> map = new IntMap<>();
private static final float maxLiquid = 70f;
private static final int maxGeneration = 2;
private static final Color tmp = new Color();
private static final Rectangle rect = new Rectangle();
private static final Rectangle rect2 = new Rectangle();
private static int seeds;
private int loadedPosition = -1;
@@ -83,7 +86,8 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
puddle.liquid = liquid;
puddle.amount = amount;
puddle.generation = generation;
puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f).add();
puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
puddle.add();
map.put(tile.packedPosition(), puddle);
}else if(p.liquid == liquid){
p.accepting = Math.max(amount, p.accepting);
@@ -153,11 +157,11 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
if(amount >= maxLiquid/2f && Timers.get(this, "update", 20)){
Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(tile.worldx(), tile.worldy()), unit -> {
Rectangle o = unit.hitbox.getRect(unit.x, unit.y);
if(!rect.overlaps(o)) return;
unit.getHitbox(rect2);
if(!rect.overlaps(rect2)) return;
unit.applyEffect(liquid.effect, 0.5f);
if(unit.velocity.len() > 0.4) {
if(unit.getVelocity().len() > 0.4) {
Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y);
}
});
@@ -192,6 +196,11 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
Draw.color();
}
@Override
public float drawSize() {
return 20;
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeInt(tile.packedPosition());
@@ -238,7 +247,7 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
}
@Override
public Puddle add() {
return add(puddleGroup);
public EntityGroup targetGroup() {
return puddleGroup;
}
}
@@ -1,7 +1,8 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.graphics.Color;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
@@ -16,7 +17,8 @@ public class Rubble extends TimedEntity implements BelowLiquidEffect{
public static void create(float x, float y, int size){
Rubble rubble = new Rubble();
rubble.size = size;
rubble.set(x, y).add();
rubble.set(x, y);
rubble.add();
}
public Rubble(){
@@ -38,7 +40,7 @@ public class Rubble extends TimedEntity implements BelowLiquidEffect{
}
@Override
public Rubble add() {
return add(groundEffectGroup);
public EntityGroup targetGroup() {
return groundEffectGroup;
}
}
@@ -1,21 +1,18 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.math.Interpolation;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.defense.ShieldBlock;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.shieldGroup;
//todo re-implement
public class Shield extends Entity{
public class Shield extends BaseEntity {
public boolean active;
public boolean hitPlayers = false;
public float radius = 0f;
@@ -53,7 +50,8 @@ public class Shield extends Entity{
}
ShieldBlock block = (ShieldBlock)tile.block();
/*
Entities.getNearby(bulletGroup, x, y, block.shieldRadius * 2*uptime + 10, entity->{
BulletEntity bullet = (BulletEntity)entity;
if((bullet.owner instanceof BaseUnit || hitPlayers)){
@@ -64,7 +62,7 @@ public class Shield extends Entity{
((ShieldBlock)tile.block()).handleBullet(tile, bullet);
}
}
});
});*/
}
@Override
@@ -83,12 +81,12 @@ public class Shield extends Entity{
public void removeDelay(){
active = false;
}
@Override
public Shield add(){
return super.add(shieldGroup);
public EntityGroup targetGroup() {
return shieldGroup;
}
@Override
public void added(){
active = true;
@@ -1,10 +1,12 @@
package io.anuke.mindustry.entities;
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.ItemTransfer;
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
import io.anuke.mindustry.graphics.Palette;
@@ -31,7 +33,7 @@ import java.util.Arrays;
import static io.anuke.mindustry.Vars.*;
/**Interface for units that build, break or mine things.*/
public interface BlockBuilder {
public interface BuilderTrait {
//these are not instance variables!
Translator[] tmptr = {new Translator(), new Translator(), new Translator(), new Translator()};
float placeDistance = 200f;
@@ -109,7 +111,7 @@ public interface BlockBuilder {
if(unit.distanceTo(tile) > placeDistance) { //out of range, skip it.
getPlaceQueue().removeFirst();
}else if(current.remove){
if(Build.validBreak(unit.team, current.x, current.y) && current.recipe == Recipe.getByResult(tile.block())){ //if it's valid, break it
if(Build.validBreak(unit.getTeam(), current.x, current.y) && current.recipe == Recipe.getByResult(tile.block())){ //if it's valid, break it
float progress = 1f / tile.getBreakTime();
TileEntity core = unit.getClosestCore();
@@ -133,7 +135,7 @@ public interface BlockBuilder {
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.drawx(), tile.drawy()), 0.4f);
if(current.progress >= 1f){
Build.breakBlock(unit.team, current.x, current.y, true, true);
Build.breakBlock(unit.getTeam(), current.x, current.y, true, true);
}
}else{
//otherwise, skip it
@@ -141,12 +143,12 @@ public interface BlockBuilder {
}
}else{
if (!(tile.block() instanceof BuildBlock)) { //check if haven't started placing
if(Build.validPlace(unit.team, current.x, current.y, current.recipe.result, current.rotation)){
if(Build.validPlace(unit.getTeam(), 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);
Build.placeBlock(unit.getTeam(), 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)));
threads.run(() -> Events.fire(BlockBuildEvent.class, unit.getTeam(), world.tile(current.x, current.y)));
}else{
//otherwise, skip it
getPlaceQueue().removeFirst();
@@ -270,8 +272,9 @@ public interface BlockBuilder {
public final Recipe recipe;
public final boolean remove;
float progress;
float[] removeAccumulator;
public float progress;
private float[] removeAccumulator;
/**This creates a build request.*/
public BuildRequest(int x, int y, int rotation, Recipe recipe) {
@@ -1,11 +1,13 @@
package io.anuke.mindustry.entities;
package io.anuke.mindustry.entities.traits;
import io.anuke.ucore.entities.component.Entity;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**Marks an entity as serializable.*/
public interface SerializableEntity {
public interface SaveTrait extends Entity{
void writeSave(DataOutputStream stream) throws IOException;
void readSave(DataInputStream stream) throws IOException;
}
@@ -0,0 +1,37 @@
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.Gdx;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.ucore.entities.component.Entity;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.threads;
public interface SyncTrait extends Entity {
static boolean isSmoothing(){
return threads.isEnabled() && threads.getFPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
}
default void setNet(float x, float y){
set(x, y);
getInterpolator().target.set(x, y);
getInterpolator().last.set(x, y);
getInterpolator().spacing = 1f;
getInterpolator().time = 0f;
}
default void interpolate(){
getInterpolator().update();
setX(getInterpolator().pos.x);
setY(getInterpolator().pos.y);
}
Interpolator getInterpolator();
//Read and write sync data, usually position
void write(ByteBuffer data);
void read(ByteBuffer data, long time);
}
@@ -1,15 +1,14 @@
package io.anuke.mindustry.entities;
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.game.Team;
import io.anuke.ucore.entities.component.VelocityTrait;
import io.anuke.ucore.util.Position;
/**Base interface for targetable entities.*/
public interface Targetable extends Position{
public interface TargetTrait extends Position, VelocityTrait {
boolean isDead();
Team getTeam();
Vector2 getVelocity();
/**Whether this entity is a valid target.*/
default boolean isValid(){
@@ -0,0 +1,8 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.mindustry.game.Team;
import io.anuke.ucore.entities.component.Entity;
public interface TeamTrait extends Entity {
Team getTeam();
}
@@ -1,12 +1,11 @@
package io.anuke.mindustry.entities.units;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.entities.Targetable;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.Units;
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;
@@ -16,6 +15,7 @@ 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.entities.EntityGroup;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@@ -32,13 +32,13 @@ 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;
protected boolean isWave;
protected TargetTrait target;
public BaseUnit(UnitType type, Team team){
this.type = type;
@@ -48,6 +48,12 @@ public abstract class BaseUnit extends Unit{
/**internal constructor used for deserialization, DO NOT USE*/
public BaseUnit(){}
/**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/
public void setWave(){
isWave = true;
inventory.setInfiniteAmmo(true);
}
public void rotate(float angle){
rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed);
}
@@ -79,7 +85,7 @@ public abstract class BaseUnit extends Unit{
}
public void updateTargeting(){
if(target == null || (target instanceof Unit && (target.isDead() || ((Unit)target).team == team))
if(target == null || (target instanceof Unit && (target.isDead() || ((Unit)target).getTeam() == team))
|| (target instanceof TileEntity && ((TileEntity) target).tile.entity == null)){
target = null;
}
@@ -120,7 +126,7 @@ public abstract class BaseUnit extends Unit{
}
@Override
public float getMaxHealth() {
public float maxHealth() {
return type.health;
}
@@ -144,12 +150,6 @@ public abstract class BaseUnit extends Unit{
return 8;
}
@Override
public void move(float x, float y){
baseRotation = Mathf.slerpDelta(baseRotation, Mathf.atan2(x, y), type.baseRotateSpeed);
super.move(x, y);
}
@Override
public float getMass() {
return type.mass;
@@ -180,12 +180,14 @@ public abstract class BaseUnit extends Unit{
if(target != null) behavior();
x = Mathf.clamp(x, 0, world.width() * tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize);
if(!isWave) {
x = Mathf.clamp(x, 0, world.width() * tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize);
}
}
@Override
public void drawSmooth(){
public void draw(){
}
@@ -204,11 +206,6 @@ public abstract class BaseUnit extends Unit{
return 14;
}
@Override
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
Bullet.create(type, this, x, y, rotation).damage = data;
}
@Override
public void onDeath(){
super.onDeath();
@@ -220,8 +217,8 @@ public abstract class BaseUnit extends Unit{
}
@Override
public void onRemoteDeath(){
onDeath();
public boolean collidesOthers() {
return !isFlying();
}
@Override
@@ -231,17 +228,16 @@ public abstract class BaseUnit extends Unit{
@Override
public void added(){
hitbox.solid = !isFlying();
hitbox.setSize(type.hitsize);
hitboxTile.setSize(type.hitsizeTile);
state.set(getStartState());
heal();
}
@Override
public BaseUnit add(){
return add(unitGroups[team.ordinal()]);
public EntityGroup targetGroup() {
return unitGroups[team.ordinal()];
}
@Override
@@ -256,46 +252,16 @@ public abstract class BaseUnit extends Unit{
byte type = stream.readByte();
this.type = UnitType.getByID(type);
add(unitGroups[team.ordinal()]);
}
@Override
public void writeSpawn(ByteBuffer buffer) {
buffer.put(type.id);
buffer.put((byte)team.ordinal());
buffer.putFloat(x);
buffer.putFloat(y);
buffer.putShort((short)health);
}
@Override
public void readSpawn(ByteBuffer buffer) {
type = UnitType.getByID(buffer.get());
team = Team.values()[buffer.get()];
x = buffer.getFloat();
y = buffer.getFloat();
health = buffer.getShort();
setNet(x, y);
add();
}
@Override
public void write(ByteBuffer data) {
data.putFloat(x);
data.putFloat(y);
data.putShort((short)(rotation *2));
data.putShort((short)(baseRotation *2));
data.putShort((short)health);
//todo
}
@Override
public void read(ByteBuffer data, long time) {
float x = data.getFloat();
float y = data.getFloat();
short rotation = data.getShort();
short baserotation = data.getShort();
short health = data.getShort();
interpolator.read(this.x, this.y, x, y, rotation/2f, baserotation/2f, time);
this.health = health;
//todo
}
}
@@ -37,7 +37,7 @@ public class FlyingUnit extends BaseUnit {
}
@Override
public void drawSmooth() {
public void draw() {
Draw.alpha(hitTime / hitDuration);
Draw.rect(type.name, x, y, rotation - 90);
@@ -52,7 +52,7 @@ public class FlyingUnit extends BaseUnit {
@Override
public void behavior() {
if(health <= health * type.retreatPercent &&
if(health <= health * type.retreatPercent && !isWave &&
Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){
setState(retreat);
}
@@ -174,7 +174,7 @@ public class FlyingUnit extends BaseUnit {
}
public void update() {
if(health >= getMaxHealth()){
if(health >= maxHealth()){
state.set(attack);
}else if(!targetHasFlag(BlockFlag.repair)){
retarget(() -> {
@@ -20,11 +20,28 @@ public abstract class GroundUnit extends BaseUnit {
protected static float maxAim = 30f;
protected float walkTime;
protected float baseRotation;
public GroundUnit(UnitType type, Team team) {
super(type, team);
}
@Override
public void interpolate() {
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.values[0];
baseRotation = interpolator.values[1];
}
@Override
public void move(float x, float y){
baseRotation = Mathf.slerpDelta(baseRotation, Mathf.atan2(x, y), type.baseRotateSpeed);
super.move(x, y);
}
@Override
public UnitState getStartState() {
return resupply;
@@ -40,7 +57,7 @@ public abstract class GroundUnit extends BaseUnit {
}
@Override
public void drawSmooth() {
public void draw() {
Draw.alpha(hitTime / hitDuration);
float walktime = walkTime;
@@ -75,7 +92,7 @@ public abstract class GroundUnit extends BaseUnit {
@Override
public void behavior() {
if(health <= health * type.retreatPercent && !inventory.isInfiniteAmmo()){
if(health <= health * type.retreatPercent && !isWave){
setState(retreat);
}
}
@@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.units.types;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.entities.BlockBuilder;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.units.BaseUnit;
@@ -29,7 +29,7 @@ import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.world;
public class Drone extends FlyingUnit implements BlockBuilder{
public class Drone extends FlyingUnit implements BuilderTrait {
protected static float healSpeed = 0.1f;
protected static float discoverRange = 120f;
protected static boolean initialized;
@@ -31,7 +31,7 @@ public class Vtol extends FlyingUnit {
}
@Override
public void drawSmooth() {
public void draw() {
Draw.alpha(hitTime / hitDuration);
Draw.rect(type.name, x, y, rotation - 90);