fixed srs rotations
This commit is contained in:
@@ -1,38 +1,52 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public final class RotationChecker {
|
public final class RotationChecker {private static final Map<Orientation, int[][]> STANDARD_WALL_KICKS = Map.of(
|
||||||
private record RotationKey(Orientation from, Orientation to) {}
|
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}},
|
||||||
private static final Map<RotationKey, int[][]> STANDARD_WALL_KICKS = Map.of(
|
Orientation.UPSIDE_DOWN, new int[][] {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}},
|
||||||
new RotationKey(Orientation.NONE, Orientation.RIGHT), new int[][] {{0,0}, {-1,0}, {-1,1}, {0,-2}, {-1,-2}},
|
Orientation.LEFT, new int[][] {{0,0}, {-1,0}, {-1,-1}, {0,2}, {-1,2}}
|
||||||
new RotationKey(Orientation.RIGHT, Orientation.NONE), new int[][] {{0,0}, {1,0}, {1,-1}, {0,2}, {1,2}},
|
|
||||||
new RotationKey(Orientation.RIGHT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {1,0}, {1,-1}, {0,2}, {1,2}},
|
|
||||||
new RotationKey(Orientation.UPSIDE_DOWN, Orientation.RIGHT), new int[][] {{0,0}, {-1,0}, {-1,1}, {0,-2}, {-1,-2}},
|
|
||||||
new RotationKey(Orientation.UPSIDE_DOWN, Orientation.LEFT), new int[][] {{0,0}, {1,0}, {1,1}, {0,-2}, {1,-2}},
|
|
||||||
new RotationKey(Orientation.LEFT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {-1,0}, {-1,-1}, {0,2}, {-1,2}},
|
|
||||||
new RotationKey(Orientation.LEFT, Orientation.NONE), new int[][] {{0,0}, {-1,0}, {-1,-1}, {0,2}, {-1,2}},
|
|
||||||
new RotationKey(Orientation.NONE, Orientation.LEFT), new int[][] {{0,0}, {1,0}, {1,1}, {0,-2}, {1,-2}}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final Map<RotationKey, int[][]> I_WALL_KICKS = Map.of(
|
private static final Map<Orientation, int[][]> I_WALL_KICKS = Map.of(
|
||||||
new RotationKey(Orientation.NONE, Orientation.RIGHT), new int[][] {{0,0}, {-2,0}, {1,0}, {-2,-1}, {1,2}},
|
Orientation.NONE, new int[][] {{0,0}, {-1,0}, {2,0}, {-1,0}, {2,0}},
|
||||||
new RotationKey(Orientation.RIGHT, Orientation.NONE), new int[][] {{0,0}, {2,0}, {-1,0}, {2,1}, {-1,-2}},
|
Orientation.RIGHT, new int[][] {{-1,0}, {0,0}, {0,0}, {0,1}, {0,-2}},
|
||||||
new RotationKey(Orientation.RIGHT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {-1,0}, {2,0}, {-1,2}, {2,-1}},
|
Orientation.UPSIDE_DOWN, new int[][] {{-1,1}, {1,1}, {-2,1}, {1,0}, {-2,0}},
|
||||||
new RotationKey(Orientation.UPSIDE_DOWN, Orientation.RIGHT), new int[][] {{0,0}, {1,0}, {-2,0}, {1,-2}, {-2,1}},
|
Orientation.LEFT, new int[][] {{0,1}, {0,1}, {0,1}, {0,-1}, {0,2}}
|
||||||
new RotationKey(Orientation.UPSIDE_DOWN, Orientation.LEFT), new int[][] {{0,0}, {2,0}, {-1,0}, {2,1}, {-1,-2}},
|
);
|
||||||
new RotationKey(Orientation.LEFT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {-2,0}, {1,0}, {-2,-1}, {1,2}},
|
|
||||||
new RotationKey(Orientation.LEFT, Orientation.NONE), new int[][] {{0,0}, {1,0}, {-2,0}, {1,-2}, {-2,1}},
|
private static final Map<Orientation, int[][]> O_WALL_KICKS = Map.of(
|
||||||
new RotationKey(Orientation.NONE, Orientation.LEFT), new int[][] {{0,0}, {-1,0}, {2,0}, {-1,2}, {2,-1}}
|
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) {
|
public static int[][] getKicksArray(Orientation from, Orientation to, Tetromino.Shape shape) {
|
||||||
RotationKey rotationKey = new RotationKey(from, to);
|
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) {
|
return switch(shape) {
|
||||||
case J, L, S, T, Z -> STANDARD_WALL_KICKS.get(rotationKey);
|
case J, L, S, T, Z -> STANDARD_WALL_KICKS.get(orientation);
|
||||||
case I -> I_WALL_KICKS.get(rotationKey);
|
case I -> I_WALL_KICKS.get(orientation);
|
||||||
default -> new int[][]{{0, 0}};
|
case O -> O_WALL_KICKS.get(orientation);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,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}};
|
||||||
@@ -53,9 +53,12 @@ public class Tetromino {
|
|||||||
|
|
||||||
// TODO: doesn't work for I-Tetromino
|
// TODO: doesn't work for I-Tetromino
|
||||||
int[][] kicksArray = RotationChecker.getKicksArray(this.orientation, newOrientation, this.shape);
|
int[][] kicksArray = RotationChecker.getKicksArray(this.orientation, newOrientation, this.shape);
|
||||||
|
System.out.println(this.shape.toString() + ": " + Arrays.deepToString(kicksArray));
|
||||||
for(int[] k : kicksArray) {
|
for(int[] k : kicksArray) {
|
||||||
Pos candidate = new Pos(this.position.x() + k[0], this.position.y() + k[1], this.position.z());
|
Pos candidate = new Pos(this.position.x() + k[0], this.position.y() + k[1], this.position.z());
|
||||||
if(this.checkCollisionAndMove(candidate, newShapeArray)) {
|
boolean moved = this.checkCollisionAndMove(candidate, newShapeArray);
|
||||||
|
System.out.println("Candidate: " + Arrays.toString(k) + " " + moved);
|
||||||
|
if(moved) {
|
||||||
this.orientation = newOrientation;
|
this.orientation = newOrientation;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -86,7 +89,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);
|
||||||
@@ -212,9 +215,8 @@ public class Tetromino {
|
|||||||
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) {
|
switch(this.shape) {
|
||||||
case I -> returnList.add(position.add(x - 1, y - 2, 0));
|
case I -> returnList.add(new Pos(position).add(x - 2, y - 2, 0));
|
||||||
case O -> returnList.add(position.add(x, y, 0));
|
default -> returnList.add(new Pos(position).add(x - 1, y - 1, 0));
|
||||||
default -> returnList.add(position.add(x - 1, y - 1, 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,7 +225,22 @@ public class Tetromino {
|
|||||||
return returnList;
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkCollision(Pos newPosition, int[][] newShapeArray) {
|
// private List<Pos> getBlockPositions(Pos position, int[][] shapeArray) {
|
||||||
|
// List<Pos> returnList = new ArrayList<>();
|
||||||
|
// if(position == null) return returnList;
|
||||||
|
//
|
||||||
|
// for(int x = 0; x < shapeArray.length; x++) {
|
||||||
|
// for(int y = 0; y < shapeArray.length; y++) {
|
||||||
|
// if(shapeArray[x][y] == 1) {
|
||||||
|
// returnList.add(new Pos(position).sub(1, 1, 0).add(x, y, 0));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return returnList;
|
||||||
|
// }
|
||||||
|
|
||||||
|
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) {
|
||||||
@@ -236,14 +253,12 @@ public class Tetromino {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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