Refactor effects to use the Factory pattern (#43)
This shows several advantages: - No need for several switchs with hardcoded names. - Easier and better control per theme (name, price…). - Easier to keep track of available effects and their order.
This commit is contained in:
parent
3429eda94c
commit
d7db9b8f82
19 changed files with 694 additions and 516 deletions
|
@ -1,142 +0,0 @@
|
||||||
/*
|
|
||||||
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
|
||||||
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package io.github.lonamiwebs.klooni;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.audio.Sound;
|
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.effects.EvaporateEffect;
|
|
||||||
import io.github.lonamiwebs.klooni.effects.ExplodeEffect;
|
|
||||||
import io.github.lonamiwebs.klooni.effects.IEffect;
|
|
||||||
import io.github.lonamiwebs.klooni.effects.SpinEffect;
|
|
||||||
import io.github.lonamiwebs.klooni.effects.VanishEffect;
|
|
||||||
import io.github.lonamiwebs.klooni.effects.WaterdropEffect;
|
|
||||||
import io.github.lonamiwebs.klooni.game.Cell;
|
|
||||||
|
|
||||||
public class Effect {
|
|
||||||
|
|
||||||
//region Members
|
|
||||||
|
|
||||||
private final int effectId;
|
|
||||||
private final Sound effectSound;
|
|
||||||
public final String name;
|
|
||||||
public final int price;
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Constructor
|
|
||||||
|
|
||||||
// This method will load the sound "sound/effect_{effectName}.mp3"
|
|
||||||
public Effect(final String effectName) {
|
|
||||||
this(effectName, effectNameToInt(effectName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Effect(final String effectName, final int id) {
|
|
||||||
name = effectName;
|
|
||||||
effectId = id;
|
|
||||||
|
|
||||||
FileHandle soundFile = Gdx.files.internal("sound/effect_" + name + ".mp3");
|
|
||||||
if (!soundFile.exists())
|
|
||||||
soundFile = Gdx.files.internal("sound/effect_vanish.mp3");
|
|
||||||
|
|
||||||
effectSound = Gdx.audio.newSound(soundFile);
|
|
||||||
price = effectId == 0 ? 0 : 200; // TODO For now they're all 200 coins except the first
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Public methods
|
|
||||||
|
|
||||||
public void playSound() {
|
|
||||||
effectSound.play(MathUtils.random(0.7f, 1f), MathUtils.random(0.8f, 1.2f), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplay() {
|
|
||||||
// TODO For now, uppercase the first letter
|
|
||||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Static methods
|
|
||||||
|
|
||||||
public static Effect[] getEffects() {
|
|
||||||
int id = 0;
|
|
||||||
return new Effect[] {
|
|
||||||
new Effect("vanish", id++),
|
|
||||||
new Effect("waterdrop", id++),
|
|
||||||
new Effect("evaporate", id++),
|
|
||||||
new Effect("spin", id++),
|
|
||||||
new Effect("explode", id++)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Name <-> ID <-> IEffect
|
|
||||||
|
|
||||||
// Effects used when clearing a row
|
|
||||||
public IEffect create(final Cell deadCell, final Vector2 culprit) {
|
|
||||||
final IEffect effect;
|
|
||||||
switch (effectId) {
|
|
||||||
default:
|
|
||||||
case 0:
|
|
||||||
effect = new VanishEffect();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
effect = new WaterdropEffect();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
effect = new EvaporateEffect();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
effect = new SpinEffect();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
effect = new ExplodeEffect();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
effect.setInfo(deadCell, culprit);
|
|
||||||
return effect;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int effectNameToInt(final String name) {
|
|
||||||
// String comparision is more expensive compared to a single integer one,
|
|
||||||
// and when creating instances of a lot of effects it's better if we can
|
|
||||||
// save some processor cycles.
|
|
||||||
if (name.equals("vanish")) return 0;
|
|
||||||
if (name.equals("waterdrop")) return 1;
|
|
||||||
if (name.equals("evaporate")) return 2;
|
|
||||||
if (name.equals("spin")) return 3;
|
|
||||||
if (name.equals("explode")) return 4;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Disposal
|
|
||||||
|
|
||||||
void dispose() {
|
|
||||||
effectSound.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
}
|
|
|
@ -22,18 +22,59 @@ import com.badlogic.gdx.Game;
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.Preferences;
|
import com.badlogic.gdx.Preferences;
|
||||||
import com.badlogic.gdx.Screen;
|
import com.badlogic.gdx.Screen;
|
||||||
|
import com.badlogic.gdx.audio.Sound;
|
||||||
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.effects.EvaporateEffectFactory;
|
||||||
|
import io.github.lonamiwebs.klooni.effects.ExplodeEffectFactory;
|
||||||
|
import io.github.lonamiwebs.klooni.effects.SpinEffectFactory;
|
||||||
|
import io.github.lonamiwebs.klooni.effects.VanishEffectFatory;
|
||||||
|
import io.github.lonamiwebs.klooni.effects.WaterdropEffectFactory;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
import io.github.lonamiwebs.klooni.screens.MainMenuScreen;
|
import io.github.lonamiwebs.klooni.screens.MainMenuScreen;
|
||||||
import io.github.lonamiwebs.klooni.screens.TransitionScreen;
|
import io.github.lonamiwebs.klooni.screens.TransitionScreen;
|
||||||
|
|
||||||
public class Klooni extends Game {
|
public class Klooni extends Game {
|
||||||
|
// region Effects
|
||||||
|
|
||||||
|
// ordered list of effects. index 0 will get default if VanishEffectFactory is removed from list
|
||||||
|
public final static IEffectFactory[] EFFECTS = {
|
||||||
|
new VanishEffectFatory(),
|
||||||
|
new WaterdropEffectFactory(),
|
||||||
|
new EvaporateEffectFactory(),
|
||||||
|
new SpinEffectFactory(),
|
||||||
|
new ExplodeEffectFactory(),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, Sound> effectSounds;
|
||||||
|
|
||||||
|
private void loadEffectSound(final String effectName) {
|
||||||
|
FileHandle soundFile = Gdx.files.internal("sound/effect_" + effectName + ".mp3");
|
||||||
|
if (!soundFile.exists())
|
||||||
|
soundFile = Gdx.files.internal("sound/effect_vanish.mp3");
|
||||||
|
|
||||||
|
effectSounds.put(effectName, Gdx.audio.newSound(soundFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playEffectSound() {
|
||||||
|
effectSounds.get(effect.getName())
|
||||||
|
.play(MathUtils.random(0.7f, 1f), MathUtils.random(0.8f, 1.2f), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
//region Members
|
//region Members
|
||||||
|
|
||||||
// TODO Not sure whether the theme should be static or not since it might load textures
|
// FIXME theme should NOT be static as it might load textures which will expose it to the race condition iff GDX got initialized before or not
|
||||||
public static Theme theme;
|
public static Theme theme;
|
||||||
public Effect effect;
|
public IEffectFactory effect;
|
||||||
|
|
||||||
|
|
||||||
public Skin skin;
|
public Skin skin;
|
||||||
|
|
||||||
|
@ -74,7 +115,15 @@ public class Klooni extends Game {
|
||||||
|
|
||||||
Gdx.input.setCatchBackKey(true); // To show the pause menu
|
Gdx.input.setCatchBackKey(true); // To show the pause menu
|
||||||
setScreen(new MainMenuScreen(this));
|
setScreen(new MainMenuScreen(this));
|
||||||
effect = new Effect(prefs.getString("effectName", "vanish"));
|
String effectName = prefs.getString("effectName", "vanish");
|
||||||
|
effectSounds = new HashMap<String, Sound>(EFFECTS.length);
|
||||||
|
effect = EFFECTS[0];
|
||||||
|
for (IEffectFactory e : EFFECTS) {
|
||||||
|
loadEffectSound(e.getName());
|
||||||
|
if (e.getName().equals(effectName)) {
|
||||||
|
effect = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
@ -99,7 +148,12 @@ public class Klooni extends Game {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
skin.dispose();
|
skin.dispose();
|
||||||
theme.dispose();
|
theme.dispose();
|
||||||
effect.dispose();
|
if (effectSounds != null) {
|
||||||
|
for (Sound s : effectSounds.values()) {
|
||||||
|
s.dispose();
|
||||||
|
}
|
||||||
|
effectSounds = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
@ -183,40 +237,40 @@ public class Klooni extends Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effects related
|
// Effects related
|
||||||
public static boolean isEffectBought(Effect effect) {
|
public static boolean isEffectBought(IEffectFactory effect) {
|
||||||
if (effect.price == 0)
|
if (effect.getPrice() == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
String[] effects = prefs.getString("boughtEffects", "").split(":");
|
String[] effects = prefs.getString("boughtEffects", "").split(":");
|
||||||
for (String e : effects)
|
for (String e : effects)
|
||||||
if (e.equals(effect.name))
|
if (e.equals(effect.getName()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean buyEffect(Effect effect) {
|
public static boolean buyEffect(IEffectFactory effect) {
|
||||||
final float money = getRealMoney();
|
final float money = getRealMoney();
|
||||||
if (effect.price > money)
|
if (effect.getPrice() > money)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
setMoney(money - effect.price);
|
setMoney(money - effect.getPrice());
|
||||||
|
|
||||||
String bought = prefs.getString("boughtEffects", "");
|
String bought = prefs.getString("boughtEffects", "");
|
||||||
if (bought.equals(""))
|
if (bought.equals(""))
|
||||||
bought = effect.name;
|
bought = effect.getName();
|
||||||
else
|
else
|
||||||
bought += ":" + effect.name;
|
bought += ":" + effect.getName();
|
||||||
|
|
||||||
prefs.putString("boughtEffects", bought);
|
prefs.putString("boughtEffects", bought);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateEffect(Effect newEffect) {
|
public void updateEffect(IEffectFactory newEffect) {
|
||||||
prefs.putString("effectName", newEffect.name).flush();
|
prefs.putString("effectName", newEffect.getName()).flush();
|
||||||
// Create a new effect, since the one passed through the parameter may dispose later
|
// Create a new effect, since the one passed through the parameter may dispose later
|
||||||
effect = new Effect(newEffect.name);
|
effect = newEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Money related
|
// Money related
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class SkinLoader {
|
||||||
|
|
||||||
private final static float bestMultiplier;
|
private final static float bestMultiplier;
|
||||||
|
|
||||||
|
// FIXME this static code is exposed to a race condition and will fail if called class gets loaded before execution of Klooni.create
|
||||||
static {
|
static {
|
||||||
// Use the height to determine the best match
|
// Use the height to determine the best match
|
||||||
// We cannot use a size which is over the device height,
|
// We cannot use a size which is over the device height,
|
||||||
|
|
|
@ -21,19 +21,19 @@ import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.Effect;
|
|
||||||
import io.github.lonamiwebs.klooni.Klooni;
|
import io.github.lonamiwebs.klooni.Klooni;
|
||||||
import io.github.lonamiwebs.klooni.Theme;
|
import io.github.lonamiwebs.klooni.Theme;
|
||||||
import io.github.lonamiwebs.klooni.game.Board;
|
import io.github.lonamiwebs.klooni.game.Board;
|
||||||
import io.github.lonamiwebs.klooni.game.GameLayout;
|
import io.github.lonamiwebs.klooni.game.GameLayout;
|
||||||
import io.github.lonamiwebs.klooni.game.Piece;
|
import io.github.lonamiwebs.klooni.game.Piece;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
// Card-like actor used to display information about a given theme
|
// Card-like actor used to display information about a given theme
|
||||||
public class EffectCard extends ShopCard {
|
public class EffectCard extends ShopCard {
|
||||||
|
|
||||||
//region Members
|
//region Members
|
||||||
|
|
||||||
private final Effect effect;
|
private final IEffectFactory effect;
|
||||||
private final Board board;
|
private final Board board;
|
||||||
|
|
||||||
// We want to create an effect from the beginning
|
// We want to create an effect from the beginning
|
||||||
|
@ -45,7 +45,7 @@ public class EffectCard extends ShopCard {
|
||||||
|
|
||||||
//region Constructor
|
//region Constructor
|
||||||
|
|
||||||
public EffectCard(final Klooni game, final GameLayout layout, final Effect effect) {
|
public EffectCard(final Klooni game, final GameLayout layout, final IEffectFactory effect) {
|
||||||
super(game, layout, effect.getDisplay(), Klooni.theme.background);
|
super(game, layout, effect.getDisplay(), Klooni.theme.background);
|
||||||
background = Theme.getBlankTexture();
|
background = Theme.getBlankTexture();
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
|
@ -118,12 +118,12 @@ public class EffectCard extends ShopCard {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void usedItemUpdated() {
|
public void usedItemUpdated() {
|
||||||
if (game.effect.name.equals(effect.name))
|
if (game.effect.getName().equals(effect.getName()))
|
||||||
priceLabel.setText("currently used");
|
priceLabel.setText("currently used");
|
||||||
else if (Klooni.isEffectBought(effect))
|
else if (Klooni.isEffectBought(effect))
|
||||||
priceLabel.setText("bought");
|
priceLabel.setText("bought");
|
||||||
else
|
else
|
||||||
priceLabel.setText("buy for "+effect.price);
|
priceLabel.setText("buy for "+effect.getPrice());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,12 +139,12 @@ public class EffectCard extends ShopCard {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUsed() {
|
public boolean isUsed() {
|
||||||
return game.effect.name.equals(effect.name);
|
return game.effect.getName().equals(effect.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getPrice() {
|
public float getPrice() {
|
||||||
return effect.price;
|
return effect.getPrice();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
package io.github.lonamiwebs.klooni.effects;
|
|
||||||
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
|
||||||
import com.badlogic.gdx.math.Interpolation;
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.game.Cell;
|
|
||||||
|
|
||||||
public class EvaporateEffect implements IEffect {
|
|
||||||
private Vector2 pos;
|
|
||||||
private float originalX;
|
|
||||||
|
|
||||||
private float size;
|
|
||||||
|
|
||||||
private Color vanishColor;
|
|
||||||
private float vanishSize;
|
|
||||||
private float vanishElapsed;
|
|
||||||
private float driftMagnitude;
|
|
||||||
private float randomOffset;
|
|
||||||
|
|
||||||
private static final float UP_SPEED = 100.0f;
|
|
||||||
private static final float LIFETIME = 3.0f;
|
|
||||||
private static final float INV_LIFETIME = 1.0f / 3.0f;
|
|
||||||
|
|
||||||
public EvaporateEffect() {
|
|
||||||
vanishElapsed = Float.POSITIVE_INFINITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setInfo(Cell deadCell, Vector2 culprit) {
|
|
||||||
pos = deadCell.pos.cpy();
|
|
||||||
originalX = pos.x;
|
|
||||||
size = deadCell.size;
|
|
||||||
|
|
||||||
vanishSize = deadCell.size;
|
|
||||||
vanishColor = deadCell.getColorCopy();
|
|
||||||
driftMagnitude = Gdx.graphics.getWidth() * 0.05f;
|
|
||||||
vanishElapsed = 0;
|
|
||||||
randomOffset = MathUtils.random(MathUtils.PI2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Batch batch) {
|
|
||||||
vanishElapsed += Gdx.graphics.getDeltaTime();
|
|
||||||
|
|
||||||
// Update the size as we fade away
|
|
||||||
final float progress = vanishElapsed * INV_LIFETIME;
|
|
||||||
vanishSize = Interpolation.fade.apply(size, 0, progress);
|
|
||||||
|
|
||||||
// Fade away depending on the time
|
|
||||||
vanishColor.set(vanishColor.r, vanishColor.g, vanishColor.b, 1.0f - progress);
|
|
||||||
|
|
||||||
// Ghostly fade upwards, by doing a lerp from our current position to the wavy one
|
|
||||||
pos.x = MathUtils.lerp(
|
|
||||||
pos.x,
|
|
||||||
originalX + MathUtils.sin(randomOffset + vanishElapsed * 3f) * driftMagnitude,
|
|
||||||
0.3f
|
|
||||||
);
|
|
||||||
pos.y += UP_SPEED * Gdx.graphics.getDeltaTime();
|
|
||||||
|
|
||||||
Cell.draw(vanishColor, batch, pos.x, pos.y, vanishSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDone() {
|
|
||||||
return vanishElapsed > LIFETIME;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
||||||
|
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.github.lonamiwebs.klooni.effects;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.game.Cell;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffect;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public class EvaporateEffectFactory implements IEffectFactory {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "evaporate";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplay() {
|
||||||
|
return "Evaporate";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPrice() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEffect create(Cell deadCell, Vector2 culprit) {
|
||||||
|
IEffect effect = new EvaporateEffect();
|
||||||
|
effect.setInfo(deadCell, culprit);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class EvaporateEffect implements IEffect {
|
||||||
|
private Vector2 pos;
|
||||||
|
private float originalX;
|
||||||
|
|
||||||
|
private float size;
|
||||||
|
|
||||||
|
private Color vanishColor;
|
||||||
|
private float vanishSize;
|
||||||
|
private float vanishElapsed;
|
||||||
|
private float driftMagnitude;
|
||||||
|
private float randomOffset;
|
||||||
|
|
||||||
|
private static final float UP_SPEED = 100.0f;
|
||||||
|
private static final float LIFETIME = 3.0f;
|
||||||
|
private static final float INV_LIFETIME = 1.0f / 3.0f;
|
||||||
|
|
||||||
|
EvaporateEffect() {
|
||||||
|
vanishElapsed = Float.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInfo(Cell deadCell, Vector2 culprit) {
|
||||||
|
pos = deadCell.pos.cpy();
|
||||||
|
originalX = pos.x;
|
||||||
|
size = deadCell.size;
|
||||||
|
|
||||||
|
vanishSize = deadCell.size;
|
||||||
|
vanishColor = deadCell.getColorCopy();
|
||||||
|
driftMagnitude = Gdx.graphics.getWidth() * 0.05f;
|
||||||
|
vanishElapsed = 0;
|
||||||
|
randomOffset = MathUtils.random(MathUtils.PI2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Batch batch) {
|
||||||
|
vanishElapsed += Gdx.graphics.getDeltaTime();
|
||||||
|
|
||||||
|
// Update the size as we fade away
|
||||||
|
final float progress = vanishElapsed * INV_LIFETIME;
|
||||||
|
vanishSize = Interpolation.fade.apply(size, 0, progress);
|
||||||
|
|
||||||
|
// Fade away depending on the time
|
||||||
|
vanishColor.set(vanishColor.r, vanishColor.g, vanishColor.b, 1.0f - progress);
|
||||||
|
|
||||||
|
// Ghostly fade upwards, by doing a lerp from our current position to the wavy one
|
||||||
|
pos.x = MathUtils.lerp(
|
||||||
|
pos.x,
|
||||||
|
originalX + MathUtils.sin(randomOffset + vanishElapsed * 3f) * driftMagnitude,
|
||||||
|
0.3f
|
||||||
|
);
|
||||||
|
pos.y += UP_SPEED * Gdx.graphics.getDeltaTime();
|
||||||
|
|
||||||
|
Cell.draw(vanishColor, batch, pos.x, pos.y, vanishSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return vanishElapsed > LIFETIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,66 +0,0 @@
|
||||||
package io.github.lonamiwebs.klooni.effects;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
|
||||||
import com.badlogic.gdx.math.Vector3;
|
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.game.Cell;
|
|
||||||
|
|
||||||
public class ExplodeEffect implements IEffect {
|
|
||||||
private Color color;
|
|
||||||
boolean dead;
|
|
||||||
|
|
||||||
private final static float EXPLOSION_X_RANGE = 0.25f;
|
|
||||||
private final static float EXPLOSION_Y_RANGE = 0.30f;
|
|
||||||
private final static float GRAVITY_PERCENTAGE = -0.60f;
|
|
||||||
|
|
||||||
class Shard {
|
|
||||||
final Vector2 pos, vel, acc;
|
|
||||||
final float size;
|
|
||||||
|
|
||||||
public Shard(final Vector2 pos, final float size) {
|
|
||||||
final float xRange = Gdx.graphics.getWidth() * EXPLOSION_X_RANGE;
|
|
||||||
final float yRange = Gdx.graphics.getHeight() * EXPLOSION_Y_RANGE;
|
|
||||||
vel = new Vector2(MathUtils.random(-xRange, +xRange), MathUtils.random(-yRange * 0.2f, +yRange));
|
|
||||||
acc = new Vector2(0f, Gdx.graphics.getHeight() * GRAVITY_PERCENTAGE);
|
|
||||||
|
|
||||||
this.size = size * MathUtils.random(0.40f, 0.60f);
|
|
||||||
this.pos = pos.cpy().add(this.size * 0.5f, this.size * 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void draw(final Batch batch, final float dt) {
|
|
||||||
vel.add(acc.x * dt, acc.y * dt).scl(0.99f);
|
|
||||||
pos.add(vel.x * dt, vel.y * dt);
|
|
||||||
Cell.draw(color, batch, pos.x, pos.y, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Shard[] shards;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setInfo(Cell deadCell, Vector2 culprit) {
|
|
||||||
color = deadCell.getColorCopy();
|
|
||||||
|
|
||||||
shards = new Shard[MathUtils.random(4, 6)];
|
|
||||||
for (int i = 0; i != shards.length; ++i)
|
|
||||||
shards[i] = new Shard(deadCell.pos, deadCell.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Batch batch) {
|
|
||||||
dead = true; // assume we're death
|
|
||||||
final Vector3 translation = batch.getTransformMatrix().getTranslation(new Vector3());
|
|
||||||
for (int i = shards.length; i-- != 0; ) {
|
|
||||||
shards[i].draw(batch, Gdx.graphics.getDeltaTime());
|
|
||||||
dead &= translation.y + shards[i].pos.y + shards[i].size < 0; // all must be dead
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDone() {
|
|
||||||
return dead;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
||||||
|
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.github.lonamiwebs.klooni.effects;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import com.badlogic.gdx.math.Vector3;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.game.Cell;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffect;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public class ExplodeEffectFactory implements IEffectFactory {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "explode";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplay() {
|
||||||
|
return "Explode";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPrice() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEffect create(Cell deadCell, Vector2 culprit) {
|
||||||
|
IEffect effect = new ExplodeEffect();
|
||||||
|
effect.setInfo(deadCell, culprit);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class ExplodeEffect implements IEffect {
|
||||||
|
private Color color;
|
||||||
|
boolean dead;
|
||||||
|
|
||||||
|
private final static float EXPLOSION_X_RANGE = 0.25f;
|
||||||
|
private final static float EXPLOSION_Y_RANGE = 0.30f;
|
||||||
|
private final static float GRAVITY_PERCENTAGE = -0.60f;
|
||||||
|
|
||||||
|
private class Shard {
|
||||||
|
final Vector2 pos, vel, acc;
|
||||||
|
final float size;
|
||||||
|
|
||||||
|
Shard(final Vector2 pos, final float size) {
|
||||||
|
final float xRange = Gdx.graphics.getWidth() * EXPLOSION_X_RANGE;
|
||||||
|
final float yRange = Gdx.graphics.getHeight() * EXPLOSION_Y_RANGE;
|
||||||
|
vel = new Vector2(MathUtils.random(-xRange, +xRange), MathUtils.random(-yRange * 0.2f, +yRange));
|
||||||
|
acc = new Vector2(0f, Gdx.graphics.getHeight() * GRAVITY_PERCENTAGE);
|
||||||
|
|
||||||
|
this.size = size * MathUtils.random(0.40f, 0.60f);
|
||||||
|
this.pos = pos.cpy().add(this.size * 0.5f, this.size * 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(final Batch batch, final float dt) {
|
||||||
|
vel.add(acc.x * dt, acc.y * dt).scl(0.99f);
|
||||||
|
pos.add(vel.x * dt, vel.y * dt);
|
||||||
|
Cell.draw(color, batch, pos.x, pos.y, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Shard[] shards;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInfo(Cell deadCell, Vector2 culprit) {
|
||||||
|
color = deadCell.getColorCopy();
|
||||||
|
|
||||||
|
shards = new Shard[MathUtils.random(4, 6)];
|
||||||
|
for (int i = 0; i != shards.length; ++i)
|
||||||
|
shards[i] = new Shard(deadCell.pos, deadCell.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Batch batch) {
|
||||||
|
dead = true; // assume we're death
|
||||||
|
final Vector3 translation = batch.getTransformMatrix().getTranslation(new Vector3());
|
||||||
|
for (int i = shards.length; i-- != 0; ) {
|
||||||
|
shards[i].draw(batch, Gdx.graphics.getDeltaTime());
|
||||||
|
dead &= translation.y + shards[i].pos.y + shards[i].size < 0; // all must be dead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return dead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
package io.github.lonamiwebs.klooni.effects;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
|
||||||
import com.badlogic.gdx.math.Interpolation;
|
|
||||||
import com.badlogic.gdx.math.Matrix4;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.game.Cell;
|
|
||||||
|
|
||||||
public class SpinEffect implements IEffect {
|
|
||||||
private float age;
|
|
||||||
private Vector2 pos;
|
|
||||||
private float size;
|
|
||||||
private Color color;
|
|
||||||
|
|
||||||
private static final float LIFETIME = 2.0f;
|
|
||||||
private static final float INV_LIFETIME = 1.0f / LIFETIME;
|
|
||||||
|
|
||||||
private static final float TOTAL_ROTATION = 600;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setInfo(Cell deadCell, Vector2 culprit) {
|
|
||||||
age = 0;
|
|
||||||
pos = deadCell.pos.cpy();
|
|
||||||
size = deadCell.size;
|
|
||||||
color = deadCell.getColorCopy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Batch batch) {
|
|
||||||
age += Gdx.graphics.getDeltaTime();
|
|
||||||
|
|
||||||
final float progress = age * INV_LIFETIME;
|
|
||||||
final float currentSize = Interpolation.pow2In.apply(size, 0, progress);
|
|
||||||
final float currentRotation = Interpolation.sine.apply(0, TOTAL_ROTATION, progress);
|
|
||||||
|
|
||||||
final Matrix4 original = batch.getTransformMatrix().cpy();
|
|
||||||
final Matrix4 rotated = batch.getTransformMatrix();
|
|
||||||
|
|
||||||
final float disp =
|
|
||||||
+ 0.5f * (size - currentSize) // the smaller, the more we need to "push" to center
|
|
||||||
+ currentSize * 0.5f; // center the cell for rotation
|
|
||||||
|
|
||||||
rotated.translate(pos.x + disp, pos.y + disp, 0);
|
|
||||||
rotated.rotate(0, 0, 1, currentRotation);
|
|
||||||
rotated.translate(currentSize * -0.5f, currentSize * -0.5f, 0); // revert centering for rotation
|
|
||||||
|
|
||||||
batch.setTransformMatrix(rotated);
|
|
||||||
Cell.draw(color, batch, 0, 0, currentSize);
|
|
||||||
batch.setTransformMatrix(original);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDone() {
|
|
||||||
return age > LIFETIME;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
||||||
|
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.github.lonamiwebs.klooni.effects;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.game.Cell;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffect;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public class SpinEffectFactory implements IEffectFactory {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "spin";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplay() {
|
||||||
|
return "Spin";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPrice() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEffect create(Cell deadCell, Vector2 culprit) {
|
||||||
|
IEffect effect = new SpinEffect();
|
||||||
|
effect.setInfo(deadCell, culprit);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class SpinEffect implements IEffect {
|
||||||
|
private float age;
|
||||||
|
private Vector2 pos;
|
||||||
|
private float size;
|
||||||
|
private Color color;
|
||||||
|
|
||||||
|
private static final float LIFETIME = 2.0f;
|
||||||
|
private static final float INV_LIFETIME = 1.0f / LIFETIME;
|
||||||
|
|
||||||
|
private static final float TOTAL_ROTATION = 600;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInfo(Cell deadCell, Vector2 culprit) {
|
||||||
|
age = 0;
|
||||||
|
pos = deadCell.pos.cpy();
|
||||||
|
size = deadCell.size;
|
||||||
|
color = deadCell.getColorCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Batch batch) {
|
||||||
|
age += Gdx.graphics.getDeltaTime();
|
||||||
|
|
||||||
|
final float progress = age * INV_LIFETIME;
|
||||||
|
final float currentSize = Interpolation.pow2In.apply(size, 0, progress);
|
||||||
|
final float currentRotation = Interpolation.sine.apply(0, TOTAL_ROTATION, progress);
|
||||||
|
|
||||||
|
final Matrix4 original = batch.getTransformMatrix().cpy();
|
||||||
|
final Matrix4 rotated = batch.getTransformMatrix();
|
||||||
|
|
||||||
|
final float disp =
|
||||||
|
+0.5f * (size - currentSize) // the smaller, the more we need to "push" to center
|
||||||
|
+ currentSize * 0.5f; // center the cell for rotation
|
||||||
|
|
||||||
|
rotated.translate(pos.x + disp, pos.y + disp, 0);
|
||||||
|
rotated.rotate(0, 0, 1, currentRotation);
|
||||||
|
rotated.translate(currentSize * -0.5f, currentSize * -0.5f, 0); // revert centering for rotation
|
||||||
|
|
||||||
|
batch.setTransformMatrix(rotated);
|
||||||
|
Cell.draw(color, batch, 0, 0, currentSize);
|
||||||
|
batch.setTransformMatrix(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return age > LIFETIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,72 +0,0 @@
|
||||||
package io.github.lonamiwebs.klooni.effects;
|
|
||||||
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
|
||||||
import com.badlogic.gdx.math.Interpolation;
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
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;
|
|
||||||
|
|
||||||
private final static float MINIMUM_SIZE = 0.3f;
|
|
||||||
|
|
||||||
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(Batch batch) {
|
|
||||||
vanishElapsed += Gdx.graphics.getDeltaTime();
|
|
||||||
|
|
||||||
// vanishElapsed might be < 0 (delay), so clamp to 0
|
|
||||||
float progress = Math.min(1f,
|
|
||||||
Math.max(vanishElapsed, 0f) / vanishLifetime);
|
|
||||||
|
|
||||||
// If one were to plot the elasticIn function, they would see that the slope increases
|
|
||||||
// a lot towards the end- a linear interpolation between the last size + the desired
|
|
||||||
// size at 20% seems to look a lot better.
|
|
||||||
vanishSize = MathUtils.lerp(
|
|
||||||
vanishSize,
|
|
||||||
Interpolation.elasticIn.apply(cell.size, 0, progress),
|
|
||||||
0.2f
|
|
||||||
);
|
|
||||||
|
|
||||||
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 vanishSize < MINIMUM_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
||||||
|
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.github.lonamiwebs.klooni.effects;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.game.Cell;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffect;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public class VanishEffectFatory implements IEffectFactory {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "vanish";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplay() {
|
||||||
|
return "Vanish";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPrice() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEffect create(Cell deadCell, Vector2 culprit) {
|
||||||
|
IEffect effect = new VanishEffect();
|
||||||
|
effect.setInfo(deadCell, culprit);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class VanishEffect implements IEffect {
|
||||||
|
private Cell cell;
|
||||||
|
|
||||||
|
private Color vanishColor;
|
||||||
|
private float vanishSize;
|
||||||
|
private float vanishElapsed;
|
||||||
|
private float vanishLifetime;
|
||||||
|
|
||||||
|
private final static float MINIMUM_SIZE = 0.3f;
|
||||||
|
|
||||||
|
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(Batch batch) {
|
||||||
|
vanishElapsed += Gdx.graphics.getDeltaTime();
|
||||||
|
|
||||||
|
// vanishElapsed might be < 0 (delay), so clamp to 0
|
||||||
|
float progress = Math.min(1f,
|
||||||
|
Math.max(vanishElapsed, 0f) / vanishLifetime);
|
||||||
|
|
||||||
|
// If one were to plot the elasticIn function, they would see that the slope increases
|
||||||
|
// a lot towards the end- a linear interpolation between the last size + the desired
|
||||||
|
// size at 20% seems to look a lot better.
|
||||||
|
vanishSize = MathUtils.lerp(
|
||||||
|
vanishSize,
|
||||||
|
Interpolation.elasticIn.apply(cell.size, 0, progress),
|
||||||
|
0.2f
|
||||||
|
);
|
||||||
|
|
||||||
|
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 vanishSize < MINIMUM_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,74 +0,0 @@
|
||||||
package io.github.lonamiwebs.klooni.effects;
|
|
||||||
|
|
||||||
|
|
||||||
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.math.MathUtils;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
|
||||||
import com.badlogic.gdx.math.Vector3;
|
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.SkinLoader;
|
|
||||||
import io.github.lonamiwebs.klooni.game.Cell;
|
|
||||||
|
|
||||||
public class WaterdropEffect implements IEffect {
|
|
||||||
private Vector2 pos;
|
|
||||||
private boolean dead;
|
|
||||||
|
|
||||||
private Color cellColor;
|
|
||||||
private Color dropColor;
|
|
||||||
private float cellSize;
|
|
||||||
|
|
||||||
private final float fallAcceleration;
|
|
||||||
private float fallSpeed;
|
|
||||||
|
|
||||||
private static final float FALL_ACCELERATION = 500.0f;
|
|
||||||
private static final float FALL_VARIATION = 50.0f;
|
|
||||||
private static final float COLOR_SPEED = 7.5f;
|
|
||||||
|
|
||||||
private final static Texture dropTexture;
|
|
||||||
|
|
||||||
static {
|
|
||||||
dropTexture = SkinLoader.loadPng("cells/drop.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
public WaterdropEffect() {
|
|
||||||
fallAcceleration = FALL_ACCELERATION + MathUtils.random(-FALL_VARIATION, FALL_VARIATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setInfo(Cell deadCell, Vector2 culprit) {
|
|
||||||
pos = deadCell.pos.cpy();
|
|
||||||
cellSize = deadCell.size;
|
|
||||||
cellColor = deadCell.getColorCopy();
|
|
||||||
dropColor = new Color(cellColor.r, cellColor.g, cellColor.b, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Batch batch) {
|
|
||||||
final float dt = Gdx.graphics.getDeltaTime();
|
|
||||||
fallSpeed += fallAcceleration * dt;
|
|
||||||
pos.y -= fallSpeed * dt;
|
|
||||||
|
|
||||||
cellColor.set(
|
|
||||||
cellColor.r, cellColor.g, cellColor.b,
|
|
||||||
Math.max(cellColor.a - COLOR_SPEED * dt, 0.0f)
|
|
||||||
);
|
|
||||||
dropColor.set(
|
|
||||||
cellColor.r, cellColor.g, cellColor.b,
|
|
||||||
Math.min(dropColor.a + COLOR_SPEED * dt, 1.0f)
|
|
||||||
);
|
|
||||||
|
|
||||||
Cell.draw(cellColor, batch, pos.x, pos.y, cellSize);
|
|
||||||
Cell.draw(dropTexture, dropColor, batch, pos.x, pos.y, cellSize);
|
|
||||||
|
|
||||||
final Vector3 translation = batch.getTransformMatrix().getTranslation(new Vector3());
|
|
||||||
dead = translation.y + pos.y + dropTexture.getHeight() < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDone() {
|
|
||||||
return dead;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
||||||
|
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.github.lonamiwebs.klooni.effects;
|
||||||
|
|
||||||
|
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.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import com.badlogic.gdx.math.Vector3;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.SkinLoader;
|
||||||
|
import io.github.lonamiwebs.klooni.game.Cell;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffect;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public class WaterdropEffectFactory implements IEffectFactory {
|
||||||
|
private Texture dropTexture;
|
||||||
|
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
if(dropTexture == null)
|
||||||
|
dropTexture = SkinLoader.loadPng("cells/drop.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "waterdrop";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplay() {
|
||||||
|
return "Waterdrop";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPrice() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEffect create(Cell deadCell, Vector2 culprit) {
|
||||||
|
init();
|
||||||
|
IEffect effect = new WaterdropEffect();
|
||||||
|
effect.setInfo(deadCell, culprit);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class WaterdropEffect implements IEffect {
|
||||||
|
private Vector2 pos;
|
||||||
|
private boolean dead;
|
||||||
|
|
||||||
|
private Color cellColor;
|
||||||
|
private Color dropColor;
|
||||||
|
private float cellSize;
|
||||||
|
|
||||||
|
private final float fallAcceleration;
|
||||||
|
private float fallSpeed;
|
||||||
|
|
||||||
|
private static final float FALL_ACCELERATION = 500.0f;
|
||||||
|
private static final float FALL_VARIATION = 50.0f;
|
||||||
|
private static final float COLOR_SPEED = 7.5f;
|
||||||
|
|
||||||
|
WaterdropEffect() {
|
||||||
|
fallAcceleration = FALL_ACCELERATION + MathUtils.random(-FALL_VARIATION, FALL_VARIATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInfo(Cell deadCell, Vector2 culprit) {
|
||||||
|
pos = deadCell.pos.cpy();
|
||||||
|
cellSize = deadCell.size;
|
||||||
|
cellColor = deadCell.getColorCopy();
|
||||||
|
dropColor = new Color(cellColor.r, cellColor.g, cellColor.b, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Batch batch) {
|
||||||
|
final float dt = Gdx.graphics.getDeltaTime();
|
||||||
|
fallSpeed += fallAcceleration * dt;
|
||||||
|
pos.y -= fallSpeed * dt;
|
||||||
|
|
||||||
|
cellColor.set(
|
||||||
|
cellColor.r, cellColor.g, cellColor.b,
|
||||||
|
Math.max(cellColor.a - COLOR_SPEED * dt, 0.0f)
|
||||||
|
);
|
||||||
|
dropColor.set(
|
||||||
|
cellColor.r, cellColor.g, cellColor.b,
|
||||||
|
Math.min(dropColor.a + COLOR_SPEED * dt, 1.0f)
|
||||||
|
);
|
||||||
|
|
||||||
|
Cell.draw(cellColor, batch, pos.x, pos.y, cellSize);
|
||||||
|
Cell.draw(dropTexture, dropColor, batch, pos.x, pos.y, cellSize);
|
||||||
|
|
||||||
|
final Vector3 translation = batch.getTransformMatrix().getTranslation(new Vector3());
|
||||||
|
dead = translation.y + pos.y + dropTexture.getHeight() < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return dead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,8 +27,8 @@ 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.Effect;
|
import io.github.lonamiwebs.klooni.interfaces.IEffect;
|
||||||
import io.github.lonamiwebs.klooni.effects.IEffect;
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
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
|
||||||
|
@ -183,7 +183,7 @@ public class Board implements BinSerializable {
|
||||||
//
|
//
|
||||||
// If the piece is put on the top left corner, all the cells will be cleared.
|
// If the piece is put on the top left corner, all the cells will be cleared.
|
||||||
// If we first cleared the columns, then the rows wouldn't have been cleared.
|
// If we first cleared the columns, then the rows wouldn't have been cleared.
|
||||||
public int clearComplete(final Effect effect) {
|
public int clearComplete(final IEffectFactory effect) {
|
||||||
int clearCount = 0;
|
int clearCount = 0;
|
||||||
boolean[] clearedRows = new boolean[cellCount];
|
boolean[] clearedRows = new boolean[cellCount];
|
||||||
boolean[] clearedCols = new boolean[cellCount];
|
boolean[] clearedCols = new boolean[cellCount];
|
||||||
|
@ -235,7 +235,7 @@ public class Board implements BinSerializable {
|
||||||
return clearCount;
|
return clearCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAll(final int clearFromX, final int clearFromY, final Effect effect) {
|
public void clearAll(final int clearFromX, final int clearFromY, final IEffectFactory effect) {
|
||||||
final Vector2 culprit = cells[clearFromY][clearFromX].pos;
|
final Vector2 culprit = cells[clearFromY][clearFromX].pos;
|
||||||
|
|
||||||
for (int i = 0; i < cellCount; ++i) {
|
for (int i = 0; i < cellCount; ++i) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.github.lonamiwebs.klooni.effects;
|
package io.github.lonamiwebs.klooni.interfaces;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
1010! Klooni, a free customizable puzzle game for Android and Desktop
|
||||||
|
Copyright (C) 2017 Lonami Exo | LonamiWebs
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.github.lonamiwebs.klooni.interfaces;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
|
import io.github.lonamiwebs.klooni.game.Cell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IEffectEfactory interface has to be implemented for each effect.
|
||||||
|
*
|
||||||
|
* It tells the name and the price of the effect and will create it, when needed.
|
||||||
|
*
|
||||||
|
* @see IEffect
|
||||||
|
*/
|
||||||
|
public interface IEffectFactory {
|
||||||
|
public String getName();
|
||||||
|
public String getDisplay();
|
||||||
|
public int getPrice();
|
||||||
|
public IEffect create(final Cell deadCell, final Vector2 culprit);
|
||||||
|
}
|
|
@ -34,7 +34,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||||
import com.badlogic.gdx.utils.SnapshotArray;
|
import com.badlogic.gdx.utils.SnapshotArray;
|
||||||
|
|
||||||
import io.github.lonamiwebs.klooni.Effect;
|
|
||||||
import io.github.lonamiwebs.klooni.Klooni;
|
import io.github.lonamiwebs.klooni.Klooni;
|
||||||
import io.github.lonamiwebs.klooni.Theme;
|
import io.github.lonamiwebs.klooni.Theme;
|
||||||
import io.github.lonamiwebs.klooni.actors.EffectCard;
|
import io.github.lonamiwebs.klooni.actors.EffectCard;
|
||||||
|
@ -43,6 +42,7 @@ import io.github.lonamiwebs.klooni.actors.ShopCard;
|
||||||
import io.github.lonamiwebs.klooni.actors.SoftButton;
|
import io.github.lonamiwebs.klooni.actors.SoftButton;
|
||||||
import io.github.lonamiwebs.klooni.actors.ThemeCard;
|
import io.github.lonamiwebs.klooni.actors.ThemeCard;
|
||||||
import io.github.lonamiwebs.klooni.game.GameLayout;
|
import io.github.lonamiwebs.klooni.game.GameLayout;
|
||||||
|
import io.github.lonamiwebs.klooni.interfaces.IEffectFactory;
|
||||||
|
|
||||||
// Screen where the user can customize the look and feel of the game
|
// Screen where the user can customize the look and feel of the game
|
||||||
class CustomizeScreen implements Screen {
|
class CustomizeScreen implements Screen {
|
||||||
|
@ -200,7 +200,7 @@ class CustomizeScreen implements Screen {
|
||||||
shopGroup.clear();
|
shopGroup.clear();
|
||||||
|
|
||||||
if (showingEffectsShop)
|
if (showingEffectsShop)
|
||||||
for (Effect effect : Effect.getEffects())
|
for (IEffectFactory effect : Klooni.EFFECTS)
|
||||||
addCard(new EffectCard(game, layout, effect));
|
addCard(new EffectCard(game, layout, effect));
|
||||||
|
|
||||||
else // showingThemesShop
|
else // showingThemesShop
|
||||||
|
|
|
@ -241,7 +241,7 @@ class GameScreen implements Screen, InputProcessor, BinSerializable {
|
||||||
if (bonus > 0) {
|
if (bonus > 0) {
|
||||||
bonusParticleHandler.addBonus(result.pieceCenter, bonus);
|
bonusParticleHandler.addBonus(result.pieceCenter, bonus);
|
||||||
if (Klooni.soundsEnabled()) {
|
if (Klooni.soundsEnabled()) {
|
||||||
game.effect.playSound();
|
game.playEffectSound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue