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; } } }