Improvements to playability at low TPS

This commit is contained in:
Anuken 2018-06-20 15:06:53 -04:00
parent 0c7f6432d8
commit 2884e4b847
6 changed files with 114 additions and 46 deletions

View File

@ -6,10 +6,7 @@ import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.Pools;
import com.badlogic.gdx.utils.*;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
@ -20,8 +17,8 @@ import io.anuke.mindustry.entities.traits.BelowLiquidTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Graphics;
@ -30,7 +27,11 @@ import io.anuke.ucore.entities.EntityDraw;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.entities.impl.EffectEntity;
import io.anuke.ucore.entities.trait.DrawTrait;
import io.anuke.ucore.entities.trait.SolidTrait;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.graphics.Lines;
@ -38,6 +39,7 @@ import io.anuke.ucore.graphics.Surface;
import io.anuke.ucore.modules.RendererModule;
import io.anuke.ucore.scene.utils.Cursors;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.ucore.core.Core.batch;
@ -51,7 +53,9 @@ public class Renderer extends RendererModule{
private FloatArray shieldHits = new FloatArray();
private Array<Callable> shieldDraws = new Array<>();
private Rectangle rect = new Rectangle(), rect2 = new Rectangle();
private Vector2 avgPosition = new Vector2();
private Vector2 avgPosition = new Translator();
private Vector2 tmpVector1 = new Translator();
private Vector2 tmpVector2 = new Translator();
private BlockRenderer blocks = new BlockRenderer();
private MinimapRenderer minimap = new MinimapRenderer();
private OverlayRenderer overlays = new OverlayRenderer();
@ -196,9 +200,9 @@ public class Renderer extends RendererModule{
blocks.drawFloor();
EntityDraw.draw(groundEffectGroup, e -> e instanceof BelowLiquidTrait);
EntityDraw.draw(puddleGroup);
EntityDraw.draw(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait));
drawAndInterpolate(groundEffectGroup, e -> e instanceof BelowLiquidTrait);
drawAndInterpolate(puddleGroup);
drawAndInterpolate(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait));
blocks.processBlocks();
blocks.drawBlocks(Layer.block);
@ -213,7 +217,7 @@ public class Renderer extends RendererModule{
Shaders.outline.color.set(Team.none.color);
Graphics.beginShaders(Shaders.outline);
EntityDraw.draw(itemGroup);
drawAndInterpolate(itemGroup);
Graphics.endShaders();
}
@ -224,12 +228,12 @@ public class Renderer extends RendererModule{
overlays.drawBottom();
EntityDraw.drawWith(playerGroup, p -> true, Player::drawBuildRequests);
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
drawAllTeams(true);
EntityDraw.draw(bulletGroup);
EntityDraw.draw(effectGroup);
drawAndInterpolate(bulletGroup);
drawAndInterpolate(effectGroup);
overlays.drawTop();
@ -238,7 +242,7 @@ public class Renderer extends RendererModule{
if(showPaths && debug) drawDebug();
EntityDraw.drawWith(playerGroup, p -> !p.isLocal && !p.isDead(), Player::drawName);
drawAndInterpolate(playerGroup, p -> !p.isLocal && !p.isDead(), Player::drawName);
batch.end();
}
@ -250,25 +254,66 @@ public class Renderer extends RendererModule{
if(group.count(p -> p.isFlying() == flying) +
playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue;
EntityDraw.drawWith(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawUnder);
EntityDraw.drawWith(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder);
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawUnder);
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder);
Shaders.outline.color.set(team.color);
Shaders.mix.color.set(Color.WHITE);
Graphics.beginShaders(Shaders.outline);
Graphics.shader(Shaders.mix, true);
EntityDraw.draw(unitGroups[team.ordinal()], u -> u.isFlying() == flying);
EntityDraw.draw(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team);
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying);
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team);
Graphics.shader();
blocks.drawTeamBlocks(Layer.turret, team);
Graphics.endShaders();
EntityDraw.drawWith(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawOver);
EntityDraw.drawWith(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver);
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawOver);
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver);
}
}
private <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group){
drawAndInterpolate(group, t -> true, DrawTrait::draw);
}
private <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw){
drawAndInterpolate(group, toDraw, DrawTrait::draw);
}
private <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){
EntityDraw.drawWith(group, toDraw, t -> {
float lastx = t.getX(), lasty = t.getY(), lastrot = 0f;
if(threads.doInterpolate() && threads.isEnabled() && t instanceof SolidTrait){
SolidTrait s = (SolidTrait)t;
lastrot = s.getRotation();
if(s.lastUpdated() != 0){
float timeSinceUpdate = TimeUtils.timeSinceMillis(s.lastUpdated());
float alpha = Math.min(timeSinceUpdate / s.updateSpacing(), 1f);
tmpVector1.set(s.lastPosition().x, s.lastPosition().y)
.lerp(tmpVector2.set(lastx, lasty), alpha);
s.setRotation(Mathf.slerp(s.lastPosition().z, lastrot, alpha));
s.set(tmpVector1.x, tmpVector1.y);
}
}
drawer.accept(t);
if(threads.doInterpolate() && threads.isEnabled()) {
t.set(lastx, lasty);
if (t instanceof SolidTrait) {
((SolidTrait) t).setRotation(lastrot);
}
}
});
}
@Override
public void resize(int width, int height){
super.resize(width, height);
@ -285,9 +330,11 @@ public class Renderer extends RendererModule{
public Vector2 averagePosition(){
avgPosition.setZero();
for(Player player : players){
avgPosition.add(player.x, player.y);
}
drawAndInterpolate(playerGroup, p -> p.isLocal, p -> {
avgPosition.add(p.x, p.y);
});
avgPosition.scl(1f / players.length);
return avgPosition;
}

View File

@ -111,6 +111,10 @@ public class ThreadHandler {
return enabled;
}
public boolean doInterpolate(){
return enabled && Math.abs(Gdx.graphics.getFramesPerSecond() - getFPS()) > 15;
}
public boolean isOnThread(){
return impl.isOnThread();
}
@ -118,7 +122,7 @@ public class ThreadHandler {
private void runLogic(){
try {
while (true) {
long time = TimeUtils.millis();
long time = TimeUtils.nanoTime();
synchronized (toRun) {
for(Runnable r : toRun){
@ -131,8 +135,8 @@ public class ThreadHandler {
logic.update();
logic.doUpdate = false;
long elapsed = TimeUtils.timeSinceMillis(time);
long target = (long) (1000 / 60f);
long elapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time));
long target = (long) ((1000) / 60f);
delta = Math.max(elapsed, target) / 1000f * 60f;

View File

@ -41,8 +41,6 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Player extends Unit implements BuilderTrait, CarryTrait {
private static final Vector2 movement = new Vector2();
public static int typeID = -1;
public static final int timerShootLeft = 0;
@ -73,6 +71,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
private Tile mining;
private CarriableTrait carrying;
private Trail trail = new Trail(16);
private Vector2 movement = new Vector2();
private boolean moved;
public Player(){
hitbox.setSize(5);
@ -242,13 +242,18 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
@Override
public float drawSize() {
return 40;
return isLocal ? Float.MAX_VALUE : 40;
}
@Override
public void draw(){
if((debug && (!showPlayer || !showUI)) || dead) return;
if(!movement.isZero() && moved){
walktime += Timers.delta() * movement.len()/1.6f * getFloorOn().speedMultiplier;
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
}
boolean snap = snapCamera && isLocal;
float px = x, py =y;
@ -491,12 +496,9 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
velocity.add(movement);
float prex = x, prey = y;
updateVelocityStatus(mech.drag, debug ? speed : mech.maxSpeed);
if(!movement.isZero()){
walktime += Timers.delta() * velocity.len()*(1f/0.5f)/speed * getFloorOn().speedMultiplier;
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
}
moved = distanceTo(prex, prey) > 0.01f;
if(!isShooting()){
if(!movement.isZero()) {

View File

@ -51,6 +51,16 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
protected float hitTime;
protected float drownTime;
@Override
public float getRotation() {
return rotation;
}
@Override
public void setRotation(float rotation) {
this.rotation = rotation;
}
@Override
public void setCarrier(CarryTrait carrier) {
this.carrier = carrier;

View File

@ -2,6 +2,7 @@ package io.anuke.mindustry.entities.bullet;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Pools;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.entities.Unit;
@ -10,6 +11,7 @@ import io.anuke.mindustry.entities.traits.TeamTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.In;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.BulletEntity;
import io.anuke.ucore.entities.trait.Entity;
@ -59,7 +61,15 @@ public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncT
bullet.team = team;
bullet.type = type;
bullet.set(x, y);
//translate bullets backwards, purely for visual reasons
float backDelta = Timers.delta();
bullet.lastPosition().set(x-bullet.velocity.x * backDelta, y-bullet.velocity.y * backDelta, bullet.angle());
bullet.setLastUpdated(TimeUtils.millis());
bullet.setUpdateSpacing((long)((Timers.delta() / 60f) * 1000));
bullet.set(x-bullet.velocity.x * backDelta, y-bullet.velocity.y * backDelta);
bullet.add();
}

View File

@ -1,12 +1,10 @@
package io.anuke.mindustry.entities.units;
import com.badlogic.gdx.math.Vector2;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.content.fx.ExplosionFx;
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.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
@ -20,7 +18,10 @@ import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
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.DataInput;
import java.io.DataOutput;
@ -30,7 +31,6 @@ import static io.anuke.mindustry.Vars.*;
public abstract class BaseUnit extends Unit{
private static int timerIndex = 0;
private static Vector2 moveVector = new Translator();
protected static final int timerTarget = timerIndex++;
protected static final int timerReload = timerIndex++;
@ -113,7 +113,7 @@ public abstract class BaseUnit extends Unit{
public void targetClosest(){
if(target != null) return;
target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange());
//target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange());
}
public UnitState getStartState(){
@ -236,11 +236,6 @@ public abstract class BaseUnit extends Unit{
CallEntity.onUnitDeath(this);
}
@Override
public boolean collidesOthers() {
return !isFlying();
}
@Override
public void added(){
hitbox.setSize(type.hitsize);