目录
1、绘制界面
上述思路是:使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。
代码如下:
java
package com.itheima.stonepuzzle;
import javax.swing.*;
public class MainFrame extends JFrame {
//data使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。
int[][] data = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
/**
* 因为初始化窗体 和 绘制游戏界面,是在进入游戏就要执行的,
* 因此只需要在new对象时执行即可,而new对象时构造方法一定会执行,
* 所以在构造方法里调用即可
*/
public MainFrame(){
//初始化窗体
initFrame();
//绘制游戏界面
paintView();
//设置窗体可见
setVisible(true);
}
/**
* 此方法用于窗体初始化
*/
public void initFrame(){
// JFrame jf = new JFrame(); --因为此类继承了JFrame,因此下面的方法可以直接调用
//设置窗体大小
setSize(514, 595);
//设置窗体关闭模式:关闭窗口时,结束程序
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//设置窗体标题
setTitle("石头迷阵单机版V1.0");
//设置窗体永在最上层
setAlwaysOnTop(true);
//设置窗体居中
setLocationRelativeTo(null);
//设置取消默认布局
setLayout(null);
}
/**
* 此方法用于绘制游戏的界面
*/
public void paintView(){
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
JLabel jl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\" + data[i][j] + ".jpg"));
//设置图片对象大小
jl.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);
//将图片对象塞进窗体
getContentPane().add(jl);
}
}
JLabel background = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\background.jpg"));
//设置图片对象大小
background.setBounds(26, 30, 450, 484);
//将图片对象塞进窗体
super.getContentPane().add(background);
}
}
运行代码,绘制界面的结果如下:
2、打乱石头方块
代码:
java
/**
* 初始化数据(随机打乱石头)
*/
public void initData(){
Random r = new Random();
//1、遍历二维数组,获取每一个元素
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
//2、随机获取 (x坐, y坐标),找到其中一个数
int x = r.nextInt(4);//x坐标
int y = r.nextInt(4);//y坐标
//3、将当前遍历到的元素,和随机获取到的元素做交换
int temp = data[i][j];
data[i][j] = data[x][y];
data[x][y] = temp;
}
}
}
3、移动业务
java
/**
* 按下键盘时出发事件
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
move(keyCode);
}
/**
* 此方法用于处理移动业务
* @param keyCode
*/
private static void move(int keyCode) {
if (keyCode == 37){
System.out.println("左移动业务...");
} else if (keyCode == 38) {
System.out.println("上移动业务...");
} else if (keyCode == 39) {
System.out.println("右移动业务...");
} else if (keyCode == 40) {
System.out.println("下移动业务...");
}
}
移动石头块,实际上只需要交换二维数组中的两个数即可,然后再刷新就实现了移动业务。
做法:
java
//寻找0号元素的位置
lo:
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] == 0) {
row = i;
col = j;
break lo;
}
}
}
下面看下上、下、左、右移动:
注意:
java
/**
* 此方法用于处理移动业务
*
* @param keyCode
*/
private void move(int keyCode) {
int temp = data[row][col];//0号元素
if (keyCode == 37 && col < 3) {
System.out.println("左移动业务...");
//左移动时,空白块和右边的数做交换
data[row][col] = data[row][col + 1];
data[row][col + 1] = temp;
//记录0号元素的列坐标也要随之改变
col++;
} else if (keyCode == 38 && row < 3) {
System.out.println("上移动业务...");
//上移动时,空白块和下边的数做交换
data[row][col] = data[row + 1][col];
data[row + 1][col] = temp;
//记录0号元素的列坐标也要随之改变
row++;
} else if (keyCode == 39 && col > 0) {
System.out.println("右移动业务...");
//右移动时,空白块和左边的数做交换
data[row][col] = data[row][col - 1];
data[row][col - 1] = temp;
//记录0号元素的列坐标也要随之改变
col--;
} else if (keyCode == 40 && row > 0) {
System.out.println("下移动业务...");
//下移动时,空白块和上边的数做交换
data[row][col] = data[row - 1][col];
data[row - 1][col] = temp;
//记录0号元素的列坐标也要随之改变
row--;
}else if (keyCode == 90){//z键
//触发作弊器
data = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
}
System.out.println(row + "," + col);
}
4、游戏判定胜利
java
/**
* 判断游戏是否胜利
* @return
*/
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;
}
5、统计步数
6、重新游戏
7、完整代码:
java
package com.itheima.stonepuzzle;
public class Test {
public static void main(String[] args) {
//启动器
new MainFrame();
}
}
java
package com.itheima.stonepuzzle;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class MainFrame extends JFrame implements KeyListener {
//data使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。
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 col; //0号元素的列坐标
int count = 0;//记录操作的次数
/**
* 因为初始化窗体 和 绘制游戏界面,是在进入游戏就要执行的,
* 因此只需要在new对象时执行即可,而new对象时构造方法一定会执行,
* 所以在构造方法里调用即可
*/
public MainFrame() {
//键盘监听:
//窗体对象.addKeyListener(KeyListener实现类对象)
//this:当前对象,两个身份
//1)窗体对象
//2)KeyListener实现类对象
this.addKeyListener(this);
//初始化窗体
initFrame();
//初始化数据(随机打乱石头)
initData();
//绘制游戏界面
paintView();
//设置窗体可见
setVisible(true);
}
/**
* 此方法用于窗体初始化
*/
public void initFrame() {
// JFrame jf = new JFrame(); --因为此类继承了JFrame,因此下面的方法可以直接调用
//设置窗体大小
setSize(514, 595);
//设置窗体关闭模式:关闭窗口时,结束程序
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//设置窗体标题
setTitle("石头迷阵单机版V1.0");
//设置窗体永在最上层
setAlwaysOnTop(true);
//设置窗体居中
setLocationRelativeTo(null);
//设置取消默认布局
setLayout(null);
}
/**
* 初始化数据(随机打乱石头)
*/
public void initData() {
Random r = new Random();
//1、遍历二维数组,获取每一个元素
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
//2、随机获取 (x坐, y坐标),找到其中一个数
int x = r.nextInt(4);//x坐标
int y = r.nextInt(4);//y坐标
//3、将当前遍历到的元素,和随机获取到的元素做交换
int temp = data[i][j];
data[i][j] = data[x][y];
data[x][y] = temp;
}
}
//寻找0号元素的位置
lo:
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] == 0) {
row = i;
col = j;
break lo;
}
}
}
}
/**
* 此方法用于绘制游戏的界面
*/
public void paintView() {
//每次绘制之前,都清空之前绘制的界面
super.getContentPane().removeAll();
//加载胜利图片资源,添加到窗体中
if (victory()){
JLabel victoryJl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\victory.jpg"));
victoryJl.setBounds(124, 230, 266, 100);
getContentPane().add(victoryJl);
}
//加载重新开始按钮
if (count > 0){
JButton jb = new JButton("重新开始");
jb.setBounds(350, 10, 100, 20);
jb.setFocusable(false);//取消焦点
jb.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
//统计步数归0
count = 0;
//重新初始化数据
initData();
//重新绘制游戏界面
paintView();
}
});
getContentPane().add(jb);
}
//加载记录步数组件
JLabel stepJl = new JLabel("步数:" + count);
stepJl.setBounds(50, 10, 100, 20);
getContentPane().add(stepJl);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
JLabel jl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\" + data[i][j] + ".jpg"));
//设置图片对象大小
jl.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);
//将图片对象塞进窗体
getContentPane().add(jl);
}
}
//加载背景图
JLabel background = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\background.jpg"));
//设置图片对象大小
background.setBounds(26, 30, 450, 484);
//将图片对象塞进窗体
super.getContentPane().add(background);
//刷新
super.getContentPane().repaint();
}
/**
* 按下键盘时出发事件
*
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
move(keyCode);
//判断是否胜利
victory();
//每次移动之后,都重新绘制游戏界面
paintView();
}
/**
* 此方法用于处理移动业务
*
* @param keyCode
*/
private void move(int keyCode) {
//如果游戏胜利了,则不允许操作
if (victory()){
return;
}
int temp = data[row][col];//0号元素
if (keyCode == 37 && col < 3) {
// System.out.println("左移动业务...");
//左移动时,空白块和右边的数做交换
data[row][col] = data[row][col + 1];
data[row][col + 1] = temp;
//记录0号元素的列坐标也要随之改变
col++;
count++;
} else if (keyCode == 38 && row < 3) {
// System.out.println("上移动业务...");
//上移动时,空白块和下边的数做交换
data[row][col] = data[row + 1][col];
data[row + 1][col] = temp;
//记录0号元素的列坐标也要随之改变
row++;
count++;
} else if (keyCode == 39 && col > 0) {
// System.out.println("右移动业务...");
//右移动时,空白块和左边的数做交换
data[row][col] = data[row][col - 1];
data[row][col - 1] = temp;
//记录0号元素的列坐标也要随之改变
col--;
count++;
} else if (keyCode == 40 && row > 0) {
// System.out.println("下移动业务...");
//下移动时,空白块和上边的数做交换
data[row][col] = data[row - 1][col];
data[row - 1][col] = temp;
//记录0号元素的列坐标也要随之改变
row--;
count++;
}else if (keyCode == 90){//z键
//触发作弊器
data = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
count++;
}
// System.out.println(row + "," + col);
}
/**
* 判断游戏是否胜利
* @return
*/
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;
}
//-------------------------------------
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
//-------------------------------------
}
界面图片已放在资源里,可下载。