diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java index 3f8d56c249..a9ada9f45c 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java @@ -800,12 +800,12 @@ public class EntityProcess extends BaseProcessor{ } } - write(def.builder, imports.asArray()); + write(def.builder, imports.toSeq()); } //write base classes last for(TypeSpec.Builder b : baseClasses){ - write(b, imports.asArray()); + write(b, imports.toSeq()); } //TODO nulls were an awful idea @@ -878,7 +878,7 @@ public class EntityProcess extends BaseProcessor{ nullsBuilder.addField(FieldSpec.builder(type, Strings.camelize(baseName)).initializer("new " + className + "()").addModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PUBLIC).build()); - write(nullBuilder, imports.asArray()); + write(nullBuilder, imports.toSeq()); } write(nullsBuilder); @@ -934,7 +934,7 @@ public class EntityProcess extends BaseProcessor{ out.addAll(getDependencies(comp)); } - defComponents.put(type, out.asArray()); + defComponents.put(type, out.toSeq()); } return defComponents.get(type); @@ -961,7 +961,7 @@ public class EntityProcess extends BaseProcessor{ //remove it again just in case out.remove(component); - componentDependencies.put(component, result.asArray()); + componentDependencies.put(component, result.toSeq()); } return componentDependencies.get(component); diff --git a/core/assets-raw/sprites/units/vanquish-treads.png b/core/assets-raw/sprites/units/vanquish-treads.png index dea46d155e..a8cbe1e0cd 100644 Binary files a/core/assets-raw/sprites/units/vanquish-treads.png and b/core/assets-raw/sprites/units/vanquish-treads.png differ diff --git a/core/assets-raw/sprites/units/vanquish.png b/core/assets-raw/sprites/units/vanquish.png index 118b862018..a1b5c2d58b 100644 Binary files a/core/assets-raw/sprites/units/vanquish.png and b/core/assets-raw/sprites/units/vanquish.png differ diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 9496ccab85..ae84c353ee 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -21,8 +21,8 @@ import static arc.math.Angles.*; import static mindustry.Vars.*; public class Fx{ - private static final Rand rand = new Rand(); - private static final Vec2 v = new Vec2(); + public static final Rand rand = new Rand(); + public static final Vec2 v = new Vec2(); public static final Effect @@ -310,11 +310,19 @@ public class Fx{ unitLand = new Effect(30, e -> { color(Tmp.c1.set(e.color).mul(1.1f)); + //TODO doesn't respect rotation / size randLenVectors(e.id, 6, 17f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.3f); }); }).layer(Layer.debris), + unitDust = new Effect(30, e -> { + color(Tmp.c1.set(e.color).mul(1.3f)); + randLenVectors(e.id, 3, 8f * e.finpow(), e.rotation, 30f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.3f); + }); + }).layer(Layer.debris), + unitLandSmall = new Effect(30, e -> { color(Tmp.c1.set(e.color).mul(1.1f)); randLenVectors(e.id, (int)(6 * e.rotation), 12f * e.finpow() * e.rotation, (x, y) -> { diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index ebdd90c805..9c961396bc 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -2429,6 +2429,10 @@ public class UnitTypes{ vanquish = new TankUnitType("vanquish"){{ hitSize = 28f; + speed = 0.6f; + health = 10000; + armor = 20f; + treadRect = new Rect(22f, 16f, 28f, 130f); }}; //endregion diff --git a/core/src/mindustry/entities/Effect.java b/core/src/mindustry/entities/Effect.java index aa32ed60db..6b164a3f98 100644 --- a/core/src/mindustry/entities/Effect.java +++ b/core/src/mindustry/entities/Effect.java @@ -166,6 +166,22 @@ public class Effect{ shake(intensity, duration, loc.getX(), loc.getY()); } + public static void floorDust(float x, float y, float size){ + Tile tile = world.tileWorld(x, y); + if(tile != null){ + Color color = tile.floor().mapColor; + Fx.unitLand.at(x, y, size, color); + } + } + + public static void floorDustAngle(Effect effect, float x, float y, float angle){ + Tile tile = world.tileWorld(x, y); + if(tile != null){ + Color color = tile.floor().mapColor; + effect.at(x, y, angle, color); + } + } + public static void create(Effect effect, float x, float y, float rotation, Color color, Object data){ if(headless || effect == Fx.none || !Core.settings.getBool("effects")) return; diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index 1a94f29fd6..f29a2c67f3 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -119,7 +119,7 @@ public class EntityCollisions{ @SuppressWarnings("unchecked") public void updatePhysics(EntityGroup group){ - QuadTree tree = group.tree(); + var tree = group.tree(); tree.clear(); group.each(s -> { diff --git a/core/src/mindustry/entities/comp/MechComp.java b/core/src/mindustry/entities/comp/MechComp.java index 18ffc784a7..ff4970e108 100644 --- a/core/src/mindustry/entities/comp/MechComp.java +++ b/core/src/mindustry/entities/comp/MechComp.java @@ -1,15 +1,12 @@ package mindustry.entities.comp; -import arc.graphics.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.annotations.Annotations.*; -import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; -import mindustry.world.*; import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; @@ -52,11 +49,7 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati } if(type.mechStepParticles){ - Tile tile = world.tileWorld(cx, cy); - if(tile != null){ - Color color = tile.floor().mapColor; - Fx.unitLand.at(cx, cy, hitSize/8f, color); - } + Effect.floorDust(cx, cy, hitSize/8f); } } diff --git a/core/src/mindustry/entities/comp/TankComp.java b/core/src/mindustry/entities/comp/TankComp.java index f721b13bb3..320ddcf555 100644 --- a/core/src/mindustry/entities/comp/TankComp.java +++ b/core/src/mindustry/entities/comp/TankComp.java @@ -1,8 +1,10 @@ package mindustry.entities.comp; +import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.annotations.Annotations.*; +import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.blocks.environment.*; @@ -11,14 +13,36 @@ import static mindustry.Vars.*; @Component abstract class TankComp implements Posc, Flyingc, Hitboxc, Unitc, ElevationMovec{ - @Import float x, y, hitSize; + @Import float x, y, hitSize, rotation; @Import UnitType type; + transient private float treadEffectTime; + transient float treadTime; transient boolean walked; @Override public void update(){ + //dust + if(walked && !headless){ + treadEffectTime += Time.delta; + if(treadEffectTime >= 6f){ + var treadRegion = type.treadRegion; + var treadRect = type.treadRect; + + float xOffset = (treadRegion.width/2f - (treadRect.x + treadRect.width/2f)) / 4f; + float yOffset = (treadRegion.height/2f - (treadRect.y + treadRect.height/2f)) / 4f; + + for(int i : Mathf.signs){ + Tmp.v1.set(xOffset * i, yOffset - treadRect.height / 2f / 4f).rotate(rotation - 90); + + Effect.floorDustAngle(type.treadEffect, Tmp.v1.x + x, Tmp.v1.y + y, rotation + 180f); + } + + treadEffectTime = 0f; + } + } + //trigger animation only when walking manually if(walked || net.client()){ float len = deltaLen(); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index b0dc05cc95..6e2a00ad57 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -34,6 +34,7 @@ import mindustry.world.blocks.units.*; import mindustry.world.consumers.*; import mindustry.world.meta.*; +import static arc.graphics.g2d.Draw.*; import static mindustry.Vars.*; //TODO document @@ -92,6 +93,7 @@ public class UnitType extends UnlockableContent{ public Effect fallEffect = Fx.fallSmoke; public Effect fallThrusterEffect = Fx.fallSmoke; public Effect deathExplosionEffect = Fx.dynamicExplosion; + public @Nullable Effect treadEffect; /** Additional sprites that are drawn with the unit. */ public Seq decals = new Seq<>(); public Seq abilities = new Seq<>(); @@ -117,6 +119,9 @@ public class UnitType extends UnlockableContent{ public boolean mechStepParticles = false; public Color mechLegColor = Pal.darkMetal; + public Rect treadRect = new Rect(); + public int treadFrames = 18; + public int itemCapacity = -1; public int ammoCapacity = -1; public AmmoType ammoType = new ItemAmmoType(Items.copper); @@ -166,8 +171,7 @@ public class UnitType extends UnlockableContent{ public Seq weapons = new Seq<>(); public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion, softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion, treadRegion; - public TextureRegion[] wreckRegions; - public TextureRegion[] segmentRegions, segmentOutlineRegions; + public TextureRegion[] wreckRegions, segmentRegions, segmentOutlineRegions, treadRegions; protected float buildTime = -1f; protected @Nullable ItemStack[] totalRequirements, cachedRequirements, firstRequirements; @@ -437,6 +441,17 @@ public class UnitType extends UnlockableContent{ mechStepParticles = hitSize > 15f; } + if(treadEffect == null){ + treadEffect = new Effect(45, e -> { + color(Tmp.c1.set(e.color).mul(1.5f)); + Fx.rand.setSeed(e.id); + for(int i = 0; i < 3; i++){ + Fx.v.trns(e.rotation + Fx.rand.range(40f), Fx.rand.random(6f * e.finpow())); + Fill.circle(e.x + Fx.v.x + Fx.rand.range(3f), e.y + Fx.v.y + Fx.rand.range(3f), e.fout() * hitSize / 28f * 3f * Fx.rand.random(0.8f, 1.1f) + 0.3f); + } + }).layer(Layer.debris); + } + canHeal = weapons.contains(w -> w.bullet.healPercent > 0f); //add mirrored weapon variants @@ -498,6 +513,12 @@ public class UnitType extends UnlockableContent{ baseJointRegion = Core.atlas.find(name + "-joint-base"); footRegion = Core.atlas.find(name + "-foot"); treadRegion = Core.atlas.find(name + "-treads"); + if(treadRegion.found()){ + treadRegions = new TextureRegion[treadFrames]; + for(int i = 0; i < treadFrames; i++){ + treadRegions[i] = Core.atlas.find(name + "-treads" + i); + } + } legBaseRegion = Core.atlas.find(name + "-leg-base", name + "-leg"); baseRegion = Core.atlas.find(name + "-base"); cellRegion = Core.atlas.find(name + "-cell", Core.atlas.find("power-cell")); @@ -963,6 +984,18 @@ public class UnitType extends UnlockableContent{ public void drawTank(T unit){ Draw.rect(treadRegion, unit.x, unit.y, unit.rotation - 90); + + if(treadRegion.found()){ + int frame = (int)(unit.treadTime()) % treadFrames; + var region = treadRegions[frame]; + float xOffset = treadRegion.width/2f - (treadRect.x + treadRect.width/2f); + float yOffset = treadRegion.height/2f - (treadRect.y + treadRect.height/2f); + + for(int i : Mathf.signs){ + Tmp.v1.set(xOffset * i, yOffset).rotate(unit.rotation - 90); + Draw.rect(region, unit.x + Tmp.v1.x / 4f, unit.y + Tmp.v1.y / 4f, treadRect.width / 4f, region.height / 4f, unit.rotation - 90); + } + } } public void drawLegs(T unit){ diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 4ffc842f12..6eededbe91 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -509,6 +509,28 @@ public class Generators{ } } + //generate tank animation + if(sample instanceof Tankc){ + Pixmap pix = get(type.treadRegion); + //slice is always 1 pixel wide + Pixmap slice = pix.crop((int)type.treadRect.x, (int)type.treadRect.y, 1, (int)type.treadRect.height); + int frames = type.treadFrames; + for(int i = 0; i < frames; i++){ + int pullOffset = 4; + Pixmap frame = new Pixmap(slice.width, slice.height); + for(int y = 0; y < slice.height; y++){ + int idx = y + i; + if(idx >= slice.height){ + idx -= slice.height; + idx += pullOffset; + } + + frame.setRaw(0, y, slice.getRaw(0, idx)); + } + save(frame, type.name + "-treads" + i); + } + } + outliner.get(type.jointRegion); outliner.get(type.footRegion); outliner.get(type.legBaseRegion);