fixed collision detection, added rotation
This commit is contained in:
		| @@ -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"); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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<iterations; k++) { | ||||
|             for(int i=0; i<arrayLength; i++) { | ||||
|                 for(int j=0; j<arrayLength; j++) { | ||||
|                     returnArray[i][arrayLength-1-j] = this.shapeArray[j][i]; | ||||
|                     returnArray[i][arrayLength-1-j] = startArray[j][i]; | ||||
|                 } | ||||
|             } | ||||
|             startArray = Arrays.stream(returnArray).map(int[]::clone).toArray(int[][]::new); | ||||
|         } | ||||
|  | ||||
|         return returnArray; | ||||
| @@ -114,20 +117,27 @@ public class Tetromino { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         System.out.println("Not part of Tetromino!!!"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private List<Pos> getBlockPositions() { | ||||
|         List<Pos> returnList = new ArrayList<>(); | ||||
|         if(this.position == null) return returnList; | ||||
|         return this.getBlockPositions(this.position, this.shapeArray); | ||||
|     } | ||||
|  | ||||
|         int arrayLength = this.shapeArray.length; | ||||
|     private List<Pos> getBlockPositions(Pos position, int[][] shapeArray) { | ||||
|         List<Pos> returnList = new ArrayList<>(); | ||||
|         if(position == null) return returnList; | ||||
|  | ||||
|         int arrayLength = shapeArray.length; | ||||
|  | ||||
|         for(int x=0; x<arrayLength; x++) { | ||||
|             for(int y=0; y<arrayLength; y++) { | ||||
|                 if(this.shapeArray[arrayLength-1-y][x] == 1) { | ||||
|                     returnList.add(this.position.add(x-1, y-1, 0)); | ||||
|                 if(shapeArray[arrayLength-1-y][x] == 1) { | ||||
|                     switch (this.shape) { | ||||
|                         case I -> 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<Pos> newBlockPositions = getBlockPositions(newPosition, newShapeArray); | ||||
|  | ||||
|         for(int x=0; x<arrayLength; x++) { | ||||
|             for(int y=0; y<arrayLength; y++) { | ||||
|                 Pos checkPosition = newPosition.add(x-1, y-1, 0); | ||||
|                 if(isPartOfTetromino(checkPosition)) continue; | ||||
|                 if(this.instance.getBlock(checkPosition) != Block.AIR) return true; | ||||
|             } | ||||
|         for(Pos pos : newBlockPositions) { | ||||
|             if(isPartOfTetromino(pos)) continue; | ||||
|             if(this.instance.getBlock(pos) != Block.AIR) return true; | ||||
|         } | ||||
|  | ||||
|         // TODO: collision check to -y not working | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private boolean checkCollisionAndMove(Pos newPosition, int[][] newShapeArray) { | ||||
|         if(!checkCollision(newPosition, newShapeArray)) { | ||||
|             this.remove(); | ||||
|             this.shapeArray = newShapeArray; | ||||
|             this.shapeArray = Arrays.stream(newShapeArray).map(int[]::clone).toArray(int[][]::new); | ||||
|             this.setPosition(newPosition); | ||||
|             this.draw(); | ||||
|             return true; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user