package loon.action.sprite.effect; import loon.action.sprite.SpriteBatch; import loon.canvas.LColor; import loon.geom.Vector2f; import loon.utils.FloatArray; import loon.utils.MathUtils; import loon.utils.TArray; import loon.utils.timer.LTimer; /* * 单纯绘制一个闪电 */ public class LightningBolt implements ILightning { public float alpha; public float alphaMultiplier; public float fadeOutRate; public LColor tint; private LTimer timer = new LTimer(0); private TArray<LightningLine> segments = new TArray<LightningLine>(); public LightningBolt(Vector2f source, Vector2f dest) { this(source, dest, new LColor(0.9f, 0.8f, 1f)); } public LightningBolt(Vector2f source, Vector2f dest, LColor color) { this.segments = CreateBolt(source, dest, 2); this.tint = color; this.alpha = 1f; this.alphaMultiplier = 0.6f; this.fadeOutRate = 0.03f; } @Override public void draw(SpriteBatch spriteBatch, float x, float y) { if (alpha <= 0) { return; } for (LightningLine segment : segments) { segment.draw(spriteBatch, x, y, tint.mul(alpha * alphaMultiplier)); } } public void setDelay(long delay) { timer.setDelay(delay); } public long getDelay() { return timer.getDelay(); } @Override public void update(long elapsedTime) { if (timer.action(elapsedTime)) { alpha -= fadeOutRate; } } public Vector2f getStart() { return segments.get(0).lineA; } public Vector2f getEnd() { return segments.last().lineB; } @Override public boolean isComplete() { return alpha <= 0; } protected static TArray<LightningLine> CreateBolt(Vector2f source, Vector2f dest, float thickness) { TArray<LightningLine> results = new TArray<LightningLine>(); Vector2f tangent = dest.sub(source); Vector2f normal = Vector2f.nor(new Vector2f(tangent.y, -tangent.x)); float length = tangent.length(); FloatArray positions = new FloatArray(); positions.add(0); for (int i = 0; i < length / 4; i++) { positions.add(rand(0, 1)); } positions.sort(); final float sway = 80; final float jaggedness = 1 / sway; Vector2f prevPoint = source; float prevDisplacement = 0; for (int i = 1; i < positions.size(); i++) { float pos = positions.get(i); float scale = (length * jaggedness) * (pos - positions.get(i - 1)); float envelope = pos > 0.95f ? 20 * (1 - pos) : 1; float displacement = rand(-sway, sway); displacement -= (displacement - prevDisplacement) * (1 - scale); displacement *= envelope; Vector2f point = source.add(tangent.mul(pos)).add(normal.mul(displacement)); results.add(new LightningLine(prevPoint, point, thickness)); prevPoint = point; prevDisplacement = displacement; } results.add(new LightningLine(prevPoint, dest, thickness)); return results; } public Vector2f getPoint(float position) { final Vector2f start = getStart(); float length = Vector2f.dst(start, getEnd()); Vector2f dir = (getEnd().sub(start)).div(length); position *= length; LightningLine line = null; for (LightningLine x : segments) { if (Vector2f.dot(x.lineB.sub(start), dir) >= position) { line = x; } } if (line == null) { return start; } float lineStartPos = Vector2f.dot(line.lineA.sub(start), dir); float lineEndPos = Vector2f.dot(line.lineB.sub(start), dir); float linePos = (position - lineStartPos) / (lineEndPos - lineStartPos); return Vector2f.lerp(line.lineA, line.lineB, linePos); } private static float rand(float min, float max) { return MathUtils.random(min, max); } @Override public void close() { segments.clear(); } }