Java 基础教程之拼图游戏的实现
1. 游戏介绍
拼图是一种经典的益智游戏,目的是将图片划分成若干个小块并打乱排列,然后将其重新组合成完整的图片。在这个项目中,我们将使用 Java 语言实现一个简单的拼图游戏,涉及的主要知识点包括 Java Swing 及基本的面向对象编程。
2. 实现步骤
2.1 项目初始化
首先,我们需要创建一个 Java 项目,并添加必要的依赖项,例如 Java Swing 库、Lombok 库等。此外,我们还需要准备一些图片资源作为游戏的素材。
2.2 实现游戏主界面
接下来,我们需要设计并实现游戏的主界面,包括图片显示区域、计时器、步数计数器等。这部分内容涉及 Java Swing 的布局、事件监听等基础知识。
public class PuzzleFrame extends JFrame {
private static final int ROWS = 3; // 拼图行数
private static final int COLS = 3; // 拼图列数
private static final int IMAGE_SIZE = 180; // 图片大小
private static final int GAP_SIZE = 5; // 图片间距
private final JPanel boardPanel; // 拼图面板
private final JLabel timeLabel; // 计时器标签
private final JLabel stepsLabel; // 步数计数器标签
public PuzzleFrame(){
// 初始化窗口大小和标题
setSize((IMAGE_SIZE + GAP_SIZE) * COLS, (IMAGE_SIZE + GAP_SIZE) * ROWS + 50);
setTitle("Puzzle Game");
// 创建面板并设置布局
JPanel mainPanel = new JPanel();
boardPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
boardPanel.setLayout(new GridLayout(ROWS, COLS, GAP_SIZE, GAP_SIZE));
// 添加拼图块
List<ImageIcon> icons = loadImages();
List<JButton> cells = createCells(icons);
for(JButton cell : cells){
boardPanel.add(cell);
}
// 创建控制面板并设置布局
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS));
// 添加计时器
timeLabel = new JLabel("Time: 0s");
controlPanel.add(timeLabel);
controlPanel.add(Box.createHorizontalStrut(20));
// 添加步数计数器
stepsLabel = new JLabel("Steps: 0");
controlPanel.add(stepsLabel);
controlPanel.add(Box.createHorizontalStrut(20));
// 添加“重新开始”按钮
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(e -> {
restartGame();
});
controlPanel.add(restartButton);
// 将面板添加到窗口中
mainPanel.add(boardPanel);
mainPanel.add(Box.createVerticalStrut(5));
mainPanel.add(controlPanel);
add(mainPanel);
// 设置窗口可见性和关闭方式
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* 读取图片资源
*/
private List<ImageIcon> loadImages(){
List<ImageIcon> icons = new ArrayList<>();
for(int i = 1; i <= ROWS * COLS; i++){
ImageIcon icon = new ImageIcon("img/" + i + ".jpg");
Image img = icon.getImage().getScaledInstance(IMAGE_SIZE, IMAGE_SIZE, Image.SCALE_SMOOTH);
icons.add(new ImageIcon(img));
}
return icons;
}
/**
* 创建拼图块
*/
private List<JButton> createCells(List<ImageIcon> icons){
List<JButton> cells = new ArrayList<>();
for(ImageIcon icon : icons){
JButton cell = new JButton(icon);
cell.setBorder(BorderFactory.createEmptyBorder());
cell.addActionListener(e -> {
cellClicked(cell);
});
cells.add(cell);
}
Collections.shuffle(cells);
return cells;
}
/**
* 点击拼图块触发的事件
*/
private void cellClicked(JButton cell){
// TODO: 实现拼图块移动逻辑
}
/**
* 重新开始游戏
*/
private void restartGame(){
// TODO: 实现重置拼图逻辑
}
}
以上代码实现了游戏主界面的布局及拼图块的加载,但还未实现拼图块的移动及拼图完成的判断。
2.3 实现拼图块移动逻辑
拼图块的移动涉及到交换两个块的位置,因此我们需要在代码中保存拼图块的位置信息及其对应的元素。具体实现可以使用一个二维数组来表示拼图面板,其中元素值为相应的拼图块对象。在每次点击时,判断目标位置是否为合法位置并进行移动操作。
public class PuzzleFrame extends JFrame {
// ...
private JButton[][] cells = new JButton[ROWS][COLS]; // 拼图块数组
private int emptyRow = ROWS - 1; // 空白块所在行
private int emptyCol = COLS - 1; // 空白块所在列
private int steps = 0; // 步数
private boolean gameOver = false; // 游戏是否结束
// ...
/**
* 创建拼图块
*/
private void createCells(List<ImageIcon> icons){
for(int i = 0; i < ROWS; i++){
for(int j = 0; j < COLS; j++){
JButton cell = new JButton();
cell.setBorder(BorderFactory.createEmptyBorder());
if(i == emptyRow && j == emptyCol){
// 如果当前是空白块,则不设置图标
} else {
ImageIcon icon = icons.get(i * COLS + j);
Image img = icon.getImage().getScaledInstance(IMAGE_SIZE, IMAGE_SIZE, Image.SCALE_SMOOTH);
cell.setIcon(new ImageIcon(img));
}
cell.addActionListener(e -> {
cellClicked(cell);
});
cells[i][j] = cell; // 加入二维数组
boardPanel.add(cell); // 加入面板
}
}
}
/**
* 点击拼图块触发的事件
*/
private void cellClicked(JButton cell){
if(gameOver){
return;
}
int row = -1, col = -1;
// 遍历二维数组查找所在位置
for(int i = 0; i < ROWS; i++){
for(int j = 0; j < COLS; j++){
if(cells[i][j] == cell){
row = i;
col = j;
break;
}
}
}
if(isLegalMove(row, col)){
// 保存移动前的坐标
int prevRow = emptyRow;
int prevCol = emptyCol;
// 移动拼图块
cells[emptyRow][emptyCol].setIcon(cell.getIcon());
cells[row][col].setIcon(null);
emptyRow = row;
emptyCol = col;
// 更新步数
steps++;
stepsLabel.setText("Steps: " + steps);
// 判断是否完成拼图
if(isGameComplete()){
gameOver = true;
JOptionPane.showMessageDialog(null, "Congratulations! You win in " + gameDuration() + "s and " + steps + " steps!");
}
}
}
/**
* 判断目标位置是否为合法位置
*/
private boolean isLegalMove(int row, int col){
return ((row == emptyRow && (col == emptyCol - 1 || col == emptyCol + 1)) ||
(col == emptyCol && (row == emptyRow - 1 || row == emptyRow + 1)));
}
/**
* 判断拼图是否完成
*/
private boolean isGameComplete(){
int count = 1;
for(int i = 0; i < ROWS; i++){
for(int j = 0; j < COLS; j++){
if(cells[i][j] == null || (i == emptyRow && j == emptyCol)){
continue;
} else {
ImageIcon icon = (ImageIcon) cells[i][j].getIcon();
if(Integer.parseInt(icon.getDescription()) != count){
return false;
}
count++;
}
}
}
return true;
}
}
以上代码实现了拼图块的移动及完成拼图后的提示等功能。
2.4 实现拼图复位逻辑
为了支持游戏重玩,我们需要对拼图块进行复位操作,这可以通过打乱拼图块数组的顺序来实现。此外,我们还需要重置步数计数器及计时器等变量。
public class PuzzleFrame extends JFrame {
// ...
/**
* 重置拼图
*/
private void restartGame(){
Collections.shuffle(Arrays.asList(cells).stream().flatMap(Arrays::stream).collect(Collectors.toList()));
emptyRow = ROWS - 1;
emptyCol = COLS - 1;
steps = 0;
stepsLabel.setText("Steps: 0");
gameOver = false;
}
/**
* 计算游戏时长
*/
private long gameDuration(){
// TODO: 计算游戏时长
}
}
2.5 完成游戏时长计算功能
最后,我们需要实现游戏时长计算功能。这可以通过侦听器的方式来实现,我们可以使用 Timer 类来辅助计时器的实现。
public class PuzzleFrame extends JFrame {
// ...
private Timer gameTimer = new Timer(1000, e -> {
int elapsed = Integer.parseInt(timeLabel.getText().substring(6, timeLabel.getText().length() - 1));
timeLabel.setText("Time: " + (elapsed + 1) + "s");
}); // 计时器
/**
* 开始新游戏
*/
public void startGame(){
restartGame();
gameTimer.start();
}
/**
* 计算游戏时长
*/
private long gameDuration(){
int elapsed = Integer.parseInt(timeLabel.getText().substring(6, timeLabel.getText().length() - 1));
gameTimer.stop();
return elapsed;
}
}
示例
示例 1: 开始新游戏
public static void main(String[] args){
PuzzleFrame puzzle = new PuzzleFrame();
puzzle.startGame();
}
示例 2: 拼图块移动
这里假设我们已经点击了拼图块 cells[1][2]
:
// 执行移动操作
cells[1][1].setIcon(cells[1][2].getIcon());
cells[1][2].setIcon(null);
emptyRow = 1;
emptyCol = 2;
// 更新步数
steps++;
stepsLabel.setText("Steps: " + steps);
// 判断是否完成拼图
if(isGameComplete()){
gameOver = true;
JOptionPane.showMessageDialog(null, "Congratulations! You win in " + gameDuration() + "s and " + steps + " steps!");
}
结语
上述代码实现了一个简单的拼图游戏,其依据代码框架可以进行更多功能的扩展和优化。此外,Java Swing 还有许多其他强大的功能可以用于构建更复杂的用户界面,希望读者可以进一步探索。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java基础教程之拼图游戏的实现 - Python技术站