2

我正在将俄罗斯方块作为 Java 中的一个有趣的副项目。

我正试图移动一个完整的俄罗斯方块片,这是一个由 4 个 Tile 对象组成的对象。

当我将棋子向下移动时,所有未被其他瓷砖之一阻挡的块
都会毫无问题地向下移动。由于以下两项检查,棋子的任何部分被其中一个瓷砖阻挡(例如,那是带有蓝色 x 的瓷砖)都不会移动:

在此处输入图像描述

public boolean isValidCoordinate(int x, int y) {
    return x >= 0 && y >= 0 && x < width && y < height-1; 
}

public boolean isOpen(int x, int y) {
        return isValidCoordinate(x, y) && getTileAt(x, y) == null;
}

从 Board 类中,我这样移动 Piece 对象:

if(keyCode == KeyEvent.VK_DOWN) {

newPiece.movePieceDown();

然后在 Piece 类中:

    public void movePieceDown() {
    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);        
}

有没有办法让俄罗斯方块的所有瓷砖都一起移动?

谢谢!


编辑:

EXE文件:

https://www.dropbox.com/s/mg9dtf2sr0sazwq/my_tetris_test2.jar

来源:

https://www.dropbox.com/s/9kt3sl6qqo54amk/Tetris%20Two.rar


代码编辑:

反向 Z 形测试:

在此处输入图像描述

起始坐标:Piece "RevZ" Coordinates: (1, 1) (2, 1) (0, 2) (1, 2)

按下键给我:

在此处输入图像描述

Board.java 类:将关键事件更改为:

public void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();
        newPiece.movePieceCheck(keyCode);
        if (newPiece.movePieceValid()) {
            newPiece.move();
        }
        repaint();  
}

Piece.java 类:我现在在移动之前检查...

public void calcNewPosition(int newX, int newY, int currTile) {     
    newPositionX[currTile] = newX;
    newPositionY[currTile] = newY;
    System.out.println("New Position: " + newPositionX[currTile] + ", " + newPositionY[currTile]);  
}

public void clearCurrPosition(int currX, int currY, int currTile) { 
        currPositionX[currTile] = currX;
        currPositionY[currTile] = currY;    
        System.out.println("Current Position: " + currPositionX[currTile] + ", " + currPositionY[currTile]);
        board.setTileAt(null, currPositionX[currTile], currPositionY[currTile]);
        if (board.getTileAt(currPositionX[currTile], currPositionY[currTile]) == null) {
            System.out.println("curr block set to null...");
    }       
}       

public void movePieceCheck(int keycode) {
    if (keycode == KeyEvent.VK_DOWN) {
        for (int i = 0; i < tile.length; i++) {
            calcNewPosition(tile[i].getX(), tile[i].getY()+1, i);
            clearCurrPosition(tile[i].getX(), tile[i].getY(), i);
        }       
    }
    if (keycode == KeyEvent.VK_RIGHT) {
        for (int i = 0; i < tile.length; i++) {
            calcNewPosition(tile[i].getX()+1, tile[i].getY(), i);
            clearCurrPosition(tile[i].getX(), tile[i].getY(), i);
        }       
    }
    if (keycode == KeyEvent.VK_LEFT) {
        for (int i = 0; i < tile.length; i++) {
            calcNewPosition(tile[i].getX()-1, tile[i].getY(), i);
            clearCurrPosition(tile[i].getX(), tile[i].getY(), i);
        }       
    }
}

public boolean movePieceValid() {   
    boolean valid = false;
    for (int i = 0; i < tile.length; i++) {
        if(tile[i].checkNewLocation(newPositionX[i], newPositionY[i])) {
            valid = true;
        }
    }       
    return valid;
}       

public void move()   {
    for (int i = 0; i < tile.length; i++) {
        tile[i].setLocation(newPositionX[i], newPositionY[i]);              
    }       
}

打印输出:

Piece "RevZ" Coordinates: (1, 1) (2, 1) (0, 2) (1, 2) 

New Position: 1, 2
Current Position: 1, 1
curr block set to null...
New Position: 2, 2
Current Position: 2, 1
curr block set to null...
New Position: 0, 3
Current Position: 0, 2
curr block set to null...
New Position: 1, 3
Current Position: 1, 2
curr block set to null...

我按照你说的先检查所有内容,然后设置位置。

现在的问题是,除了在检查发生时无法移动的块之外,它都在移动,因为原始块在那里。但这很奇怪,因为我在移动碎片之前将那个旧位置设置为空,所以它应该是空的。

4

2 回答 2

3

好吧,这并不奇怪,因为您如您所说检查位置是否valid是,据我了解,没有其他部分存在。

你的问题是这样的:

tile3.setLocation(tile3.getX(), tile3.getY()+1);
tile4.setLocation(tile4.getX(), tile4.getY()+1);  

我敢打赌,卡住的是第 3 部分。所以要解决这个问题,只需改变这两个的顺序。但是现在问题来了,当你旋转这块时会发生什么,然后它们应该按什么顺序移动?

我认为最好先计算每个正方形的新位置,然后将它们从当前位置中删除。然后将它们全部吸引到新位置:

calculateNewPositions();
clearCurrentPositions();
drawSquares();

这应该可以在没有太多麻烦的情况下变得非常通用,因此它可以处理不同的情况(即当您旋转对象时)而不会有太多麻烦。

于 2013-03-08T02:08:16.280 回答
2

我认为您的问题是每个 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 调用第二个方法。

于 2013-03-08T02:20:02.823 回答