diff --git a/core/src/io/github/lonamiwebs/klooni/effects/IEffect.java b/core/src/io/github/lonamiwebs/klooni/effects/IEffect.java new file mode 100644 index 0000000..1d70e57 --- /dev/null +++ b/core/src/io/github/lonamiwebs/klooni/effects/IEffect.java @@ -0,0 +1,12 @@ +package io.github.lonamiwebs.klooni.effects; + +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector2; + +import io.github.lonamiwebs.klooni.game.Cell; + +public interface IEffect { + void setInfo(Cell deadCell, Vector2 culprit); + void draw(SpriteBatch batch); + boolean isDone(); +} diff --git a/core/src/io/github/lonamiwebs/klooni/effects/VanishEffect.java b/core/src/io/github/lonamiwebs/klooni/effects/VanishEffect.java new file mode 100644 index 0000000..9068ef0 --- /dev/null +++ b/core/src/io/github/lonamiwebs/klooni/effects/VanishEffect.java @@ -0,0 +1,65 @@ +package io.github.lonamiwebs.klooni.effects; + + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Interpolation; +import com.badlogic.gdx.math.Vector2; + +import io.github.lonamiwebs.klooni.game.Cell; + +public class VanishEffect implements IEffect { + private Cell cell; + + private Color vanishColor; + private float vanishSize; + private float vanishElapsed; + private float vanishLifetime; + + public VanishEffect() { + vanishElapsed = Float.POSITIVE_INFINITY; + } + + @Override + public void setInfo(Cell deadCell, Vector2 culprit) { + cell = deadCell; + + vanishSize = cell.size; + vanishColor = cell.getColorCopy(); + vanishLifetime = 1f; + + // The vanish distance is this measure (distance² + size³ * 20% size) + // because it seems good enough. The more the distance, the more the + // delay, but we decrease the delay depending on the cell size too or + // it would be way too high + Vector2 center = new Vector2(cell.pos.x + cell.size * 0.5f, cell.pos.y + 0.5f); + float vanishDist = Vector2.dst2( + culprit.x, culprit.y, center.x, center.y) / ((float)Math.pow(cell.size, 4.0f) * 0.2f); + + // Negative time = delay, + 0.4*lifetime because elastic interpolation has that delay + vanishElapsed = vanishLifetime * 0.4f - vanishDist; + } + + @Override + public void draw(SpriteBatch batch) { + // Draw the previous vanishing cell + if (vanishElapsed <= vanishLifetime) { + vanishElapsed += Gdx.graphics.getDeltaTime(); + + // vanishElapsed might be < 0 (delay), so clamp to 0 + float progress = Math.min(1f, + Math.max(vanishElapsed, 0f) / vanishLifetime); + + vanishSize = Interpolation.elasticIn.apply(cell.size, 0, progress); + + float centerOffset = cell.size * 0.5f - vanishSize * 0.5f; + Cell.draw(vanishColor, batch, cell.pos.x + centerOffset, cell.pos.y + centerOffset, vanishSize); + } + } + + @Override + public boolean isDone() { + return false; + } +} diff --git a/core/src/io/github/lonamiwebs/klooni/game/Board.java b/core/src/io/github/lonamiwebs/klooni/game/Board.java index 3a842b1..56a956b 100644 --- a/core/src/io/github/lonamiwebs/klooni/game/Board.java +++ b/core/src/io/github/lonamiwebs/klooni/game/Board.java @@ -22,12 +22,15 @@ import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import io.github.lonamiwebs.klooni.Klooni; +import io.github.lonamiwebs.klooni.effects.IEffect; +import io.github.lonamiwebs.klooni.effects.VanishEffect; import io.github.lonamiwebs.klooni.serializer.BinSerializable; // Represents the on screen board, with all the put cells @@ -39,6 +42,7 @@ public class Board implements BinSerializable { public final int cellCount; public float cellSize; private Cell[][] cells; + private final Array effects; // Particle effects once they vanish final Vector2 pos; private final Sound stripClearSound; @@ -57,6 +61,7 @@ public class Board implements BinSerializable { lastPutPiecePos = new Vector2(); pos = new Vector2(); + effects = new Array(32); // 32 capacity for 3 rows (most common) // Cell size depends on the layout to be updated first layout.update(this); @@ -118,6 +123,12 @@ public class Board implements BinSerializable { for (int i = 0; i < cellCount; ++i) for (int j = 0; j < cellCount; ++j) cells[i][j].draw(batch); + + for (int i = effects.size; i-- != 0;) { + effects.get(i).draw(batch); + if (effects.get(i).isDone()) + effects.removeIndex(i); + } } public boolean canPutPiece(Piece piece) { @@ -197,16 +208,26 @@ public class Board implements BinSerializable { float pan = 0; // Do clear those rows and columns - for (int i = 0; i < cellCount; ++i) - if (clearedRows[i]) - for (int j = 0; j < cellCount; ++j) - cells[i][j].vanish(lastPutPiecePos); + // TODO Don't always use "vanish effect" + for (int i = 0; i < cellCount; ++i) { + if (clearedRows[i]) { + for (int j = 0; j < cellCount; ++j) { + VanishEffect effect = new VanishEffect(); + effect.setInfo(cells[i][j], lastPutPiecePos); + effects.add(effect); + cells[i][j].set(-1); + } + } + } for (int j = 0; j < cellCount; ++j) { if (clearedCols[j]) { pan += 2f * (j - cellCount / 2) / (float)cellCount; for (int i = 0; i < cellCount; ++i) { - cells[i][j].vanish(lastPutPiecePos); + VanishEffect effect = new VanishEffect(); + effect.setInfo(cells[i][j], lastPutPiecePos); + effects.add(effect); + cells[i][j].set(-1); } } } diff --git a/core/src/io/github/lonamiwebs/klooni/game/Cell.java b/core/src/io/github/lonamiwebs/klooni/game/Cell.java index 0834568..f174f4d 100644 --- a/core/src/io/github/lonamiwebs/klooni/game/Cell.java +++ b/core/src/io/github/lonamiwebs/klooni/game/Cell.java @@ -17,12 +17,10 @@ */ package io.github.lonamiwebs.klooni.game; -import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.math.Vector2; import java.io.DataInputStream; @@ -41,15 +39,8 @@ public class Cell implements BinSerializable { // Negative index indicates that the cell is empty private int colorIndex; - private Vector2 pos; - private float size; - - // No need to store the vanish color as a color index since - // this is something quick and shouldn't really affect the UX - private Color vanishColor; - private float vanishSize; - private float vanishElapsed; - private float vanishLifetime; + public final Vector2 pos; + public final float size; //endregion @@ -60,7 +51,6 @@ public class Cell implements BinSerializable { size = cellSize; colorIndex = -1; - vanishElapsed = Float.POSITIVE_INFINITY; } //endregion @@ -68,51 +58,17 @@ public class Cell implements BinSerializable { //region Package local methods // Sets the cell to be non-empty and of the specified color index - void set(int ci) { + public void set(int ci) { colorIndex = ci; } void draw(SpriteBatch batch) { // Always query the color to the theme, because it might have changed draw(Klooni.theme.getCellColor(colorIndex), batch, pos.x, pos.y, size); - - // Draw the previous vanishing cell - if (vanishElapsed <= vanishLifetime) { - vanishElapsed += Gdx.graphics.getDeltaTime(); - - // vanishElapsed might be < 0 (delay), so clamp to 0 - float progress = Math.min(1f, - Math.max(vanishElapsed, 0f) / vanishLifetime); - - vanishSize = Interpolation.elasticIn.apply(size, 0, progress); - - float centerOffset = size * 0.5f - vanishSize * 0.5f; - draw(vanishColor, batch, pos.x + centerOffset, pos.y + centerOffset, vanishSize); - } } - // Vanish from indicates the point which caused the vanishing to happen, - // in this case, a piece was put. The closer it was put, the faster - // this piece will vanish. This immediately marks the piece as empty. - void vanish(Vector2 vanishFrom) { - if (isEmpty()) // We cannot vanish twice - return; - - vanishSize = size; - vanishColor = Klooni.theme.getCellColor(colorIndex).cpy(); - vanishLifetime = 1f; - colorIndex = -1; - - // The vanish distance is this measure (distance² + size³ * 20% size) - // because it seems good enough. The more the distance, the more the - // delay, but we decrease the delay depending on the cell size too or - // it would be way too high - Vector2 center = new Vector2(pos.x + size * 0.5f, pos.y + 0.5f); - float vanishDist = Vector2.dst2( - vanishFrom.x, vanishFrom.y, center.x, center.y) / (size * size * size * size * 0.2f); - - // Negative time = delay, + 0.4*lifetime because elastic interpolation has that delay - vanishElapsed = vanishLifetime * 0.4f - vanishDist; + public Color getColorCopy() { + return Klooni.theme.getCellColor(colorIndex).cpy(); } boolean isEmpty() {