我正在使用俄罗斯方块旋转算法。我刚才在我的另一个winforms应用程序中使用了该算法,它运行得很好。现在我想在Android中编写一个俄罗斯方块游戏,所以我再次用Java编写算法。
然而,这次它不起作用。很久以前,当我是初学程序员时,我编写了算法,所以代码有点糟糕。这是Java中的算法:
public static final int CLOCKWISE = 1;
public static final int ANTICLOCKWISE = -1;
public static Point rotateClockwise (int x, int y) {
int temp;
temp = y;
y = x;
x = -temp;
return new Point (x, y);
}
public static Point rotateAnticlockwise (int x, int y) {
int temp;
temp = x;
x = y;
y = -temp;
return new Point (x, y);
}
public static boolean tryRotateTetrimino (Tetrimino tetrimino,
int rotationPointBlockIndex, int direction) {
//Local variable declarations
boolean a, b, c, d;
TetrisBlock rotationBlock = tetrimino.blocks[rotationPointBlockIndex];
int X1, Y1, X2, Y2, X3, Y3, X4, Y4;
//Assign coordinates relative to the centre of rotation.
X1 = tetrimino.blocks[0].getX () - rotationBlock.getX ();
Y1 = tetrimino.blocks[0].getY () - rotationBlock.getY ();
X2 = tetrimino.blocks[1].getX () - rotationBlock.getX ();
Y2 = tetrimino.blocks[1].getY () - rotationBlock.getY ();
X3 = tetrimino.blocks[2].getX () - rotationBlock.getX ();
Y3 = tetrimino.blocks[2].getY () - rotationBlock.getY ();
X4 = tetrimino.blocks[3].getX () - rotationBlock.getX ();
Y4 = tetrimino.blocks[3].getY () - rotationBlock.getY ();
//Rotate the coordinates.
if (direction == CLOCKWISE) {
X1 = rotateClockwise (X1, Y1).x;
Y1 = rotateClockwise (X1, Y1).y;
X2 = rotateClockwise (X2, Y2).x;
Y2 = rotateClockwise (X2, Y2).y;
X3 = rotateClockwise (X3, Y3).x;
Y3 = rotateClockwise (X3, Y3).y;
X4 = rotateClockwise (X4, Y4).x;
Y4 = rotateClockwise (X4, Y4).y;
} else {
X1 = rotateAnticlockwise (X1, Y1).x;
Y1 = rotateAnticlockwise (X1, Y1).y;
X2 = rotateAnticlockwise (X2, Y2).x;
Y2 = rotateAnticlockwise (X2, Y2).y;
X3 = rotateAnticlockwise (X3, Y3).x;
Y3 = rotateAnticlockwise (X3, Y3).y;
X4 = rotateAnticlockwise (X4, Y4).x;
Y4 = rotateAnticlockwise (X4, Y4).y;
}
//Declares two arrays of absolute x and y coordinates.
int[] xArray = new int[] { rotationBlock.getX() + X1,
rotationBlock.getX() + X2,
rotationBlock.getX() + X3,
rotationBlock.getX() + X4 };
int[] yArray = new int[] { rotationBlock.getY() + Y1,
rotationBlock.getY() + Y2,
rotationBlock.getY() + Y3,
rotationBlock.getY() + Y4 };
//Check if the coordinates are valid
a = tetrimino.checkPositionValid (xArray[0], yArray[0]);
b = tetrimino.checkPositionValid (xArray[1], yArray[1]);
c = tetrimino.checkPositionValid (xArray[2], yArray[2]);
d = tetrimino.checkPositionValid (xArray[3], yArray[3]);
//If the coordinates are valid, assign them to each of the blocks.
if (a && b && c && d) {
for (int i = 0 ; i < 4 ; i++) {
tetrimino.blocks[i].setX (xArray[i]);
tetrimino.blocks[i].setY (yArray[i]);
}
return true;
}
return false;
}
我认为除了我以外,所有人都很难理解这段代码。我曾经写过世界上最糟糕的代码。当terimino可以旋转并旋转时,此方法返回true。参数rotationPointBlockIndex表示旋转中心。因此,我可以尝试旋转tetrimino关于每个俄罗斯方块块,如下:
if (TetrisUtility.tryRotateTetrimino (this, 0, TetrisUtility.CLOCKWISE))
TetrisUtility.addRotationIndex (this);
else if (TetrisUtility.tryRotateTetrimino (this, 1, TetrisUtility.CLOCKWISE))
TetrisUtility.addRotationIndex (this);
else if (TetrisUtility.tryRotateTetrimino (this, 2, TetrisUtility.CLOCKWISE))
TetrisUtility.addRotationIndex (this);
else if (TetrisUtility.tryRotateTetrimino (this, 3, TetrisUtility.CLOCKWISE))
TetrisUtility.addRotationIndex (this);
请注意,setX和setY方法将改变俄罗斯方块的物理位置。
我做的和以前完全一样,但它不起作用。 例如:
O
O
O O
旋转,然后变成
O
O
O
似乎有两个俄罗斯方块块重叠了。
如果您认为我的算法错误并希望建议另一个算法,您能用Tetrimino类和TetrisBlock类来解释它吗?
Tetrimino.java
public abstract class Tetrimino {
public TetrisBlock[] blocks;
protected int interval = 1000;
protected boolean paused = false;
protected Handler handler;
protected TetrisBlock[][] tetrisBlockMatrix;
protected ArrayList<ITetrisEventListener> landedEventListeners;
protected Runnable task = new TimerTask () {
@Override
public void run() {
if (!paused) {
moveDown ();
if (handler != null)
handler.postDelayed (task, interval);
}
}
};
public static final int LEFT = -1;
public static final int RIGHT = 1;
protected abstract TetrisBlock[] getTouchingSides();
protected void landed () {
for (int i = 0 ; i < landedEventListeners.size () ; i++) {
landedEventListeners.get (i).onLanded (this);
}
}
public void registerLandedListeners (ITetrisEventListener listener) {
landedEventListeners.add (listener);
}
public void moveDown () {
if (!checkLanded ()) {
for (TetrisBlock block:blocks) {
block.moveDown ();
}
} else {
handler = null;
landed ();
}
}
protected boolean checkLanded () {
TetrisBlock[] touchingSides = getTouchingSides ();
for (TetrisBlock block:touchingSides) {
if (block.getY () >= 21) {
return true;
}
if (tetrisBlockMatrix[block.getX ()][block.getY () + 1] != null) {
return true;
}
}
return false;
}
public boolean checkPositionValid (int x, int y) {
if (x < 0 || y < 0 ||
x > 15 || y > 21)
return false;
if (tetrisBlockMatrix[x][y] == null)
return true;
return false;
}
public void move (int side) {
if (side == 1 || side == -1) {
for (TetrisBlock block:blocks) {
block.setX (block.getX () + side);
}
for (TetrisBlock block:blocks) {
if (!checkPositionValid (block.getX (), block.getY ())) {
if (side == LEFT)
move (RIGHT);
else
move (LEFT);
}
}
} else {
throw new IllegalArgumentException ();
}
}
public void addTetrisBlocksToMatrix (TetrisBlock[][] matrix) {
for (TetrisBlock block:blocks) {
if (matrix[block.getX ()][block.getY ()] == null) {
matrix[block.getX ()][block.getY ()] = block;
} else {
throw new IllegalArgumentException ();
}
}
}
public void setTimerEnabled (boolean value) {
if (value && paused) {
handler.post (task);
} else {
paused = true;
}
}
public void setTimerInterval (int milliseconds) {
interval = milliseconds;
}
protected Tetrimino (TetrisBlock[][] matrix, TetrisActivity activity) {
this.tetrisBlockMatrix = matrix;
handler = new Handler ();
handler.post (task);
landedEventListeners = new ArrayList<> ();
blocks = new TetrisBlock[4];
}
}
TetrisBlock.java
public class TetrisBlock {
private static final int LENGTH_IN_DP = 20;
private TetrisActivity activity;
private ImageView picture;
private int color;
private int x;
private int y;
private AbsoluteLayout.LayoutParams getLayoutParams () {
return (AbsoluteLayout.LayoutParams) picture.getLayoutParams ();
}
public TetrisActivity getActivity() {
return activity;
}
public ImageView getPicture() {
return picture;
}
public int getY() {
AbsoluteLayout.LayoutParams params = getLayoutParams ();
return params.y / getLengthInPixels ();
}
public void setY(int y) {
this.y = y;
AbsoluteLayout.LayoutParams params = getLayoutParams ();
params.y = y * getLengthInPixels ();
picture.setLayoutParams (params);
}
public int getX() {
AbsoluteLayout.LayoutParams params = getLayoutParams ();
return params.x / getLengthInPixels ();
}
public void setX(int x) {
this.x = x;
AbsoluteLayout.LayoutParams params = getLayoutParams ();
params.x = x * getLengthInPixels ();
picture.setLayoutParams (params);
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
picture.setBackgroundColor (color);
}
public TetrisBlock (int color, int x, int y, TetrisActivity activity) {
this.activity = activity;
picture = new ImageView (activity);
setColor (color);
picture.setImageResource (R.drawable.tetrisblock);
int w, h;
w = getLengthInPixels ();
h = getLengthInPixels ();
AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams (w,
h, x * getLengthInPixels (), y * getLengthInPixels ());
picture.setLayoutParams (params);
picture.setScaleType (ImageView.ScaleType.FIT_CENTER);
((AbsoluteLayout)activity.findViewById (R.id.main_frame)).addView (picture);
}
public void moveDown () {
setY (getY () + 1);
}
public int getLengthInPixels () {
return (int)(LENGTH_IN_DP * activity.getScale () + 0.5F);
}
}
答案 0 :(得分:3)
问题在于,当您旋转时,您将X坐标设置为新值并覆盖旧值,当您仍然需要它来进行第二次旋转功能调用时。例如,当您应该传递原始值时,X1的旋转值将传递给rotateClockwise
的第二次调用:
X1 = rotateClockwise (X1, Y1).x;
Y1 = rotateClockwise (X1, Y1).y;
只需调用一次,然后将x和y值分配给变量:
Point point1 = rotateClockwise (X1, Y1);
X1 = point1.x; Y1 = point1.y;