package mindustry.entities; import arc.Core; import arc.struct.Array; import arc.func.Cons; import arc.graphics.Color; import arc.graphics.g2d.*; import arc.math.Mathf; import arc.math.geom.Position; import arc.util.pooling.Pools; import mindustry.entities.type.EffectEntity; import mindustry.entities.traits.ScaleTrait; public class Effects{ private static final EffectContainer container = new EffectContainer(); private static Array effects = new Array<>(); private static ScreenshakeProvider shakeProvider; private static float shakeFalloff = 10000f; private static EffectProvider provider = (effect, color, x, y, rotation, data) -> { EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new); entity.effect = effect; entity.color = color; entity.rotation = rotation; entity.data = data; entity.set(x, y); entity.add(); }; public static void setEffectProvider(EffectProvider prov){ provider = prov; } public static void setScreenShakeProvider(ScreenshakeProvider provider){ shakeProvider = provider; } public static void renderEffect(int id, Effect render, Color color, float life, float rotation, float x, float y, Object data){ container.set(id, color, life, render.lifetime, rotation, x, y, data); render.draw.render(container); Draw.reset(); } public static Effect getEffect(int id){ if(id >= effects.size || id < 0) throw new IllegalArgumentException("The effect with ID \"" + id + "\" does not exist!"); return effects.get(id); } public static Array all(){ return effects; } public static void effect(Effect effect, float x, float y, float rotation){ provider.createEffect(effect, Color.white, x, y, rotation, null); } public static void effect(Effect effect, float x, float y){ effect(effect, x, y, 0); } public static void effect(Effect effect, Color color, float x, float y){ provider.createEffect(effect, color, x, y, 0f, null); } public static void effect(Effect effect, Position loc){ provider.createEffect(effect, Color.white, loc.getX(), loc.getY(), 0f, null); } public static void effect(Effect effect, Color color, float x, float y, float rotation){ provider.createEffect(effect, color, x, y, rotation, null); } public static void effect(Effect effect, Color color, float x, float y, float rotation, Object data){ provider.createEffect(effect, color, x, y, rotation, data); } public static void effect(Effect effect, float x, float y, float rotation, Object data){ provider.createEffect(effect, Color.white, x, y, rotation, data); } /** Default value is 1000. Higher numbers mean more powerful shake (less falloff). */ public static void setShakeFalloff(float falloff){ shakeFalloff = falloff; } private static void shake(float intensity, float duration){ if(shakeProvider == null) throw new RuntimeException("Screenshake provider is null! Set it first."); shakeProvider.accept(intensity, duration); } public static void shake(float intensity, float duration, float x, float y){ if(Core.camera == null) return; float distance = Core.camera.position.dst(x, y); if(distance < 1) distance = 1; shake(Mathf.clamp(1f / (distance * distance / shakeFalloff)) * intensity, duration); } public static void shake(float intensity, float duration, Position loc){ shake(intensity, duration, loc.getX(), loc.getY()); } public interface ScreenshakeProvider{ void accept(float intensity, float duration); } public static class Effect{ private static int lastid = 0; public final int id; public final EffectRenderer draw; public final float lifetime; /** Clip size. */ public float size; public Effect(float life, float clipsize, EffectRenderer draw){ this.id = lastid++; this.lifetime = life; this.draw = draw; this.size = clipsize; effects.add(this); } public Effect(float life, EffectRenderer draw){ this(life, 28f, draw); } } public static class EffectContainer implements ScaleTrait{ public float x, y, time, lifetime, rotation; public Color color; public int id; public Object data; private EffectContainer innerContainer; public void set(int id, Color color, float life, float lifetime, float rotation, float x, float y, Object data){ this.x = x; this.y = y; this.color = color; this.time = life; this.lifetime = lifetime; this.id = id; this.rotation = rotation; this.data = data; } public void scaled(float lifetime, Cons cons){ if(innerContainer == null) innerContainer = new EffectContainer(); if(time <= lifetime){ innerContainer.set(id, color, time, lifetime, rotation, x, y, data); cons.get(innerContainer); } } @Override public float fin(){ return time / lifetime; } } public interface EffectProvider{ void createEffect(Effect effect, Color color, float x, float y, float rotation, Object data); } public interface EffectRenderer{ void render(EffectContainer effect); } }