develop-tetris-srs #11
@@ -82,11 +82,11 @@ class Tetris extends StatelessGame {
|
|||||||
|
|
||||||
private void onPlayerInteract(@NotNull PlayerUseItemEvent event) {
|
private void onPlayerInteract(@NotNull PlayerUseItemEvent event) {
|
||||||
event.setItemUseTime(0);
|
event.setItemUseTime(0);
|
||||||
this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseRight);
|
this.tetrisGames.get(event.getPlayer()).pressedButtonRaw(TetrisGame.Button.mouseRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) {
|
private void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) {
|
||||||
this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseLeft);
|
this.tetrisGames.get(event.getPlayer()).pressedButtonRaw(TetrisGame.Button.mouseLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPlayerTick(PlayerTickEvent event) {
|
private void onPlayerTick(PlayerTickEvent event) {
|
||||||
@@ -100,11 +100,11 @@ class Tetris extends StatelessGame {
|
|||||||
|
|
||||||
if(player.getGameMode() == GameMode.SPECTATOR) return;
|
if(player.getGameMode() == GameMode.SPECTATOR) return;
|
||||||
|
|
||||||
if(player.inputs().forward()) tetrisGame.pressedButton(TetrisGame.Button.W);
|
if(player.inputs().forward()) tetrisGame.pressedButtonRaw(TetrisGame.Button.W);
|
||||||
if(player.inputs().backward()) tetrisGame.pressedButton(TetrisGame.Button.S);
|
if(player.inputs().backward()) tetrisGame.pressedButtonRaw(TetrisGame.Button.S);
|
||||||
if(player.inputs().right()) tetrisGame.pressedButton(TetrisGame.Button.D);
|
if(player.inputs().right()) tetrisGame.pressedButtonRaw(TetrisGame.Button.D);
|
||||||
if(player.inputs().left()) tetrisGame.pressedButton(TetrisGame.Button.A);
|
if(player.inputs().left()) tetrisGame.pressedButtonRaw(TetrisGame.Button.A);
|
||||||
if(player.inputs().jump()) tetrisGame.pressedButton(TetrisGame.Button.space);
|
if(player.inputs().jump()) tetrisGame.pressedButtonRaw(TetrisGame.Button.space);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void letPlayerLoose(Player player) {
|
private void letPlayerLoose(Player player) {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
|
||||||
|
|
||||||
|
public enum Orientation {
|
||||||
|
NONE,
|
||||||
|
RIGHT,
|
||||||
|
LEFT,
|
||||||
|
UPSIDE_DOWN;
|
||||||
|
|
||||||
|
public Orientation rotated(boolean clockwise) {
|
||||||
|
switch(this) {
|
||||||
|
|
|||||||
|
case NONE -> {
|
||||||
|
return clockwise ? Orientation.RIGHT : Orientation.LEFT;
|
||||||
|
}
|
||||||
|
case RIGHT -> {
|
||||||
|
return clockwise ? Orientation.UPSIDE_DOWN : Orientation.NONE;
|
||||||
|
}
|
||||||
|
case UPSIDE_DOWN -> {
|
||||||
|
return clockwise ? Orientation.LEFT : Orientation.RIGHT;
|
||||||
|
}
|
||||||
|
case LEFT -> {
|
||||||
|
return clockwise ? Orientation.NONE : Orientation.UPSIDE_DOWN;
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
Pupsi marked this conversation as resolved
MineTec
commented
ist default hier überhaupt erreichbar? ist default hier überhaupt erreichbar?
|
|||||||
|
return Orientation.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public final class RotationChecker {private static final Map<Orientation, int[][]> STANDARD_WALL_KICKS = Map.of(
|
||||||
|
Pupsi marked this conversation as resolved
MineTec
commented
zeilenumbruch zeilenumbruch
|
|||||||
|
Orientation.NONE, new int[][] {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}},
|
||||||
|
Orientation.RIGHT, new int[][] {{0,0}, {1,0}, {1,-1}, {0,2}, {1,2}},
|
||||||
|
Orientation.UPSIDE_DOWN, new int[][] {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}},
|
||||||
|
Orientation.LEFT, new int[][] {{0,0}, {-1,0}, {-1,-1}, {0,2}, {-1,2}}
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Map<Orientation, int[][]> I_WALL_KICKS = Map.of(
|
||||||
|
Orientation.NONE, new int[][] {{0,0}, {-1,0}, {2,0}, {-1,0}, {2,0}},
|
||||||
|
Orientation.RIGHT, new int[][] {{-1,0}, {0,0}, {0,0}, {0,1}, {0,-2}},
|
||||||
|
Orientation.UPSIDE_DOWN, new int[][] {{-1,1}, {1,1}, {-2,1}, {1,0}, {-2,0}},
|
||||||
|
Orientation.LEFT, new int[][] {{0,1}, {0,1}, {0,1}, {0,-1}, {0,2}}
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Map<Orientation, int[][]> O_WALL_KICKS = Map.of(
|
||||||
|
Orientation.NONE, new int[][] {{0,0}},
|
||||||
|
Orientation.RIGHT, new int[][] {{0,-1}},
|
||||||
|
Orientation.UPSIDE_DOWN, new int[][] {{-1,-1}},
|
||||||
|
Orientation.LEFT, new int[][] {{-1,0}}
|
||||||
|
);
|
||||||
|
|
||||||
|
public static int[][] getKicksArray(Orientation from, Orientation to, Tetromino.Shape shape) {
|
||||||
|
int[][] firstOffsets = getOffsetData(from, shape);
|
||||||
|
int[][] secondOffsets = getOffsetData(to, shape);
|
||||||
|
int[][] result = new int[firstOffsets.length][2];
|
||||||
|
|
||||||
|
for(int i = 0; i < firstOffsets.length; i++) {
|
||||||
|
result[i] = subtractInt(firstOffsets[i], secondOffsets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] subtractInt(int[] first, int[] second) {
|
||||||
|
return IntStream.range(0, first.length)
|
||||||
|
.map(i -> first[i] - second[i])
|
||||||
|
.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[][] getOffsetData(Orientation orientation, Tetromino.Shape shape) {
|
||||||
|
return switch(shape) {
|
||||||
|
case J, L, S, T, Z -> STANDARD_WALL_KICKS.get(orientation);
|
||||||
|
case I -> I_WALL_KICKS.get(orientation);
|
||||||
|
case O -> O_WALL_KICKS.get(orientation);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,9 @@ 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.instance.game.stateless.StatelessGame;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minestom.server.MinecraftServer;
|
|
||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.scoreboard.Sidebar;
|
import net.minestom.server.scoreboard.Sidebar;
|
||||||
import net.minestom.server.timer.Scheduler;
|
import net.minestom.server.timer.Task;
|
||||||
import net.minestom.server.timer.TaskSchedule;
|
import net.minestom.server.timer.TaskSchedule;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -23,6 +22,8 @@ public class TetrisGame {
|
|||||||
private final Map<Button, Long> lastPresses = new HashMap<>();
|
private final Map<Button, Long> lastPresses = new HashMap<>();
|
||||||
private final List<TetrisGame> otherTetrisGames = new ArrayList<>();
|
private final List<TetrisGame> otherTetrisGames = new ArrayList<>();
|
||||||
private final Random random;
|
private final Random random;
|
||||||
|
private Task tetrominoLockTask;
|
||||||
|
private Task hardTetrominoLockTask;
|
||||||
public boolean lost = false;
|
public boolean lost = false;
|
||||||
public boolean paused = true;
|
public boolean paused = true;
|
||||||
public Tetromino currentTetromino;
|
public Tetromino currentTetromino;
|
||||||
@@ -53,25 +54,28 @@ public class TetrisGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pressedButton(Button button) {
|
public void pressedButtonRaw(Button button) {
|
||||||
final int standardButtonDelay = 100;
|
final int standardButtonDelay = 95;
|
||||||
final int buttonDebounce = 70;
|
final int wsButtonDebounce = 70;
|
||||||
|
|
||||||
if(this.lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis() - standardButtonDelay) return;
|
if(this.lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis() - standardButtonDelay) return;
|
||||||
|
|
||||||
this.lastPresses.put(button, System.currentTimeMillis());
|
switch(button) {
|
||||||
if(button == Button.W) this.lastPresses.put(button, System.currentTimeMillis() + buttonDebounce);
|
case W -> this.lastPresses.put(button, System.currentTimeMillis() + wsButtonDebounce);
|
||||||
if(button == Button.S) this.lastPresses.put(button, System.currentTimeMillis() - buttonDebounce);
|
case S -> this.lastPresses.put(button, System.currentTimeMillis() - wsButtonDebounce);
|
||||||
|
case mouseLeft, mouseRight -> this.lastPresses.put(button, 0L);
|
||||||
|
default -> this.lastPresses.put(button, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
if(this.lost || this.paused) return;
|
if(this.lost || this.paused) return;
|
||||||
|
|
||||||
|
Pupsi marked this conversation as resolved
MineTec
commented
hier ein if, welches hier ein if, welches `left`, `right` und `rotate` abfängt und `this.stopTetrominoLockTask(false)` macht ist glaub ich schöner als die 3 Methoden, die praktisch nur weiterreichen...
|
|||||||
switch(button) {
|
switch(button) {
|
||||||
case A -> this.currentTetromino.moveLeft();
|
case A -> this.moveLeft();
|
||||||
case S -> this.moveDown();
|
case S -> this.moveDown();
|
||||||
case D -> this.currentTetromino.moveRight();
|
case D -> this.moveRight();
|
||||||
case W -> this.hardDrop();
|
case W -> this.hardDrop();
|
||||||
case mouseLeft -> this.currentTetromino.rotate(false);
|
case mouseLeft -> this.rotate(false);
|
||||||
case mouseRight -> this.currentTetromino.rotate(true);
|
case mouseRight -> this.rotate(true);
|
||||||
case space -> this.switchHold();
|
case space -> this.switchHold();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,8 +86,7 @@ public class TetrisGame {
|
|||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
Scheduler scheduler = MinecraftServer.getSchedulerManager();
|
this.instance.scheduler().submitTask(() -> {
|
||||||
scheduler.submitTask(() -> {
|
|
||||||
if(this.lost) return TaskSchedule.stop();
|
if(this.lost) return TaskSchedule.stop();
|
||||||
int standardTickDelay = 40;
|
int standardTickDelay = 40;
|
||||||
if(this.isFast) standardTickDelay = 20;
|
if(this.isFast) standardTickDelay = 20;
|
||||||
@@ -111,8 +114,9 @@ public class TetrisGame {
|
|||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
if(this.lost || this.paused) return;
|
if(this.lost || this.paused) return;
|
||||||
|
if(!this.currentTetromino.isGrounded()) this.stopTetrominoLockTask(true);
|
||||||
if(!this.currentTetromino.moveDown()) {
|
if(!this.currentTetromino.moveDown()) {
|
||||||
this.setActiveTetrominoDown();
|
this.scheduleTetrominoLock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,33 +143,42 @@ public class TetrisGame {
|
|||||||
this.lost = true;
|
this.lost = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean moveDown() {
|
private void moveDown() {
|
||||||
if(!this.currentTetromino.moveDown()) {
|
if(!this.currentTetromino.moveDown()) {
|
||||||
this.setActiveTetrominoDown();
|
this.scheduleTetrominoLock();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
this.score += 1;
|
this.score += 1;
|
||||||
this.updateInfo();
|
this.updateInfo();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hardDrop() {
|
private void moveLeft() {
|
||||||
|
if(this.currentTetromino.moveLeft()) this.stopTetrominoLockTask(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveRight() {
|
||||||
|
if(this.currentTetromino.moveRight()) this.stopTetrominoLockTask(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rotate(boolean clockwise) {
|
||||||
|
if(this.currentTetromino.rotate(clockwise)) this.stopTetrominoLockTask(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hardDrop() {
|
||||||
if(!this.currentTetromino.moveDown()) {
|
if(!this.currentTetromino.moveDown()) {
|
||||||
this.setActiveTetrominoDown();
|
this.lockActiveTetromino();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
this.score += 2;
|
do {
|
||||||
this.updateInfo();
|
|
||||||
while(this.currentTetromino.moveDown()) {
|
|
||||||
this.score += 2;
|
this.score += 2;
|
||||||
this.updateInfo();
|
} while(this.currentTetromino.moveDown());
|
||||||
}
|
this.updateInfo();
|
||||||
this.setActiveTetrominoDown();
|
this.lockActiveTetromino();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean switchHold() {
|
private void switchHold() {
|
||||||
if(!this.holdPossible) return false;
|
if(!this.holdPossible) return;
|
||||||
|
this.stopTetrominoLockTask(true);
|
||||||
|
|
||||||
Tetromino newCurrentTetromino;
|
Tetromino newCurrentTetromino;
|
||||||
if(this.holdTetromino == null) {
|
if(this.holdTetromino == null) {
|
||||||
@@ -189,7 +202,6 @@ public class TetrisGame {
|
|||||||
this.holdTetromino.setPosition(this.holdPosition.add(xChange, 0, 0));
|
this.holdTetromino.setPosition(this.holdPosition.add(xChange, 0, 0));
|
||||||
this.holdTetromino.drawAsEntities();
|
this.holdTetromino.drawAsEntities();
|
||||||
this.holdPossible = false;
|
this.holdPossible = false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNextTetrominoes() {
|
private void updateNextTetrominoes() {
|
||||||
@@ -235,7 +247,40 @@ public class TetrisGame {
|
|||||||
this.sidebar.updateLineScore("2", this.level);
|
this.sidebar.updateLineScore("2", this.level);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setActiveTetrominoDown() {
|
private void scheduleTetrominoLock() {
|
||||||
|
if(this.tetrominoLockTask == null || !this.tetrominoLockTask.isAlive())
|
||||||
|
this.tetrominoLockTask = this.instance.scheduler().scheduleTask(() -> {
|
||||||
|
MineTec
commented
tasks hierfür fühlen sich falsch an... tasks hierfür fühlen sich falsch an...
Wo kommen die Limits (500ms) her? Ist das im Original auch genau so?
Pupsi
commented
Ja, die 500ms sind wie in den Tetris Guidelines. Allerdings gibt es dort keinen hard lock task, sondern einen Counter. Ja, die 500ms sind wie in den Tetris Guidelines. Allerdings gibt es dort keinen hard lock task, sondern einen Counter.
Änder ich um.
|
|||||||
|
if(this.currentTetromino.isGrounded()) {
|
||||||
|
this.lockActiveTetromino();
|
||||||
|
} else {
|
||||||
|
this.stopTetrominoLockTask(true);
|
||||||
|
}
|
||||||
|
return TaskSchedule.stop();
|
||||||
|
}, TaskSchedule.millis(500));
|
||||||
|
if(this.hardTetrominoLockTask == null || !this.hardTetrominoLockTask.isAlive())
|
||||||
|
this.hardTetrominoLockTask = this.instance.scheduler().scheduleTask(() -> {
|
||||||
|
if(this.currentTetromino.isGrounded()) {
|
||||||
|
this.lockActiveTetromino();
|
||||||
|
} else {
|
||||||
|
this.stopTetrominoLockTask(true);
|
||||||
|
}
|
||||||
|
return TaskSchedule.stop();
|
||||||
|
}, TaskSchedule.millis(6000));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTetrominoLockTask(boolean resetHard) {
|
||||||
|
if(this.tetrominoLockTask != null) {
|
||||||
|
this.tetrominoLockTask.cancel();
|
||||||
|
this.tetrominoLockTask = null;
|
||||||
|
}
|
||||||
|
if(resetHard && this.hardTetrominoLockTask != null) {
|
||||||
|
this.hardTetrominoLockTask.cancel();
|
||||||
|
this.hardTetrominoLockTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lockActiveTetromino() {
|
||||||
|
this.stopTetrominoLockTask(true);
|
||||||
this.currentTetromino.removeOwnEntities();
|
this.currentTetromino.removeOwnEntities();
|
||||||
this.currentTetromino = this.nextTetrominoes.removeFirst();
|
this.currentTetromino = this.nextTetrominoes.removeFirst();
|
||||||
this.currentTetromino.remove();
|
this.currentTetromino.remove();
|
||||||
|
|||||||
@@ -8,14 +8,12 @@ import net.minestom.server.entity.metadata.other.FallingBlockMeta;
|
|||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.tag.Tag;
|
import net.minestom.server.tag.Tag;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class Tetromino {
|
public class Tetromino {
|
||||||
private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK;
|
private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK;
|
||||||
private final static Tag<String> uuidTag = Tag.String("uuid");
|
private final static Tag<String> uuidTag = Tag.String("uuid");
|
||||||
|
private Orientation orientation = Orientation.NONE;
|
||||||
private final Shape shape;
|
private final Shape shape;
|
||||||
private final StatelessGame instance;
|
private final StatelessGame instance;
|
||||||
private final UUID uuid;
|
private final UUID uuid;
|
||||||
@@ -28,10 +26,10 @@ public class Tetromino {
|
|||||||
this.uuid = UUID.randomUUID();
|
this.uuid = UUID.randomUUID();
|
||||||
|
|
||||||
switch(this.shape) {
|
switch(this.shape) {
|
||||||
case I -> this.shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}};
|
case I -> this.shapeArray = new int[][]{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 1, 1, 1, 1}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
|
||||||
case J -> this.shapeArray = new int[][]{{1, 0, 0}, {1, 1, 1}, {0, 0, 0}};
|
case J -> this.shapeArray = new int[][]{{1, 0, 0}, {1, 1, 1}, {0, 0, 0}};
|
||||||
case L -> this.shapeArray = new int[][]{{0, 0, 1}, {1, 1, 1}, {0, 0, 0}};
|
case L -> this.shapeArray = new int[][]{{0, 0, 1}, {1, 1, 1}, {0, 0, 0}};
|
||||||
case O -> this.shapeArray = new int[][]{{1, 1}, {1, 1}};
|
case O -> this.shapeArray = new int[][]{{0, 1, 1}, {0, 1, 1}, {0, 0, 0}};
|
||||||
case S -> this.shapeArray = new int[][]{{0, 1, 1}, {1, 1, 0}, {0, 0, 0}};
|
case S -> this.shapeArray = new int[][]{{0, 1, 1}, {1, 1, 0}, {0, 0, 0}};
|
||||||
case T -> this.shapeArray = new int[][]{{0, 1, 0}, {1, 1, 1}, {0, 0, 0}};
|
case T -> this.shapeArray = new int[][]{{0, 1, 0}, {1, 1, 1}, {0, 0, 0}};
|
||||||
case Z -> this.shapeArray = new int[][]{{1, 1, 0}, {0, 1, 1}, {0, 0, 0}};
|
case Z -> this.shapeArray = new int[][]{{1, 1, 0}, {0, 1, 1}, {0, 0, 0}};
|
||||||
@@ -43,12 +41,23 @@ public class Tetromino {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(Pos newPosition) {
|
public void setPosition(Pos newPosition) {
|
||||||
this.position = newPosition;
|
this.position = new Pos(newPosition.x(), newPosition.y(), newPosition.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean rotate(boolean clockwise) {
|
public boolean rotate(boolean clockwise) {
|
||||||
int[][] newShapeArray = this.getTurnedShapeArray(clockwise);
|
int[][] newShapeArray = this.getTurnedShapeArray(clockwise);
|
||||||
return this.checkCollisionAndMove(this.position, newShapeArray);
|
Orientation newOrientation = this.orientation.rotated(clockwise);
|
||||||
|
|
||||||
|
int[][] kicksArray = RotationChecker.getKicksArray(this.orientation, newOrientation, this.shape);
|
||||||
|
for(int[] k : kicksArray) {
|
||||||
|
Pos candidate = new Pos(this.position.x() + k[0], this.position.y() + k[1], this.position.z());
|
||||||
|
if(this.checkCollisionAndMove(candidate, newShapeArray)) {
|
||||||
|
this.orientation = newOrientation;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean moveDown() {
|
public boolean moveDown() {
|
||||||
@@ -73,7 +82,7 @@ public class Tetromino {
|
|||||||
public void draw(boolean withGhost) {
|
public void draw(boolean withGhost) {
|
||||||
if(withGhost) {
|
if(withGhost) {
|
||||||
Pos ghostPos = this.position;
|
Pos ghostPos = this.position;
|
||||||
while(!this.checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) {
|
while(!this.hasCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) {
|
||||||
ghostPos = ghostPos.sub(0, 1, 0);
|
ghostPos = ghostPos.sub(0, 1, 0);
|
||||||
}
|
}
|
||||||
Pos positionChange = this.position.sub(ghostPos);
|
Pos positionChange = this.position.sub(ghostPos);
|
||||||
@@ -182,7 +191,7 @@ public class Tetromino {
|
|||||||
|
|
||||||
private boolean isPartOfTetromino(Pos position) {
|
private boolean isPartOfTetromino(Pos position) {
|
||||||
return this.getBlockPositions().stream()
|
return this.getBlockPositions().stream()
|
||||||
.anyMatch(pos -> pos.equals(position));
|
.anyMatch(pos -> pos.sameBlock(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Pos> getBlockPositions() {
|
private List<Pos> getBlockPositions() {
|
||||||
@@ -198,10 +207,10 @@ public class Tetromino {
|
|||||||
for(int x = 0; x < arrayLength; x++) {
|
for(int x = 0; x < arrayLength; x++) {
|
||||||
for(int y = 0; y < arrayLength; y++) {
|
for(int y = 0; y < arrayLength; y++) {
|
||||||
if(shapeArray[arrayLength - 1 - y][x] == 1) {
|
if(shapeArray[arrayLength - 1 - y][x] == 1) {
|
||||||
switch(this.shape) {
|
if(Objects.requireNonNull(this.shape) == Shape.I) {
|
||||||
case I -> returnList.add(position.add(x - 1, y - 2, 0));
|
returnList.add(position.add(x - 2, y - 2, 0));
|
||||||
case O -> returnList.add(position.add(x, y, 0));
|
} else {
|
||||||
default -> returnList.add(position.add(x - 1, y - 1, 0));
|
returnList.add(position.add(x - 1, y - 1, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +219,7 @@ public class Tetromino {
|
|||||||
return returnList;
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkCollision(Pos newPosition, int[][] newShapeArray) {
|
private boolean hasCollision(Pos newPosition, int[][] newShapeArray) {
|
||||||
List<Pos> newBlockPositions = this.getBlockPositions(newPosition, newShapeArray);
|
List<Pos> newBlockPositions = this.getBlockPositions(newPosition, newShapeArray);
|
||||||
|
|
||||||
for(Pos pos : newBlockPositions) {
|
for(Pos pos : newBlockPositions) {
|
||||||
@@ -222,15 +231,17 @@ public class Tetromino {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isGrounded() {
|
||||||
|
return this.hasCollision(this.position.sub(0, 1, 0), this.shapeArray);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkCollisionAndMove(Pos newPosition, int[][] newShapeArray) {
|
private boolean checkCollisionAndMove(Pos newPosition, int[][] newShapeArray) {
|
||||||
if(!this.checkCollision(newPosition, newShapeArray)) {
|
if(this.hasCollision(newPosition, newShapeArray)) return false;
|
||||||
this.remove();
|
this.remove();
|
||||||
this.shapeArray = Arrays.stream(newShapeArray).map(int[]::clone).toArray(int[][]::new);
|
this.shapeArray = Arrays.stream(newShapeArray).map(int[]::clone).toArray(int[][]::new);
|
||||||
this.setPosition(newPosition);
|
this.setPosition(newPosition);
|
||||||
this.draw();
|
this.draw();
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Shape {
|
public enum Shape {
|
||||||
|
|||||||
Reference in New Issue
Block a user
Das switch statement ließe sich etwas vereinfachen