added ghost tetromino

This commit is contained in:
Lars Neuhaus 2024-10-22 00:36:57 +02:00
parent f56023004a
commit 710838645f
4 changed files with 78 additions and 37 deletions

View File

@ -93,21 +93,20 @@ class Tetris extends StatelessGame {
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15));
this.tetrisGame.generate();
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent event) {
// if(!getSpawn().withView(event.getNewPosition()).equals(event.getNewPosition())) {
// event.setCancelled(true);
// event.getPlayer().setSprinting(false);
// }
Player player = event.getPlayer();
Pos previousPosition = event.getPlayer().getPosition();
Pos currentPosition = event.getNewPosition();
if(this.tetrisGame == null) return;
event.setNewPosition(this.tetrisGame.getPlayerSpawnPosition().withView(event.getNewPosition()));
player.setSprinting(false);
Vec movementVector = currentPosition.asVec().sub(previousPosition.asVec());
float yaw = player.getPosition().yaw();
@ -145,8 +144,6 @@ class Tetris extends StatelessGame {
}
if(previousPosition.y() < currentPosition.y()) pressedButton(Button.space);
// event.setNewPosition(getSpawn().withView(event.getNewPosition()));
}
protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) {
@ -162,11 +159,9 @@ class Tetris extends StatelessGame {
p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build());
p.setSprinting(false);
// p.setGameMode(GameMode.SPECTATOR);
// Entity anvil = new Entity(EntityType.FALLING_BLOCK);
// ((FallingBlockMeta) anvil.getEntityMeta()).setBlock(Block.ANVIL);
// anvil.setInstance(this, getSpawn());
// anvil.addPassenger(p);
this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15));
this.tetrisGame.generate();
p.teleport(this.tetrisGame.getPlayerSpawnPosition());
this.tetrisGame.sidebar.addViewer(p);
return super.onPlayerJoin(p);

View File

@ -9,6 +9,7 @@ import net.minestom.server.instance.block.Block;
public class Playfield {
private final Pos lowerLeftCorner;
private final StatelessGame instance;
private final int height = 22;
public Playfield(Pos lowerLeftCorner, StatelessGame instance) {
this.lowerLeftCorner = lowerLeftCorner;
@ -16,7 +17,7 @@ public class Playfield {
}
public Pos getPlayerSpawnPosition() {
return this.lowerLeftCorner.add(6, 8, 15);
return this.lowerLeftCorner.add(6, 8, 20);
}
public Pos getTetrominoSpawnPosition() {
@ -27,28 +28,36 @@ public class Playfield {
return this.lowerLeftCorner.add(-4, 19, 0);
}
public Pos getNextPosition() {
return this.lowerLeftCorner.add(14, 19, 0);
}
public void generate() {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x=0; x<12; x++) {
for(int y=0; y<22; y++) {
for(int y=0; y<this.height; y++) {
batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.GLASS);
batch.setBlock(this.lowerLeftCorner.add(x, y, -1), Block.BLACK_CONCRETE);
if(x==0 || x==11 || y==0) {
batch.setBlock(this.lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE);
batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.GRAY_CONCRETE);
}
}
}
batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE);
batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 1), Block.STONE);
batch.setBlock(getPlayerSpawnPosition().sub(1, 1, 1), Block.STONE);
batch.setBlock(getPlayerSpawnPosition().sub(1, 1, 0), Block.STONE);
BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {});
}
public int removeFullLines() {
int removedLinesCounter = 0;
for(int y=1; y<22; y++) {
for(int y=1; y<this.height; y++) {
boolean isFullLine = true;
for(int x=1; x<11; x++) {
if(this.instance.getBlock(this.lowerLeftCorner.add(x, y, 1)) == Block.AIR) isFullLine = false;
@ -62,8 +71,19 @@ public class Playfield {
return removedLinesCounter;
}
public void removeBlock(Block block) {
for(int x=0; x<12; x++) {
for(int y=0; y<this.height; y++) {
if(this.instance.getBlock(this.lowerLeftCorner.add(x, y, 1)).equals(block)) {
this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), Block.AIR);
}
}
}
}
private void removeFullLine(int positionY) {
for(int y=positionY; y<22; y++) {
for(int y=positionY; y<this.height; y++) {
for(int x=1; x<11; x++) {
Block blockAbove = this.instance.getBlock(this.lowerLeftCorner.add(x, y+1, 1));
this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), blockAbove);

View File

@ -25,23 +25,30 @@ public class TetrisGame {
private Tetromino holdTetromino;
private final List<Tetromino> tetrominoBag = new ArrayList<>();
private boolean holdPossible = true;
private final Pos nextPosition;
private final Pos holdPosition;
private final Pos tetrominoSpawnPosition;
public Sidebar sidebar = new Sidebar(Component.text("Info:"));
public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) {
this(instance, lowerLeftCorner, new Tetromino(instance, Tetromino.Shape.J), new Tetromino(instance, Tetromino.Shape.T));
this(instance, lowerLeftCorner, Tetromino.Shape.J);
}
public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) {
public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape) {
this.instance = instance;
this.playfield = new Playfield(lowerLeftCorner, this.instance);
this.currentTetromino = startTetromino;
this.nextTetromino = nextTetromino;
this.holdPosition = this.playfield.getHoldPosition();
this.nextPosition = this.playfield.getNextPosition();
this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition();
this.buildSidebar();
this.currentTetromino = new Tetromino(this.instance, startTetrominoShape, this.playfield);
this.nextTetromino = this.getNextTetromino();
}
public Pos getPlayerSpawnPosition() {
return this.playfield.getPlayerSpawnPosition();
}
public void start() {
@ -115,7 +122,7 @@ public class TetrisGame {
}
this.currentTetromino.remove();
this.holdTetromino = this.currentTetromino;
this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.shape, this.playfield);
this.currentTetromino = newCurrentTetromino;
this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
@ -123,7 +130,7 @@ public class TetrisGame {
if(!this.currentTetromino.moveDown()) loose();
this.holdTetromino.setPosition(this.holdPosition);
this.holdTetromino.draw();
this.holdTetromino.draw(false);
this.holdPossible = false;
return true;
}
@ -132,12 +139,17 @@ public class TetrisGame {
private Tetromino getNextTetromino() {
if(this.tetrominoBag.isEmpty()) {
for(Tetromino.Shape shape : Tetromino.Shape.values()) {
this.tetrominoBag.add(new Tetromino(this.instance, shape));
this.tetrominoBag.add(new Tetromino(this.instance, shape, this.playfield));
}
Collections.shuffle(this.tetrominoBag);
}
return this.tetrominoBag.removeFirst();
if(this.nextTetromino != null) this.nextTetromino.remove();
Tetromino tetromino = this.tetrominoBag.removeFirst();
tetromino.setPosition(this.nextPosition);
tetromino.draw(false);
return tetromino;
}
private void loose() {
@ -169,8 +181,8 @@ public class TetrisGame {
}
private void setActiveTetrominoDown() {
currentTetromino = nextTetromino;
nextTetromino = getNextTetromino();
this.currentTetromino = this.nextTetromino;
this.nextTetromino = getNextTetromino();
int removedLines = this.playfield.removeFullLines();
switch (removedLines) {
@ -197,9 +209,9 @@ public class TetrisGame {
this.updateSidebar();
currentTetromino.setPosition(this.tetrominoSpawnPosition);
currentTetromino.draw();
if(!currentTetromino.moveDown()) {
this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
this.currentTetromino.draw();
if(!this.currentTetromino.moveDown()) {
loose();
}
}

View File

@ -9,10 +9,12 @@ import java.util.Arrays;
import java.util.List;
public class Tetromino {
private final Shape shape;
public final Shape shape;
private final StatelessGame instance;
private final Playfield playfield;
private Pos position;
private int[][] shapeArray;
private final Block ghostBlock = Block.ICE;
public enum Shape {
I,
@ -24,9 +26,10 @@ public class Tetromino {
Z
}
public Tetromino(StatelessGame instance, Shape shape) {
public Tetromino(StatelessGame instance, Shape shape, Playfield playfield) {
this.instance = instance;
this.shape = shape;
this.playfield = playfield;
switch (this.shape) {
case I -> shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}};
@ -39,10 +42,6 @@ public class Tetromino {
}
}
public Pos getPosition() {
return this.position;
}
public void setPosition(Pos newPosition) {
this.position = newPosition;
}
@ -68,6 +67,20 @@ public class Tetromino {
}
public void draw() {
this.draw(true);
}
public void draw(boolean withGhost) {
if(withGhost) {
this.playfield.removeBlock(this.ghostBlock);
Pos ghostPos = this.position;
while (!checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) {
ghostPos = ghostPos.sub(0, 1, 0);
}
Pos positionChange = this.position.sub(ghostPos);
getBlockPositions().forEach(pos -> this.instance.setBlock(pos.sub(positionChange), this.ghostBlock));
}
getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock()));
}
@ -150,6 +163,7 @@ public class Tetromino {
for(Pos pos : newBlockPositions) {
if(isPartOfTetromino(pos)) continue;
if(this.instance.getBlock(pos) == this.ghostBlock) continue;
if(this.instance.getBlock(pos) != Block.AIR) return true;
}