Make the clear-row vanish effect a lot more generic
This commit is contained in:
parent
cbb13f672f
commit
0713d4a5de
4 changed files with 108 additions and 54 deletions
12
core/src/io/github/lonamiwebs/klooni/effects/IEffect.java
Normal file
12
core/src/io/github/lonamiwebs/klooni/effects/IEffect.java
Normal file
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,12 +22,15 @@ import com.badlogic.gdx.audio.Sound;
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.Klooni;
|
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;
|
import io.github.lonamiwebs.klooni.serializer.BinSerializable;
|
||||||
|
|
||||||
// Represents the on screen board, with all the put cells
|
// Represents the on screen board, with all the put cells
|
||||||
|
@ -39,6 +42,7 @@ public class Board implements BinSerializable {
|
||||||
public final int cellCount;
|
public final int cellCount;
|
||||||
public float cellSize;
|
public float cellSize;
|
||||||
private Cell[][] cells;
|
private Cell[][] cells;
|
||||||
|
private final Array<IEffect> effects; // Particle effects once they vanish
|
||||||
|
|
||||||
final Vector2 pos;
|
final Vector2 pos;
|
||||||
private final Sound stripClearSound;
|
private final Sound stripClearSound;
|
||||||
|
@ -57,6 +61,7 @@ public class Board implements BinSerializable {
|
||||||
|
|
||||||
lastPutPiecePos = new Vector2();
|
lastPutPiecePos = new Vector2();
|
||||||
pos = new Vector2();
|
pos = new Vector2();
|
||||||
|
effects = new Array<IEffect>(32); // 32 capacity for 3 rows (most common)
|
||||||
|
|
||||||
// Cell size depends on the layout to be updated first
|
// Cell size depends on the layout to be updated first
|
||||||
layout.update(this);
|
layout.update(this);
|
||||||
|
@ -118,6 +123,12 @@ public class Board implements BinSerializable {
|
||||||
for (int i = 0; i < cellCount; ++i)
|
for (int i = 0; i < cellCount; ++i)
|
||||||
for (int j = 0; j < cellCount; ++j)
|
for (int j = 0; j < cellCount; ++j)
|
||||||
cells[i][j].draw(batch);
|
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) {
|
public boolean canPutPiece(Piece piece) {
|
||||||
|
@ -197,16 +208,26 @@ public class Board implements BinSerializable {
|
||||||
float pan = 0;
|
float pan = 0;
|
||||||
|
|
||||||
// Do clear those rows and columns
|
// Do clear those rows and columns
|
||||||
for (int i = 0; i < cellCount; ++i)
|
// TODO Don't always use "vanish effect"
|
||||||
if (clearedRows[i])
|
for (int i = 0; i < cellCount; ++i) {
|
||||||
for (int j = 0; j < cellCount; ++j)
|
if (clearedRows[i]) {
|
||||||
cells[i][j].vanish(lastPutPiecePos);
|
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) {
|
for (int j = 0; j < cellCount; ++j) {
|
||||||
if (clearedCols[j]) {
|
if (clearedCols[j]) {
|
||||||
pan += 2f * (j - cellCount / 2) / (float)cellCount;
|
pan += 2f * (j - cellCount / 2) / (float)cellCount;
|
||||||
for (int i = 0; i < cellCount; ++i) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,10 @@
|
||||||
*/
|
*/
|
||||||
package io.github.lonamiwebs.klooni.game;
|
package io.github.lonamiwebs.klooni.game;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
import com.badlogic.gdx.math.Interpolation;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
|
@ -41,15 +39,8 @@ public class Cell implements BinSerializable {
|
||||||
// Negative index indicates that the cell is empty
|
// Negative index indicates that the cell is empty
|
||||||
private int colorIndex;
|
private int colorIndex;
|
||||||
|
|
||||||
private Vector2 pos;
|
public final Vector2 pos;
|
||||||
private float size;
|
public final 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;
|
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
@ -60,7 +51,6 @@ public class Cell implements BinSerializable {
|
||||||
size = cellSize;
|
size = cellSize;
|
||||||
|
|
||||||
colorIndex = -1;
|
colorIndex = -1;
|
||||||
vanishElapsed = Float.POSITIVE_INFINITY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
@ -68,51 +58,17 @@ public class Cell implements BinSerializable {
|
||||||
//region Package local methods
|
//region Package local methods
|
||||||
|
|
||||||
// Sets the cell to be non-empty and of the specified color index
|
// Sets the cell to be non-empty and of the specified color index
|
||||||
void set(int ci) {
|
public void set(int ci) {
|
||||||
colorIndex = ci;
|
colorIndex = ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(SpriteBatch batch) {
|
void draw(SpriteBatch batch) {
|
||||||
// Always query the color to the theme, because it might have changed
|
// Always query the color to the theme, because it might have changed
|
||||||
draw(Klooni.theme.getCellColor(colorIndex), batch, pos.x, pos.y, size);
|
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,
|
public Color getColorCopy() {
|
||||||
// in this case, a piece was put. The closer it was put, the faster
|
return Klooni.theme.getCellColor(colorIndex).cpy();
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
|
|
Loading…
Reference in a new issue