俄罗斯方块旋转算法不起作用

时间:2015-07-21 04:25:02

标签: java android algorithm

我正在使用俄罗斯方块旋转算法。我刚才在我的另一个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);
}
}

1 个答案:

答案 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;