120 lines
4.5 KiB
Java
120 lines
4.5 KiB
Java
package eu.midnightdust.yaytris.game;
|
|
|
|
import eu.midnightdust.yaytris.Tetris;
|
|
import eu.midnightdust.yaytris.util.SoundEffect;
|
|
import eu.midnightdust.yaytris.util.Vec2i;
|
|
|
|
import java.awt.*;
|
|
|
|
public class Tetromino {
|
|
private final TetrominoShape shape;
|
|
private int[][] collision;
|
|
private Vec2i centerPos;
|
|
private int fallLength = 0;
|
|
|
|
public Tetromino(TetrominoShape shape) {
|
|
this.shape = shape;
|
|
this.collision = shape.boundary;
|
|
this.centerPos = Vec2i.of(Tetris.getSpace().getMapWidth()/2-1, -1);
|
|
}
|
|
|
|
public boolean fall() {
|
|
Vec2i newPos = centerPos.offset(Vec2i.of(0, 1));
|
|
if (collidesVertically(newPos)) {
|
|
SoundEffect.BOOP.play();
|
|
int[] affectedLines = new int[this.collision.length];
|
|
int line = centerPos.getY();
|
|
for (int i = 0; i < this.collision.length; i++) {
|
|
affectedLines[i] = line;
|
|
line++;
|
|
}
|
|
Tetris.getSpace().onLinesChanged(this, affectedLines);
|
|
Tetris.getSpace().increaseScore(20-fallLength);
|
|
return false;
|
|
}
|
|
fallLength += 1;
|
|
centerPos = newPos;
|
|
return true;
|
|
}
|
|
|
|
public void move(int xOffset) {
|
|
Vec2i newPos = centerPos.offset(Vec2i.of(xOffset, 0));
|
|
if (collidesHorizontally(newPos, xOffset)) {
|
|
return;
|
|
}
|
|
centerPos = newPos;
|
|
}
|
|
|
|
private boolean collidesVertically(Vec2i newPos) {
|
|
if (Tetris.getSpace() == null) return false;
|
|
|
|
boolean collides = newPos.getY() + this.collision.length > Tetris.getSpace().getMapHeight(); // Bottom check
|
|
|
|
if (!collides) { // Check for other tetrominos
|
|
for (int i = 0; i < collision[0].length; i++) {
|
|
int maxCollisionY = collision.length - 1;
|
|
while (collision[maxCollisionY][i] == 0) maxCollisionY--; // Figure out the collision box's bounding
|
|
|
|
if (newPos.getY()+maxCollisionY < 0 || newPos.getY()+maxCollisionY >= Tetris.getSpace().getMapHeight() || newPos.getX() + i >= Tetris.getSpace().getMapWidth()) continue;
|
|
collides |= Tetris.getSpace().getGameMap()[newPos.getY() + maxCollisionY][newPos.getX() + i] != null;
|
|
}
|
|
}
|
|
return collides;
|
|
}
|
|
|
|
private boolean collidesHorizontally(Vec2i newPos, int xOffset) {
|
|
if (Tetris.getSpace() == null) return false;
|
|
|
|
boolean collides = newPos.getX() < 0 || newPos.getX() + collision[0].length > Tetris.getSpace().getMapWidth(); // Side check
|
|
if (!collides) { // Check for other tetrominos
|
|
for (int i = 0; i < collision.length; i++) {
|
|
int maxCollisionX = xOffset >= 0 ? collision[i].length - 1 : 0;
|
|
while (collision[i][maxCollisionX] == 0) maxCollisionX += xOffset >= 0 ? -1 : 1; // Figure out the collision box's bounding
|
|
|
|
if (newPos.getY()+i < 0 || newPos.getY()+i >= Tetris.getSpace().getMapHeight()) continue;
|
|
collides |= Tetris.getSpace().getGameMap()[newPos.getY() + i][newPos.getX() + maxCollisionX] != null;
|
|
}
|
|
}
|
|
return collides;
|
|
}
|
|
|
|
public void rotate() {
|
|
int M = collision.length;
|
|
int N = collision[0].length;
|
|
|
|
int[][] newCollision = new int[N][M];
|
|
for (int i = 0; i < M; i++) {
|
|
for (int j = 0; j < N; j++) {
|
|
newCollision[j][M-i-1] = collision[i][j];
|
|
}
|
|
}
|
|
int[][] prevCollision = this.collision;
|
|
this.collision = newCollision;
|
|
int offset = 0;
|
|
for (int i = 0; i < 4; i++) {
|
|
if (collidesHorizontally(this.centerPos.offset(Vec2i.of(offset, 0)), -i)) offset = -i;
|
|
}
|
|
if (collidesVertically(this.centerPos.offset(Vec2i.of(offset, 0))) || collidesHorizontally(this.centerPos.offset(Vec2i.of(offset, 0)), offset)) this.collision = prevCollision;
|
|
else this.centerPos = centerPos.offset(Vec2i.of(offset, 0));
|
|
}
|
|
|
|
public Color[] getLine(int line) {
|
|
Color[] l = new Color[Tetris.getSpace().getMapWidth()];
|
|
for (int i = 0; i < l.length; i++) {
|
|
int relY = line - centerPos.getY();
|
|
if (relY >= collision.length || relY < 0) continue;
|
|
int relX = i-centerPos.getX();
|
|
if (relX >= collision[relY].length || relX < 0) continue;
|
|
|
|
if (collision[relY][relX] != 0) l[i] = shape.color;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
public void fallToBottom() {
|
|
while (true) {
|
|
if (!fall()) break;
|
|
}
|
|
}
|
|
}
|