Unit wreck visuals

This commit is contained in:
Anuken
2020-07-08 23:48:12 -04:00
parent b0f69263c7
commit 29e9d064df
17 changed files with 2982 additions and 2035 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 567 KiB

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 KiB

After

Width:  |  Height:  |  Size: 1006 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 184 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 185 KiB

View File

@@ -183,6 +183,27 @@ public class Fx{
Fill.circle(e.x, e.y, (7f - e.fin() * 7f)/2f); Fill.circle(e.x, e.y, (7f - e.fin() * 7f)/2f);
}), }),
fallSmoke = new Effect(110, e -> {
color(Color.gray, Color.darkGray, e.rotation);
Fill.circle(e.x, e.y, e.fout() * 3.5f);
}),
unitWreck = new Effect(200f, e -> {
if(!(e.data instanceof TextureRegion)) return;
Draw.mixcol(Pal.rubble, 1f);
TextureRegion reg = e.data();
float vel = e.fin(Interp.pow5Out) * 2f * Mathf.randomSeed(e.id, 1f);
float totalRot = Mathf.randomSeed(e.id + 1, 10f);
Tmp.v1.trns(Mathf.randomSeed(e.id + 2, 360f), vel);
Draw.z(Mathf.lerp(Layer.flyingUnitLow, Layer.debris, e.fin()));
Draw.alpha(e.fout(Interp.pow5Out));
Draw.rect(reg, e.x + Tmp.v1.x, e.y + Tmp.v1.y, e.rotation - 90 + totalRot * e.fin(Interp.pow5Out));
}),
rocketSmoke = new Effect(120, e -> { rocketSmoke = new Effect(120, e -> {
color(Color.gray); color(Color.gray);
alpha(Mathf.clamp(e.fout()*1.6f - Interp.pow3In.apply(e.rotation)*1.2f)); alpha(Mathf.clamp(e.fout()*1.6f - Interp.pow3In.apply(e.rotation)*1.2f));

View File

@@ -377,6 +377,7 @@ public class UnitTypes implements ContentList{
engineOffset = 38; engineOffset = 38;
engineSize = 7.3f; engineSize = 7.3f;
hitsize = 58f; hitsize = 58f;
destructibleWreck = false;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
y = 1.5f; y = 1.5f;

View File

@@ -55,6 +55,10 @@ public class Effects{
} }
} }
public static void decal(TextureRegion region, float x, float y, float rotation){
decal(region, x, y, rotation, 3600f, Pal.rubble);
}
public static void decal(TextureRegion region, float x, float y, float rotation, float lifetime, Color color){ public static void decal(TextureRegion region, float x, float y, float rotation, float lifetime, Color color){
if(headless || region == null || !Core.atlas.isFound(region)) return; if(headless || region == null || !Core.atlas.isFound(region)) return;

View File

@@ -11,7 +11,7 @@ import static mindustry.Vars.*;
/** Utility class for unit and team interactions.*/ /** Utility class for unit and team interactions.*/
public class Units{ public class Units{
private static Rect hitrect = new Rect(); private static final Rect hitrect = new Rect();
private static Unit result; private static Unit result;
private static float cdist; private static float cdist;
private static boolean boolResult; private static boolean boolResult;

View File

@@ -19,10 +19,10 @@ abstract class DecalComp implements Drawc, Timedc, Rotc, Posc{
public void draw(){ public void draw(){
Draw.z(Layer.scorch); Draw.z(Layer.scorch);
Draw.color(color); Draw.mixcol(color, 1f);
Draw.alpha(1f - Mathf.curve(fin(), 0.98f)); Draw.alpha(1f - Mathf.curve(fin(), 0.98f));
Draw.rect(region, x, y, rotation); Draw.rect(region, x, y, rotation);
Draw.color(); Draw.reset();
} }
@Replace @Replace

View File

@@ -164,7 +164,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
public void update(){ public void update(){
type.update(base()); type.update(base());
drag(type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f)); drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f);
//apply knockback based on spawns //apply knockback based on spawns
if(team != state.rules.waveTeam){ if(team != state.rules.waveTeam){
@@ -176,6 +176,36 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
} }
//simulate falling down
if(dead){
//less drag when dead
drag = 0.01f;
//standard fall smoke
if(Mathf.chanceDelta(0.1)){
Tmp.v1.setToRandomDirection().scl(hitSize);
type.fallEffect.at(x + Tmp.v1.x, y + Tmp.v1.y);
}
//thruster fall trail
if(Mathf.chanceDelta(0.2)){
float offset = type.engineOffset/2f + type.engineOffset/2f*elevation;
float range = Mathf.range(type.engineSize);
type.fallThrusterEffect.at(
x + Angles.trnsx(rotation + 180, offset) + Mathf.range(range),
y + Angles.trnsy(rotation + 180, offset) + Mathf.range(range),
Mathf.random()
);
}
//move down
elevation -= type.fallSpeed * Time.delta();
if(isGrounded()){
destroy();
}
}
Tile tile = tileOn(); Tile tile = tileOn();
Floor floor = floorOn(); Floor floor = floorOn();
@@ -197,7 +227,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
//AI only updates on the server //AI only updates on the server
if(!net.client()){ if(!net.client() && !dead){
controller.updateUnit(); controller.updateUnit();
} }
@@ -208,6 +238,43 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
} }
/** Actually destroys the unit, removing it and creating explosions. **/
public void destroy(){
float explosiveness = 2f + item().explosiveness * stack().amount;
float flammability = item().flammability * stack().amount;
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame);
float shake = hitSize / 3f;
Effects.scorch(x, y, (int)(hitSize / 5));
Fx.explosion.at(this);
Effects.shake(shake, shake, this);
type.deathSound.at(this);
Events.fire(new UnitDestroyEvent(base()));
if(explosiveness > 7f && isLocal()){
Events.fire(Trigger.suicideBomb);
}
//if this unit crash landed (was flying), damage stuff in a radius
if(type.flying){
Damage.damage(team,x, y, hitSize * 1.1f, hitSize * type.crashDamageMultiplier, true, false, true);
}
if(!headless){
for(int i = 0; i < type.wreckRegions.length; i++){
if(type.wreckRegions[i].found()){
float range = type.hitsize/4f;
Tmp.v1.rnd(range);
Effects.decal(type.wreckRegions[i], x + Tmp.v1.x, y + Tmp.v1.y, rotation - 90);
}
}
}
remove();
}
@Override @Override
public void display(Table table){ public void display(Table table){
type.display(base(), table); type.display(base(), table);
@@ -238,22 +305,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
health = 0; health = 0;
dead = true; dead = true;
float explosiveness = 2f + item().explosiveness * stack().amount; //don't waste time when the unit is already on the ground, just destroy it
float flammability = item().flammability * stack().amount; if(isGrounded()){
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame); destroy();
Effects.scorch(x, y, (int)(hitSize / 5));
Fx.explosion.at(this);
Effects.shake(2f, 2f, this);
type.deathSound.at(this);
Events.fire(new UnitDestroyEvent(base()));
if(explosiveness > 7f && isLocal()){
Events.fire(Trigger.suicideBomb);
} }
remove();
} }
@Override @Override

View File

@@ -35,15 +35,21 @@ public class UnitType extends UnlockableContent{
public @NonNull Prov<? extends Unit> constructor; public @NonNull Prov<? extends Unit> constructor;
public @NonNull Prov<? extends UnitController> defaultController = () -> !flying ? new GroundAI() : new FlyingAI(); public @NonNull Prov<? extends UnitController> defaultController = () -> !flying ? new GroundAI() : new FlyingAI();
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f; public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f; public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, fallSpeed = 0.018f;
public float health = 200f, range = -1, armor = 0f; public float health = 200f, range = -1, armor = 0f;
public float crashDamageMultiplier = 4f;
public boolean targetAir = true, targetGround = true; public boolean targetAir = true, targetGround = true;
public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false; public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false;
public boolean canBoost = false; public boolean canBoost = false;
public boolean destructibleWreck = true;
public float wreckHealth = 15f;
public float sway = 1f; public float sway = 1f;
public int payloadCapacity = 1; public int payloadCapacity = 1;
public int commandLimit = 24; public int commandLimit = 24;
public float baseElevation = 0f; public float baseElevation = 0f;
public float deathShake = 2f;
public Effect fallEffect = Fx.fallSmoke;
public Effect fallThrusterEffect = Fx.fallSmoke;
//TODO document //TODO document
public int legCount = 4, legGroupSize = 2; public int legCount = 4, legGroupSize = 2;
@@ -72,8 +78,7 @@ public class UnitType extends UnlockableContent{
public Seq<Weapon> weapons = new Seq<>(); public Seq<Weapon> weapons = new Seq<>();
public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion, public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion,
occlusionRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion; occlusionRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion;
public TextureRegion[] partRegions; public TextureRegion[] partRegions, partCellRegions, wreckRegions;
public TextureRegion[] partCellRegions;
public UnitType(String name){ public UnitType(String name){
super(name); super(name);
@@ -186,6 +191,11 @@ public class UnitType extends UnlockableContent{
partRegions[i] = Core.atlas.find(name + "-part" + i); partRegions[i] = Core.atlas.find(name + "-part" + i);
partCellRegions[i] = Core.atlas.find(name + "-cell" + i); partCellRegions[i] = Core.atlas.find(name + "-cell" + i);
} }
wreckRegions = new TextureRegion[3];
for(int i = 0; i < wreckRegions.length; i++){
wreckRegions[i] = Core.atlas.find(name + "-wreck" + i);
}
} }
@Override @Override

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=b877b22de07db3cd2843a59eb92f5dfe1c61ae78 archash=dc2078079498cd673f5784ff875a573afb82473d

View File

@@ -5,6 +5,7 @@ import arc.files.*;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import arc.util.noise.*; import arc.util.noise.*;
@@ -344,6 +345,43 @@ public class Generators{
} }
image.save("unit-" + type.name + "-full"); image.save("unit-" + type.name + "-full");
Rand rand = new Rand();
rand.setSeed(type.name.hashCode());
//generate random wrecks
int splits = 3;
float degrees = rand.random(360f);
float offsetRange = Math.max(image.width, image.height) * 0.15f;
Vec2 offset = new Vec2(1, 1).rotate(rand.random(360f)).setLength(rand.random(0, offsetRange)).add(image.width/2f, image.height/2f);
Image[] wrecks = new Image[splits];
for(int i = 0; i < wrecks.length; i++){
wrecks[i] = new Image(image.width, image.height);
}
RidgedPerlin r = new RidgedPerlin(1, 3);
VoronoiNoise vn = new VoronoiNoise(type.id, true);
image.each((x, y) -> {
//add darker cracks on top
boolean rValue = Math.max(r.getValue(x, y, 1f / (20f + image.width/8f)), 0) > 0.16f;
//cut out random chunks with voronoi
boolean vval = vn.noise(x, y, 1f / (14f + image.width/40f)) > 0.47;
float dst = offset.dst(x, y);
//distort edges with random noise
float noise = (float)Noise.rawNoise(dst / (9f + image.width/70f)) * (60 + image.width/30f);
int section = (int)Mathf.clamp(Mathf.mod(offset.angleTo(x, y) + noise + degrees, 360f) / 360f * splits, 0, splits - 1);
if(!vval) wrecks[section].draw(x, y, image.getColor(x, y).mul(rValue ? 0.7f : 1f));
});
for(int i = 0; i < wrecks.length; i++){
wrecks[i].save(type.name + "-wreck" + i);
}
//TODO GENERATE WRECKS
}catch(IllegalArgumentException e){ }catch(IllegalArgumentException e){
Log.err("WARNING: Skipping unit @: @", type.name, e.getMessage()); Log.err("WARNING: Skipping unit @: @", type.name, e.getMessage());
} }

View File

@@ -39,6 +39,12 @@ class Image{
this(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)); this(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
} }
Image copy(){
Image out =new Image(width, height);
out.draw(this);
return out;
}
boolean isEmpty(int x, int y){ boolean isEmpty(int x, int y){
if(!Structs.inBounds(x, y, width, height)){ if(!Structs.inBounds(x, y, width, height)){
return true; return true;