我只是不知道如何循环它,以便一旦该形状停止移动,它就会在屏幕顶部添加另一个形状。
在你的计时器逻辑中你有:
component.moveRectangleBy(dx,dy);
因此,这假设您始终有一个“活动”组件。您需要能够确定组件何时位于底部,以便可以重置组件。
因此,您可以重构您的侦听器代码,使其看起来像这样:
if (component == null)
component = // a new random shape
else
{
component.moveRectangleBy(...);
if (component.isAtBottom()) // a method you will need to write
component == null;
}
无论如何,我也玩过我自己的俄罗斯方块游戏。目前:
- 添加随机碎片
- 将棋子沿着棋盘向下移动
- 使用 4 个箭头键移动/旋转俄罗斯方块
- 删除整行
基本设计分为 4 类:
- TetrisIcon - 绘制一个带边框的正方形
- TetrisPiece - 俄罗斯方块的 4x4 数组表示。值为 1 表示应绘制 TetricIcon。
- TetrisBoard - 包含要绘制的俄罗斯方块图标列表以及当前在棋盘上移动的俄罗斯方块。当俄罗斯方块到达底部时,其各个俄罗斯方块图标将被移动到棋盘上。
- 俄罗斯方块 - 构建框架并开始游戏。
如果你想玩它,那就玩得开心:
Tetris:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.awt.geom.*;
public class Tetris extends JPanel
{
private final static int TETRIS_ICON_SIZE = 20;
private List<TetrisPiece> tetrisPieces = new ArrayList<TetrisPiece>();
private TetrisBoard board;
private Random random = new Random();
public Tetris()
{
setLayout( new BorderLayout() );
createTetrisPieces();
board = new TetrisBoard(20, 10, 20);
add(board, BorderLayout.LINE_START);
/*
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 5, 5);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 5, 6);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 6, 5);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 0, 0);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 0, 19);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 9, 0);
board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 9, 19);
board.setTetrisPiece( tetrisPieces.get(1) );
*/
JButton start = new JButton( new StartAction() );
add(start, BorderLayout.PAGE_END);
}
private void createTetrisPieces()
{
int[][] shape =
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.RED, TETRIS_ICON_SIZE)) );
shape = new int[][]
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.YELLOW, TETRIS_ICON_SIZE)) );
shape = new int[][]
{
{0, 0, 1, 0},
{0, 0, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.MAGENTA, TETRIS_ICON_SIZE)) );
shape = new int[][]
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.CYAN, TETRIS_ICON_SIZE)) );
shape = new int[][]
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 1, 0},
{0, 0, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.WHITE, TETRIS_ICON_SIZE)) );
shape = new int[][]
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{1, 1, 0, 0},
{0, 0, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.BLUE, TETRIS_ICON_SIZE)) );
shape = new int[][]
{
{0, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};
tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.GREEN, TETRIS_ICON_SIZE)) );
}
class StartAction extends AbstractAction
{
public StartAction()
{
super("Start Game");
}
@Override
public void actionPerformed(ActionEvent e)
{
new Timer(1000, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e2)
{
if (board.getTetrisPiece() == null)
{
int piece = random.nextInt( tetrisPieces.size() );
board.setTetrisPiece( tetrisPieces.get( piece ) );
}
else
{
board.moveShapeDown();
}
}
}).start();
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Tetris");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Tetris());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
俄罗斯方块板:
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
class TetrisBoard extends JPanel
{
private List<TetrisIcon[]> board;
private int rows;
private int columns;
private int size;
private TetrisPiece tetrisPiece;
public TetrisBoard(int rows, int columns, int size)
{
this.rows = rows;
this.columns = columns;
this.size = size;
board = new ArrayList<TetrisIcon[]>(rows);
for (int i = 0; i < rows; i++)
board.add( new TetrisIcon[columns] );
setBackground( Color.BLACK );
addKeyBindings();
}
private void addKeyBindings()
{
InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
String leftName = "LEFT";
KeyStroke leftKeyStroke = KeyStroke.getKeyStroke( leftName );
inputMap.put(leftKeyStroke, leftName);
actionMap.put(leftName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
moveShapeLeft();
}
});
String rightName = "RIGHT";
KeyStroke rightKeyStroke = KeyStroke.getKeyStroke( rightName );
inputMap.put(rightKeyStroke, rightName);
actionMap.put(rightName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
moveShapeRight();
}
});
String downName = "DOWN";
KeyStroke downKeyStroke = KeyStroke.getKeyStroke( downName );
inputMap.put(downKeyStroke, downName);
actionMap.put(downName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
// moveShapeDown();
dropShape();
}
});
String upName = "UP";
KeyStroke upKeyStroke = KeyStroke.getKeyStroke( upName );
inputMap.put(upKeyStroke, upName);
actionMap.put(upName, new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
rotateShape();
}
});
}
public TetrisPiece getTetrisPiece()
{
return tetrisPiece;
}
public void setTetrisPiece(TetrisPiece tetrisPiece)
{
this.tetrisPiece = new TetrisPiece(tetrisPiece.getShape(), tetrisPiece.getIcon());
this.tetrisPiece.setLocation( new Point(4, 0) );
repaint();
}
public void setTetrisIconAt(TetrisIcon icon, int x, int y)
{
TetrisIcon[] row = board.get(y);
row[x] = icon;
}
public TetrisIcon getTetrisIconAt(int x, int y)
{
TetrisIcon[] row = board.get(y);
return row[x];
}
public void moveShapeLeft()
{
if (tetrisPiece == null) return;
Point possibleLocation = new Point(tetrisPiece.getX() - 1, tetrisPiece.getY());
if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
tetrisPiece.setLocation( possibleLocation );
repaint();
}
}
public void moveShapeRight()
{
if (tetrisPiece == null) return;
Point possibleLocation = new Point(tetrisPiece.getX() + 1, tetrisPiece.getY());
if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
tetrisPiece.setLocation( possibleLocation );
repaint();
}
}
public void dropShape()
{
if (tetrisPiece == null) return;
Point possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
while ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
moveShapeDown();
possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
}
// addTetrisPieceToBoard();
// tetrisPiece = null;
}
public void moveShapeDown()
{
if (tetrisPiece == null) return;
Point possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
{
tetrisPiece.setLocation( possibleLocation );
repaint();
}
else
{
tetrisPieceAtBottom();
}
}
private void tetrisPieceAtBottom()
{
Point location = tetrisPiece.getLocation();
int row = Math.min(rows, location.y + 4);
row--;
addTetrisPieceToBoard();
int rowsRemoved = 0;
for (; row >= location.y; row--)
{
// System.out.println(row);
TetrisIcon[] icons = board.get(row);
if ( fullRow(row) )
{
board.remove(row);
rowsRemoved++;
}
}
for (int i = 0; i < rowsRemoved; i++)
board.add(0, new TetrisIcon[columns]);
if (rowsRemoved > 0)
repaint();
}
private boolean fullRow(int row)
{
for (int column = 0; column < columns; column++)
{
// System.out.println(row + " : " + column);
if ( getTetrisIconAt(column, row) == null)
return false;
}
return true;
}
private void addTetrisPieceToBoard()
{
int x = tetrisPiece.getX();
int y = tetrisPiece.getY();
for (int r = 0; r < tetrisPiece.getRows(); r++)
{
for (int c = 0; c < tetrisPiece.getColumns(); c++)
{
TetrisIcon icon = tetrisPiece.getIconAt(r, c);
if (icon != null)
{
setTetrisIconAt(icon, x, y);
}
x++;
}
x = tetrisPiece.getX();
y++;
}
tetrisPiece = null;
}
public void rotateShape()
{
if (tetrisPiece == null) return;
int[][] rotatedShape = tetrisPiece.getRotatedShape();
if ( canMoveShape(tetrisPiece.getLocation(), rotatedShape) )
{
tetrisPiece.setShape( rotatedShape );
repaint();
}
}
private boolean canMoveShape(Point location, int[][] shape)
{
for (int r = 0; r < shape.length; r ++)
{
for (int c = 0; c < shape.length; c++)
{
if (shape[r][c] == 1)
{
int x = location.x + c;
int y = location.y + r;
// Past left edge
if (x < 0) return false;
// Past right edge
if (x >= columns) return false;
// Past bottom edge
if (y >= rows) return false;
// Collision with TetrisIcon
if (getTetrisIconAt(x, y) != null) return false;
}
}
}
return true;
}
@Override
public Dimension getPreferredSize()
{
int width = (columns * size) + columns - 1;
int height = (rows * size) + rows - 1;
return new Dimension(width, height);
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent( g );
int x = 0;
int y = 0;
int offset = size + 1;
for (int r = 0; r < rows; r++)
{
TetrisIcon[] row = board.get(r);
for (int c = 0; c < row.length; c++)
{
TetrisIcon icon = row[c];
if (icon != null)
{
icon.paintIcon(this, g, x, y);
}
x += offset;
}
x = 0;
y += offset;
}
// paint shape
if (tetrisPiece != null)
{
paintShape(g, offset);
}
}
private void paintShape(Graphics g, int offset)
{
int x = tetrisPiece.getX() * offset;
int y = tetrisPiece.getY() * offset;
for (int r = 0; r < tetrisPiece.getRows(); r++)
{
for (int c = 0; c < tetrisPiece.getColumns(); c++)
{
TetrisIcon icon = tetrisPiece.getIconAt(r, c);
if (icon != null)
{
icon.paintIcon(this, g, x, y);
}
x += offset;
}
x = tetrisPiece.getX() * offset;
y += offset;
}
}
}
俄罗斯方块块:
import java.awt.Point;
public class TetrisPiece
{
private int[][] shape;
private TetrisIcon icon;
private Point location = new Point();
public TetrisPiece(int[][] shape, TetrisIcon icon)
{
setShape(shape);
this.icon = icon;
}
public TetrisIcon getIcon()
{
return icon;
}
public int[][] getShape()
{
return shape;
}
public void setShape(int[][] shape)
{
this.shape = shape;
}
public TetrisIcon getIconAt(int x, int y)
{
return (shape[x][y] == 1) ? icon : null;
}
public Point getLocation()
{
return location;
}
public void setLocation(Point location)
{
this.location = location;
}
public int getX()
{
return location.x;
}
public int getY()
{
return location.y;
}
public int getRows()
{
return shape.length;
}
public int getColumns()
{
return shape[0].length;
}
public int[][] getRotatedShape()
{
int[][] rotatedShape = new int[shape.length][shape[0].length];
int x = 0;
int y = 0;
for (int c = shape.length - 1; c >= 0; c--)
{
for (int r = 0; r < shape[0].length; r++)
{
rotatedShape[x][y] = shape[r][c];
y++;
}
x++;
y = 0;
}
return rotatedShape;
}
}
俄罗斯方块图标:
import java.awt.*;
import javax.swing.*;
public class TetrisIcon implements Icon
{
private Color color;
private int size;
public TetrisIcon(Color color, int size)
{
this.color = color;
this.size = size;
}
public int getIconWidth()
{
return size;
}
public int getIconHeight()
{
return size;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
int width = getIconWidth() - 1;
int height = getIconHeight() - 1;
g.translate(x, y);
g.setColor(color);
g.fillRect(0, 0, width, height);
g.setColor(Color.LIGHT_GRAY);
g.drawLine(0, 0, width, 0);
g.drawLine(0, 0, 0, height);
g.setColor(Color.DARK_GRAY);
g.drawLine(width, 0, width, height);
g.drawLine(0, height, width, height);
g.translate(-x, -y);
}
}