1. 设计游戏的目的
- 锻炼逻辑思维能力
- 利用Java的图形化界面,写一个项目,知道前面学习的知识点在实际开发中的应用场景
2. 游戏的最终效果呈现
Hello,各位同学大家好。今天,我们要写一个非常有意思的小游戏 —《拼图小游戏》
我们先来看一下游戏的最终成品展示,然后再一步一步的从0开始,完成游戏里面每一个细节。
游戏运行之后,就是这样的界面。
刚开始打开,是登录页面,因为是第一次运行,需要注册。点击注册就会跳转到注册页面
在注册页面我们可以注册账号,用户名如果已存在则会注册失败。
在游戏主界面中,我们可以利用上下左右移动小图片去玩游戏,还有快捷键A可以查看最终效果,W一键通关。
3. 实现思路
我们在写游戏的时候,也是一部分一部分完成的。
先写游戏主界面,实现步骤如下:
1,完成最外层窗体的搭建。
2,再把菜单添加到窗体当中。
3,把小图片添加到窗体当中。
4,打乱数字图片的顺序。
5,让数字图片可以移动起来。
6,通关之后的胜利判断。
7,添加其他额外的功能。
4. 三行代码实现主界面搭建
界面效果:
实现步骤:
-
创建App类, 编写main方法
作用: 程序的主入口
-
书写以下代码
1 2 3 4 5 6 7 8
| JFrame jFrame = new JFrame();
jFrame.setSize(514,595);
jFrame.setVisible(true);
|
5. 主界面的其他设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| JFrame jFrame = new JFrame();
jFrame.setSize(514,595);
jFrame.setLocationRelativeTo(null);
jFrame.setAlwaysOnTop(true);
jFrame.setDefaultCloseOperation(3);
jFrame.setTitle("拼图游戏单机版 v1.0");
jFrame.setVisible(true);
|
注意事项:
jFrame.setVisible(true);必须要写在最后一行。
6. 利用继承简化代码
需求:
如果把所有的代码都写在main方法中,那么main方法里面的代码,就包含游戏主界面的代码,登录界面的代码,注册界面的代码,会变得非常臃肿后期维护也是一件非常难的事情,所以我们需要用继承改进,改进之后,代码就可以分类了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| public class LoginJFrame extends JFrame {
public LoginJFrame(){ this.setSize(488,430); this.setTitle("拼图 登录"); this.setAlwaysOnTop(true); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setVisible(true); } }
public class RegisterJFrame extends JFrame { public RegisterJFrame(){ this.setSize(488,500); this.setTitle("拼图 注册"); this.setAlwaysOnTop(true); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setVisible(true);
getContentPane(); } }
public class GameJFrame extends JFrame {
public GameJFrame() { this.setSize(603, 680); this.setTitle("拼图单机版 v1.0"); this.setAlwaysOnTop(true); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setLayout(null); this.setVisible(true); } }
|
注意点:
其中this表示当前窗体的意思。
7. 菜单制作
菜单就是下图红色边框的内容。
7.1菜单的组成
在菜单中有:JMenuBar、JMenu、JMenuItem三个角色。
JMenuBar:如上图中红色边框
JMenu:如上图蓝色边框
JMenuItem:如上图绿色字体处
其中JMenuBar是整体,一个界面中一般只有一个JMenuBar。
而JMenu是菜单中的选项,可以有多个。
JMenuItem是选项下面的条目,也可以有多个。
7.2代码书写步骤
1,创建JMenuBar对象
2,创建JMenu对象
3,创建JMenuItem对象
4,把JMenuItem添加到JMenu中
5,把JMenu添加到JMenuBar中
6,把整个JMenuBar设置到整个界面中
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| JMenuBar jMenuBar = new JMenuBar();
jMenuBar.setSize(514, 20);
JMenu jMenu1 = new JMenu("功能");
jMenuItem1 = new JMenuItem("重新游戏");
jMenu1.add(jMenuItem1);
jMenuBar.add(jMenu1);
this.setJMenuBar(jMenuBar);
|
8.添加图片
在上图中,其实是15张小图片。我们在添加图片的时候,要把添加图片的操作重复15次,才能把所有图片都添加到界面当中。
8.1使用到的Java类
ImageIcon:描述图片的类,可以关联计算中任意位置的图片。
但是一般会把图片拷贝到当前项目中。
JLabel:用来管理图片,文字的类。
可以用来设置位置,宽高。
8.2位置坐标
界面左上角的点可以看做是坐标的原点,横向的是X轴,纵向的是Y轴。
图片的位置其实取决于图片左上角的点,在坐标中的位置。
如果是(0,0)那么该图片会显示再屏幕的左上角。
8.3添加步骤:
1,取消整个界面的默认居中布局
2,创建ImageIcon对象,并制定图片位置。
3,创建JLabel对象,并把ImageIcon对象放到小括号中。
4,利用JLabel对象设置大小,宽高。
5,将JLabel对象添加到整个界面当中。
代码示例:
1 2 3 4 5 6 7 8 9 10 11
| this.setLayout(null);
ImageIcon imageIcon1 = new ImageIcon("image\\1.png");
JLabel jLabel1 = new JLabel(imageIcon1);
jLabel1.setBounds(0, 0, 100, 100);
this.add(jLabel1);
|
以此类推,只要能确定15张图片的位置,把上面的代码重复写15遍,就可以将所有图片都添加到界面中了。
8.4 打乱图片的位置
每一张图片都对应1~15之间的数字,空白处为0,打乱图片实际上就是把数字打乱,添加图片的时候按照打乱的图片添加即可
8.4.1 打乱数组中数据的练习
int[] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
要求:打乱一维数组中的数据,并按照4个一组的方式添加到二维数组中。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class Test1 { public static void main(String[] args) {
int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; Random r = new Random(); for (int i = 0; i < tempArr.length; i++) { int index = r.nextInt(tempArr.length); int temp = tempArr[i]; tempArr[i] = tempArr[index]; tempArr[index] = temp; } for (int i = 0; i < tempArr.length; i++) { System.out.print(tempArr[i] + " "); } System.out.println();
int[][] data = new int[4][4];
for (int i = 0; i < tempArr.length; i++) { data[i / 4][i % 4] = tempArr[i]; }
for (int i = 0; i < data.length; i++) { for (int j = 0; j < data[i].length; j++) { System.out.print(data[i][j] + " "); } System.out.println(); } } }
|
8.4.2 打乱图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| public class GameJFrame extends JFrame {
int[][] data = new int[4][4];
public GameJFrame() { initJFrame();
initJMenuBar();
initData();
initImage();
this.setVisible(true);
}
private void initData() { int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; Random r = new Random(); for (int i = 0; i < tempArr.length; i++) { int index = r.nextInt(tempArr.length); int temp = tempArr[i]; tempArr[i] = tempArr[index]; tempArr[index] = temp; }
for (int i = 0; i < tempArr.length; i++) { data[i / 4][i % 4] = tempArr[i]; }
}
private void initImage() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int num = data[i][j]; JLabel jLabel = new JLabel(new ImageIcon("C:\\Users\\moon\\IdeaProjects\\basic-code\\puzzlegame\\image\\animal\\animal3\\" + num + ".jpg")); jLabel.setBounds(105 * j, 105 * i, 105, 105); this.getContentPane().add(jLabel); }
}
}
private void initJMenuBar() { JMenuBar jMenuBar = new JMenuBar();
JMenu functionJMenu = new JMenu("功能"); JMenu aboutJMenu = new JMenu("关于我们");
JMenuItem replayItem = new JMenuItem("重新游戏"); JMenuItem reLoginItem = new JMenuItem("重新登录"); JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
functionJMenu.add(replayItem); functionJMenu.add(reLoginItem); functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
jMenuBar.add(functionJMenu); jMenuBar.add(aboutJMenu);
this.setJMenuBar(jMenuBar); }
private void initJFrame() { this.setSize(603, 680); this.setTitle("拼图单机版 v1.0"); this.setAlwaysOnTop(true); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setLayout(null);
} }
|
9. 事件
事件是可以被组件识别的操作。
9.1 常见的三个核心要素
- 事件源: 按钮 图片 窗体…
- 事件:某些操作
- 绑定监听:当事件源上发生了某个事件,则执行某段代码
9.2 常见的三种事件监听
- 键盘监听 KeyListener
- 鼠标监听 MouseListener
- 动作监听 ActionListener
9.3 动作监听
包含:
9.3.1 事件的三种实现方式
方式一:实现类
定义实现类实现ActionListener接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class Test3 { public static void main(String[] args) { JFrame jFrame = new JFrame(); jFrame.setSize(603, 680); jFrame.setTitle("事件演示"); jFrame.setAlwaysOnTop(true); jFrame.setLocationRelativeTo(null); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setLayout(null);
JButton jtb = new JButton("点我啊"); jtb.setBounds(0,0,100,50); jtb.addActionListener(new MyActionListener());
jFrame.getContentPane().add(jtb);
jFrame.setVisible(true); } }
public class MyActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { System.out.println("按钮被点击了"); } }
|
方式二:匿名内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class Test3 { public static void main(String[] args) { JFrame jFrame = new JFrame(); jFrame.setSize(603, 680); jFrame.setTitle("事件演示"); jFrame.setAlwaysOnTop(true); jFrame.setLocationRelativeTo(null); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setLayout(null);
JButton jtb = new JButton("点我啊"); jtb.setBounds(0,0,100,50);
jtb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("达咩~不要点我哟~"); } });
jFrame.getContentPane().add(jtb);
jFrame.setVisible(true); } }
|
方式三:本类实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class MyJFrame extends JFrame implements ActionListener {
JButton jtb1 = new JButton("点我啊"); JButton jtb2 = new JButton("再点我啊");
public MyJFrame(){ this.setSize(603, 680); this.setTitle("拼图单机版 v1.0"); this.setAlwaysOnTop(true); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setLayout(null);
jtb1.setBounds(0,0,100,50); jtb1.addActionListener(this);
jtb2.setBounds(100,0,100,50); jtb2.addActionListener(this);
this.getContentPane().add(jtb1); this.getContentPane().add(jtb2);
this.setVisible(true); }
@Override public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if(source == jtb1){ jtb1.setSize(200,200); }else if(source == jtb2){ Random r = new Random(); jtb2.setLocation(r.nextInt(500),r.nextInt(500)); } } }
|