added tetromino controlls

This commit is contained in:
Lars Neuhaus 2024-10-21 00:27:58 +02:00
parent 5acfe8f6af
commit 1332a42bf6
4 changed files with 174 additions and 17 deletions

View File

@ -46,7 +46,7 @@ class Tetris extends StatelessGame {
protected void onStart() {
super.onStart();
this.tetrisGame.generate();
this.tetrisGame.start();
}
protected void pressedButton(Button button) {
@ -54,9 +54,18 @@ class Tetris extends StatelessGame {
lastPresses.put(button, System.currentTimeMillis());
switch (button) {
case A -> System.out.println("A");
case S -> System.out.println("S");
case D -> System.out.println("D");
case A -> {
System.out.println("A");
System.out.println(this.tetrisGame.currentTetromino.moveLeft());
}
case S -> {
System.out.println("S");
System.out.println(this.tetrisGame.currentTetromino.moveDown());
}
case D -> {
System.out.println("D");
System.out.println(this.tetrisGame.currentTetromino.moveRight());
}
case W -> System.out.println("W");
case mouseLeft -> System.out.println("mouse left");
case mouseRight -> System.out.println("mouse right");
@ -71,6 +80,7 @@ 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

View File

@ -17,6 +17,10 @@ public class Playfield {
return lowerLeftCorner.add(6, 8, 15);
}
public Pos getTetrominoSpawnPosition() {
return this.lowerLeftCorner.add(5, 21, 1);
}
public void generate(StatelessGame instance) {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();

View File

@ -1,18 +1,26 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.timer.Scheduler;
import net.minestom.server.timer.TaskSchedule;
import java.util.Random;
public class TetrisGame {
private final StatelessGame instance;
private final Playfield playfield;
private int speed = 1;
private int lines = 0;
private Tetromino currentTetromino;
public Tetromino currentTetromino;
private Tetromino nextTetromino;
private final Random random = new Random();
private final Pos tetrominoSpawnPosition;
public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) {
this(instance, lowerLeftCorner, new Tetromino(Tetromino.Shape.J), new Tetromino(Tetromino.Shape.T));
this(instance, lowerLeftCorner, new Tetromino(instance, Tetromino.Shape.J), new Tetromino(instance, Tetromino.Shape.T));
}
public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) {
@ -20,9 +28,49 @@ public class TetrisGame {
this.currentTetromino = startTetromino;
this.nextTetromino = nextTetromino;
this.instance = instance;
this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition();
}
public void start() {
Scheduler scheduler = MinecraftServer.getSchedulerManager();
scheduler.submitTask(() -> {
this.tick();
return TaskSchedule.tick(40/this.speed);
});
}
public void generate() {
this.playfield.generate(this.instance);
this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
this.currentTetromino.draw();
}
public void tick() {
if(!currentTetromino.moveDown()) {
currentTetromino = nextTetromino;
currentTetromino.setPosition(this.tetrominoSpawnPosition);
currentTetromino.draw();
nextTetromino = getNextTetromino();
}
}
private Tetromino getNextTetromino() {
int randomNumber = random.nextInt(1, 7);
Tetromino.Shape nextShape;
switch (randomNumber) {
case 2 -> nextShape = Tetromino.Shape.J;
case 3 -> nextShape = Tetromino.Shape.L;
case 4 -> nextShape = Tetromino.Shape.O;
case 5 -> nextShape = Tetromino.Shape.S;
case 6 -> nextShape = Tetromino.Shape.T;
case 7 -> nextShape = Tetromino.Shape.Z;
default -> nextShape = Tetromino.Shape.I;
}
return new Tetromino(this.instance, nextShape);
}
}

View File

@ -1,14 +1,16 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import java.util.ArrayList;
import java.util.List;
public class Tetromino {
private final Shape shape;
private final StatelessGame instance;
private Pos position;
private int[][] shapeArray;
public enum Shape {
@ -21,7 +23,8 @@ public class Tetromino {
Z
}
public Tetromino(Shape shape) {
public Tetromino(StatelessGame instance, Shape shape) {
this.instance = instance;
this.shape = shape;
switch (this.shape) {
@ -35,6 +38,58 @@ public class Tetromino {
}
}
public Pos getPosition() {
return this.position;
}
public void setPosition(Pos newPosition) {
this.position = newPosition;
}
public boolean rotate(boolean clockwise) {
int[][] newShapeArray = this.getTurnedShapeArray(clockwise);
return checkCollisionAndMove(this.position, newShapeArray);
}
public boolean moveDown() {
Pos newPosition = this.position.sub(0, 1, 0);
return checkCollisionAndMove(newPosition, this.shapeArray);
}
public boolean moveLeft() {
Pos newPosition = this.position.sub(1, 0, 0);
return checkCollisionAndMove(newPosition, this.shapeArray);
}
public boolean moveRight() {
Pos newPosition = this.position.add(1, 0, 0);
return checkCollisionAndMove(newPosition, this.shapeArray);
}
public void draw() {
getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock()));
}
public void remove() {
this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, Block.AIR));
}
private Block getColoredBlock() {
Block returnBlock;
switch (this.shape) {
case I -> returnBlock = Block.LIGHT_BLUE_CONCRETE;
case J -> returnBlock = Block.BLUE_CONCRETE;
case L -> returnBlock = Block.ORANGE_CONCRETE;
case O -> returnBlock = Block.YELLOW_CONCRETE;
case S -> returnBlock = Block.GREEN_CONCRETE;
case T -> returnBlock = Block.PURPLE_CONCRETE;
case Z -> returnBlock = Block.RED_CONCRETE;
default -> returnBlock = Block.WHITE_CONCRETE;
}
return returnBlock;
}
private int[][] getTurnedShapeArray(boolean clockwise) {
int iterations = 1;
if(!clockwise) iterations = 3;
@ -53,17 +108,57 @@ public class Tetromino {
return returnArray;
}
public void draw(StatelessGame instance, Pos spawnPosition) {
private boolean isPartOfTetromino(Pos position) {
for(Pos blockPosition : getBlockPositions()) {
if(position.sameBlock(blockPosition)) {
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;
int arrayLength = this.shapeArray.length;
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x=-1; x<arrayLength-1; x++) {
for(int y=-1; y<arrayLength-1; y++) {
batch.setBlock(spawnPosition.add(x, y, 0), Block.WHITE_CONCRETE);
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));
}
}
}
BatchUtil.loadAndApplyBatch(batch, instance, () -> {});
return returnList;
}
private boolean checkCollision(Pos newPosition, int[][] newShapeArray) {
int arrayLength = newShapeArray.length;
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;
}
}
// 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.setPosition(newPosition);
this.draw();
return true;
}
return false;
}
}