我认为您的问题是每个 Tile 决定其是否被阻塞和移动的逻辑之一是错误的。建议:
- Tile 类不应该决定它是否应该移动。
- 相反,它应该有一个方法来检查它是否没有被阻塞,就是这样。
- Piece 类应遍历其 Tile 集合,并对其组成的 Tile 对象调用此方法。
- 如果一个 Tile 被阻挡,Piece 应该确保它没有被它自己的 Tiles 阻挡。
- 如果棋子被非棋子棋子阻挡,棋子应该取消移动。
- 如果所有的瓷砖都没有被阻挡,或者任何瓷砖被自己的一块瓷砖阻挡,那么一块应该遍历瓷砖
ArrayList<Tile>
,告诉每个瓷砖移动。
为了他人的利益,这是您在单个文件中的完整程序:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TetrisSscce extends JPanel {
static TetrisSscce runMe;
BoardSscce board;
public TetrisSscce() { // creates a new Panel window and sets properties
JFrame f = new JFrame("Tetris");
// width (height), length, tilesize
board = new BoardSscce(4, 6, 30);
f.add(board);
f.setSize(board.getWidth(), board.getHeight());
f.setVisible(true);
f.setResizable(false);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation((screensize.width - f.getWidth()) / 2,
(screensize.height - f.getHeight()) / 2 - 100);
}
public static void main(String[] args) {
runMe = new TetrisSscce();
}
}
class BoardSscce extends JPanel implements KeyListener {
private TileSscce grid[][];
private TileSscce activetile;
private int width, height, tilesize;
private String piece;
private PieceSscce newPiece;
public BoardSscce(int w, int h, int ts) { // add elements to the Tetris panel
width = w;
height = h;
tilesize = ts;
grid = new TileSscce[height][width];
// activetile = new TileSscce(this,0, 0); //add new tile to "this" board
newPiece = new PieceSscce(this, randomPiece());
addKeyListener(this);
setFocusable(true);
}
public String randomPiece() {
String[] Pieces = { "L", "O", "Z", "RevZ", "Bar", "T", "RevL" };
String randomShape;
int rand = (int) (Math.random() * Pieces.length);
randomShape = Pieces[rand];
return randomShape;
}
// dimensions of board = width * tilesize
public int getWidth() {
// 4 * 30 = 120 width
return width * tilesize;
}
public int getHeight() {
// 6 * 30 = 180 height
return height * tilesize;
}
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] != null) {
// if there is a non-null space, that is a tetris piece.. fill it
// red
if (grid[row][col].getColor() != null) {
g.setColor(grid[row][col].getColor());
g.fillRect(col * tilesize, row * tilesize, tilesize, tilesize);
}
}
}
}
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_DOWN) {
// checkBottomFull(0,4);
// collisionCheck(activetile.getX(),activetile.getY());
// checkEndGame(activetile.getX(), activetile.getY());
// activetile.setLocation(activetile.getX(), activetile.getY()+1);
// need to move Object newPiece down as a unit of 4 tiles
newPiece.movePieceDown();
// System.out.println("coordinates: " + activetile.getX() + ", " +
// activetile.getY());
repaint();
}
if (keyCode == KeyEvent.VK_RIGHT) {
// activetile.setLocation(activetile.getX()+1, activetile.getY());
// System.out.println("coordinates: " + activetile.getX() + ", " +
// activetile.getY());
newPiece.movePieceRight();
repaint();
}
if (keyCode == KeyEvent.VK_LEFT) {
// activetile.setLocation(activetile.getX()-1, activetile.getY());
// System.out.println("coordinates: " + activetile.getX() + ", " +
// activetile.getY());
newPiece.movePieceLeft();
repaint();
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
// check if (x, y) is a safe coordinate, ie, within the grid array bounds
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < width && y < height - 1;
}
// returns the tile at (x, y) or null if empty
public TileSscce getTileAt(int x, int y) {
if (isValidCoordinate(x, y))
return grid[y][x];
return null;
}
// sets the tile at (x, y) to tile
public void setTileAt(TileSscce tile, int x, int y) {
if (isValidCoordinate(x, y))
grid[y][x] = tile;
}
public boolean isOpen(int x, int y) {
return isValidCoordinate(x, y) && getTileAt(x, y) == null;
}
public void collisionCheck(int x, int y) {
/*
* if (activetile.getY() == this.height-2 || getTileAt(x, y+1) != null) {
* //activetile = new TileSscce(this, 0, 0); newPiece = new
* PieceSscce(this, randomPiece()); }
*/
}
public void checkBottomFull(int x, int y) {
while (getTileAt(x, y) != null) {
say("(" + x + ", " + y + ")");
if (x == 3) {
say("row is full");
// replace full row with tiles from above
for (int i = 0; i < 4; i++) {
for (int j = 5; j > 0; j--) {
grid[j][i] = getTileAt(i, j - 1);
}
}
break;
}
x++;
}
}
public void checkEndGame(int x, int y) {
if (y == 0 && !isOpen(x, y + 1)) {
say("Game over");
for (int i = 0; i < 4; i++) {
for (int j = 5; j > 0; j--) {
grid[j][i] = null;
}
}
}
}
public void say(String word) {
System.out.println(word);
}
public void sayint(int number) {
System.out.println(number);
}
}
class PieceSscce {
public int[] pieceCoordinates;
public String shape;
public BoardSscce board;
public TileSscce tile[];
public TileSscce tile1;
public TileSscce tile2;
public TileSscce tile3;
public TileSscce tile4;
// don't need to pass in board because I'm already utilizing the Tiles class,
// which knows about the board
public PieceSscce(BoardSscce b, String randomPiece) {
shape = randomPiece;
board = b;
// set what the shape coordinates should be based on what "shape" is
pieceCoordinates = new int[8];
setInitialShapeCoordinates(shape);
tile = new TileSscce[4];
tile1 = new TileSscce(board, pieceCoordinates[0], pieceCoordinates[1]);
tile2 = new TileSscce(board, pieceCoordinates[2], pieceCoordinates[3]);
tile3 = new TileSscce(board, pieceCoordinates[4], pieceCoordinates[5]);
tile4 = new TileSscce(board, pieceCoordinates[6], pieceCoordinates[7]);
}
public void movePieceDown() {
for (int i = 0; i < 4; i++) {
}
tile1.setLocation(tile1.getX(), tile1.getY() + 1);
tile2.setLocation(tile2.getX(), tile2.getY() + 1);
tile3.setLocation(tile3.getX(), tile3.getY() + 1);
tile4.setLocation(tile4.getX(), tile4.getY() + 1);
}
public void movePieceRight() {
tile1.setLocation(tile1.getX() + 1, tile1.getY());
tile2.setLocation(tile2.getX() + 1, tile2.getY());
tile3.setLocation(tile3.getX() + 1, tile3.getY());
tile4.setLocation(tile4.getX() + 1, tile4.getY());
}
public void movePieceLeft() {
tile1.setLocation(tile1.getX() - 1, tile1.getY());
tile2.setLocation(tile2.getX() - 1, tile2.getY());
tile3.setLocation(tile3.getX() - 1, tile3.getY());
tile4.setLocation(tile4.getX() - 1, tile4.getY());
}
public void setInitialShapeCoordinates(String shape) {
System.out.println(shape);
if (shape == "L") {
// piece 1
pieceCoordinates[0] = 0;
pieceCoordinates[1] = 1;
// piece2
pieceCoordinates[2] = 1;
pieceCoordinates[3] = 1;
// piece3
pieceCoordinates[4] = 2;
pieceCoordinates[5] = 1;
// piece4
pieceCoordinates[6] = 2;
pieceCoordinates[7] = 2;
} else if (shape == "O") {
// piece 1
pieceCoordinates[0] = 0;
pieceCoordinates[1] = 1;
// piece2
pieceCoordinates[2] = 1;
pieceCoordinates[3] = 1;
// piece3
pieceCoordinates[4] = 0;
pieceCoordinates[5] = 2;
// piece4
pieceCoordinates[6] = 1;
pieceCoordinates[7] = 2;
} else if (shape == "Z") {
// piece 1
pieceCoordinates[0] = 0;
pieceCoordinates[1] = 1;
// piece2
pieceCoordinates[2] = 1;
pieceCoordinates[3] = 1;
// piece3
pieceCoordinates[4] = 1;
pieceCoordinates[5] = 2;
// piece4
pieceCoordinates[6] = 2;
pieceCoordinates[7] = 2;
} else if (shape == "RevZ") {
// piece 1
pieceCoordinates[0] = 1;
pieceCoordinates[1] = 1;
// piece2
pieceCoordinates[2] = 2;
pieceCoordinates[3] = 1;
// piece3
pieceCoordinates[4] = 0;
pieceCoordinates[5] = 2;
// piece4
pieceCoordinates[6] = 1;
pieceCoordinates[7] = 2;
} else if (shape == "Bar") {
// piece 1
pieceCoordinates[0] = 0;
pieceCoordinates[1] = 1;
// piece2
pieceCoordinates[2] = 1;
pieceCoordinates[3] = 1;
// piece3
pieceCoordinates[4] = 2;
pieceCoordinates[5] = 1;
// piece4
pieceCoordinates[6] = 3;
pieceCoordinates[7] = 1;
} else if (shape == "T") {
// piece 1
pieceCoordinates[0] = 1;
pieceCoordinates[1] = 1;
// piece2
pieceCoordinates[2] = 0;
pieceCoordinates[3] = 2;
// piece3
pieceCoordinates[4] = 1;
pieceCoordinates[5] = 2;
// piece4
pieceCoordinates[6] = 2;
pieceCoordinates[7] = 2;
} else if (shape == "RevL") {
// piece 1
pieceCoordinates[0] = 0;
pieceCoordinates[1] = 2;
// piece2
pieceCoordinates[2] = 1;
pieceCoordinates[3] = 2;
// piece3
pieceCoordinates[4] = 2;
pieceCoordinates[5] = 2;
// piece4
pieceCoordinates[6] = 2;
pieceCoordinates[7] = 1;
}
}
}
class TileSscce {
private BoardSscce board;
private int currX, currY;
public TileSscce(BoardSscce b, int x, int y) {
board = b;
// when TileSscce is instantiated, set its position
setLocation(x, y);
}
public int getX() {
return currX;
}
public int getY() {
return currY;
}
public void setLocation(int newX, int newY) {
if (board.isValidCoordinate(newX, newY) && board.isOpen(newX, newY)) {
board.setTileAt(null, currX, currY);
currX = newX;
currY = newY;
board.setTileAt(this, currX, currY);
}
}
public Color getColor() {
double rand = Math.random() * (2 - 0);
/*
* Random rand = new Random(); float r = rand.nextFloat(); float g =
* rand.nextFloat(); float b = rand.nextFloat();
*/
// Color randomColor = new Color(r, g, b);
if (rand == 1) {
return Color.GRAY;
} else {
return Color.RED;
}
}
public Color setColor() {
return Color.GREEN;
}
}
正如 Daniel 指出的那样,您需要将逻辑拆分为如何检查被阻塞的部分以及如何移动。您应该首先检查一块所持有的所有瓷砖上的块,然后让块告诉所有瓷砖移动而不是您正在做的事情 - 检查每个块是否有块,如果未阻挡则移动它。
例如,给 Tile 这样的东西:
// method to check if position OK
public boolean checkNewLocation(int newX, int newY) {
boolean newLocationOK = board.isValidCoordinate(newX, newY)
&& board.isOpen(newX, newY);
return newLocationOK;
}
// method to move to new position.
public void setLocation(int newX, int newY) {
board.setTileAt(null, currX, currY);
currX = newX;
currY = newY;
board.setTileAt(this, currX, currY);
}
所以 Piece 将遍历它的 Tiles 调用第一个方法,然后如果一切正常,移动 Tiles 调用第二个方法。