parent
4dce6b1fe0
commit
4ef4783035
@ -0,0 +1,284 @@
|
||||
package tetris;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
public class GamePanel extends JPanel {
|
||||
private static final int BLOCK_SIZE = 30;
|
||||
private static final int ROWS = 20, COLS = 10;
|
||||
private final int[][] board = new int[ROWS][COLS];
|
||||
private Block currentBlock, nextBlock;
|
||||
private Timer timer;
|
||||
private int fallSpeed = 500, score = 0;
|
||||
private final NextBlockPanel nextBlockPanel;
|
||||
private final ResourceManager resManager = ResourceManager.getInstance();
|
||||
|
||||
public GamePanel(NextBlockPanel nextBlockPanel) {
|
||||
this.nextBlockPanel = nextBlockPanel;
|
||||
setPreferredSize(new Dimension(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE));
|
||||
setBackground(Color.BLACK);
|
||||
initControls();
|
||||
initTimer();
|
||||
newGame();
|
||||
|
||||
addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initControls() {
|
||||
addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
switch (e.getKeyCode()) {
|
||||
case KeyEvent.VK_SPACE:
|
||||
togglePause();
|
||||
break;
|
||||
case KeyEvent.VK_LEFT:
|
||||
if (!isPaused && !isGameOver) handleMove(-1, 0);
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:
|
||||
if (!isPaused && !isGameOver) handleMove(1, 0);
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:
|
||||
if (!isPaused && !isGameOver) hardDrop();
|
||||
break;
|
||||
case KeyEvent.VK_UP:
|
||||
if (!isPaused && !isGameOver) rotateBlock();
|
||||
break;
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleMove(int dx, int dy) {
|
||||
if (canMove(dx, dy)) {
|
||||
if (dx == -1) currentBlock.moveLeft();
|
||||
else if (dx == 1) currentBlock.moveRight();
|
||||
}
|
||||
}
|
||||
|
||||
public void togglePause() {
|
||||
isPaused = !isPaused;
|
||||
if (timer != null) {
|
||||
if (isPaused) {
|
||||
timer.stop();
|
||||
} else {
|
||||
timer.setDelay(fallSpeed);
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
requestFocusInWindow();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private boolean canMove(int dx, int dy) {
|
||||
int[][] shape = currentBlock.getShape();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
for (int j = 0; j < shape[i].length; j++) {
|
||||
if (shape[i][j] == 1) {
|
||||
int newX = currentBlock.getX() + j + dx;
|
||||
int newY = currentBlock.getY() + i + dy;
|
||||
if (newX < 0 || newX >= COLS || newY >= ROWS || (newY >= 0 && board[newY][newX] != 0))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void rotateBlock() {
|
||||
Block temp = new Block(currentBlock.getType());
|
||||
temp.moveTo(currentBlock.getX(), currentBlock.getY());
|
||||
temp.rotate();
|
||||
if (canRotate(temp)) currentBlock.rotate();
|
||||
}
|
||||
|
||||
private boolean canRotate(Block block) {
|
||||
int[][] shape = block.getShape();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
for (int j = 0; j < shape[i].length; j++) {
|
||||
if (shape[i][j] == 1) {
|
||||
int x = block.getX() + j;
|
||||
int y = block.getY() + i;
|
||||
if (x < 0 || x >= COLS || y >= ROWS || (y >= 0 && board[y][x] != 0))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void hardDrop() {
|
||||
while (canMove(0, 1)) currentBlock.moveDown();
|
||||
mergeBlock();
|
||||
clearLines();
|
||||
spawnNewBlock();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void mergeBlock() {
|
||||
int[][] shape = currentBlock.getShape();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
for (int j = 0; j < shape[i].length; j++) {
|
||||
if (shape[i][j] == 1) {
|
||||
int y = currentBlock.getY() + i;
|
||||
int x = currentBlock.getX() + j;
|
||||
if (y < 0) gameOver();
|
||||
else board[y][x] = currentBlock.getType() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int[] SCORE_TABLE = {100, 300, 500, 800};
|
||||
|
||||
private void clearLines() {
|
||||
int linesCleared = 0;
|
||||
for (int i = ROWS - 1; i >= 0; i--) {
|
||||
if (isLineFull(i)) {
|
||||
if (i > 0) {
|
||||
System.arraycopy(board, 0, board, 1, i);
|
||||
}
|
||||
Arrays.fill(board[0], 0);
|
||||
linesCleared++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (linesCleared > 0) {
|
||||
resManager.playClearSound(); // 添加消除音效
|
||||
score += (linesCleared < 4) ? SCORE_TABLE[linesCleared - 1] : SCORE_TABLE[3];
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
nextBlockPanel.updateScore();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLineFull(int row) {
|
||||
for (int cell : board[row])
|
||||
if (cell == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void spawnNewBlock() {
|
||||
currentBlock = (nextBlock != null) ? nextBlock : new Block(new Random().nextInt(7));
|
||||
nextBlock = new Block(new Random().nextInt(7));
|
||||
nextBlockPanel.setNextBlock(nextBlock);
|
||||
if (!canSpawn()) gameOver();
|
||||
}
|
||||
|
||||
private boolean canSpawn() {
|
||||
if (currentBlock.getY() < 0) return false;
|
||||
|
||||
int[][] shape = currentBlock.getShape();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
for (int j = 0; j < shape[i].length; j++) {
|
||||
if (shape[i][j] == 1) {
|
||||
int y = currentBlock.getY() + i;
|
||||
int x = currentBlock.getX() + j;
|
||||
if (x < 0 || x >= COLS || y >= ROWS || y < 0 || board[y][x] != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void newGame() {
|
||||
for (int[] row : board) Arrays.fill(row, 0);
|
||||
score = 0;
|
||||
spawnNewBlock();
|
||||
isGameOver = isPaused = false;
|
||||
if (timer != null) {
|
||||
timer.start();
|
||||
}
|
||||
requestFocusInWindow();
|
||||
}
|
||||
|
||||
private void initTimer() {
|
||||
timer = new Timer(fallSpeed, e -> {
|
||||
if (!isPaused && !isGameOver) {
|
||||
if (canMove(0, 1)) {
|
||||
currentBlock.moveDown();
|
||||
} else {
|
||||
mergeBlock();
|
||||
clearLines();
|
||||
spawnNewBlock();
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setFallSpeed(int speed) {
|
||||
fallSpeed = speed;
|
||||
if (timer != null) {
|
||||
timer.setDelay(speed);
|
||||
if (!isPaused) {
|
||||
timer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
private void gameOver() {
|
||||
isGameOver = true;
|
||||
timer.stop();
|
||||
JOptionPane.showMessageDialog(this, "得分: " + score);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
// 绘制游戏背景图
|
||||
Image gameBg = resManager.getGameBackground();
|
||||
if (gameBg != null) {
|
||||
g.drawImage(gameBg, 0, 0, getWidth(), getHeight(), this);
|
||||
}
|
||||
|
||||
// 绘制固定方块
|
||||
for (int i = 0; i < ROWS; i++) {
|
||||
for (int j = 0; j < COLS; j++) {
|
||||
if (board[i][j] != 0) {
|
||||
int type = board[i][j] - 1;
|
||||
Image blockImage = resManager.getBlockImage(type);
|
||||
if (blockImage != null) {
|
||||
g.drawImage(blockImage, j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制当前方块
|
||||
if (currentBlock != null) {
|
||||
int[][] shape = currentBlock.getShape();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
for (int j = 0; j < shape[i].length; j++) {
|
||||
if (shape[i][j] == 1) {
|
||||
int x = (currentBlock.getX() + j) * BLOCK_SIZE;
|
||||
int y = (currentBlock.getY() + i) * BLOCK_SIZE;
|
||||
if (y < getHeight()) {
|
||||
int type = currentBlock.getType();
|
||||
Image blockImage = resManager.getBlockImage(type);
|
||||
if (blockImage != null) {
|
||||
g.drawImage(blockImage, x, y, BLOCK_SIZE, BLOCK_SIZE, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPaused = false, isGameOver = false;
|
||||
}
|
Loading…
Reference in new issue