Implemented passable liquids

This commit is contained in:
Anuken 2018-04-07 23:24:33 -04:00
parent 117e2e2cb6
commit 98ec2dcf44
18 changed files with 265 additions and 94 deletions

Binary file not shown.

View File

@ -1,5 +1,5 @@
#Autogenerated file. Do not modify.
#Sat Apr 07 20:46:33 EDT 2018
#Sat Apr 07 23:21:47 EDT 2018
version=release
androidBuildCode=870
name=Mindustry

View File

@ -144,7 +144,7 @@ public class Vars{
public static final EntityGroup<Bullet> bulletGroup = Entities.addGroup(Bullet.class);
public static final EntityGroup<Shield> shieldGroup = Entities.addGroup(Shield.class, false);
public static final EntityGroup<EffectEntity> effectGroup = Entities.addGroup(EffectEntity.class, false);
public static final EntityGroup<EffectEntity> staticEffectGroup = Entities.addGroup(EffectEntity.class, false);
public static final EntityGroup<EffectEntity> groundEffectGroup = Entities.addGroup(EffectEntity.class, false);
public static final EntityGroup<BaseUnit>[] unitGroups = new EntityGroup[Team.values().length];
static{

View File

@ -21,7 +21,7 @@ public class StatusEffects {
@Override
public TransitionResult getTransition(Unit unit, StatusEffect to, float time, float newTime, TransitionResult result){
if(to == oiled){
unit.damage(1f, false);
unit.damage(1f);
Effects.effect(EnvironmentFx.burning, unit.x + Mathf.range(unit.getSize()/2f), unit.y + Mathf.range(unit.getSize()/2f));
return result.set(this, Math.min(time + newTime, baseDuration + oiled.baseDuration));
}
@ -31,7 +31,7 @@ public class StatusEffects {
@Override
public void update(Unit unit, float time){
unit.damage(0.04f * Timers.delta(), false);
unit.damagePeriodic(0.04f);
if(Mathf.chance(Timers.delta() * 0.2f)){
Effects.effect(EnvironmentFx.burning, unit.x + Mathf.range(unit.getSize()/2f), unit.y + Mathf.range(unit.getSize()/2f));
@ -87,7 +87,7 @@ public class StatusEffects {
@Override
public void update(Unit unit, float time){
unit.velocity.scl(0.8f);
unit.damage(0.1f * Timers.delta(), false);
unit.damagePeriodic(0.1f);
if(Mathf.chance(Timers.delta() * 0.2f)){
Effects.effect(EnvironmentFx.melting, unit.x + Mathf.range(unit.getSize()/2f), unit.y + Mathf.range(unit.getSize()/2f));

View File

@ -1,7 +1,9 @@
package io.anuke.mindustry.content.blocks;
import com.badlogic.gdx.graphics.Color;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.Liquids;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.graphics.DrawLayer;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.world.Block;
@ -21,6 +23,9 @@ public class Blocks {
blockpart = new BlockPart(),
defaultFloor = new Floor("defaultfloor") {{
}},
space = new Floor("space") {{
variants = 0;
drawLayer = DrawLayer.space;
@ -32,32 +37,46 @@ public class Blocks {
}},
deepwater = new Floor("deepwater") {{
liquidColor = Color.valueOf("546bb3");
speedMultiplier = 0.3f;
variants = 0;
solid = true;
liquidDrop = Liquids.water;
liquid = true;
status = StatusEffects.wet;
statusIntensity = 1f;
drownTime = 140f;
drawLayer = DrawLayer.water;
}},
water = new Floor("water") {{
liquidColor = Color.valueOf("546bb3");
speedMultiplier = 0.5f;
variants = 0;
solid = true;
status = StatusEffects.wet;
statusIntensity = 0.9f;
liquidDrop = Liquids.water;
liquid = true;
drawLayer = DrawLayer.water;
}},
lava = new Floor("lava") {{
liquidColor = Color.valueOf("ed5334");
speedMultiplier = 0.2f;
damageTaken = 0.1f;
status = StatusEffects.melting;
statusIntensity = 0.8f;
variants = 0;
solid = true;
liquidDrop = Liquids.lava;
liquid = true;
drawLayer = DrawLayer.lava;
}},
oil = new Floor("oil") {{
liquidColor = Color.valueOf("292929");
status = StatusEffects.oiled;
statusIntensity = 1f;
speedMultiplier = 0.2f;
variants = 0;
solid = true;
liquidDrop = Liquids.oil;
liquid = true;
drawLayer = DrawLayer.oil;

View File

@ -2,13 +2,16 @@ package io.anuke.mindustry.content.fx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Colors;
import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp;
import static io.anuke.mindustry.Vars.tilesize;
@ -251,6 +254,21 @@ public class BlockFx {
Lines.lineAngle(e.x + x, e.y + y, Mathf.atan2(x, y), e.fslope()*4f + 1f);
});
Draw.reset();
}),
ripple = new GroundEffect(false, 30, e -> {
Draw.color(Hue.shift(Tmp.c1.set(e.color), 2, 0.1f));
Lines.stroke(e.fout() + 0.4f);
Lines.circle(e.x, e.y, 2f + e.fin()*4f);
Draw.reset();
}),
bubble = new Effect(20, e -> {
Draw.color(Hue.shift(Tmp.c1.set(e.color), 2, 0.1f));
Lines.stroke(e.fout() + 0.2f);
Angles.randLenVectors(e.id, 3, 11f, (x, y) -> {
Lines.circle(e.x + x, e.y + y, 1f + e.fin() * 3f);
});
Draw.reset();
});
}

View File

@ -1,7 +1,7 @@
package io.anuke.mindustry.content.fx;
import com.badlogic.gdx.graphics.Color;
import io.anuke.mindustry.entities.effect.StaticEffectEntity.StaticEffect;
import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.graphics.Draw;
@ -88,7 +88,7 @@ public class ShootFx {
Draw.reset();
}),
shellEjectSmall = new StaticEffect(30f, 400f, e -> {
shellEjectSmall = new GroundEffect(30f, 400f, e -> {
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
float rot = e.rotation + 90f;
for(int i : Mathf.signs){
@ -103,7 +103,7 @@ public class ShootFx {
Draw.color();
}),
shellEjectMedium = new StaticEffect(34f, 400f, e -> {
shellEjectMedium = new GroundEffect(34f, 400f, e -> {
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
float rot = e.rotation + 90f;
for(int i : Mathf.signs){
@ -126,7 +126,7 @@ public class ShootFx {
Draw.color();
}),
shellEjectBig = new StaticEffect(22f, 400f, e -> {
shellEjectBig = new GroundEffect(22f, 400f, e -> {
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
float rot = e.rotation + 90f;
for(int i : Mathf.signs){

View File

@ -352,7 +352,7 @@ public class Control extends Module{
if(!state.is(State.paused) || Net.active()){
Entities.update(effectGroup);
Entities.update(staticEffectGroup);
Entities.update(groundEffectGroup);
if(respawntime > 0){

View File

@ -13,11 +13,12 @@ import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.entities.effect.StaticEffectEntity;
import io.anuke.mindustry.entities.effect.StaticEffectEntity.StaticEffect;
import io.anuke.mindustry.entities.effect.GroundEffectEntity;
import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.BlockRenderer;
@ -60,17 +61,25 @@ public class Renderer extends RendererModule{
Lines.setCircleVertices(14);
Core.cameraScale = baseCameraScale;
Effects.setEffectProvider((name, color, x, y, rotation) -> {
Effects.setEffectProvider((effect, color, x, y, rotation) -> {
if(effect == Fx.none) return;
if(Settings.getBool("effects")){
Rectangle view = rect.setSize(camera.viewportWidth, camera.viewportHeight)
.setCenter(camera.position.x, camera.position.y);
Rectangle pos = rect2.setSize(name.size).setCenter(x, y);
Rectangle pos = rect2.setSize(effect.size).setCenter(x, y);
if(view.overlaps(pos)){
int id = new EffectEntity(name, color, rotation).set(x, y).add(effectGroup).id;
int id = 0;
if(name instanceof StaticEffect){
new StaticEffectEntity((StaticEffect) name, color, rotation).set(x, y).add(staticEffectGroup).id = id;
if(!(effect instanceof GroundEffect) || ((GroundEffect)effect).isStatic) {
id = new EffectEntity(effect, color, rotation).set(x, y).add(effectGroup).id;
}
if(effect instanceof GroundEffect){
GroundEffectEntity r = new GroundEffectEntity((GroundEffect) effect, color, rotation).set(x, y).add(groundEffectGroup);
if(((GroundEffect)effect).isStatic){
r.id = id;
}
}
}
}
@ -191,7 +200,7 @@ public class Renderer extends RendererModule{
blocks.drawFloor();
Entities.draw(staticEffectGroup);
Entities.draw(groundEffectGroup);
blocks.processBlocks();
blocks.drawBlocks(Layer.overlay);

View File

@ -4,16 +4,16 @@ import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.Weapons;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.resource.Mech;
import io.anuke.mindustry.resource.Upgrade;
import io.anuke.mindustry.resource.Weapon;
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.Inputs;
import io.anuke.ucore.core.Settings;
@ -77,7 +77,7 @@ public class Player extends Unit{
@Override
public boolean isFlying(){
return mech.flying;
return mech.flying || noclip;
}
@Override
@ -87,13 +87,14 @@ public class Player extends Unit{
@Override
public void damage(float amount){
if(debug || mech.flying) return;
//if(debug || mech.flying) return;
hitTime = hitDuration;
health -= amount;
if(health <= 0 && !dead && isLocal){ //remote players don't die normally
onDeath();
dead = true;
if(!debug) {
health -= amount;
if(health <= 0 && !dead && isLocal){ //remote players don't die normally
onDeath();
dead = true;
}
}
}
@ -105,6 +106,7 @@ public class Player extends Unit{
@Override
public void onDeath(){
dead = true;
drownTime = 0f;
if(Net.active()){
NetEvents.handleUnitDeath(this);
}
@ -148,9 +150,16 @@ public class Player extends Unit{
float ft = Mathf.sin(walktime, 6f, 2f);
Floor floor = getFloorOn();
Draw.color();
Draw.alpha(hitTime / hitDuration);
if(!mech.flying) {
if(floor.liquid){
Draw.tint(Color.WHITE, floor.liquidColor, 0.5f);
}
for (int i : Mathf.signs) {
tr.trns(baseRotation, ft * i);
Draw.rect(mname + "-leg", x + tr.x, y + tr.y, 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90);
@ -159,6 +168,12 @@ public class Player extends Unit{
Draw.rect(mname + "-base", x, y,baseRotation- 90);
}
if(floor.liquid) {
Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f);
}else {
Draw.tint(Color.WHITE);
}
Draw.rect(mname, x, y, rotation -90);
for (int i : Mathf.signs) {
@ -202,7 +217,7 @@ public class Player extends Unit{
Tile tile = world.tileWorld(x, y);
//if player is in solid block
if(tile != null && ((tile.floor().liquid && tile.block() == Blocks.air) || tile.solid())){
if(tile != null && tile.solid()){
stucktime += Timers.delta();
}else{
stucktime = 0f;
@ -248,15 +263,12 @@ public class Player extends Unit{
movement.limit(speed);
if(!noclip){
move(movement.x*Timers.delta(), movement.y*Timers.delta());
}else{
x += movement.x*Timers.delta();
y += movement.y*Timers.delta();
}
velocity.add(movement);
updateVelocity(0.4f, speed);
if(!movement.isZero()){
walktime += Timers.delta();
walktime += Timers.delta() * velocity.len()*(1f/0.5f)/speed * getFloorOn().speedMultiplier;
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
}

View File

@ -1,10 +1,17 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.game.Team;
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.util.Mathf;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.world;
public abstract class Unit extends SyncEntity {
//total duration of hit effect
@ -14,6 +21,7 @@ public abstract class Unit extends SyncEntity {
public Team team = Team.blue;
public Vector2 velocity = new Vector2();
public float hitTime;
public float drownTime;
@Override
public void damage(float amount){
@ -26,6 +34,55 @@ public abstract class Unit extends SyncEntity {
return other instanceof Bullet && state.teams.areEnemies((((Bullet) other).team), team);
}
public Floor getFloorOn(){
Tile tile = world.tileWorld(x, y);
return (Floor)(tile == null || (!(tile.floor() instanceof Floor)) ? Blocks.defaultFloor : tile.floor());
}
public void updateVelocity(float drag, float maxVelocity){
Floor floor = getFloorOn();
velocity.limit(maxVelocity);
if(isFlying()) {
x += velocity.x / getMass();
y += velocity.y / getMass();
}else{
if(floor.liquid && velocity.len() > 0.4f && Timers.get(this, "flooreffect", 14 - (velocity.len() * floor.speedMultiplier)*2f)){
Effects.effect(floor.walkEffect, floor.liquidColor, x, y);
}
status.handleApply(this, floor.status, floor.statusIntensity);
if(floor.damageTaken > 0f){
damagePeriodic(floor.damageTaken);
}
if(floor.drownTime > 0){
drownTime += Timers.delta() * 1f/floor.drownTime;
if(Timers.get(this, "drowneffect", 15)){
Effects.effect(floor.drownUpdateEffect, floor.liquidColor, x, y);
}
}else{
drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f);
}
drownTime = Mathf.clamp(drownTime);
if(drownTime >= 1f){
damage(health + 1, false);
}
move(velocity.x / getMass() * floor.speedMultiplier, velocity.y / getMass() * floor.speedMultiplier);
}
velocity.scl(Mathf.clamp(1f-drag* floor.dragMultiplier* Timers.delta()));
}
public void damagePeriodic(float amount){
damage(amount * Timers.delta(), Timers.get(this, "damageeffect", 20));
}
public void damage(float amount, boolean withEffect){
if(withEffect){
damage(amount);

View File

@ -0,0 +1,64 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.graphics.Color;
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.function.EffectRenderer;
import io.anuke.ucore.util.Mathf;
public class GroundEffectEntity extends EffectEntity {
private boolean once;
public GroundEffectEntity(GroundEffect effect, Color color, float rotation) {
super(effect, color, rotation);
}
@Override
public void update(){
GroundEffect effect = (GroundEffect)renderer;
if(effect.isStatic) {
time += Timers.delta();
time = Mathf.clamp(time, 0, effect.staticLife);
if (!once && time >= lifetime) {
once = true;
time = 0f;
} else if (once && time >= effect.staticLife) {
remove();
}
}else{
super.update();
}
}
@Override
public void drawOver(){
GroundEffect effect = (GroundEffect)renderer;
if(once && effect.isStatic)
Effects.renderEffect(id, renderer, color, lifetime, rotation, x, y);
else if(!effect.isStatic)
Effects.renderEffect(id, renderer, color, time, rotation, x, y);
}
public static class GroundEffect extends Effect{
public final float staticLife;
public final boolean isStatic;
public GroundEffect(float life, float staticLife, EffectRenderer draw) {
super(life, draw);
this.staticLife = staticLife;
this.isStatic = false;
}
public GroundEffect(boolean isStatic, float life, EffectRenderer draw) {
super(life, draw);
this.staticLife = 0f;
this.isStatic = isStatic;
}
}
}

View File

@ -1,45 +0,0 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.graphics.Color;
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.function.EffectRenderer;
import io.anuke.ucore.util.Mathf;
public class StaticEffectEntity extends EffectEntity {
private boolean once;
public StaticEffectEntity(StaticEffect effect, Color color, float rotation) {
super(effect, color, rotation);
}
@Override
public void update(){
time += Timers.delta();
time = Mathf.clamp(time, 0, ((StaticEffect)renderer).staticLife);
if(!once && time >= lifetime){
once = true;
time = 0f;
}else if(once && time >= ((StaticEffect)renderer).staticLife){
remove();
}
}
@Override
public void drawOver(){
if(once) Effects.renderEffect(id, renderer, color, lifetime, rotation, x, y);
}
public static class StaticEffect extends Effect{
public final float staticLife;
public StaticEffect(float life, float staticLife, EffectRenderer draw) {
super(life, draw);
this.staticLife = staticLife;
}
}
}

View File

@ -1,13 +1,16 @@
package io.anuke.mindustry.entities.units;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.ObjectSet;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.TeamInfo.TeamData;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
@ -42,11 +45,23 @@ public abstract class GroundUnitType extends UnitType{
float ft = Mathf.sin(walktime, 6f, 2f);
Floor floor = unit.getFloorOn();
if(floor.liquid){
Draw.tint(Hue.mix(Color.WHITE, floor.liquidColor, 0.5f));
}
for (int i : Mathf.signs) {
tr1.trns(unit.baseRotation, ft * i);
Draw.rect(name + "-leg", unit.x + tr1.x, unit.y + tr1.y, 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), unit.baseRotation - 90);
}
if(floor.liquid) {
Draw.tint(Color.WHITE, floor.liquidColor, unit.drownTime * 0.4f);
}else {
Draw.tint(Color.WHITE);
}
Draw.rect(name + "-base", unit.x, unit.y, unit.baseRotation- 90);
Draw.rect(name, unit.x, unit.y, unit.rotation -90);

View File

@ -76,16 +76,7 @@ public abstract class UnitType {
unit.status.update(unit);
unit.velocity.limit(maxVelocity);
if(isFlying) {
unit.x += unit.velocity.x / mass;
unit.y += unit.velocity.y / mass;
}else{
unit.move(unit.velocity.x / mass, unit.velocity.y / mass);
}
unit.velocity.scl(Mathf.clamp(1f-drag* Timers.delta()));
unit.updateVelocity(drag, maxVelocity);
if(unit.target != null) behavior(unit);

View File

@ -145,9 +145,13 @@ public class SettingsMenuDialog extends SettingsDialog{
renderer.pixelSurface.setScale(Core.cameraScale);
renderer.shadowSurface.setScale(Core.cameraScale);
renderer.shieldSurface.setScale(Core.cameraScale);
//Graphics.getEffects1().setScale(Core.cameraScale);
//Graphics.getEffects2().setScale(Core.cameraScale);
}else{
renderer.shadowSurface.setScale(1);
renderer.shieldSurface.setScale(1);
//Graphics.getEffects1().setScale(1);
//Graphics.getEffects2().setScale(1);
}
renderer.setPixelate(b);
});

View File

@ -1,9 +1,14 @@
package io.anuke.mindustry.world.blocks.types;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.entities.StatusEffect;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
@ -14,12 +19,32 @@ public class Floor extends Block{
protected TextureRegion tempRegion = new TextureRegion();
protected Predicate<Block> blends = block -> block != this;
protected boolean blend = true;
public float speedMultiplier = 1f;
public float dragMultiplier = 1f;
public float damageTaken = 0f;
public float drownTime = 0f;
public Effect walkEffect = BlockFx.ripple;
public Effect drownUpdateEffect = BlockFx.bubble;
public StatusEffect status = StatusEffects.none;
public float statusIntensity = 0.6f;
public Color liquidColor;
public Floor(String name) {
super(name);
variants = 3;
}
@Override
public void init(){
super.init();
if(liquid && liquidColor == null){
throw new RuntimeException("All liquids must define a liquidColor! Problematic block: " + name);
}
}
@Override
public void drawNonLayer(Tile tile){
MathUtils.random.setSeed(tile.id());

View File

@ -166,6 +166,8 @@ public class Teleporter extends PowerBlock{
catastrophicFailure(tile);
}
//TODO draw warning info!
if (entity.teleporting) {
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 2f, 0.01f);
float liquidUsed = Math.min(liquidCapacity, liquidUse * Timers.delta());