1

我正在制作一个类似于俄罗斯方块的游戏,它使用正方形和椭圆。我想制作一种方法,当在它们旁边放置一个相同颜色的圆圈时,将删除相似颜色的块。我希望它也删除连接到这些块的所有类似颜色的块。当代理棋子碰到棋盘底部或 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 的子类并继承其方法。

4

1 回答 1

1

您需要编写一个 Floodfill 算法来完成此操作。泛光填充用于在 MSPaint 或 Photoshop 等图像编辑程序中填充相同颜色的连接像素。

这是它的工作原理(已编辑):

  1. 将起点压入堆栈
  2. 当堆栈不为空时,获取下一个点。
  3. 如果该点的项目是有效颜色,它将在您的网格中设置为空。
  4. 如果该点的项目是有效颜色,则将所有主要邻居推入堆栈。

我将尽可能使用您上面的代码发布一些算法的示例代码。

public void removeLikeColorsFrom(ColorShape[][] _tiles, int x, int y){
    Color colorToReturn = _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(colorToReturn)){
            _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));
        }
    }
}

此代码通过从起始位置递归扩展来工作。与所需颜色共享颜色并连接在不需要对角线的路径上的 ColorShapes 将按照您在评论中的要求设置为 null。

于 2013-07-06T02:42:39.883 回答