diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 3626e30..f873c62 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -50,25 +50,31 @@ class Tetris extends StatelessGame { } protected void pressedButton(Button button) { - if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-200) return; + if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; lastPresses.put(button, System.currentTimeMillis()); switch (button) { case A -> { System.out.println("A"); - System.out.println(this.tetrisGame.currentTetromino.moveLeft()); + System.out.println(this.tetrisGame.moveLeft()); } case S -> { System.out.println("S"); - System.out.println(this.tetrisGame.currentTetromino.moveDown()); + System.out.println(this.tetrisGame.moveDown()); } case D -> { System.out.println("D"); - System.out.println(this.tetrisGame.currentTetromino.moveRight()); + System.out.println(this.tetrisGame.moveRight()); } case W -> System.out.println("W"); - case mouseLeft -> System.out.println("mouse left"); - case mouseRight -> System.out.println("mouse right"); + case mouseLeft -> { + System.out.println("mouse left"); + System.out.println(this.tetrisGame.rotate(false)); + } + case mouseRight -> { + System.out.println("mouse right"); + System.out.println(this.tetrisGame.rotate(true)); + } case space -> System.out.println("space"); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 44bf742..9f1e060 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -8,34 +8,61 @@ import net.minestom.server.instance.block.Block; public class Playfield { private final Pos lowerLeftCorner; + private final StatelessGame instance; - public Playfield(Pos lowerLeftCorner) { + public Playfield(Pos lowerLeftCorner, StatelessGame instance) { this.lowerLeftCorner = lowerLeftCorner; + this.instance = instance; } public Pos getPlayerSpawnPosition() { - return lowerLeftCorner.add(6, 8, 15); + return this.lowerLeftCorner.add(6, 8, 15); } public Pos getTetrominoSpawnPosition() { return this.lowerLeftCorner.add(5, 21, 1); } - public void generate(StatelessGame instance) { + public void generate() { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); for(int x=0; x<12; x++) { for(int y=0; y<21; y++) { - batch.setBlock(lowerLeftCorner.add(x, y, 0), Block.STONE); + batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.STONE); if(x==0 || x==11 || y==0) { - batch.setBlock(lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE); + batch.setBlock(this.lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE); } } } batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE); - BatchUtil.loadAndApplyBatch(batch, instance, () -> {}); + BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {}); + } + + public int removeFullLines() { + int removedLinesCounter = 0; + for(int y=1; y<21; 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; + } + if(isFullLine) { + removeFullLine(y); + removedLinesCounter += 1; + y -= 1; + } + } + return removedLinesCounter; + } + + private void removeFullLine(int positionY) { + for(int y=positionY; y<21; 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); + } + } } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index d3be554..3bd3414 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -11,10 +11,13 @@ import java.util.Random; public class TetrisGame { private final StatelessGame instance; private final Playfield playfield; - private int speed = 1; + private int level = 1; private int lines = 0; + private int score = 0; + private boolean lost = false; public Tetromino currentTetromino; private Tetromino nextTetromino; + private Tetromino holdTetromino; private final Random random = new Random(); private final Pos tetrominoSpawnPosition; @@ -24,10 +27,10 @@ public class TetrisGame { } public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) { - this.playfield = new Playfield(lowerLeftCorner); + this.instance = instance; + this.playfield = new Playfield(lowerLeftCorner, this.instance); this.currentTetromino = startTetromino; this.nextTetromino = nextTetromino; - this.instance = instance; this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition(); } @@ -35,28 +38,53 @@ public class TetrisGame { public void start() { Scheduler scheduler = MinecraftServer.getSchedulerManager(); scheduler.submitTask(() -> { + if(this.lost) return TaskSchedule.stop(); this.tick(); - return TaskSchedule.tick(40/this.speed); + return TaskSchedule.tick(40/this.level); }); } public void generate() { - this.playfield.generate(this.instance); + this.playfield.generate(); this.currentTetromino.setPosition(this.tetrominoSpawnPosition); this.currentTetromino.draw(); } public void tick() { + if(this.lost) return; if(!currentTetromino.moveDown()) { - currentTetromino = nextTetromino; - currentTetromino.setPosition(this.tetrominoSpawnPosition); - currentTetromino.draw(); - nextTetromino = getNextTetromino(); + setActiveTetrominoDown(); } } + public boolean rotate(boolean clockwise) { + if(this.lost) return false; + return this.currentTetromino.rotate(clockwise); + } + + public boolean moveLeft() { + if(this.lost) return false; + return this.currentTetromino.moveLeft(); + } + + public boolean moveRight() { + if(this.lost) return false; + return this.currentTetromino.moveRight(); + } + + public boolean moveDown() { + if(this.lost) return false; + if(!this.currentTetromino.moveDown()) { + this.setActiveTetrominoDown(); + return false; + } + this.score += 1; + return true; + } + + private Tetromino getNextTetromino() { int randomNumber = random.nextInt(1, 7); Tetromino.Shape nextShape; @@ -73,4 +101,39 @@ public class TetrisGame { return new Tetromino(this.instance, nextShape); } + + private void loose() { + this.lost = true; + } + + private void setActiveTetrominoDown() { + currentTetromino = nextTetromino; + nextTetromino = getNextTetromino(); + + int removedLines = this.playfield.removeFullLines(); + switch (removedLines) { + case 1 -> { + this.lines += 1; + this.score += 40 * this.level; + } + case 2 -> { + this.lines += 3; + this.score += 100 * this.level; + } + case 3 -> { + this.lines += 5; + this.score += 300 * this.level; + } + case 4 -> { + this.lines += 8; + this.score += 1200 * this.level; + } + } + + currentTetromino.setPosition(this.tetrominoSpawnPosition); + currentTetromino.draw(); + if(!currentTetromino.moveDown()) { + loose(); + } + } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index 00ddf1e..d95c945 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -5,6 +5,7 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.instance.block.Block; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class Tetromino { @@ -95,14 +96,16 @@ public class Tetromino { if(!clockwise) iterations = 3; int arrayLength = this.shapeArray.length; + int[][] startArray = Arrays.stream(this.shapeArray).map(int[]::clone).toArray(int[][]::new); int[][] returnArray = new int[arrayLength][arrayLength]; for(int k=0; k getBlockPositions() { - List returnList = new ArrayList<>(); - if(this.position == null) return returnList; + return this.getBlockPositions(this.position, this.shapeArray); + } - int arrayLength = this.shapeArray.length; + private List getBlockPositions(Pos position, int[][] shapeArray) { + List returnList = new ArrayList<>(); + if(position == null) return returnList; + + int arrayLength = shapeArray.length; for(int x=0; x returnList.add(position.add(x-1, y-2, 0)); + case O -> returnList.add(position.add(x, y, 0)); + default -> returnList.add(position.add(x-1, y-1, 0)); + } } } } @@ -136,25 +146,20 @@ public class Tetromino { } private boolean checkCollision(Pos newPosition, int[][] newShapeArray) { - int arrayLength = newShapeArray.length; + List newBlockPositions = getBlockPositions(newPosition, newShapeArray); - for(int x=0; x