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.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<IEffect> 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<IEffect>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue