Unit wreck visuals
|
Before Width: | Height: | Size: 567 KiB After Width: | Height: | Size: 592 KiB |
|
Before Width: | Height: | Size: 856 KiB After Width: | Height: | Size: 1006 KiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 185 KiB |
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||