2015-07-21 61 views
2

我正在使用俄羅斯方塊旋轉算法。前段時間我在另一個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指示旋轉中心。因此,我可以嘗試旋轉的俄羅斯大約每俄羅斯方塊塊,像這樣:

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); 
} 
} 

回答

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; 
+0

哦,是的,我明白了!非常感謝你!我嘗試。 – Sweeper

+0

哦,它的工作!接受答案! – Sweeper