我正在制作一个类似于俄罗斯方块的游戏,它使用正方形和椭圆。我想制作一种方法,当在它们旁边放置一个相同颜色的圆圈时,将删除相似颜色的块。我希望它也删除连接到这些块的所有类似颜色的块。当代理棋子碰到棋盘底部或 2D 数组中的其他形状时,代理棋子会被添加到颜色形状的 2D 数组中。
编辑:我更新了添加威廉的洪水填充算法的代码。但是我从他的行中得到一个空指针:
if(_tiles[next.x][next.y].getColor().equals(colorToRemove))
这是我的主要 JPanel,其中 2D 数组是:
import javax.swing.JPanel;
import javax.swing.JLabel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;
public class GamePanel extends JPanel implements ActionListener
{
public static final int COL_COUNT = 8;
private static final int VISIBLE_ROW_COUNT = 16;
public static final int ROW_COUNT = VISIBLE_ROW_COUNT;
public static final int TILE_SIZE = 30;
private boolean _pauseState;
private JLabel _pauseText;
private int _randomNum;
private javax.swing.Timer _timer; // = new javax.swing.Timer(500, this); //board timer
//2D array of ColorShapes to record Color Shape placements
private ColorShape[][] _tiles;
private ProxyPiece _proxyPiece;
private Piece _newPiece;
//Key Interactors for the up,left,and down arrow keys
private LeftListener _leftListener;
private RightListener _rightListener;
private DownListener _downListener;
private PauseListener _pauseListener;
public GamePanel()
{
this.setBackground(Color.BLACK);
_pauseState = false;
_timer = new javax.swing.Timer(500, this);
_pauseText = new JLabel("PAUSED");
_pauseText.setLocation(30,100);
add(_pauseText);
_leftListener = new LeftListener(this);
_rightListener = new RightListener(this);
_downListener = new DownListener(this);
_pauseListener = new PauseListener(this);
_tiles = new ColorShape[8][17];
_proxyPiece = new ProxyPiece();
_proxyPiece.setPiece(this.newPiece());
for (int i = 0; i<16; i++){
for(int j=0; j<8;j++){
_tiles[j][i] = null;
}
}
//create a hidden bottom row of black rectangles to act as a boundary for the pieces in the array
for (int j=0; j<8;j++){
_tiles[j][16] = new ColorRectangle(Color.BLACK);
}
_timer.start();
}
public void dropDown(){
if(_tiles[_proxyPiece.getXLocation()/30][_proxyPiece.getYLocation()/30 + 1] == null){
_proxyPiece.moveDown();
}
else if ((_tiles[_proxyPiece.getXLocation()/30][_proxyPiece.getYLocation()/30 + 1] != null) && (_tiles[3][0] == null)){
//record the piece into array
int _currentCol = _proxyPiece.getXLocation()/30;
int _currentRow = _proxyPiece.getYLocation()/30;
_tiles[_currentCol][_currentRow - 1] = _proxyPiece.getFirstPiece();
_tiles[_currentCol][_currentRow] = _proxyPiece.getSecondPiece();
repaint();
purge();
//checks for a GameOver
if(_tiles[3][0] != null){
_timer.stop();
System.out.println("Game Over");
}
_proxyPiece.setPiece(this.newPiece());
repaint();
}
}
// i = row , j = col
public void purge(){
for (int i = 0; i<16; i++){
for(int j=0; j<8;j++){
if(_tiles[j][i] != null){
if(_tiles[j][i].getShapeType() == 2){ //checks if object is a circle
//insert a recursive function that looks up,down,left,right for similar colors and sets spot to null
removeLikeColorsFrom(_tiles,j,i);
}
else continue;
}
else continue;
}
}
repaint();
}
//flood fill algorithm
// x=col , y=row
public void removeLikeColorsFrom(ColorShape[][] _tiles, int x, int y){
Color colorToRemove = _tiles[x][y].getColor();
Stack<Point> stack = new Stack<Point>();
stack.add(new Point(x,y));
while(!stack.empty()){
Point next = stack.pop();
//check if this shape is the proper color
if(_tiles[next.x][next.y].getColor().equals(colorToRemove)){
_tiles[next.x][next.y] = null;
x = next.x;
y = next.y;
//now push all neighbors onto stack for processing
if(x-1>-1 && _tiles[x-1][y] != null)
stack.push(new Point(x-1,y));
if(x+1<_tiles.length)
stack.push(new Point(x+1,y));
if(y+1<_tiles[0].length)
stack.push(new Point(x,y+1));
if(y-1>-1)
stack.push(new Point(x,y-1));
}
}
}
public void actionPerformed(java.awt.event.ActionEvent e){
if(_proxyPiece.getPiece() == null){
_proxyPiece.setPiece(this.newPiece());
}
else {
dropDown();
repaint();
}
}
//factory method that produces a random shape
public Piece newPiece(){
_randomNum = randomNumber(1,3);
switch (_randomNum){
case 1:
return new Piece(new ColorEllipse(randomColor()), new ColorEllipse(randomColor())); //a new 2 Ellipse Piece w/ random colors
case 2:
return new Piece(new ColorRectangle(randomColor()), new ColorRectangle(randomColor()));
case 3:
return new Piece(new ColorEllipse(randomColor()), new ColorRectangle(randomColor()));
default:
System.out.println("randomNumber failed");
}
//default return value to test if switch case failed
return new Piece(new ColorRectangle(Color.RED), new ColorRectangle(Color.RED));
}
public Color randomColor(){
_randomNum = randomNumber(1,4);
switch(_randomNum){
case 1:
return Color.GREEN;
case 2:
return Color.BLUE;
case 3:
return Color.RED;
case 4:
return Color.YELLOW;
}
//default return value to test if switch case failed
return Color.RED;
}
public static int randomNumber(int low, int high){
return low + (int)(Math.random()*(high-low+1));
}
public void paintComponent(Graphics g) {
if (_pauseState == false){
_pauseText.setVisible(false);
super.paintComponent(g);
// simplify the positioning of things.
g.translate(0, 0);
//Draws the board outline and fills it white
g.setColor(Color.WHITE);
g.drawRect(0, 0, 240, 480);
g.fillRect(0, 0, 240, 480);
//Draws a dark gray grid
g.setColor(Color.DARK_GRAY);
for(int x = 0; x < COL_COUNT + 1; x++) {
for(int y = 0; y < VISIBLE_ROW_COUNT+1; y++) {
g.drawLine(0, y * TILE_SIZE, COL_COUNT * TILE_SIZE, y * TILE_SIZE);
g.drawLine(x * TILE_SIZE, 0, x * TILE_SIZE, VISIBLE_ROW_COUNT * TILE_SIZE);
}
}
Graphics2D aBetterPen = (Graphics2D)g;
_proxyPiece.fill(aBetterPen);
for (int i = 0; i<16; i++){
for(int j=0; j<8;j++){
if(_tiles[j][i] != null)
_tiles[j][i].fill(aBetterPen);
}
}
}
else if (_pauseState == true){
_pauseText.setVisible(true);
super.paintComponent(g);
// simplify the positioning of things.
g.translate(0, 0);
g.setColor(Color.WHITE);
g.drawRect(0, 0, 240, 480);
g.fillRect(0, 0, 240, 480);
}
}
private class LeftListener extends KeyInteractor{
public LeftListener (JPanel aPanel){
super(aPanel, KeyEvent.VK_LEFT);
}
public void actionPerformed(ActionEvent e){
if( (_proxyPiece.getXLocation()>0) && (_tiles[_proxyPiece.getXLocation()/30 - 1][_proxyPiece.getYLocation()/30] == null) ){
_proxyPiece.moveLeft();
repaint();
}
}
}
private class RightListener extends KeyInteractor{
public RightListener (JPanel aPanel){
super(aPanel, KeyEvent.VK_RIGHT);
}
public void actionPerformed(ActionEvent e){
if( ((_proxyPiece.getXLocation()<210)) && (_tiles[_proxyPiece.getXLocation()/30 + 1][_proxyPiece.getYLocation()/30] == null) ){
_proxyPiece.moveRight();
repaint();
}
}
}
private class DownListener extends KeyInteractor{
public DownListener (JPanel aPanel){
super(aPanel, KeyEvent.VK_DOWN);
}
public void actionPerformed(ActionEvent e){
//Loop that will keep dropping the piece until it hits another piece or the bottom of the board
while(_tiles[_proxyPiece.getXLocation()/30][_proxyPiece.getYLocation()/30 + 1] == null){
dropDown();
}
}
}
private class PauseListener extends KeyInteractor{
public PauseListener (JPanel aPanel){
super(aPanel, KeyEvent.VK_P);
}
public void actionPerformed(ActionEvent e){
if (_pauseState == false){
_timer.stop();
_pauseState = true;
repaint();
}
else if (_pauseState == true){
_timer.start();
_pauseState = false;
repaint();
}
}
}
}
这是我的 ProxyPiece 类:
import java.awt.*;
public class ProxyPiece
{
private Piece _currentPiece; // peer object
public ProxyPiece()
{
super();
_currentPiece = null;
}
public Piece getPiece(){
return _currentPiece;
}
public ColorShape getFirstPiece(){
return _currentPiece.getFirstShape();
}
public ColorShape getSecondPiece(){
return _currentPiece.getSecondShape();
}
public void setPiece(Piece aPiece){
_currentPiece = aPiece;
}
public void moveLeft(){
_currentPiece.moveLeft();
}
public void moveRight(){
_currentPiece.moveRight();
}
public void moveDown(){
_currentPiece.moveDown();
}
public int getXLocation(){
return _currentPiece.getXLocation();
}
public int getYLocation(){
return _currentPiece.getYLocation();
}
public void rotate(){}
public void fill(Graphics2D aBetterPen){
_currentPiece.fill(aBetterPen);
}
}
这是我的作品课:
import java.awt.*;
public class Piece
{
private final int X_START = 90;
private final int Y_START = 0;
private ColorShape _colorShape;
private ColorEllipse _colorEllipse1, _colorEllipse2;
private ColorRectangle _colorRectangle1, _colorRectangle2;
private int _type;
public Piece(ColorEllipse firstEllipse, ColorEllipse secondEllipse)
{
_colorEllipse1 = firstEllipse;
_colorEllipse2 = secondEllipse;
_type = 1; //a Piece that has 2 Ellipses
this.setLocation(X_START,Y_START);
}
public Piece(ColorRectangle firstRectangle, ColorRectangle secondRectangle)
{
_colorRectangle1 = firstRectangle;
_colorRectangle2 = secondRectangle;
_type = 2; //a Piece that has 2 squares
this.setLocation(X_START,Y_START);
}
public Piece(ColorEllipse firstEllipse, ColorRectangle secondRectangle)
{
_colorEllipse1 = firstEllipse;
_colorRectangle1 = secondRectangle;
_type = 3; //a Piece that has 1 ellipse and 1 square
this.setLocation(X_START,Y_START);
}
public void setLocation(int x, int y){
if (_type == 1){
_colorEllipse1.setLocation(x,y);
_colorEllipse2.setLocation(x,y+30);
}
else if (_type == 2){
_colorRectangle1.setLocation(x,y);
_colorRectangle2.setLocation(x,y+30);
}
else if (_type == 3){
_colorEllipse1.setLocation(x,y);
_colorRectangle1.setLocation(x,y+30);
}
}
//public void rotate(){
// newX = centerOfRotationX - centerOfRotationY + oldYLocation;
// newY = centerOfRotationY - centerOfRotationX - oldXLocation;
//
// this.setLocation(newX, newY);
//}
public void moveLeft(){
if (_type == 1){
if((int)_colorEllipse1.getX() > 0){
this.setLocation((int)_colorEllipse1.getX()-30, (int)_colorEllipse1.getY());
}
}
else if (_type == 2){
if((int)_colorRectangle1.getX() > 0){
this.setLocation((int)_colorRectangle1.getX()-30, (int)_colorRectangle1.getY());
}
}
else if (_type == 3){
if((int)_colorEllipse1.getX() > 0){
this.setLocation((int)_colorEllipse1.getX()-30, (int)_colorEllipse1.getY());
}
}
}
public void moveRight(){
if (_type == 1){
if((int)_colorEllipse1.getX() < 210){
this.setLocation((int)_colorEllipse1.getX()+30, (int)_colorEllipse1.getY());
}
}
else if (_type == 2){
if((int)_colorRectangle1.getX() < 210){
this.setLocation((int)_colorRectangle1.getX()+30, (int)_colorRectangle1.getY());
}
}
else if (_type == 3){
if((int)_colorEllipse1.getX() < 210){
this.setLocation((int)_colorEllipse1.getX()+30, (int)_colorEllipse1.getY());
}
}
}
public void moveDown(){
if (_type == 1){
this.setLocation((int)_colorEllipse1.getX(), (int)_colorEllipse1.getY()+30);
}
else if (_type == 2){
this.setLocation((int)_colorRectangle1.getX(), (int)_colorRectangle1.getY()+30);
}
else if (_type == 3){
this.setLocation((int)_colorEllipse1.getX(), (int)_colorEllipse1.getY()+30);
}
}
public int getXLocation(){
if (_type == 1){
return (int)_colorEllipse1.getX();
}
else if (_type == 2){
return (int)_colorRectangle1.getX();
}
else if (_type == 3){
return (int)_colorEllipse1.getX();
}
return 1;
}
public int getYLocation(){
if (_type == 1){
return (int)_colorEllipse1.getY()+30;
}
else if (_type == 2){
return (int)_colorRectangle1.getY()+30;
}
else if (_type == 3){
return (int)_colorEllipse1.getY()+30;
}
return 1;
}
public void fill(Graphics2D aBetterPen){
if (_type == 1){
_colorEllipse1.fill(aBetterPen);
_colorEllipse2.fill(aBetterPen);
}
else if (_type == 2){
_colorRectangle1.fill(aBetterPen);
_colorRectangle2.fill(aBetterPen);
}
else if (_type == 3){
_colorEllipse1.fill(aBetterPen);
_colorRectangle1.fill(aBetterPen);
}
}
public ColorShape getFirstShape(){
if (_type == 1){
return _colorEllipse1;
}
else if (_type == 2){
return _colorRectangle1;
}
else if (_type == 3){
return _colorEllipse1;
}
return null;
}
public ColorShape getSecondShape(){
if (_type == 1){
return _colorEllipse2;
}
else if (_type == 2){
return _colorRectangle2;
}
else if (_type == 3){
return _colorRectangle1;
}
return null;
}
}
我的 ColorEllipse 是 Ellipse 2D Double 而 ColorRectangle 是 Rectangle 2D double。它们都是 ColorShape 的子类并继承其方法。