Add custom Theme system using external files

This commit is contained in:
Lonami Exo 2017-01-30 15:52:10 +01:00
parent eb9b6ee5f1
commit 219e229bb9
7 changed files with 135 additions and 93 deletions

View file

@ -0,0 +1,19 @@
{
"name": "Default",
"price": 0,
"colors": {
"background": "e6e6e6ff",
"buttons": [
"00ff33ff",
"ffd700ff",
"2389fcff",
"d94848ff"
],
"cells": [
"7988bfff", "98dc53ff", "4cd4aeff",
"fec63dff", "ec9548ff", "e66a82ff", "da6554ff",
"57cb84ff", "5abee2ff"
]
},
"cell_texture": "basic.png"
}

View file

@ -11,12 +11,17 @@ import io.github.lonamiwebs.klooni.screens.MainMenuScreen;
public class Klooni extends Game { public class Klooni extends Game {
// TODO Not sure whether the theme should be static or not since it might load textures
public static Theme theme;
public Skin skin; public Skin skin;
@Override @Override
public void create() { public void create() {
prefs = Gdx.app.getPreferences("io.github.lonamiwebs.klooni.game"); prefs = Gdx.app.getPreferences("io.github.lonamiwebs.klooni.game");
// Use only one instance for the theme, so anyone using it uses the most up-to-date
theme = Theme.getTheme(prefs.getString("themeName", "default"));
// TODO Better way to have this skin somewhere // TODO Better way to have this skin somewhere
// Gotta create that darn .json! // Gotta create that darn .json!
skin = new Skin(Gdx.files.internal("skin/uiskin.json")); skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
@ -54,6 +59,7 @@ public class Klooni extends Game {
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
skin.dispose(); skin.dispose();
theme.dispose();
} }
//region Settings //region Settings

View file

@ -0,0 +1,87 @@
package io.github.lonamiwebs.klooni;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
public class Theme {
private String displayName;
private String name;
private int price;
private Color background;
private Color[] cells;
private Color[] buttons;
private Theme() { }
public static Theme[] getThemes() {
FileHandle[] handles = Gdx.files.internal("themes").list();
Theme[] result = new Theme[handles.length];
for (int i = 0; i < handles.length; i++) {
result[i] = Theme.fromFile(handles[i]);
}
return result;
}
static Theme getTheme(final String name) {
return new Theme().update(name);
}
private static Theme fromFile(FileHandle handle) {
return new Theme().update(handle);
}
public Theme update(final String name) {
return update(Gdx.files.internal("themes/"+name+".theme"));
}
private Theme update(final FileHandle handle) {
final JsonValue json = new JsonReader().parse(handle.readString());
name = handle.nameWithoutExtension();
displayName = json.getString("name");
price = json.getInt("price");
JsonValue colors = json.get("colors");
background = new Color( // Java won't allow unsigned integers, we need to use Long
(int)Long.parseLong(colors.getString("background"), 16));
JsonValue buttonColors = colors.get("buttons");
buttons = new Color[buttonColors.size];
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new Color((int)Long.parseLong(buttonColors.getString(i), 16));
}
JsonValue cellColors = colors.get("cells");
cells = new Color[cellColors.size];
for (int i = 0; i < cells.length; i++) {
cells[i] = new Color((int)Long.parseLong(cellColors.getString(i), 16));
}
String cellTextureFile = json.getString("cell_texture");
return this;
}
// TODO Avoid creating game.skin.newDrawable all the time without disposing
public ImageButton.ImageButtonStyle getStyle(final Skin skin, int button, final String imageName) {
return new ImageButton.ImageButtonStyle(
skin.newDrawable("button_up", buttons[button]),
skin.newDrawable("button_down", buttons[button]),
null, skin.getDrawable(imageName), null, null);
}
public Color getCellColor(int colorIndex) {
return cells[colorIndex];
}
void dispose() {
}
}

View file

@ -7,16 +7,12 @@ import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import io.github.lonamiwebs.klooni.Klooni;
// Pieces can be L shaped and be rotated 0 to 3 times to make it random // Pieces can be L shaped and be rotated 0 to 3 times to make it random
// Maximum cellSize = 4 // Maximum cellSize = 4
public class Piece { public class Piece {
private final static int[] colors = {
0x7988bfff, 0x98dc53ff, 0x4cd4aeff, // Squares
0xfec63dff, 0xec9548ff, 0xe66a82ff, 0xda6554ff, // Lines
0x57cb84ff, 0x5abee2ff // L's
};
final Vector2 pos; final Vector2 pos;
float cellSize = 10f; // Default float cellSize = 10f; // Default
@ -26,7 +22,7 @@ public class Piece {
final Color color; final Color color;
private Piece(int cols, int rows, boolean swapSize, int colorIndex) { private Piece(int cols, int rows, boolean swapSize, int colorIndex) {
color = new Color(colors[colorIndex]); color = Klooni.theme.getCellColor(colorIndex);
pos = new Vector2(); pos = new Vector2();
cellCols = swapSize ? rows : cols; cellCols = swapSize ? rows : cols;
@ -40,7 +36,7 @@ public class Piece {
} }
private Piece(int lSize, int rotateCount, int colorIndex) { private Piece(int lSize, int rotateCount, int colorIndex) {
color = new Color(colors[colorIndex]); color = Klooni.theme.getCellColor(colorIndex);
pos = new Vector2(); pos = new Vector2();
cellCols = cellRows = lSize; cellCols = cellRows = lSize;

View file

@ -4,7 +4,6 @@ package io.github.lonamiwebs.klooni.screens;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input; import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen; import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.Stage;
@ -14,7 +13,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup; 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.scenes.scene2d.utils.Drawable;
import io.github.lonamiwebs.klooni.Klooni; import io.github.lonamiwebs.klooni.Klooni;
@ -35,13 +33,7 @@ public class CustomizeScreen implements Screen {
optionsGroup.space(12); optionsGroup.space(12);
// Back to the previous screen // Back to the previous screen
ImageButton.ImageButtonStyle backStyle = new ImageButton.ImageButtonStyle( final ImageButton backButton = new ImageButton(Klooni.theme.getStyle(game.skin, 1, "back_texture"));
game.skin.newDrawable("button_up", Color.GOLD),
game.skin.newDrawable("button_down", Color.GOLD),
null, game.skin.getDrawable("back_texture"), null, null);
final ImageButton backButton = new ImageButton(backStyle);
optionsGroup.addActor(backButton);
backButton.addListener(new ChangeListener() { backButton.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
@ -49,18 +41,12 @@ public class CustomizeScreen implements Screen {
dispose(); dispose();
} }
}); });
optionsGroup.addActor(backButton);
// Turn sound on/off // Turn sound on/off
Drawable soundDrawable = game.skin.getDrawable( final ImageButton soundButton = new ImageButton(Klooni.theme.getStyle(
Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture"); game.skin, 0, Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture"));
ImageButton.ImageButtonStyle soundStyle = new ImageButton.ImageButtonStyle(
game.skin.newDrawable("button_up", Color.LIME),
game.skin.newDrawable("button_down", Color.LIME),
null, soundDrawable, null, null);
final ImageButton soundButton = new ImageButton(soundStyle);
optionsGroup.addActor(soundButton);
soundButton.addListener(new ChangeListener() { soundButton.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
@ -69,36 +55,27 @@ public class CustomizeScreen implements Screen {
Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture"); Klooni.soundsEnabled() ? "sound_on_texture" : "sound_off_texture");
} }
}); });
optionsGroup.addActor(soundButton);
// Issues // Issues
ImageButton.ImageButtonStyle issuesStyle = new ImageButton.ImageButtonStyle( final ImageButton issuesButton = new ImageButton(Klooni.theme.getStyle(game.skin, 3, "issues_texture"));
game.skin.newDrawable("button_up", Color.FIREBRICK),
game.skin.newDrawable("button_down", Color.FIREBRICK),
null, game.skin.getDrawable("issues_texture"), null, null);
final ImageButton issuesButton = new ImageButton(issuesStyle);
optionsGroup.addActor(issuesButton);
issuesButton.addListener(new ChangeListener() { issuesButton.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
Gdx.net.openURI("https://github.com/LonamiWeb/Klooni1010/issues"); Gdx.net.openURI("https://github.com/LonamiWeb/Klooni1010/issues");
} }
}); });
optionsGroup.addActor(issuesButton);
// Website // Website
ImageButton.ImageButtonStyle webStyle = new ImageButton.ImageButtonStyle( final ImageButton webButton = new ImageButton(Klooni.theme.getStyle(game.skin, 2, "web_texture"));
game.skin.newDrawable("button_up", new Color(0x6E99FFFF)),
game.skin.newDrawable("button_down", new Color(0x6E99FFFF)),
null, game.skin.getDrawable("web_texture"), null, null);
final ImageButton webButton = new ImageButton(webStyle);
optionsGroup.addActor(webButton);
webButton.addListener(new ChangeListener() { webButton.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
Gdx.net.openURI("https://lonamiwebs.github.io"); Gdx.net.openURI("https://lonamiwebs.github.io");
} }
}); });
optionsGroup.addActor(webButton);
table.add(new ScrollPane(optionsGroup)).pad(20, 4, 12, 4); table.add(new ScrollPane(optionsGroup)).pad(20, 4, 12, 4);
table.row(); table.row();

View file

@ -3,7 +3,6 @@ package io.github.lonamiwebs.klooni.screens;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input; import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen; import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
@ -32,56 +31,34 @@ public class MainMenuScreen extends InputListener implements Screen {
stage.addActor(table); stage.addActor(table);
// Play button // Play button
ImageButton.ImageButtonStyle playStyle = new ImageButton.ImageButtonStyle( final ImageButton playButton = new ImageButton(Klooni.theme.getStyle(game.skin, 0, "play_texture"));
game.skin.newDrawable("button_up", Color.GREEN),
game.skin.newDrawable("button_down", Color.GREEN),
null, game.skin.getDrawable("play_texture"), null, null);
final ImageButton playButton = new ImageButton(playStyle);
table.add(playButton).colspan(3).fill().space(16);
playButton.addListener(new ChangeListener() { playButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
game.setScreen(new GameScreen(game)); game.setScreen(new GameScreen(game));
dispose(); dispose();
} }
}); });
table.add(playButton).colspan(3).fill().space(16);
table.row(); table.row();
// Star button (on GitHub) // Star button (on GitHub)
ImageButton.ImageButtonStyle starStyle = new ImageButton.ImageButtonStyle( final ImageButton starButton = new ImageButton(Klooni.theme.getStyle(game.skin, 1, "star_texture"));
game.skin.newDrawable("button_up", Color.YELLOW),
game.skin.newDrawable("button_down", Color.YELLOW),
null, game.skin.getDrawable("star_texture"), null, null);
final ImageButton starButton = new ImageButton(starStyle);
table.add(starButton).space(16); table.add(starButton).space(16);
// Stats button (high scores) // Stats button (high scores)
ImageButton.ImageButtonStyle statsStyle = new ImageButton.ImageButtonStyle( final ImageButton statsButton = new ImageButton(Klooni.theme.getStyle(game.skin, 2, "stats_texture"));
game.skin.newDrawable("button_up", Color.BLUE),
game.skin.newDrawable("button_down", Color.BLUE),
null, game.skin.getDrawable("stats_texture"), null, null);
final ImageButton statsButton = new ImageButton(statsStyle);
table.add(statsButton).space(16); table.add(statsButton).space(16);
// Palette button (buy colors) // Palette button (buy colors)
ImageButton.ImageButtonStyle paletteStyle = new ImageButton.ImageButtonStyle( final ImageButton paletteButton = new ImageButton(Klooni.theme.getStyle(game.skin, 3, "palette_texture"));
game.skin.newDrawable("button_up", Color.FIREBRICK),
game.skin.newDrawable("button_down", Color.FIREBRICK),
null, game.skin.getDrawable("palette_texture"), null, null);
final ImageButton paletteButton = new ImageButton(paletteStyle);
table.add(paletteButton).space(16);
paletteButton.addListener(new ChangeListener() { paletteButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
game.setScreen(new CustomizeScreen(game, game.getScreen())); game.setScreen(new CustomizeScreen(game, game.getScreen()));
// Don't dispose because then it needs to take us to the previous screen // Don't dispose because then it needs to take us to the previous screen
} }
}); });
table.add(paletteButton).space(16);
} }
@Override @Override

View file

@ -42,12 +42,7 @@ public class PauseMenuStage extends Stage {
addActor(band); addActor(band);
// Home screen button // Home screen button
ImageButton.ImageButtonStyle homeStyle = new ImageButton.ImageButtonStyle( final ImageButton homeButton = new ImageButton(Klooni.theme.getStyle(game.skin, 3, "home_texture"));
game.skin.newDrawable("button_up", Color.FIREBRICK),
game.skin.newDrawable("button_down", Color.FIREBRICK),
null, game.skin.getDrawable("home_texture"), null, null);
final ImageButton homeButton = new ImageButton(homeStyle);
table.add(homeButton).space(16); table.add(homeButton).space(16);
homeButton.addListener(new ChangeListener() { homeButton.addListener(new ChangeListener() {
@ -58,12 +53,7 @@ public class PauseMenuStage extends Stage {
}); });
// Replay button // Replay button
ImageButton.ImageButtonStyle replayStyle = new ImageButton.ImageButtonStyle( final ImageButton replayButton = new ImageButton(Klooni.theme.getStyle(game.skin, 0, "replay_texture"));
game.skin.newDrawable("button_up", Color.GREEN),
game.skin.newDrawable("button_down", Color.GREEN),
null, game.skin.getDrawable("replay_texture"), null, null);
final ImageButton replayButton = new ImageButton(replayStyle);
table.add(replayButton).space(16); table.add(replayButton).space(16);
replayButton.addListener(new ChangeListener() { replayButton.addListener(new ChangeListener() {
@ -77,12 +67,7 @@ public class PauseMenuStage extends Stage {
table.row(); table.row();
// Palette button (buy colors) // Palette button (buy colors)
ImageButton.ImageButtonStyle paletteStyle = new ImageButton.ImageButtonStyle( final ImageButton paletteButton = new ImageButton(Klooni.theme.getStyle(game.skin, 1, "palette_texture"));
game.skin.newDrawable("button_up", Color.YELLOW),
game.skin.newDrawable("button_down", Color.YELLOW),
null, game.skin.getDrawable("palette_texture"), null, null);
final ImageButton paletteButton = new ImageButton(paletteStyle);
table.add(paletteButton).space(16); table.add(paletteButton).space(16);
paletteButton.addListener(new ChangeListener() { paletteButton.addListener(new ChangeListener() {
@ -95,12 +80,7 @@ public class PauseMenuStage extends Stage {
// Continue playing OR share (if game over) button // Continue playing OR share (if game over) button
// TODO Enable both actions for this button // TODO Enable both actions for this button
ImageButton.ImageButtonStyle playStyle = new ImageButton.ImageButtonStyle( final ImageButton playButton = new ImageButton(Klooni.theme.getStyle(game.skin, 2, "play_texture"));
game.skin.newDrawable("button_up", Color.BLUE),
game.skin.newDrawable("button_down", Color.BLUE),
null, game.skin.getDrawable("play_texture"), null, null);
final ImageButton playButton = new ImageButton(playStyle);
table.add(playButton).space(16); table.add(playButton).space(16);
playButton.addListener(new ChangeListener() { playButton.addListener(new ChangeListener() {