Make the clear-row vanish effect a lot more generic

This commit is contained in:
Lonami Exo 2017-07-08 20:57:20 +02:00
parent cbb13f672f
commit 0713d4a5de
4 changed files with 108 additions and 54 deletions

View 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();
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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() {