WarpPI/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisGame.java

235 lines
6.3 KiB
Java

package it.cavallium.warppi.extra.tetris;
import java.util.Arrays;
public class TetrisGame {
public static final int WIDTH = 10, HEIGHT = 22;
public static final double TICK_TIME = 0.25, DOWN_TIME = 0.10, MOVE_TIMER = 0.125;
private double tickTimer, downTimer, leftTimer, rightTimer, upTimer;
private BlockColor[] grid;
private BlockColor[] hovergrid;
private volatile BlockColor[] renderedGrid;
private GameStatus gameStatus;
private int score;
private double currentTime;
private Tetromino currentTetromino;
private Tetromino nextTetromino;
public TetrisGame() {
resetVariables();
}
void playAgain() {
resetVariables();
gameStatus = GameStatus.PLAYING;
placeNextTetromino();
}
private void resetVariables() {
grid = new BlockColor[WIDTH * HEIGHT];
hovergrid = new BlockColor[WIDTH * HEIGHT];
renderedGrid = new BlockColor[WIDTH * HEIGHT];
score = 0;
currentTime = 0;
tickTimer = 0;
gameStatus = GameStatus.INITIAL;
currentTetromino = null;
nextTetromino = generateRandomTetromino();
nextTetromino.fixInitialPosition();
}
public void update(float dt, ButtonInfo leftPressed, ButtonInfo rightPressed, ButtonInfo downPressed,
ButtonInfo upPressed, ButtonInfo okPressed, ButtonInfo backPressed) {
currentTime += dt;
tickTimer += dt;
leftTimer += dt;
rightTimer += dt;
downTimer += dt;
upTimer += dt;
if (leftPressed.hasUnreadData()) {
for (int i = leftPressed.readPressed(); i > 0; i--) {
move(this.currentTetromino, -1, 0, 0);
}
leftTimer = -MOVE_TIMER;
} else if (leftPressed.isPressedNow()) {
while (leftTimer >= MOVE_TIMER) {
leftTimer -= MOVE_TIMER;
move(this.currentTetromino, -1, 0, 0);
}
} else {
leftTimer = 0;
}
if (rightPressed.hasUnreadData()) {
for (int i = rightPressed.readPressed(); i > 0; i--) {
move(this.currentTetromino, 1, 0, 0);
}
rightTimer = -MOVE_TIMER;
} else if (rightPressed.isPressedNow()) {
while (rightTimer >= MOVE_TIMER) {
rightTimer -= MOVE_TIMER;
move(this.currentTetromino, 1, 0, 0);
}
} else {
rightTimer = 0;
}
if (upPressed.hasUnreadData()) {
for (int i = upPressed.readPressed(); i > 0; i--) {
move(this.currentTetromino, 0, 0, 1);
}
upTimer = -MOVE_TIMER;
} else if (upPressed.isPressedNow()) {
while (upTimer >= MOVE_TIMER) {
upTimer -= MOVE_TIMER;
move(this.currentTetromino, 0, 0, 1);
}
} else {
upTimer = 0;
}
if (downPressed.isPressedNow()) {
downPressed.readPressed();
while (downTimer >= DOWN_TIME) {
downTimer -= DOWN_TIME;
move(this.currentTetromino, 0, 1, 0);
}
} else {
downTimer = 0;
}
while (tickTimer >= TICK_TIME) {
tickTimer -= TICK_TIME;
gameTick(leftPressed, rightPressed, downPressed, okPressed, backPressed);
}
if (gameStatus == GameStatus.INITIAL) {
playAgain();
} else {
}
renderGrid();
}
public void gameTick(ButtonInfo leftPressed, ButtonInfo rightPressed, ButtonInfo downPressed, ButtonInfo okPressed,
ButtonInfo backPressed) {
if (move(this.currentTetromino, 0, 1, 0)) {
} else {
// Spawn new tetromino and write the old to the permanent grid
drawCurrentTetromino(grid);
checkLines();
placeNextTetromino();
if (move(this.currentTetromino, 0, 0, 0) == false) {
// Lose
this.gameStatus = GameStatus.LOST;
playAgain();
}
}
}
private void checkLines() {
for (int i = HEIGHT - 1; i >= 0; i--) {
boolean scored = true;
while (scored) {
for (int x = 0; x < WIDTH; x++) {
if (this.grid[x + i * WIDTH] == null) {
scored = false;
break;
}
}
if (scored) {
this.score += WIDTH;
for (int x = 0; x < WIDTH; x++) {
int y = i;
while (y > 0) {
this.grid[x + (y) * WIDTH] = this.grid[x + (y - 1) * WIDTH];
y--;
}
}
}
}
}
}
private boolean move(Tetromino t, int dX, int dY, int dRotation) {
byte rot = (byte) ((t.getRotation() + dRotation) % 4);
boolean[] block = t.getRenderedBlock(rot);
int blockSize = t.getTetrominoGridSize();
int half1 = (int) Math.floor(((double) t.getTetrominoGridSize()) / 2d);
int half2 = blockSize - half1;
byte aX = (byte) (t.getX() + dX), aY = (byte) (t.getY() + dY);
int blockX = 0, blockY = 0;
for (int x = aX - half1; x < aX + half2; x++) {
for (int y = aY - half1; y < aY + half2; y++) {
if (block[blockX + blockY * blockSize] == true) {
if (x >= 0 & y >= 0 & x < WIDTH & (x + y * WIDTH) < this.grid.length) {
if (this.grid[x + y * WIDTH] != null) {
return false;
}
} else {
return false;
}
}
blockY++;
}
blockY = 0;
blockX++;
}
t.setRotation(rot);
t.setX(aX);
t.setY(aY);
return true;
}
public void renderGrid() {
this.renderedGrid = Arrays.copyOf(grid, grid.length);
drawCurrentTetromino(this.renderedGrid);
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
final int offset = x + y * WIDTH;
renderedGrid[offset] = hovergrid[offset] != null ? hovergrid[offset] : renderedGrid[offset];
}
}
}
private void placeNextTetromino() {
currentTetromino = nextTetromino;
nextTetromino = generateRandomTetromino();
nextTetromino.fixInitialPosition();
}
private Tetromino generateRandomTetromino() {
int s = (int) (Math.random() * 7);
final byte middleX = (byte) ((WIDTH - 1) / 2), middleY = 0, rotation = (byte) (Math.random() * 4);
switch (s) {
case 0:
return new TetrominoICyan(middleX, middleY, rotation);
case 1:
return new TetrominoJBlue(middleX, middleY, rotation);
case 2:
return new TetrominoLOrange(middleX, middleY, rotation);
case 3:
return new TetrominoOYellow(middleX, middleY, rotation);
case 4:
return new TetrominoSGreen(middleX, middleY, rotation);
case 5:
return new TetrominoTPurple(middleX, middleY, rotation);
default:
return new TetrominoZRed(middleX, middleY, rotation);
}
}
public Tetromino getNextTetromino() {
return this.nextTetromino;
}
private void drawCurrentTetromino(BlockColor[] grid) {
currentTetromino.draw(grid, WIDTH);
}
public BlockColor[] getRenderedGrid() {
return renderedGrid;
}
public int getScore() {
return this.score;
}
}