package org.test.cat.puzzle.game;
import java.util.ArrayList;
import loon.LSystem;
import loon.LTexture;
import loon.LTextures;
import loon.Screen;
import loon.action.sprite.effect.RippleEffect;
import loon.canvas.LColor;
import loon.event.GameKey;
import loon.event.GameTouch;
import loon.event.SysKey;
import loon.font.BMFont;
import loon.geom.RectBox;
import loon.opengl.GLEx;
import loon.utils.MathUtils;
import loon.utils.timer.LTimerContext;
public class Puzzle extends Screen {
private static final int BOARD_TOP = -816;
private static final int BOARD_LEFT = 12;
public static final int SPIN_SCALAR = 2;
public static final int MAX_PIECE = 6;
public static final int TILE = 0;
public static final int REMOVE_MARKER = 1;
public static final int FALL_MARKER = 2;
public static final int MATCH_HINT = 3;
public static final int PLAY = 0;
public static final int SWAP = 1;
public static final int REMOVE = 2;
public static final int FALL = 3;
public static final int SWAP_BACK = 4;
public static final int HINT = 5;
private LTexture bottom;
private LTexture edge;
private LTexture[] kitis = new LTexture[9];
private LTexture logo;
private LTexture matchesLabel;
private LTexture scoreLabel;
private LTexture timeLabel;
private LTexture kitty;
private BMFont font;
private BMFont numbers;
private boolean starting = true;
private float ang;
private int time;
private int score;
private int matches;
private int[][][] tiles = new int[8][20][10];
private int selectedx;
private int selectedy;
private boolean selected;
private int tappedx;
private int tappedy;
private int state;
private float swapx;
private float swapy;
private float removeStep;
private int fallOffset;
private long start;
private RectBox hintRect;
private RectBox quitRect;
private int gameOverCounter;
private int movesLeft;
public Puzzle() {
}
private String pad(int value, int len) {
String v = "" + value;
while (v.length() < len) {
v = "0" + v;
}
return v;
}
public void onLoad() {
try {
font = new BMFont("assets/puzzle.fnt", "assets/puzzle_00.tga");
} catch (Exception e) {
e.printStackTrace();
}
try {
numbers = new BMFont("assets/numbers.fnt", "assets/numbers_00.tga");
} catch (Exception e) {
e.printStackTrace();
}
//优先绘制用户界面
fristUserDraw();
RippleEffect effect = new RippleEffect();
add(effect);
bottom = LTextures.loadTexture("assets/bottom.png");
edge = LTextures.loadTexture("assets/edges.png");
logo = LTextures.loadTexture("assets/logo.png");
matchesLabel = LTextures.loadTexture("assets/matches.png");
scoreLabel = LTextures.loadTexture("assets/score.png");
timeLabel = LTextures.loadTexture("assets/time.png");
kitty = LTextures.loadTexture("assets/kitty.png");
for (int i = 1; i < 10; i++) {
kitis[i - 1] = LTextures.loadTexture("assets/" + i + ".png");
}
kitis[2] = kitis[6];
kitis[4] = kitis[8];
hintRect = new RectBox(469, 375, 100, 30);
quitRect = new RectBox(468, 415, 100, 30);
clearBoard();
setBackground("assets/background.png");
}
ArrayList<Integer> list = new ArrayList<Integer>();
private ArrayList<Integer> getValidPieces(int x, int y) {
list.clear();
for (int i = 0; i < MAX_PIECE; i++) {
list.add(new Integer(i));
}
if (x > 0) {
list.remove(new Integer(tiles[x - 1][y][TILE]));
}
if (x < 7) {
list.remove(new Integer(tiles[x + 1][y][TILE]));
}
if (y > 0) {
list.remove(new Integer(tiles[x][y - 1][TILE]));
}
if (y < 9) {
list.remove(new Integer(tiles[x][y + 1][TILE]));
}
return list;
}
private void start() {
gameOverCounter = 0;
start = System.currentTimeMillis();
starting = false;
matches = 0;
score = 0;
time = 0;
clearBoard();
fillSpaces();
state = PLAY;
}
private void clearBoard() {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 20; y++) {
tiles[x][y][TILE] = -1;
}
}
}
private void drawNumberString(GLEx g, BMFont font, String str, int y) {
font.drawString(g, str,
(456 + ((180 - (numbers.stringWidth(str))) / 2)), y + 1);
font.drawString(g, str,
(455 + ((180 - (numbers.stringWidth(str))) / 2)), y);
}
public void render(GLEx g) {
}
private void finishRemove() {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 20; y++) {
if (tiles[x][y][REMOVE_MARKER] == 1) {
tiles[x][y][REMOVE_MARKER] = 0;
tiles[x][y][TILE] = -1;
}
}
}
}
private void fillSpaces() {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 20; y++) {
ArrayList<Integer> pieces = getValidPieces(x, y);
if (tiles[x][y][TILE] == -1) {
tiles[x][y][TILE] = ((Integer) pieces.get((int) (Math
.random() * pieces.size()))).intValue();
}
}
}
}
private int findFalls() {
int foundFalls = 0;
for (int y = 19; y > 0; y--) {
for (int x = 0; x < 8; x++) {
tiles[x][y][FALL_MARKER] = 0;
if ((tiles[x][y][TILE] == -1) && (tiles[x][y - 1][TILE] != -1)) {
tiles[x][y][TILE] = tiles[x][y - 1][TILE];
tiles[x][y - 1][TILE] = -1;
tiles[x][y][FALL_MARKER] = 1;
foundFalls++;
fallOffset = 64;
}
}
}
return foundFalls;
}
private int findMoves() {
int total = 0;
for (int y = 13; y < 20; y++) {
for (int x = 0; x < 8; x++) {
if (x < 7) {
swap(x, y, x + 1, y);
int matches = findMatches(false);
swap(x, y, x + 1, y);
if (matches != 0) {
total++;
}
}
if (y < 19) {
swap(x, y, x, y + 1);
int matches = findMatches(false);
swap(x, y, x, y + 1);
if (matches != 0) {
total++;
}
}
}
}
return total;
}
private void hint() {
if (state == PLAY) {
int total = findMoves();
if (total == 0) {
} else {
int move = (int) (Math.random() * total);
for (int y = 13; y < 20; y++) {
for (int x = 0; x < 8; x++) {
if (x < 7) {
swap(x, y, x + 1, y);
int matches = findMatches(false);
swap(x, y, x + 1, y);
if (matches != 0) {
move--;
if (move <= 1) {
tiles[x][y][MATCH_HINT] = 360 * SPIN_SCALAR;
tiles[x + 1][y][MATCH_HINT] = 360 * SPIN_SCALAR;
state = HINT;
return;
}
}
}
if (y < 19) {
swap(x, y, x, y + 1);
int matches = findMatches(false);
swap(x, y, x, y + 1);
if (matches != 0) {
move--;
if (move <= 1) {
tiles[x][y][MATCH_HINT] = 360 * SPIN_SCALAR;
tiles[x][y + 1][MATCH_HINT] = 360 * SPIN_SCALAR;
state = HINT;
return;
}
}
}
}
}
}
}
}
private void swap(int x1, int y1, int x2, int y2) {
int t1 = tiles[x1][y1][TILE];
tiles[x1][y1][TILE] = tiles[x2][y2][TILE];
tiles[x2][y2][TILE] = t1;
}
private int findMatches() {
return findMatches(true);
}
private int findMatches(boolean updateGameState) {
int foundMatches = 0;
for (int y = 19; y > 12; y--) {
for (int x = 0; x < 8; x++) {
int ours = tiles[x][y][TILE];
if (ours != -1) {
if ((x > 0) && (x < 7)) {
if ((tiles[x - 1][y][TILE] == ours)
&& (tiles[x + 1][y][TILE] == ours)) {
int bonus = 100;
boolean newMatch = true;
if (tiles[x - 1][y][REMOVE_MARKER] == 1) {
newMatch = false;
bonus *= 2;
}
if (tiles[x + 1][y][REMOVE_MARKER] == 1) {
newMatch = false;
bonus *= 2;
}
foundMatches++;
if (updateGameState) {
tiles[x - 1][y][REMOVE_MARKER] = 1;
tiles[x][y][REMOVE_MARKER] = 1;
tiles[x + 1][y][REMOVE_MARKER] = 1;
score += bonus;
if (newMatch) {
matches++;
}
}
}
}
if ((y > 13) && (y < 19)) {
if ((tiles[x][y - 1][TILE] == ours)
&& (tiles[x][y + 1][TILE] == ours)) {
int bonus = 100;
boolean newMatch = true;
if (tiles[x][y - 1][REMOVE_MARKER] == 1) {
newMatch = false;
bonus *= 2;
}
if (tiles[x][y + 1][REMOVE_MARKER] == 1) {
newMatch = false;
bonus *= 2;
}
foundMatches++;
if (updateGameState) {
tiles[x][y - 1][REMOVE_MARKER] = 1;
tiles[x][y][REMOVE_MARKER] = 1;
tiles[x][y + 1][REMOVE_MARKER] = 1;
score += bonus;
if (newMatch) {
matches++;
}
}
}
}
}
}
}
return foundMatches;
}
private void swap() {
int xd = tappedx - selectedx;
int yd = tappedy - selectedy;
swapx = xd * 54;
swapy = yd * 64;
selected = false;
state = SWAP;
}
public void mousePressed(int button, int x, int y) {
if (starting) {
start();
} else {
if (quitRect.contains(x, y)) {
starting = true;
return;
}
if (hintRect.contains(x, y)) {
hint();
return;
}
if (state == PLAY) {
if (button != 0) {
selected = false;
return;
}
x -= 11;
y -= -831;
x /= 54;
y /= 64;
if ((x >= 0) && (x < 8) && (y >= 2) && (y < 20)) {
if (!selected) {
selected = true;
selectedx = x;
selectedy = y;
} else {
int xd = Math.abs(x - selectedx);
int yd = Math.abs(y - selectedy);
if ((xd == 0) && (yd == 0)) {
selected = false;
} else if (xd + yd == 1) {
tappedx = x;
tappedy = y;
selected = false;
swap();
}
}
} else {
selected = false;
}
}
}
}
public void draw(GLEx g) {
if (!isOnLoadComplete()) {
return;
}
g.saveTx();
g.scale(0.8f, 1);
bottom.draw(2, 450);
edge.draw(9, 0, edge.getWidth(), 450);
g.restoreTx();
matchesLabel.draw(460, 10);
scoreLabel.draw(480, 130);
timeLabel.draw(490, 250);
kitty.draw(535, 340);
font.drawString(g, "HELP", 470, 386, LColor.black);
font.drawString(g, "QUIT", 469, 426, LColor.black);
font.drawString(g, "HELP", 469, 385, LColor.white);
font.drawString(g, "QUIT", 468, 425, LColor.white);
if (numbers != null) {
String str = pad(matches, 4);
drawNumberString(g, numbers, str, 50);
str = pad(score, 7);
drawNumberString(g, numbers, str, 170);
str = pad(time / 60, 2) + ":" + pad(time % 60, 2);
drawNumberString(g, numbers, str, 290);
}
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 20; y++) {
int tile = tiles[x][y][TILE];
float yofs = 0;
float xofs = 0;
if (tile != -1) {
if (selected) {
if ((selectedx == x) && (selectedy == y)) {
yofs = (MathUtils.cos(ang) * 4);
g.setColor(1f, 1f, 0f, 0.5f);
g.fillOval(BOARD_LEFT + (x * 54),
(BOARD_TOP + (y * 64)), 54, 44);
g.setColor(LColor.black);
g.drawOval(BOARD_LEFT + (x * 54),
(BOARD_TOP + (y * 64)), 54, 44);
g.resetColor();
}
}
if ((state == SWAP) || (state == SWAP_BACK)) {
int xbase = swapx < 0 ? -54 : 54;
int ybase = swapy < 0 ? -64 : 64;
if ((selectedx == x) && (selectedy == y)) {
if (swapx != 0) {
xofs = xbase - swapx;
}
if (swapy != 0) {
yofs = ybase - swapy;
}
}
if ((tappedx == x) && (tappedy == y)) {
if (swapx != 0) {
xofs = -(xbase - swapx);
}
if (swapy != 0) {
yofs = -(ybase - swapy);
}
}
}
float size = 1;
if (state == REMOVE) {
if (tiles[x][y][REMOVE_MARKER] == 1) {
size = removeStep;
xofs = (54 - (54 * size)) / 2;
yofs = (64 - (64 * size)) / 2;
}
}
if (state == FALL) {
if (tiles[x][y][FALL_MARKER] == 1) {
yofs = -fallOffset;
}
}
if ((state == HINT) && (tiles[x][y][MATCH_HINT] > 0)) {
int xp = 11 + (x * 54);
int yp = -831 + (y * 64);
kitis[tile].draw(xp, yp, tiles[x][y][MATCH_HINT]
/ SPIN_SCALAR);
} else {
kitis[tile].draw((11 + (x * 54) + xofs), (-831
+ (y * 64) + yofs), (54 * size), (64 * size));
}
}
}
}
if (starting) {
g.resetColor();
g.setColor(0, 0, 0, 0.7f);
g.fillRect(50, 50, 540, 380);
g.setColor(0, 0, 0);
g.drawRect(50, 50, 540, 380);
g.drawRect(48, 48, 544, 384);
g.resetColor();
g.drawRect(49, 49, 542, 382);
logo.draw(180, 60);
if (gameOverCounter > 0) {
g.drawString("Well Done!", 280, 300);
} else {
String mes = "这是一款拼图游戏示例";
g.drawString(mes,
(getWidth() - g.getFont().stringWidth(mes)) / 2, 180);
g.drawString("Click to Start", 255,
(385 + (MathUtils.cos(ang) * 8)));
}
}
}
public void alter(LTimerContext timer) {
if (!isOnLoadComplete()) {
return;
}
long delta = timer.timeSinceLastUpdate;
time = (int) ((System.currentTimeMillis() - start) / 1000);
if (starting) {
time = 0;
}
ang += delta * 0.01f;
if (state == HINT) {
boolean found = false;
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 20; y++) {
if (tiles[x][y][MATCH_HINT] > 0) {
tiles[x][y][MATCH_HINT] -= delta;
found = true;
}
}
}
if (!found) {
state = PLAY;
}
}
if (state == REMOVE) {
removeStep -= delta * 0.005f;
if (removeStep < 0) {
removeStep = 0;
finishRemove();
int falls = findFalls();
if (falls == 0) {
fillSpaces();
int matches = findMatches();
if (matches == 0) {
state = PLAY;
} else {
state = REMOVE;
removeStep = 1;
}
} else {
fallOffset = 64;
state = FALL;
}
}
}
if (state == FALL) {
fallOffset -= delta * 0.5f;
if (fallOffset <= 0) {
fallOffset = 0;
int falls = findFalls();
if (falls == 0) {
fillSpaces();
int matches = findMatches();
if (matches == 0) {
state = PLAY;
} else {
state = REMOVE;
removeStep = 1;
}
} else {
fallOffset = 64;
state = FALL;
}
}
}
if ((state == SWAP) || (state == SWAP_BACK)) {
float swapSpeed = 0.17f;
if (swapx > 0) {
swapx -= delta * swapSpeed;
swapx = Math.max(0, swapx);
}
if (swapy > 0) {
swapy -= delta * swapSpeed;
swapy = Math.max(0, swapy);
}
if (swapx < 0) {
swapx += delta * swapSpeed;
swapx = Math.min(0, swapx);
}
if (swapy < 0) {
swapy += delta * swapSpeed;
swapy = Math.min(0, swapy);
}
if ((swapx == 0) && (swapy == 0)) {
int temp = tiles[tappedx][tappedy][TILE];
tiles[tappedx][tappedy][TILE] = tiles[selectedx][selectedy][TILE];
tiles[selectedx][selectedy][TILE] = temp;
if (state == SWAP_BACK) {
state = PLAY;
} else {
int matches = findMatches();
if (matches == 0) {
swap();
state = SWAP_BACK;
} else {
removeStep = 1;
state = REMOVE;
}
}
}
}
if (gameOverCounter > 0) {
gameOverCounter -= delta;
if (gameOverCounter <= 0) {
clearBoard();
}
}
if ((!starting) && (state == PLAY)) {
movesLeft = findMoves();
if (movesLeft == 0) {
starting = true;
gameOverCounter = 2000;
}
}
}
public void touchDown(GameTouch e) {
mousePressed(e.getButton(), e.x(), e.y());
}
public void touchUp(GameTouch e) {
}
public void touchMove(GameTouch e) {
}
public void touchDrag(GameTouch e) {
}
public void onKeyDown(GameKey e) {
if (e.getKeyCode() == SysKey.ESCAPE) {
if (starting) {
LSystem.exit();
} else {
starting = true;
}
}
}
@Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void resume() {
// TODO Auto-generated method stub
}
@Override
public void pause() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
}
}