Implemented puddles of liquid

This commit is contained in:
Anuken
2018-04-16 17:32:35 -04:00
parent 871b6548ab
commit bece87c790
11 changed files with 227 additions and 10 deletions

View File

@@ -11,12 +11,14 @@ public class Liquids {
water = new Liquid("water", Color.valueOf("486acd")) {
{
heatCapacity = 0.4f;
effect = StatusEffects.wet;
}
},
lava = new Liquid("lava", Color.valueOf("e37341")) {
{
temperature = 0.7f;
temperature = 0.8f;
viscosity = 0.8f;
effect = StatusEffects.melting;
}
},
oil = new Liquid("oil", Color.valueOf("313131")) {
@@ -24,12 +26,14 @@ public class Liquids {
viscosity = 0.7f;
flammability = 0.6f;
explosiveness = 0.6f;
effect = StatusEffects.oiled;
}
},
cryofluid = new Liquid("cryofluid", Color.SKY) {
{
heatCapacity = 0.75f;
temperature = 0.5f;
effect = StatusEffects.freezing;
}
};
}

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.content.bullets;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.GridPoint2;
import io.anuke.mindustry.content.Liquids;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.BulletFx;
@@ -8,7 +9,9 @@ import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.Bullet;
import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.effect.DamageArea;
import io.anuke.mindustry.entities.effect.Fire;
import io.anuke.mindustry.entities.effect.Lightning;
import io.anuke.mindustry.entities.effect.Puddle;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.resource.Liquid;
import io.anuke.ucore.core.Effects;
@@ -16,8 +19,12 @@ import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.world;
public class TurretBullets {
public static final BulletType
@@ -220,6 +227,15 @@ public class TurretBullets {
@Override
public void hit(Bullet b, float hitx, float hity) {
Effects.effect(hiteffect, liquid.color, hitx, hity);
Puddle.deposit(world.tileWorld(hitx, hity), liquid, 5f);
if(liquid.temperature <= 0.5f && liquid.flammability < 0.3f){
float intensity = 400f;
Fire.extinguish(world.tileWorld(hitx, hity), intensity);
for(GridPoint2 p : Geometry.d4){
Fire.extinguish(world.tileWorld(hitx + p.x*tilesize, hity + p.y*tilesize), intensity);
}
}
}
}
}

View File

@@ -43,6 +43,16 @@ public class EnvironmentFx {
Draw.color();
}),
steam = new Effect(35f, e -> {
Draw.color(Color.LIGHT_GRAY);
Angles.randLenVectors(e.id, 2, 2f + e.fin()*7f, (x, y) -> {
Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f);
});
Draw.color();
}),
fireballsmoke = new Effect(25f, e -> {
Draw.color(Color.GRAY);

View File

@@ -18,7 +18,7 @@ public class Fire extends TimedEntity {
private static GridMap<Fire> map = new GridMap<>();
private Tile tile;
private float flammability = -1;
private float baseFlammability = -1, puddleFlammability;
public static void create(Tile tile){
if(!map.containsKey(tile.x, tile.y)){
@@ -26,6 +26,12 @@ public class Fire extends TimedEntity {
}
}
public static void extinguish(Tile tile, float intensity){
if(map.containsKey(tile.x, tile.y)){
map.get(tile.x, tile.y).time += intensity * Timers.delta();
}
}
private Fire(Tile tile){
this.tile = tile;
lifetime = 1000f;
@@ -38,12 +44,14 @@ public class Fire extends TimedEntity {
TileEntity entity = tile.target().entity;
boolean damage = entity != null;
float flammability = baseFlammability + puddleFlammability;
if(!damage && flammability <= 0){
time += Timers.delta()*8;
}
if (flammability < 0){
flammability = tile.block().getFlammability(tile);
if (baseFlammability < 0){
baseFlammability = tile.block().getFlammability(tile);
}
if(damage) {
@@ -59,6 +67,13 @@ public class Fire extends TimedEntity {
if(Mathf.chance(0.1 * Timers.delta())){
Effects.effect(EnvironmentFx.fire, tile.worldx() + Mathf.range(4f), tile.worldy() + Mathf.range(4f));
Puddle p = Puddle.getPuddle(tile);
if(p != null){
puddleFlammability = p.getFlammability()/3f;
}else{
puddleFlammability = 0;
}
if(damage){
entity.damage(0.4f);
}

View File

@@ -0,0 +1,163 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.Rectangle;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.resource.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.GridMap;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.world;
public class Puddle extends Entity {
private static final GridMap<Puddle> map = new GridMap<>();
private static final float maxLiquid = 70f;
private static final int maxGeneration = 2;
private static final Color tmp = new Color();
private static final Rectangle rect = new Rectangle();
private Tile tile;
private Liquid liquid;
private float amount;
private int generation;
private float accepting;
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){
deposit(tile, source, liquid, amount, 0);
}
public static void deposit(Tile tile, Liquid liquid, float amount){
deposit(tile, tile, liquid, amount, 0);
}
public static Puddle getPuddle(Tile tile){
return map.get(tile.x, tile.y);
}
private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){
Puddle p = map.get(tile.x, tile.y);
if(p == null){
Puddle puddle = new Puddle(tile, source, liquid, amount, generation).add();
map.put(tile.x, tile.y, puddle);
}else if(p.liquid == liquid){
p.accepting = Math.max(amount, p.accepting);
if(generation == 0 && Timers.get(p, "ripple", 50) && p.amount >= maxLiquid/2f){
Effects.effect(BlockFx.ripple, p.liquid.color, (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
}
}else{
reactPuddle(p, liquid, amount);
}
}
private static void reactPuddle(Puddle p, Liquid liquid, float amount){
if((p.liquid.flammability > 0.3f && liquid.temperature > 0.7f) ||
liquid.flammability > 0.3f && p.liquid.temperature > 0.7f){ //flammable liquid + hot liquid
Fire.create(p.tile);
if(Mathf.chance(0.006 * amount)){
new Fireball(p.x, p.y, p.liquid.flameColor, Mathf.random(360f)).add();
}
}else if(p.liquid.temperature > 0.7f && liquid.temperature < 0.55f){ //cold liquid poured onto hot puddle
if(Mathf.chance(0.5f * amount)){
Effects.effect(EnvironmentFx.steam, p.x, p.y);
}
p.amount -= 0.1f * amount;
}else if(liquid.temperature > 0.7f && p.liquid.temperature < 0.55f){ //hot liquid poured onto cold puddle
if(Mathf.chance(0.8f * amount)){
Effects.effect(EnvironmentFx.steam, p.x, p.y);
}
p.amount -= 0.4f * amount;
}
}
private Puddle(Tile tile, Tile source, Liquid liquid, float amount, int generation) {
this.tile = tile;
this.liquid = liquid;
this.amount = amount;
this.generation = generation;
set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
}
public float getFlammability(){
return liquid.flammability * amount;
}
@Override
public void update() {
float addSpeed = accepting > 0 ? 3f : 0f;
amount -= Timers.delta() * (1f - liquid.viscosity) /(5f+addSpeed);
amount += accepting;
accepting = 0f;
if(amount >= maxLiquid/1.5f && generation < maxGeneration){
float deposited = Math.min((amount - maxLiquid/1.5f)/4f, 0.3f) * Timers.delta();
for(GridPoint2 point : Geometry.d4){
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
if(other.block() == Blocks.air){
deposit(other, tile, liquid, deposited, generation + 1);
amount -= deposited/4f;
}
}
}
if(amount >= maxLiquid/2f && Timers.get(this, "update", 20)){
Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(tile.worldx(), tile.worldy()), unit -> {
Rectangle o = unit.hitbox.getRect(unit.x, unit.y);
if(!rect.overlaps(o)) return;
unit.applyEffect(liquid.effect, 0.5f);
if(unit.velocity.len() > 0.4) {
Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y);
}
});
if(liquid.temperature > 0.7f && tile.entity != null && Mathf.chance(0.3 * Timers.delta())){
Fire.create(tile);
}
}
amount = Mathf.clamp(amount, 0, maxLiquid);
if(amount <= 0f){
remove();
}
}
@Override
public void draw() {
float f = Mathf.clamp(amount/(maxLiquid/1.5f));
Draw.color(Hue.shift(tmp.set(liquid.color), 2, -0.05f));
Fill.circle(x, y, f * 8f);
Angles.randLenVectors(id, 3, f * 6f, (ex, ey) -> {
Fill.circle(x + ex, y + ey, f * 5f);
});
Draw.color();
}
@Override
public void removed() {
map.remove(tile.x, tile.y);
}
@Override
public Puddle add() {
return add(Vars.groundEffectGroup);
}
}

View File

@@ -2,6 +2,8 @@ package io.anuke.mindustry.resource;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.entities.StatusEffect;
import io.anuke.ucore.util.Bundles;
public class Liquid {
@@ -24,6 +26,8 @@ public class Liquid {
public float explosiveness;
/**the burning color of this liquid*/
public Color flameColor = Color.valueOf("ffb763");
/**The associated status effect.*/
public StatusEffect effect = StatusEffects.none;
public Liquid(String name, Color color) {
this.name = name;

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.world;
import com.badlogic.gdx.math.GridPoint2;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.Puddle;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.resource.Liquid;
import io.anuke.ucore.util.Mathf;
@@ -108,7 +109,7 @@ public abstract class BaseBlock {
}
}
public float tryMoveLiquid(Tile tile, Tile next){
public float tryMoveLiquid(Tile tile, Tile next, boolean leak){
if(next == null) return 0;
next = next.target();
@@ -132,6 +133,10 @@ public abstract class BaseBlock {
tile.entity.liquid.amount -= amount;
return flow;
}
}else if(leak && !next.block().solid && !next.block().hasLiquids){
float leakAmount = Math.min(tile.entity.liquid.amount, tile.entity.liquid.amount/1.5f);
Puddle.deposit(next, tile, tile.entity.liquid.liquid, leakAmount);
tile.entity.liquid.amount -= leakAmount;
}
return 0;
}

View File

@@ -46,7 +46,7 @@ public class Conduit extends LiquidBlock {
entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquid.amount/liquidCapacity, 0.05f);
if(tile.entity.liquid.amount > 0.001f && tile.entity.timer.get(timerFlow, 1)){
tryMoveLiquid(tile, tile.getNearby(tile.getRotation()));
tryMoveLiquid(tile, tile.getNearby(tile.getRotation()), true);
}
}

View File

@@ -37,7 +37,7 @@ public class LiquidBridge extends ItemBridge {
if(entity.uptime >= 0.5f){
if(tryMoveLiquid(tile, other) > 0.1f){
if(tryMoveLiquid(tile, other, false) > 0.1f){
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f);
}else{
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f);

View File

@@ -37,7 +37,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge {
if(entity.uptime >= 0.5f){
if(tryMoveLiquid(tile, other) > 0.1f){
if(tryMoveLiquid(tile, other, false) > 0.1f){
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f);
}else{
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f);