自学Java篇之JFrame创建《石头迷阵小游戏》
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
自学Java篇之JFrame创建《石头迷阵小游戏》
根据黑马程序员java教程自学完java基础觉得石头迷阵小游戏案例具有一定的编程练习价值记录之。
最终效果
案例主要思想流程
主要是思想是创建一个4*4的二维数组data初始化时打乱数组元素存放石头编号再根据编号0,1,2…进行imagelabel读取石头图片组合展示到画板中。
监听键盘上下左右间根据键盘监听的数值进行if判断将0编号的石头即黑方块根据上下左右对应的进行交换即是对二维数组里的元素进行交换交换一次就进行对二维数组展现一次即刷新面板重新展现一次石头可以想成图片一帧帧切换。
根据移动到最后数组的元素等于胜利时的数组元素时面板展示胜利图片添加上步数统计即监听键盘按了几次以及重新开始按钮即是对程序的重新运行打乱数组重新展示。
1、创建窗口完整框架
首先创建两个类分别为MainFrame类和test类前者用于游戏类的编写后者用于运行游戏类代码。
MainFrame类
package StonePuzzie;
import javax.swing.*;
import java.util.Random;
public class MainFrame extends JFrame {
int[][] data = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
// MainFrame类创建自己构造方法
public MainFrame(){
// 1、数据初始化
initData();
// 2、初始化窗体
initFrame();
// 3、绘制窗体
painView();
// 设置窗口可见
setVisible(true);
}
/**
* chushi初始化数据随机打乱二维数据
*/
public void initData(){
/*
创建rondom对象进行随机生产xy用于确定data数组的下标替换值
达到打乱数组顺序效果
*/
Random r = new Random();
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
int randomX = r.nextInt(4);
int randomY = r.nextInt(4);
int temp = data[i][j]; data[i][j] = data[randomX][randomY]; data[randomX][randomY] = temp;
}
}
}
/**
* 用于初始化窗体
*/
public void initFrame(){
setSize(514,595);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("石头迷阵v1.0");
setAlwaysOnTop(true);
setLocationRelativeTo(null);
setLayout(null);
}
/**
* 用于绘制游戏界面
*/
public void painView(){
for (int i=0;i<4;i++){
for (int j=0;j<4;j++){
System.out.println(data[i][j]);
JLabel imageLabel = new JLabel(new ImageIcon("D:\\image\\"+data[i][j]+".png"));
imageLabel.setBounds(50+100*j,90+100*i,100,100);
getContentPane().add(imageLabel);
}
}
JLabel background = new JLabel(new ImageIcon("D:\\image\\background.png"));
background.setBounds(26,30,450,484);
getContentPane().add(background);
super.getContentPane().repaint();
}
}
test类
package StonePuzzie;
public class test {
public static void main(String[] args) {
// 调用执行构造方法
// 相当于 MainFrame mainFrame =new MainFrame();
new MainFrame();
}
}
这样就完成第一步初始化窗口展示
2、添加移动石头业务模块
使用键盘上下左右键进行对石头的移动就需要使用接口KeyListener对键盘进行监听所有MainFrame类需要实现接口即implements KeyListener。再重写接口中的keyPressed监听键盘按下的事件。方法中添加move方法的代码用于移动石块。
前提是需要在数据初始化时找到黑方块。”0“编号的数组下标。再进行对0编号进行move操作
寻找0编号数组下标
int row; // 0号元素行坐标位置
int column; // 0号元素列坐标位置
// 用于确定0格子的位置
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] == 0) {
row = i;
column = j;
}
}
编写move方法代码
private void move(int keyCode) {
//左移动
if (keyCode == 37) {
if (column == 3) {
return;
}
// 空白块和右侧数据交换
// data[row][column] data[row][column+1]
int temp = data[row][column];
data[row][column] = data[row][column + 1];
data[row][column + 1] = temp;
column++;
// 上移动
} else if (keyCode == 38) {
if (row == 3) {
return;
}
// 空白块和下面的数据交换
// data[row][column] data[row+1][column]
int temp = data[row][column];
data[row][column] = data[row + 1][column];
data[row + 1][column] = temp;
row++;
// 右移动
} else if (keyCode == 39) {
if (column == 0) {
return;
}
// 空白块和左侧的数据交换
// data[row][column] data[row][column-1]
int temp = data[row][column];
data[row][column] = data[row][column - 1];
data[row][column - 1] = temp;
column--;
// 下移动
} else if (keyCode == 40) {
if (row == 0) {
return;
}
// 空白块和上面的数据交换
// data[row][column] data[row-1][column]
int temp = data[row][column];
data[row][column] = data[row - 1][column];
data[row - 1][column] = temp;
row--;
}
重写监听键盘接口实现方法
@Override
public void keyPressed(KeyEvent e) {
// 获得键盘按下的键的键值。
int keyCode = e.getKeyCode();
System.out.println("键值为");
System.out.println(keyCode);
// 传入move方法
move(keyCode);
// 执行一次移动后需要进行重新绘制游戏界面
painView();
}
3、添加判断胜利模块
该模块的添加应该在展示用于绘制界面的方法painView()中每次移动后需要重新绘制界面时需要进行一个判断看现在的数组是否等于胜利的数组win输出胜利的图片
判断是否胜利返回布尔值true or false
int[][] win = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
/**
* 判断游戏是否胜利
*/
public boolean victory() {
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] != win[i][j]) {
return false;
}
}
}
return true;
}
中插入判断代码
if(victory()){
// 加载胜利图片资源, 添加到窗体中
JLabel winLabel = new JLabel(new ImageIcon("D:\\image\\win.png"));
winLabel.setBounds(124,230,266, 88);
getContentPane().add(winLabel);
}
4、添加记录步数和“重新游戏”模块
该模块的记录步数需要一开始定一个全局变量count并且点击重新游戏的时候count赋值为0在move代码中每进行一次移动count++最后在窗体展示的代码painView()中创建一个窗体展示记录步数展示再创建一个按钮点击按钮后事件进行对游戏重新开始重新初始化数组count归为0。
记录步数
int count
JLabel scoreLabel = new JLabel("步数为:" + count);
scoreLabel.setBounds(50,20,100,20);
getContentPane().add(scoreLabel);
重新开始按钮
JButton btn = new JButton("重新游戏");
btn.setBounds(350,20,100,20);
getContentPane().add(btn);
// 取消按钮焦点。
btn.setFocusable(false);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
count =0;
initData();
painView();
}
});
5、添加作弊器一键“胜利“
添加作弊器主要是在键盘按键监听事件中添加一个if判断如果自己设定的按键比如z键值为90然后在move代码中写入对数据data重新赋值为胜利时的win数组一样的数据
else if (keyCode == 90) {
// 触发作弊器
data = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
}
6、整体代码
MainFrame类
package com.itheima.stonepuzzle;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class MainFrame extends JFrame implements KeyListener {
int[][] data = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
int[][] win = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
int row; // 0号元素行坐标位置
int column; // 0号元素列坐标位置
int count; // 统计步数
//构造方法
public MainFrame() {
// 窗体对象.addKeyListener(KeyListener实现类对象);
this.addKeyListener(this);
// this : 当前类对象
// 1) 窗体对象
// 2) KeyListener实现类对象
// 初始化窗体
initFrame();
// 初始化数据
initData();
// 绘制游戏界面
paintView();
// 设置窗体可见
setVisible(true);
}
/**
* 初始化数据 (打乱二维数组)
*/
public void initData() {
// 准备Random对象
Random r = new Random();
// 遍历二维数组, 获取到每一个元素
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
int randomX = r.nextInt(4);
int randomY = r.nextInt(4);
// data[i][j]
// data[randomX][randomY]
int temp = data[i][j];
data[i][j] = data[randomX][randomY];
data[randomX][randomY] = temp;
}
}
// 用于确定0格子的位置
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] == 0) {
row = i;
column = j;
}
}
}
}
/**
* 此方法用于初始化窗体
*/
public void initFrame() {
// 设置窗体大小
setSize(514, 595);
// 设置窗体关闭模式
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 设置窗体标题
setTitle("石头迷阵单机版V1.0");
// 设置窗体置顶
setAlwaysOnTop(true);
// 设置窗体居中
setLocationRelativeTo(null);
// 取消默认布局
setLayout(null);
}
/**
* 此方法用于绘制游戏界面
*/
public void paintView() {
getContentPane().removeAll();
if(victory()){
// 加载胜利图片资源, 添加到窗体中
JLabel winLabel = new JLabel(new ImageIcon("D:\\image\\win.png"));
winLabel.setBounds(124,230,266, 88);
getContentPane().add(winLabel);
}
JButton btn = new JButton("重新游戏");
btn.setBounds(350,20,100,20);
getContentPane().add(btn);
btn.setFocusable(false);
btn.addActionListener(e -> {
count = 0;
initData();
paintView();
});
JLabel scoreLabel = new JLabel("步数为:" + count);
scoreLabel.setBounds(50,20,100,20);
getContentPane().add(scoreLabel);
for (int i = 0; i < 4; i++) {
// i = 0 1 2 3
for (int j = 0; j < 4; j++) {
// j = 0 1 2 3
JLabel imageLabel = new JLabel(new ImageIcon("D:\\image\\" + data[i][j] + ".png"));
imageLabel.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);
getContentPane().add(imageLabel);
}
}
JLabel background = new JLabel(new ImageIcon("D:\\image\\background.png"));
background.setBounds(26, 30, 450, 484);
getContentPane().add(background);
getContentPane().repaint();
}
/**
* 判断游戏是否胜利
*/
public boolean victory() {
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] != win[i][j]) {
return false;
}
}
}
return true;
}
/**
* 此方法用于处理移动业务
*/
private void move(int keyCode) {
if(victory()){
return;
}
//左移动
if (keyCode == 37) {
if (column == 3) {
return;
}
// 空白块和右侧数据交换
// data[row][column] data[row][column+1]
int temp = data[row][column];
data[row][column] = data[row][column + 1];
data[row][column + 1] = temp;
column++;
count++;
// 上移动
} else if (keyCode == 38) {
if (row == 3) {
return;
}
// 空白块和下面的数据交换
// data[row][column] data[row+1][column]
int temp = data[row][column];
data[row][column] = data[row + 1][column];
data[row + 1][column] = temp;
row++;
count++;
// 右移动
} else if (keyCode == 39) {
if (column == 0) {
return;
}
// 空白块和左侧的数据交换
// data[row][column] data[row][column-1]
int temp = data[row][column];
data[row][column] = data[row][column - 1];
data[row][column - 1] = temp;
column--;
count++;
// 下移动
} else if (keyCode == 40) {
if (row == 0) {
return;
}
// 空白块和上面的数据交换
// data[row][column] data[row-1][column]
int temp = data[row][column];
data[row][column] = data[row - 1][column];
data[row - 1][column] = temp;
row--;
count++;
} else if (keyCode == 90) {
// 触发作弊器
data = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
}
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
// System.out.println("键值");
// System.out.println(keyCode);
move(keyCode);
// 每一次移动之后, 都重新绘制游戏界面
paintView();
}
// ----------------------------------------------------
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
// ----------------------------------------------------
}
test类运行。
最后
创作分享不易如果觉得对您有一定的帮助请点个小小关注bo。