Added Android automatic shooting
This commit is contained in:
@@ -20,7 +20,10 @@ import io.anuke.mindustry.entities.units.BaseUnit;
|
|||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.ucore.core.*;
|
import io.anuke.ucore.core.Core;
|
||||||
|
import io.anuke.ucore.core.Effects;
|
||||||
|
import io.anuke.ucore.core.Graphics;
|
||||||
|
import io.anuke.ucore.core.Settings;
|
||||||
import io.anuke.ucore.entities.EffectEntity;
|
import io.anuke.ucore.entities.EffectEntity;
|
||||||
import io.anuke.ucore.entities.Entities;
|
import io.anuke.ucore.entities.Entities;
|
||||||
import io.anuke.ucore.entities.Entity;
|
import io.anuke.ucore.entities.Entity;
|
||||||
@@ -33,15 +36,12 @@ import io.anuke.ucore.graphics.Surface;
|
|||||||
import io.anuke.ucore.modules.RendererModule;
|
import io.anuke.ucore.modules.RendererModule;
|
||||||
import io.anuke.ucore.scene.utils.Cursors;
|
import io.anuke.ucore.scene.utils.Cursors;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
import io.anuke.ucore.util.Tmp;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
import static io.anuke.ucore.core.Core.batch;
|
import static io.anuke.ucore.core.Core.batch;
|
||||||
import static io.anuke.ucore.core.Core.camera;
|
import static io.anuke.ucore.core.Core.camera;
|
||||||
|
|
||||||
public class Renderer extends RendererModule{
|
public class Renderer extends RendererModule{
|
||||||
private final static float shieldHitDuration = 18f;
|
|
||||||
|
|
||||||
public Surface effectSurface;
|
public Surface effectSurface;
|
||||||
|
|
||||||
private int targetscale = baseCameraScale;
|
private int targetscale = baseCameraScale;
|
||||||
@@ -143,15 +143,18 @@ public class Renderer extends RendererModule{
|
|||||||
Graphics.clear(Color.BLACK);
|
Graphics.clear(Color.BLACK);
|
||||||
}else{
|
}else{
|
||||||
Vector2 position = averagePosition();
|
Vector2 position = averagePosition();
|
||||||
|
boolean flying = players[0].isFlying();
|
||||||
|
|
||||||
setCamera(position.x, position.y);
|
if(!flying){
|
||||||
|
setCamera(position.x, position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f, world.height() * tilesize - tilesize / 2f);
|
||||||
|
|
||||||
float prex = camera.position.x, prey = camera.position.y;
|
float prex = camera.position.x, prey = camera.position.y;
|
||||||
updateShake(0.75f);
|
updateShake(0.75f);
|
||||||
clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f, world.height() * tilesize - tilesize / 2f);
|
|
||||||
|
|
||||||
float deltax = camera.position.x - prex, deltay = camera.position.y - prey;
|
float deltax = camera.position.x - prex, deltay = camera.position.y - prey;
|
||||||
|
|
||||||
float lastx = camera.position.x, lasty = camera.position.y;
|
float lastx = camera.position.x, lasty = camera.position.y;
|
||||||
|
|
||||||
if(snapCamera){
|
if(snapCamera){
|
||||||
@@ -243,6 +246,7 @@ public class Renderer extends RendererModule{
|
|||||||
Entities.drawWith(playerGroup, p -> p.isFlying() == flying && p.team == team, Unit::drawUnder);
|
Entities.drawWith(playerGroup, p -> p.isFlying() == flying && p.team == team, Unit::drawUnder);
|
||||||
|
|
||||||
Shaders.outline.color.set(team.color);
|
Shaders.outline.color.set(team.color);
|
||||||
|
Shaders.mix.color.set(Color.WHITE);
|
||||||
|
|
||||||
Graphics.beginShaders(Shaders.outline);
|
Graphics.beginShaders(Shaders.outline);
|
||||||
Graphics.shader(Shaders.mix, true);
|
Graphics.shader(Shaders.mix, true);
|
||||||
@@ -328,57 +332,6 @@ public class Renderer extends RendererModule{
|
|||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawShield(){
|
|
||||||
if(shieldGroup.size() == 0 && shieldDraws.size == 0) return;
|
|
||||||
|
|
||||||
Graphics.surface(renderer.effectSurface, false);
|
|
||||||
Draw.color(Color.ROYAL);
|
|
||||||
Entities.draw(shieldGroup);
|
|
||||||
for(Callable c : shieldDraws){
|
|
||||||
c.run();
|
|
||||||
}
|
|
||||||
Draw.reset();
|
|
||||||
Graphics.surface();
|
|
||||||
|
|
||||||
for(int i = 0; i < shieldHits.size / 3; i++){
|
|
||||||
float time = shieldHits.get(i * 3 + 2);
|
|
||||||
|
|
||||||
time += Timers.delta() / shieldHitDuration;
|
|
||||||
shieldHits.set(i * 3 + 2, time);
|
|
||||||
|
|
||||||
if(time >= 1f){
|
|
||||||
shieldHits.removeRange(i * 3, i * 3 + 2);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture texture = effectSurface.texture();
|
|
||||||
Shaders.shield.color.set(Color.SKY);
|
|
||||||
|
|
||||||
Tmp.tr2.setRegion(texture);
|
|
||||||
Shaders.shield.region = Tmp.tr2;
|
|
||||||
Shaders.shield.hits = shieldHits;
|
|
||||||
|
|
||||||
if(Shaders.shield.isFallback){
|
|
||||||
Draw.color(1f, 1f, 1f, 0.3f);
|
|
||||||
Shaders.outline.color = Color.SKY;
|
|
||||||
Shaders.outline.region = Tmp.tr2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Graphics.end();
|
|
||||||
Graphics.shader(Shaders.shield.isFallback ? Shaders.outline : Shaders.shield);
|
|
||||||
Graphics.setScreen();
|
|
||||||
|
|
||||||
Core.batch.draw(texture, 0, Gdx.graphics.getHeight(), Gdx.graphics.getWidth(), -Gdx.graphics.getHeight());
|
|
||||||
|
|
||||||
Graphics.shader();
|
|
||||||
Graphics.end();
|
|
||||||
Graphics.beginCam();
|
|
||||||
|
|
||||||
Draw.color();
|
|
||||||
shieldDraws.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockRenderer getBlocks() {
|
public BlockRenderer getBlocks() {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ public interface BlockBuilder {
|
|||||||
/**Returns the queue for storing build requests.*/
|
/**Returns the queue for storing build requests.*/
|
||||||
Queue<BuildRequest> getPlaceQueue();
|
Queue<BuildRequest> getPlaceQueue();
|
||||||
|
|
||||||
|
/**Return whether this builder's place queue contains items.*/
|
||||||
|
default boolean isBuilding(){
|
||||||
|
return getPlaceQueue().size != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**If a place request matching this signature is present, it is removed.
|
/**If a place request matching this signature is present, it is removed.
|
||||||
* Otherwise, a new place request is added to the queue.*/
|
* Otherwise, a new place request is added to the queue.*/
|
||||||
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
|
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.math.Vector2;
|
|||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.badlogic.gdx.utils.Pools;
|
import com.badlogic.gdx.utils.Pools;
|
||||||
import com.badlogic.gdx.utils.Queue;
|
import com.badlogic.gdx.utils.Queue;
|
||||||
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.content.Mechs;
|
import io.anuke.mindustry.content.Mechs;
|
||||||
import io.anuke.mindustry.content.Weapons;
|
import io.anuke.mindustry.content.Weapons;
|
||||||
import io.anuke.mindustry.content.fx.ExplosionFx;
|
import io.anuke.mindustry.content.fx.ExplosionFx;
|
||||||
@@ -14,16 +15,14 @@ import io.anuke.mindustry.entities.bullet.BulletType;
|
|||||||
import io.anuke.mindustry.entities.effect.DamageArea;
|
import io.anuke.mindustry.entities.effect.DamageArea;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.graphics.Palette;
|
import io.anuke.mindustry.graphics.Palette;
|
||||||
|
import io.anuke.mindustry.graphics.Trail;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.net.NetEvents;
|
import io.anuke.mindustry.net.NetEvents;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||||
import io.anuke.mindustry.world.blocks.types.storage.CoreBlock.CoreEntity;
|
import io.anuke.mindustry.world.blocks.types.storage.CoreBlock.CoreEntity;
|
||||||
import io.anuke.ucore.core.Core;
|
import io.anuke.ucore.core.*;
|
||||||
import io.anuke.ucore.core.Effects;
|
|
||||||
import io.anuke.ucore.core.Inputs;
|
|
||||||
import io.anuke.ucore.core.Timers;
|
|
||||||
import io.anuke.ucore.entities.SolidEntity;
|
import io.anuke.ucore.entities.SolidEntity;
|
||||||
import io.anuke.ucore.graphics.Draw;
|
import io.anuke.ucore.graphics.Draw;
|
||||||
import io.anuke.ucore.graphics.Fill;
|
import io.anuke.ucore.graphics.Fill;
|
||||||
@@ -38,10 +37,14 @@ import java.nio.ByteBuffer;
|
|||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Player extends Unit implements BlockBuilder {
|
public class Player extends Unit implements BlockBuilder {
|
||||||
private static final float speed = 1.1f;
|
private static final float walkSpeed = 1.1f;
|
||||||
|
private static final float flySpeed = 0.4f;
|
||||||
|
private static final float flyMaxSpeed = 3f;
|
||||||
private static final float dashSpeed = 1.8f;
|
private static final float dashSpeed = 1.8f;
|
||||||
private static final Vector2 movement = new Vector2();
|
private static final Vector2 movement = new Vector2();
|
||||||
|
|
||||||
|
//region instance variables, constructor
|
||||||
|
|
||||||
public String name = "name";
|
public String name = "name";
|
||||||
public String uuid;
|
public String uuid;
|
||||||
public boolean isAdmin;
|
public boolean isAdmin;
|
||||||
@@ -51,17 +54,16 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
public Weapon weapon = Weapons.blaster;
|
public Weapon weapon = Weapons.blaster;
|
||||||
public Mech mech = Mechs.standard;
|
public Mech mech = Mechs.standard;
|
||||||
|
|
||||||
public float targetAngle = 0f;
|
|
||||||
public boolean dashing = false;
|
|
||||||
|
|
||||||
public int clientid = -1;
|
public int clientid = -1;
|
||||||
public int playerIndex = 0;
|
public int playerIndex = 0;
|
||||||
public boolean isLocal = false;
|
public boolean isLocal = false;
|
||||||
public Timer timer = new Timer(4);
|
public Timer timer = new Timer(4);
|
||||||
|
public Targetable target;
|
||||||
|
|
||||||
private boolean respawning;
|
private boolean respawning;
|
||||||
private float walktime;
|
private float walktime;
|
||||||
private Queue<BuildRequest> placeQueue = new Queue<>();
|
private Queue<BuildRequest> placeQueue = new Queue<>();
|
||||||
|
private Trail trail = new Trail(16);
|
||||||
|
|
||||||
public Player(){
|
public Player(){
|
||||||
hitbox.setSize(5);
|
hitbox.setSize(5);
|
||||||
@@ -71,11 +73,25 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
heal();
|
heal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region unit and event overrides, utility methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getArmor() {
|
public float getArmor() {
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptsAmmo(Item item) {
|
||||||
|
return weapon.getAmmoType(item) != null && inventory.canAcceptAmmo(weapon.getAmmoType(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAmmo(Item item) {
|
||||||
|
inventory.addAmmo(weapon.getAmmoType(item));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
|
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
|
||||||
Weapon weapon = Upgrade.getByID(Bits.getLeftByte(data));
|
Weapon weapon = Upgrade.getByID(Bits.getLeftByte(data));
|
||||||
@@ -131,14 +147,33 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoteDeath(){
|
public void onRemoteDeath() {
|
||||||
dead = true;
|
dead = true;
|
||||||
respawning = false;
|
respawning = false;
|
||||||
Effects.effect(ExplosionFx.explosion, this);
|
Effects.effect(ExplosionFx.explosion, this);
|
||||||
Effects.shake(4f, 5f, this);
|
Effects.shake(4f, 5f, this);
|
||||||
Effects.sound("die", this);
|
Effects.sound("die", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region draw methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawSmooth(){
|
public void drawSmooth(){
|
||||||
if((debug && (!showPlayer || !showUI)) || dead) return;
|
if((debug && (!showPlayer || !showUI)) || dead) return;
|
||||||
@@ -219,6 +254,8 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
if(!isShooting() && getCurrentRequest() != null && !dead) {
|
if(!isShooting() && getCurrentRequest() != null && !dead) {
|
||||||
drawBuilding(this);
|
drawBuilding(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trail.draw(Palette.lighterOrange, Palette.lightishOrange, 5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawName(){
|
public void drawName(){
|
||||||
@@ -284,7 +321,11 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
|
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region update methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
hitTime = Math.max(0f, hitTime - Timers.delta());
|
hitTime = Math.max(0f, hitTime - Timers.delta());
|
||||||
@@ -309,6 +350,11 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
updateMech();
|
updateMech();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float wobblyness = 0.6f;
|
||||||
|
|
||||||
|
trail.update(x + Angles.trnsx(rotation + 180f, 6f) + Mathf.range(wobblyness),
|
||||||
|
y + Angles.trnsy(rotation + 180f, 6f) + Mathf.range(wobblyness));
|
||||||
|
|
||||||
if(!isShooting()) {
|
if(!isShooting()) {
|
||||||
updateBuilding(this);
|
updateBuilding(this);
|
||||||
}
|
}
|
||||||
@@ -317,26 +363,6 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
y = Mathf.clamp(y, 0, world.height() * tilesize);
|
y = Mathf.clamp(y, 0, world.height() * tilesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Resets all values of the player.*/
|
|
||||||
public void reset(){
|
|
||||||
weapon = Weapons.blaster;
|
|
||||||
team = Team.blue;
|
|
||||||
inventory.clear();
|
|
||||||
upgrades.clear();
|
|
||||||
placeQueue.clear();
|
|
||||||
|
|
||||||
add();
|
|
||||||
heal();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShooting(){
|
|
||||||
return control.input(playerIndex).canShoot() && control.input(playerIndex).isShooting() && inventory.hasAmmo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Queue<BuildRequest> getPlaceQueue(){
|
|
||||||
return placeQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateMech(){
|
protected void updateMech(){
|
||||||
Tile tile = world.tileWorld(x, y);
|
Tile tile = world.tileWorld(x, y);
|
||||||
|
|
||||||
@@ -347,9 +373,7 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
|
|
||||||
if(ui.chatfrag.chatOpen()) return;
|
if(ui.chatfrag.chatOpen()) return;
|
||||||
|
|
||||||
dashing = Inputs.keyDown("dash");
|
float speed = Inputs.keyDown("dash") ? (debug ? Player.dashSpeed * 5f : Player.dashSpeed) : Player.walkSpeed;
|
||||||
|
|
||||||
float speed = dashing ? (debug ? Player.dashSpeed * 5f : Player.dashSpeed) : Player.speed ;
|
|
||||||
|
|
||||||
float carrySlowdown = 0.3f;
|
float carrySlowdown = 0.3f;
|
||||||
|
|
||||||
@@ -370,8 +394,12 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
boolean shooting = isShooting();
|
boolean shooting = isShooting();
|
||||||
|
|
||||||
if(shooting){
|
if(shooting){
|
||||||
weapon.update(this, true);
|
Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(),
|
||||||
weapon.update(this, false);
|
Vars.control.input(playerIndex).getMouseY());
|
||||||
|
float vx = vec.x, vy = vec.y;
|
||||||
|
|
||||||
|
weapon.update(this, true, vx, vy);
|
||||||
|
weapon.update(this, false, vx, vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
movement.limit(speed);
|
movement.limit(speed);
|
||||||
@@ -396,32 +424,83 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateFlying(){
|
protected void updateFlying(){
|
||||||
rotation = Mathf.slerpDelta(rotation, targetAngle, 0.1f);
|
if(Units.invalidateTarget(target, this)){
|
||||||
}
|
target = null;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public Player set(float x, float y){
|
float targetX = Core.camera.position.x, targetY = Core.camera.position.y;
|
||||||
this.x = x;
|
float attractDst = 15f;
|
||||||
this.y = y;
|
|
||||||
if(mobile && !isLocal){
|
movement.set(targetX - x, targetY - y).limit(flySpeed);
|
||||||
Core.camera.position.set(x, y, 0f);
|
movement.setAngle(Mathf.slerpDelta(movement.angle(), velocity.angle(), 0.05f));
|
||||||
|
|
||||||
|
if(distanceTo(targetX, targetY) < attractDst){
|
||||||
|
movement.setZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
velocity.add(movement);
|
||||||
|
updateVelocityStatus(0.1f, flyMaxSpeed);
|
||||||
|
|
||||||
|
//hovering effect
|
||||||
|
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.08f);
|
||||||
|
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.08f);
|
||||||
|
|
||||||
|
if(velocity.len() <= 0.2f){
|
||||||
|
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 1f);
|
||||||
|
}else{
|
||||||
|
rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len()/10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//update shooting if not building and there's ammo left
|
||||||
|
if(!isBuilding() && inventory.hasAmmo()){
|
||||||
|
|
||||||
|
//autofire: mobile only!
|
||||||
|
if(mobile) {
|
||||||
|
if (target == null) {
|
||||||
|
target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange());
|
||||||
|
} else {
|
||||||
|
//rotate toward and shoot the target
|
||||||
|
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f);
|
||||||
|
|
||||||
|
Vector2 intercept =
|
||||||
|
Predict.intercept(x, y, target.getX(), target.getY(), target.getVelocity().x - velocity.x, target.getVelocity().y - velocity.y, inventory.getAmmo().bullet.speed);
|
||||||
|
|
||||||
|
weapon.update(this, true, intercept.x, intercept.y);
|
||||||
|
weapon.update(this, false, intercept.x, intercept.y);
|
||||||
|
}
|
||||||
|
}else if(isShooting()){ //desktop shooting, TODO
|
||||||
|
Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(),
|
||||||
|
Vars.control.input(playerIndex).getMouseY());
|
||||||
|
float vx = vec.x, vy = vec.y;
|
||||||
|
|
||||||
|
weapon.update(this, true, vx, vy);
|
||||||
|
weapon.update(this, false, vx, vy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//endregion
|
||||||
public boolean acceptsAmmo(Item item) {
|
|
||||||
return weapon.getAmmoType(item) != null && inventory.canAcceptAmmo(weapon.getAmmoType(item));
|
//region utility methods
|
||||||
|
|
||||||
|
/**Resets all values of the player.*/
|
||||||
|
public void reset(){
|
||||||
|
weapon = Weapons.blaster;
|
||||||
|
team = Team.blue;
|
||||||
|
inventory.clear();
|
||||||
|
upgrades.clear();
|
||||||
|
placeQueue.clear();
|
||||||
|
|
||||||
|
add();
|
||||||
|
heal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean isShooting(){
|
||||||
public void addAmmo(Item item) {
|
return control.input(playerIndex).canShoot() && control.input(playerIndex).isShooting() && inventory.hasAmmo();
|
||||||
inventory.addAmmo(weapon.getAmmoType(item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Queue<BuildRequest> getPlaceQueue(){
|
||||||
public Player add(){
|
return placeQueue;
|
||||||
return add(playerGroup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -429,6 +508,10 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
return "Player{" + id + ", mech=" + mech.name + ", local=" + isLocal + ", " + x + ", " + y + "}\n";
|
return "Player{" + id + ", mech=" + mech.name + ", local=" + isLocal + ", " + x + ", " + y + "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region read and write methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSave(DataOutputStream stream) throws IOException {
|
public void writeSave(DataOutputStream stream) throws IOException {
|
||||||
stream.writeBoolean(isLocal);
|
stream.writeBoolean(isLocal);
|
||||||
@@ -502,7 +585,6 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
data.putFloat(rotation);
|
data.putFloat(rotation);
|
||||||
data.putFloat(baseRotation);
|
data.putFloat(baseRotation);
|
||||||
data.putShort((short)health);
|
data.putShort((short)health);
|
||||||
data.put((byte)(dashing ? 1 : 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -515,8 +597,9 @@ public class Player extends Unit implements BlockBuilder {
|
|||||||
byte dashing = data.get();
|
byte dashing = data.get();
|
||||||
|
|
||||||
this.health = health;
|
this.health = health;
|
||||||
this.dashing = dashing == 1;
|
|
||||||
|
|
||||||
interpolator.read(this.x, this.y, x, y, rot, baseRot, time);
|
interpolator.read(this.x, this.y, x, y, rot, baseRot, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,15 @@ public class Predict {
|
|||||||
private static Vector2 vec = new Vector2();
|
private static Vector2 vec = new Vector2();
|
||||||
private static Vector2 vresult = new Vector2();
|
private static Vector2 vresult = new Vector2();
|
||||||
|
|
||||||
/**Returns resulting predicted vector.
|
/**Calculates of intercept of a stationary and moving target. Do not call from multiple threads!
|
||||||
* Don't call from multiple threads.*/
|
* @param srcx X of shooter
|
||||||
|
* @param srcy Y of shooter
|
||||||
|
* @param dstx X of target
|
||||||
|
* @param dsty Y of target
|
||||||
|
* @param dstvx X velocity of target (subtract shooter X velocity if needed)
|
||||||
|
* @param dstvy Y velocity of target (subtract shooter Y velocity if needed)
|
||||||
|
* @param v speed of bullet
|
||||||
|
* @return the intercept location*/
|
||||||
public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v) {
|
public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v) {
|
||||||
float tx = dstx - srcx,
|
float tx = dstx - srcx,
|
||||||
ty = dsty - srcy,
|
ty = dsty - srcy,
|
||||||
|
|||||||
18
core/src/io/anuke/mindustry/entities/Targetable.java
Normal file
18
core/src/io/anuke/mindustry/entities/Targetable.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package io.anuke.mindustry.entities;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import io.anuke.mindustry.game.Team;
|
||||||
|
import io.anuke.ucore.util.Position;
|
||||||
|
|
||||||
|
/**Base interface for targetable entities.*/
|
||||||
|
public interface Targetable extends Position{
|
||||||
|
|
||||||
|
boolean isDead();
|
||||||
|
Team getTeam();
|
||||||
|
Vector2 getVelocity();
|
||||||
|
|
||||||
|
/**Whether this entity is a valid target.*/
|
||||||
|
default boolean isValid(){
|
||||||
|
return !isDead();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package io.anuke.mindustry.entities;
|
package io.anuke.mindustry.entities;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import io.anuke.mindustry.content.fx.Fx;
|
import io.anuke.mindustry.content.fx.Fx;
|
||||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||||
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.net.NetEvents;
|
import io.anuke.mindustry.net.NetEvents;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
@@ -23,19 +25,19 @@ import java.io.IOException;
|
|||||||
import static io.anuke.mindustry.Vars.tileGroup;
|
import static io.anuke.mindustry.Vars.tileGroup;
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class TileEntity extends Entity{
|
public class TileEntity extends Entity implements Targetable{
|
||||||
public static final float timeToSleep = 60f*4; //4 seconds to fall asleep
|
public static final float timeToSleep = 60f*4; //4 seconds to fall asleep
|
||||||
public static int sleepingEntities = 0;
|
public static int sleepingEntities = 0;
|
||||||
|
|
||||||
public Tile tile;
|
public Tile tile;
|
||||||
public Timer timer;
|
public Timer timer;
|
||||||
public float health;
|
public float health;
|
||||||
public boolean dead = false;
|
|
||||||
|
|
||||||
public PowerModule power;
|
public PowerModule power;
|
||||||
public InventoryModule items;
|
public InventoryModule items;
|
||||||
public LiquidModule liquids;
|
public LiquidModule liquids;
|
||||||
|
|
||||||
|
private boolean dead = false;
|
||||||
private boolean sleeping;
|
private boolean sleeping;
|
||||||
private float sleepTime;
|
private float sleepTime;
|
||||||
|
|
||||||
@@ -82,7 +84,11 @@ public class TileEntity extends Entity{
|
|||||||
sleepingEntities --;
|
sleepingEntities --;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDead() {
|
||||||
|
return dead;
|
||||||
|
}
|
||||||
|
|
||||||
public void write(DataOutputStream stream) throws IOException{}
|
public void write(DataOutputStream stream) throws IOException{}
|
||||||
public void read(DataInputStream stream) throws IOException{}
|
public void read(DataInputStream stream) throws IOException{}
|
||||||
|
|
||||||
@@ -128,7 +134,17 @@ public class TileEntity extends Entity{
|
|||||||
NetEvents.handleBlockDamaged(this);
|
NetEvents.handleBlockDamaged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Team getTeam() {
|
||||||
|
return tile.getTeam();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector2 getVelocity() {
|
||||||
|
return Vector2.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
synchronized (Tile.tileSetLock) {
|
synchronized (Tile.tileSetLock) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import java.io.IOException;
|
|||||||
import static io.anuke.mindustry.Vars.state;
|
import static io.anuke.mindustry.Vars.state;
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public abstract class Unit extends SyncEntity implements SerializableEntity {
|
public abstract class Unit extends SyncEntity implements SerializableEntity, Targetable {
|
||||||
/**total duration of hit flash effect*/
|
/**total duration of hit flash effect*/
|
||||||
public static final float hitDuration = 9f;
|
public static final float hitDuration = 9f;
|
||||||
|
|
||||||
@@ -175,6 +175,11 @@ public abstract class Unit extends SyncEntity implements SerializableEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector2 getVelocity() {
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
public void drawUnder(){}
|
public void drawUnder(){}
|
||||||
public void drawOver(){}
|
public void drawOver(){}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ public class UnitInventory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Returns ammo range, or MAX_VALUE if this inventory has no ammo.*/
|
||||||
|
public float getAmmoRange(){
|
||||||
|
return hasAmmo() ? getAmmo().getRange() : Float.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
public AmmoType getAmmo() {
|
public AmmoType getAmmo() {
|
||||||
return ammos.size == 0 ? null : ammos.peek().type;
|
return ammos.size == 0 ? null : ammos.peek().type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,36 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
public class Units {
|
public class Units {
|
||||||
private static Rectangle rect = new Rectangle();
|
private static Rectangle rect = new Rectangle();
|
||||||
|
|
||||||
|
/**Validates a target.
|
||||||
|
* @param target The target to validate
|
||||||
|
* @param team The team of the thing doing tha targeting
|
||||||
|
* @param x The X position of the thing doign the targeting
|
||||||
|
* @param y The Y position of the thing doign the targeting
|
||||||
|
* @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){
|
||||||
|
if(target == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(range != Float.MAX_VALUE && target.distanceTo(x, y) > range){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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){
|
||||||
|
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){
|
||||||
|
return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.inventory.getAmmoRange());
|
||||||
|
}
|
||||||
|
|
||||||
/**Returns whether there are any entities on this tile.*/
|
/**Returns whether there are any entities on this tile.*/
|
||||||
public static boolean anyEntities(Tile tile){
|
public static boolean anyEntities(Tile tile){
|
||||||
Block type = tile.block();
|
Block type = tile.block();
|
||||||
@@ -95,6 +125,16 @@ 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){
|
||||||
|
Unit unit = getClosestEnemy(team, x, y, range, u -> true);
|
||||||
|
if(unit != null){
|
||||||
|
return unit;
|
||||||
|
}else{
|
||||||
|
return findEnemyTile(team, x, y, range, tile -> true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**Returns the closest enemy of this team. Filter by predicate.*/
|
/**Returns the closest enemy of this team. Filter by predicate.*/
|
||||||
public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
||||||
Unit[] result = {null};
|
Unit[] result = {null};
|
||||||
@@ -103,7 +143,7 @@ public class Units {
|
|||||||
rect.setSize(range*2f).setCenter(x, y);
|
rect.setSize(range*2f).setCenter(x, y);
|
||||||
|
|
||||||
getNearbyEnemies(team, rect, e -> {
|
getNearbyEnemies(team, rect, e -> {
|
||||||
if (!predicate.test(e))
|
if (e.isDead() || !predicate.test(e))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float dist = Vector2.dst(e.x, e.y, x, y);
|
float dist = Vector2.dst(e.x, e.y, x, y);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class Bullet extends BulletEntity<BulletType>{
|
|||||||
if (tile == null) return false;
|
if (tile == null) return false;
|
||||||
tile = tile.target();
|
tile = tile.target();
|
||||||
|
|
||||||
if (tile.entity != null && tile.entity.collide(this) && !tile.entity.dead && tile.entity.tile.getTeam() != team) {
|
if (tile.entity != null && tile.entity.collide(this) && !tile.entity.isDead() && tile.entity.tile.getTeam() != team) {
|
||||||
tile.entity.collision(this);
|
tile.entity.collision(this);
|
||||||
remove();
|
remove();
|
||||||
type.hit(this);
|
type.hit(this);
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package io.anuke.mindustry.entities.units;
|
package io.anuke.mindustry.entities.units;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
import io.anuke.mindustry.entities.Targetable;
|
||||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
|
||||||
import io.anuke.mindustry.entities.TileEntity;
|
import io.anuke.mindustry.entities.TileEntity;
|
||||||
import io.anuke.mindustry.entities.Unit;
|
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.game.Team;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.world.BlockFlag;
|
import io.anuke.mindustry.world.BlockFlag;
|
||||||
import io.anuke.ucore.core.Effects;
|
import io.anuke.ucore.core.Effects;
|
||||||
import io.anuke.ucore.core.Effects.Effect;
|
import io.anuke.ucore.core.Effects.Effect;
|
||||||
import io.anuke.ucore.entities.Entity;
|
|
||||||
import io.anuke.ucore.util.Angles;
|
import io.anuke.ucore.util.Angles;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
import io.anuke.ucore.util.Timer;
|
import io.anuke.ucore.util.Timer;
|
||||||
@@ -26,7 +26,7 @@ public class BaseUnit extends Unit{
|
|||||||
public Timer timer = new Timer(5);
|
public Timer timer = new Timer(5);
|
||||||
public float walkTime = 0f;
|
public float walkTime = 0f;
|
||||||
public StateMachine state = new StateMachine();
|
public StateMachine state = new StateMachine();
|
||||||
public Entity target;
|
public Targetable target;
|
||||||
|
|
||||||
public BaseUnit(UnitType type, Team team){
|
public BaseUnit(UnitType type, Team team){
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.units;
|
package io.anuke.mindustry.entities.units;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.TileEntity;
|
|
||||||
import io.anuke.mindustry.entities.Unit;
|
import io.anuke.mindustry.entities.Unit;
|
||||||
import io.anuke.mindustry.entities.Units;
|
import io.anuke.mindustry.entities.Units;
|
||||||
import io.anuke.mindustry.type.AmmoType;
|
import io.anuke.mindustry.type.AmmoType;
|
||||||
@@ -59,7 +58,7 @@ public class FlyingUnitType extends UnitType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void circle(BaseUnit unit, float circleLength){
|
protected void circle(BaseUnit unit, float circleLength){
|
||||||
vec.set(unit.target.x - unit.x, unit.target.y - unit.y);
|
vec.set(unit.target.getX() - unit.x, unit.target.getY() - unit.y);
|
||||||
|
|
||||||
if(vec.len() < circleLength){
|
if(vec.len() < circleLength){
|
||||||
vec.rotate((circleLength-vec.len())/circleLength * 180f);
|
vec.rotate((circleLength-vec.len())/circleLength * 180f);
|
||||||
@@ -71,7 +70,7 @@ public class FlyingUnitType extends UnitType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void attack(BaseUnit unit, float circleLength){
|
protected void attack(BaseUnit unit, float circleLength){
|
||||||
vec.set(unit.target.x - unit.x, unit.target.y - unit.y);
|
vec.set(unit.target.getX() - unit.x, unit.target.getY() - unit.y);
|
||||||
|
|
||||||
float ang = unit.angleTo(unit.target);
|
float ang = unit.angleTo(unit.target);
|
||||||
float diff = Angles.angleDist(ang, unit.rotation);
|
float diff = Angles.angleDist(ang, unit.rotation);
|
||||||
@@ -113,8 +112,7 @@ public class FlyingUnitType extends UnitType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update(BaseUnit unit) {
|
public void update(BaseUnit unit) {
|
||||||
if(unit.target != null && (unit.target instanceof TileEntity &&
|
if(Units.invalidateTarget(unit.target, unit.team, unit.x, unit.y)){
|
||||||
(((TileEntity)unit.target).tile.getTeam() == unit.team || !((TileEntity)unit.target).tile.breakable()))){
|
|
||||||
unit.target = null;
|
unit.target = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,7 @@ public abstract class GroundUnitType extends UnitType{
|
|||||||
public void updateTargeting(BaseUnit unit) {
|
public void updateTargeting(BaseUnit unit) {
|
||||||
super.updateTargeting(unit);
|
super.updateTargeting(unit);
|
||||||
|
|
||||||
if(unit.target != null && unit.inventory.hasAmmo() &&
|
if(Units.invalidateTarget(unit.target, unit)){
|
||||||
!(unit.target instanceof TileEntity) && unit.target.distanceTo(unit) > unit.inventory.getAmmo().getRange()){
|
|
||||||
unit.target = null;
|
unit.target = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class Drone extends FlyingUnitType {
|
|||||||
Shapes.laser("beam", "beam-end",
|
Shapes.laser("beam", "beam-end",
|
||||||
unit.x + Angles.trnsx(unit.rotation, len),
|
unit.x + Angles.trnsx(unit.rotation, len),
|
||||||
unit.y + Angles.trnsy(unit.rotation, len),
|
unit.y + Angles.trnsy(unit.rotation, len),
|
||||||
unit.target.x, unit.target.y);
|
unit.target.getX(), unit.target.getY());
|
||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class OverlayRenderer {
|
|||||||
Shaders.outline.color.set(Palette.accent);
|
Shaders.outline.color.set(Palette.accent);
|
||||||
Graphics.beginShaders(Shaders.outline);
|
Graphics.beginShaders(Shaders.outline);
|
||||||
|
|
||||||
input.drawBottom();
|
input.drawOutlined();
|
||||||
|
|
||||||
Graphics.endShaders();
|
Graphics.endShaders();
|
||||||
}
|
}
|
||||||
|
|||||||
53
core/src/io/anuke/mindustry/graphics/Trail.java
Normal file
53
core/src/io/anuke/mindustry/graphics/Trail.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package io.anuke.mindustry.graphics;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.utils.FloatArray;
|
||||||
|
import io.anuke.ucore.graphics.Draw;
|
||||||
|
import io.anuke.ucore.graphics.Fill;
|
||||||
|
import io.anuke.ucore.graphics.Lines;
|
||||||
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
|
/**Class that renders a trail.*/
|
||||||
|
public class Trail {
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
private FloatArray points = new FloatArray();
|
||||||
|
|
||||||
|
public Trail(int length){
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(float curx, float cury){
|
||||||
|
points.add(curx, cury);
|
||||||
|
|
||||||
|
if(points.size > length*2) {
|
||||||
|
float[] items = points.items;
|
||||||
|
System.arraycopy(items, 2, items, 0, points.size - 2);
|
||||||
|
points.size -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(Color start, Color end, float stroke){
|
||||||
|
|
||||||
|
for(int i = 0; i < points.size - 2; i += 2){
|
||||||
|
float x = points.get(i);
|
||||||
|
float y = points.get(i + 1);
|
||||||
|
float x2 = points.get(i + 2);
|
||||||
|
float y2 = points.get(i + 3);
|
||||||
|
float s = Mathf.clamp((float)(i) / points.size);
|
||||||
|
|
||||||
|
Draw.color(start, end, s);
|
||||||
|
|
||||||
|
Lines.stroke(s * stroke);
|
||||||
|
Lines.line(x, y, x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(points.size >= 2){
|
||||||
|
Fill.circle(points.get(points.size-2), points.get(points.size-1), stroke/2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw.color(start);
|
||||||
|
|
||||||
|
Draw.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color;
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import com.badlogic.gdx.input.GestureDetector;
|
import com.badlogic.gdx.input.GestureDetector;
|
||||||
import com.badlogic.gdx.input.GestureDetector.GestureListener;
|
import com.badlogic.gdx.input.GestureDetector.GestureListener;
|
||||||
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import com.badlogic.gdx.utils.Align;
|
import com.badlogic.gdx.utils.Align;
|
||||||
@@ -13,6 +14,9 @@ import io.anuke.mindustry.content.blocks.Blocks;
|
|||||||
import io.anuke.mindustry.content.fx.Fx;
|
import io.anuke.mindustry.content.fx.Fx;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
|
import io.anuke.mindustry.entities.Targetable;
|
||||||
|
import io.anuke.mindustry.entities.Unit;
|
||||||
|
import io.anuke.mindustry.entities.Units;
|
||||||
import io.anuke.mindustry.graphics.Palette;
|
import io.anuke.mindustry.graphics.Palette;
|
||||||
import io.anuke.mindustry.graphics.Shaders;
|
import io.anuke.mindustry.graphics.Shaders;
|
||||||
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
|
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
|
||||||
@@ -20,16 +24,12 @@ import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
|
|||||||
import io.anuke.mindustry.type.Recipe;
|
import io.anuke.mindustry.type.Recipe;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.ucore.core.Core;
|
import io.anuke.ucore.core.*;
|
||||||
import io.anuke.ucore.core.Effects;
|
|
||||||
import io.anuke.ucore.core.Graphics;
|
|
||||||
import io.anuke.ucore.core.Inputs;
|
|
||||||
import io.anuke.ucore.graphics.Draw;
|
import io.anuke.ucore.graphics.Draw;
|
||||||
import io.anuke.ucore.graphics.Lines;
|
import io.anuke.ucore.graphics.Lines;
|
||||||
import io.anuke.ucore.scene.Group;
|
import io.anuke.ucore.scene.Group;
|
||||||
import io.anuke.ucore.scene.builders.imagebutton;
|
import io.anuke.ucore.scene.builders.imagebutton;
|
||||||
import io.anuke.ucore.scene.builders.table;
|
import io.anuke.ucore.scene.builders.table;
|
||||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
@@ -41,7 +41,7 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
/**Maximum speed the player can pan.*/
|
/**Maximum speed the player can pan.*/
|
||||||
private static final float maxPanSpeed = 1.3f;
|
private static final float maxPanSpeed = 1.3f;
|
||||||
/**Distance to edge of screen to start panning.*/
|
/**Distance to edge of screen to start panning.*/
|
||||||
private final float edgePan = Unit.dp.scl(60f);
|
private final float edgePan = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(60f);
|
||||||
|
|
||||||
//gesture data
|
//gesture data
|
||||||
private Vector2 pinch1 = new Vector2(-1, -1), pinch2 = pinch1.cpy();
|
private Vector2 pinch1 = new Vector2(-1, -1), pinch2 = pinch1.cpy();
|
||||||
@@ -54,6 +54,9 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
/**Animation scale for line.*/
|
/**Animation scale for line.*/
|
||||||
private float lineScale;
|
private float lineScale;
|
||||||
|
/**Animation data for crosshair.*/
|
||||||
|
private float crosshairScale;
|
||||||
|
private Targetable lastTarget;
|
||||||
|
|
||||||
/**List of currently selected tiles to place.*/
|
/**List of currently selected tiles to place.*/
|
||||||
private Array<PlaceRequest> selection = new Array<>();
|
private Array<PlaceRequest> selection = new Array<>();
|
||||||
@@ -73,6 +76,24 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
Inputs.addProcessor(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
|
Inputs.addProcessor(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//region utility methods
|
||||||
|
|
||||||
|
/**Check and assign targets for a specific position.*/
|
||||||
|
void checkTargets(float x, float y){
|
||||||
|
Unit unit = Units.getClosestEnemy(player.team, x, y, 20f, u -> true);
|
||||||
|
|
||||||
|
if(unit != null){
|
||||||
|
player.target = unit;
|
||||||
|
}else{
|
||||||
|
Tile tile = world.tileWorld(x, y);
|
||||||
|
if(tile != null) tile = tile.target();
|
||||||
|
|
||||||
|
if(tile != null && state.teams.areEnemies(player.team, tile.getTeam())){
|
||||||
|
player.target = tile.entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**Returns whether this tile is in the list of requests, or at least colliding with one.*/
|
/**Returns whether this tile is in the list of requests, or at least colliding with one.*/
|
||||||
boolean hasRequest(Tile tile){
|
boolean hasRequest(Tile tile){
|
||||||
return getRequest(tile) != null;
|
return getRequest(tile) != null;
|
||||||
@@ -156,6 +177,10 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region UI and drawing
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildUI(Group group) {
|
public void buildUI(Group group) {
|
||||||
|
|
||||||
@@ -217,11 +242,11 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDrawing(){
|
public boolean isDrawing(){
|
||||||
return selection.size > 0 || removals.size > 0;
|
return selection.size > 0 || removals.size > 0 || lineMode || player.target != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawBottom(){
|
public void drawOutlined(){
|
||||||
|
|
||||||
Shaders.mix.color.set(Palette.accent);
|
Shaders.mix.color.set(Palette.accent);
|
||||||
Graphics.shader(Shaders.mix);
|
Graphics.shader(Shaders.mix);
|
||||||
@@ -321,9 +346,31 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw.color();
|
//draw targeting crosshair
|
||||||
|
if(player.target != null){
|
||||||
|
if(player.target != lastTarget){
|
||||||
|
crosshairScale = 0f;
|
||||||
|
lastTarget = player.target;
|
||||||
|
}
|
||||||
|
|
||||||
|
crosshairScale = Mathf.lerpDelta(crosshairScale, 1f, 0.2f);
|
||||||
|
|
||||||
|
Draw.color(Palette.remove);
|
||||||
|
Lines.stroke(1f);
|
||||||
|
|
||||||
|
float radius = Interpolation.swingIn.apply(crosshairScale);
|
||||||
|
|
||||||
|
Lines.poly(player.target.getX(), player.target.getY(), 4, 7f * radius, Timers.time()*1.5f);
|
||||||
|
Lines.spikes(player.target.getX(), player.target.getY(), 3f * radius, 6f * radius, 4, Timers.time()*1.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region input events
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean touchDown(int screenX, int screenY, int pointer, int button){
|
public boolean touchDown(int screenX, int screenY, int pointer, int button){
|
||||||
if(state.is(State.menu)) return false;
|
if(state.is(State.menu)) return false;
|
||||||
@@ -432,6 +479,8 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
public boolean tap(float x, float y, int count, int button) {
|
public boolean tap(float x, float y, int count, int button) {
|
||||||
if(state.is(State.menu) || lineMode) return false;
|
if(state.is(State.menu) || lineMode) return false;
|
||||||
|
|
||||||
|
checkTargets(Graphics.world(x, y).x, Graphics.world(x, y).y);
|
||||||
|
|
||||||
//get tile on cursor
|
//get tile on cursor
|
||||||
Tile cursor = tileAt(x, y);
|
Tile cursor = tileAt(x, y);
|
||||||
|
|
||||||
@@ -502,9 +551,9 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
vector.set(panX, panY).scl((Core.camera.viewportWidth * Core.camera.zoom) / Gdx.graphics.getWidth());
|
vector.set(panX, panY).scl((Core.camera.viewportWidth * Core.camera.zoom) / Gdx.graphics.getWidth());
|
||||||
vector.limit(maxPanSpeed);
|
vector.limit(maxPanSpeed);
|
||||||
|
|
||||||
player.x += vector.x;
|
//pan view
|
||||||
player.y += vector.y;
|
Core.camera.position.x += vector.x;
|
||||||
player.targetAngle = vector.angle();
|
Core.camera.position.y += vector.y;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
lineScale = 0f;
|
lineScale = 0f;
|
||||||
@@ -540,9 +589,8 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
//pan player
|
//pan player
|
||||||
player.x -= dx;
|
Core.camera.position.x -= dx;
|
||||||
player.y += dy;
|
Core.camera.position.y += dy;
|
||||||
player.targetAngle = Mathf.atan2(dx, -dy) + 180f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -577,9 +625,9 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
initzoom = initialDistance;
|
initzoom = initialDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Math.abs(distance - initzoom) > Unit.dp.scl(100f) && !zoomed){
|
if(Math.abs(distance - initzoom) > io.anuke.ucore.scene.ui.layout.Unit.dp.scl(100f) && !zoomed){
|
||||||
int amount = (distance > initzoom ? 1 : -1);
|
int amount = (distance > initzoom ? 1 : -1);
|
||||||
renderer.scaleCamera(Math.round(Unit.dp.scl(amount)));
|
renderer.scaleCamera(Math.round(io.anuke.ucore.scene.ui.layout.Unit.dp.scl(amount)));
|
||||||
initzoom = distance;
|
initzoom = distance;
|
||||||
zoomed = true;
|
zoomed = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -598,6 +646,8 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
|||||||
@Override public boolean touchDown(float x, float y, int pointer, int button) { return false; }
|
@Override public boolean touchDown(float x, float y, int pointer, int button) { return false; }
|
||||||
@Override public boolean fling(float velocityX, float velocityY, int button) { return false; }
|
@Override public boolean fling(float velocityX, float velocityY, int button) { return false; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
class PlaceRequest{
|
class PlaceRequest{
|
||||||
float x, y;
|
float x, y;
|
||||||
Recipe recipe;
|
Recipe recipe;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawBottom(){
|
public void drawOutlined(){
|
||||||
Tile cursor = tileAt(control.gdxInput().getX(), control.gdxInput().getY());
|
Tile cursor = tileAt(control.gdxInput().getX(), control.gdxInput().getY());
|
||||||
|
|
||||||
if(cursor == null) return;
|
if(cursor == null) return;
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawBottom(){
|
public void drawOutlined(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package io.anuke.mindustry.type;
|
package io.anuke.mindustry.type;
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.ObjectMap;
|
import com.badlogic.gdx.utils.ObjectMap;
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.content.fx.Fx;
|
import io.anuke.mindustry.content.fx.Fx;
|
||||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
import io.anuke.mindustry.entities.Unit;
|
import io.anuke.mindustry.entities.Unit;
|
||||||
|
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.net.NetEvents;
|
import io.anuke.mindustry.net.NetEvents;
|
||||||
import io.anuke.ucore.core.Effects;
|
import io.anuke.ucore.core.Effects;
|
||||||
import io.anuke.ucore.core.Effects.Effect;
|
import io.anuke.ucore.core.Effects.Effect;
|
||||||
import io.anuke.ucore.core.Graphics;
|
|
||||||
import io.anuke.ucore.util.Angles;
|
import io.anuke.ucore.util.Angles;
|
||||||
import io.anuke.ucore.util.Bits;
|
import io.anuke.ucore.util.Bits;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
@@ -44,7 +42,7 @@ public class Weapon extends Upgrade {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(Player p, boolean left){
|
public void update(Player p, boolean left, float pointerX, float pointerY){
|
||||||
int t = left ? 1 : 2;
|
int t = left ? 1 : 2;
|
||||||
int t2 = !left ? 1 : 2;
|
int t2 = !left ? 1 : 2;
|
||||||
if(p.inventory.hasAmmo() && p.timer.get(t, reload)){
|
if(p.inventory.hasAmmo() && p.timer.get(t, reload)){
|
||||||
@@ -52,8 +50,7 @@ public class Weapon extends Upgrade {
|
|||||||
p.timer.reset(t2, reload/2f);
|
p.timer.reset(t2, reload/2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.set(Graphics.world(Vars.control.input(p.playerIndex).getMouseX(),
|
tr.set(pointerX, pointerY).sub(p.x, p.y);
|
||||||
Vars.control.input(p.playerIndex).getMouseY())).sub(p.x, p.y);
|
|
||||||
if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist);
|
if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist);
|
||||||
|
|
||||||
float cx = tr.x + p.x, cy = tr.y + p.y;
|
float cx = tr.x + p.x, cy = tr.y + p.y;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class RepairTurret extends PowerTurret {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(entity.blockTarget != null && entity.blockTarget.dead){
|
if(entity.blockTarget != null && entity.blockTarget.isDead()){
|
||||||
entity.blockTarget = null;
|
entity.blockTarget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public abstract class Turret extends Block{
|
|||||||
super.setStats();
|
super.setStats();
|
||||||
/*
|
/*
|
||||||
if(ammo != null) stats.add("ammo", ammo);
|
if(ammo != null) stats.add("ammo", ammo);
|
||||||
if(ammo != null) stats.add("ammocapacity", maxammo);
|
if(ammo != null) stats.add("ammocapacity", maxAmmo);
|
||||||
if(ammo != null) stats.add("ammoitem", ammoMultiplier);*/
|
if(ammo != null) stats.add("ammoitem", ammoMultiplier);*/
|
||||||
stats.add("range", (int)range);
|
stats.add("range", (int)range);
|
||||||
stats.add("inaccuracy", (int)inaccuracy);
|
stats.add("inaccuracy", (int)inaccuracy);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.anuke.mindustry.world.blocks.types.defense.turrets;
|
package io.anuke.mindustry.world.blocks.types.defense.turrets;
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.ObjectMap;
|
import com.badlogic.gdx.utils.ObjectMap;
|
||||||
|
import io.anuke.mindustry.entities.Unit;
|
||||||
import io.anuke.mindustry.type.AmmoEntry;
|
import io.anuke.mindustry.type.AmmoEntry;
|
||||||
import io.anuke.mindustry.type.AmmoType;
|
import io.anuke.mindustry.type.AmmoType;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
@@ -10,7 +11,7 @@ import io.anuke.mindustry.world.Tile;
|
|||||||
import io.anuke.mindustry.world.blocks.types.defense.Turret;
|
import io.anuke.mindustry.world.blocks.types.defense.Turret;
|
||||||
|
|
||||||
public class ItemTurret extends Turret {
|
public class ItemTurret extends Turret {
|
||||||
protected int maxammo = 100;
|
protected int maxAmmo = 100;
|
||||||
//TODO implement this!
|
//TODO implement this!
|
||||||
/**A value of 'null' means this turret does not need ammo.*/
|
/**A value of 'null' means this turret does not need ammo.*/
|
||||||
protected AmmoType[] ammoTypes;
|
protected AmmoType[] ammoTypes;
|
||||||
@@ -18,6 +19,24 @@ public class ItemTurret extends Turret {
|
|||||||
|
|
||||||
public ItemTurret(String name) {
|
public ItemTurret(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
hasItems = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int acceptStack(Item item, int amount, Tile tile, Unit source) {
|
||||||
|
TurretEntity entity = tile.entity();
|
||||||
|
|
||||||
|
AmmoType type = ammoMap.get(item);
|
||||||
|
|
||||||
|
if(type == null) return 0;
|
||||||
|
|
||||||
|
return Math.min((int)((maxAmmo - entity.totalAmmo) / ammoMap.get(item).quantityMultiplier), amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//currently can't remove items from turrets.
|
||||||
|
@Override
|
||||||
|
public int removeStack(Tile tile, Item item, int amount) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -26,6 +45,7 @@ public class ItemTurret extends Turret {
|
|||||||
|
|
||||||
AmmoType type = ammoMap.get(item);
|
AmmoType type = ammoMap.get(item);
|
||||||
entity.totalAmmo += type.quantityMultiplier;
|
entity.totalAmmo += type.quantityMultiplier;
|
||||||
|
entity.items.addItem(item, 1);
|
||||||
|
|
||||||
//find ammo entry by type
|
//find ammo entry by type
|
||||||
for(int i = 0; i < entity.ammo.size; i ++){
|
for(int i = 0; i < entity.ammo.size; i ++){
|
||||||
@@ -48,12 +68,12 @@ public class ItemTurret extends Turret {
|
|||||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||||
TurretEntity entity = tile.entity();
|
TurretEntity entity = tile.entity();
|
||||||
|
|
||||||
return ammoMap != null && ammoMap.get(item) != null && entity.totalAmmo + ammoMap.get(item).quantityMultiplier <= maxammo;
|
return ammoMap != null && ammoMap.get(item) != null && entity.totalAmmo + ammoMap.get(item).quantityMultiplier <= maxAmmo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBars(){
|
public void setBars(){
|
||||||
bars.add(new BlockBar(BarType.inventory, true, tile -> (float)tile.<TurretEntity>entity().totalAmmo / maxammo));
|
bars.replace(new BlockBar(BarType.inventory, true, tile -> (float)tile.<TurretEntity>entity().totalAmmo / maxAmmo));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user