Files
TetrisClone/src/main/java/eu/midnightdust/yaytris/game/Tetromino.java
2025-06-29 18:24:02 +02:00

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