javaGUI练习游戏华容道(横刀立马)

玩法

玩玩就知道了

实现过程

  1. 使用什么GUI、怎么构建GUI
    解决方法:使用javax库的swing框架的JFrame提供的底层框架和JButton提供的按钮模块,再使用awt库的event事件模块中的子类方法实现对各个按钮事件以及鼠标事件的监听,从而实现主要程序模块,包括建立程序窗口、实现交互模块。

  2. Javax库显示不可到达(not accessible)
    解决方法:java11以上版本的java工程中需要在module-info.java文件中显式地声明需要java.desktop,即requires java.desktop,才能access这个javax库。

  3. 启动程序时,出现打开了两个JFrame窗口的问题
    解决方法:原先的出错部分长这样:HuaRongDao huaRongDao = new HuaRongDao();
    huaRongDao.setVisible(true);
    但是这样做会导致先隐式声明一次visible,再显式地声明一次,便会出现重复声明的问题。再深层次的问题在于HuaRongDao类中的构造函数中已经setVisible了。
    改正之后的形式应为:
    new HuaRongDao();
    即可。

  4. 如何便于调节各个模块的大小以及位置?
    解决方法:
    使用final int的unitEdgeLength定义标准一条边长度,
    这样只需要修改此量即可做到调节各部分大小,但是不改变比例

  5. 如何把背景变成白色?
    解决方法:
    使用JFrame的getContentPane()方法的setBackgroud()方法,传参为Color.white即可。

  6. 如何在JFrame上添加按钮元件?
    解决方法:
    使用add()方法,传参为JButton按钮元件

  7. 如何实现键盘方向键移动角色方块操作?
    解决方法:
    HuaRongDao类实现KeyListener类的方法keyPressed,
    这个方法传入监听的KeyEvent,做相应判断传入go即可。

  8. 如何选择操控对象?
    解决方法:
    MouseListener类mousePressed方法可以获取对什么对象进行的点击,即可获取当前对象。

  9. 怎么体现角色方块被选中?
    解决方法:
    对Characters类实现FocusListener的focusGained方法和focusLost方法,对相应状态进行颜色调节即可得到交互效果。

  10. 怎么实现鼠标悬停按钮颜色变化?
    解决方法:
    对JButton类(子类也适用)进行鼠标悬停效果的启用,实现mouseEntered方法和mouseExited方法,进行相应颜色的修改。

  11. 怎么退出程序、重新进行游戏
    解决方法:
    使用dispose()方法关闭当前JFrame框架,使用new HuaRongDao()创建新的框架进行重启程序,实现再次游玩;使用exit(0)退出程序,实现程序的正常退出。

  12. 怎么实现方块的正常移动?怎么制定交互逻辑?
    解决方法:
    鼠标点击:使用JButton类的getBounds()方法中的width和height获取当前方块的宽和高,使用MouseEvent的点击的相对位置坐标x和y,判断x、y与方块的相对位置关系,相应确定移动方块的方向。
    如果此方向上没有方块,则执行移动,否则不执行。注意:此处并非同时向两个方向移动,而是有先后顺序,所以不存在线程问题。
    键盘方向键:相应判断、移动即可。

  13. 怎么实现游戏胜利的判断?
    解决方法:
    判断character[0]即曹操的位置(左上角),若在(2单位,4单位)处(胜利位置),则使用JOptionPane单元,调用子窗显示胜利信息。

  14. 怎么实现游戏胜利后禁用操作?
    解决方法:
    首先使用JButton的setEnabled(false)方法禁用所有角色方块按钮。
    然后设置listenerOver布尔型全局变量为true,在所有移动方块操作前确保对此变量进行判断并直接结束操作。

  15. 怎么更加体现游戏性?
    解决方法:加入步骤数。

快照

快照1

源码

package:huaRongDao

HuaRongDao.java

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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
package huaRongDao;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

// 主要程序架构,协调各个按钮子类、监听事件、交互模块
public class HuaRongDao extends JFrame implements ActionListener, MouseListener, KeyListener {
/**
* 序列化版本UID,用于序列化和反序列化
*/
private static final long serialVersionUID = 1L;

static final int unitEdgeLength = 100;
private static final int unitWidthLength = 4;
private int step = 0;
private boolean listenerOver = false;

// 框架创建
JFrame frame = new JFrame("华容道(横刀立马)");

// 角色创建
Characters characters[] = new Characters[10];

// 创建上下左右四个边界
Borders left, right, above, below;

// 创建重新开始按钮
RestartButton restart = new RestartButton("重新开始");

// 创建结束游戏按钮
QuitGame quitGame = new QuitGame("结束游戏");


// 华容道主框架的构造函数
public HuaRongDao() {

// 设置布局
frame.setLayout(null);

// 子部件初始化
init();

// 设置关闭
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

// 设置框架,左上角坐标为(200,200),高为8倍单位边长,宽为6倍边长。
frame.setBounds(2*unitEdgeLength, 2*unitEdgeLength, 6*unitEdgeLength, 8*unitEdgeLength);

// 设置背景颜色
frame.getContentPane().setBackground(Color.white);

// 显示
frame.setVisible(true);

// 验证
frame.validate();
}

// 子部件初始化
public void init() {

// 添加结束游戏按钮
frame.add(quitGame);

// 设置
quitGame.setBounds(3*unitEdgeLength - (int)(0.7*unitEdgeLength), (int)(6.8*unitEdgeLength), (int)(1.4*unitEdgeLength), (int)(0.5*unitEdgeLength));
quitGame.addActionListener(this);

// 添加初始化按钮
frame.add(restart);

// 设置
restart.setBounds(3*unitEdgeLength - (int)(0.7*unitEdgeLength), (int)(6.3*unitEdgeLength), (int)(1.4*unitEdgeLength), (int)(0.5*unitEdgeLength));
restart.addActionListener(this);

String[] name = { "曹操", "关羽", "张飞", "马超", "赵云", "黄忠", "兵", "兵", "兵", "兵" };
for (int i = 0; i < name.length; i++) {
characters[i] = new Characters(i, name[i]);

characters[i].addMouseListener(this);

characters[i].addKeyListener(this);

frame.add(characters[i]);
}

// 设置角色按钮边界
characters[0].setBounds(2*unitEdgeLength, unitEdgeLength, 2*unitEdgeLength, 2*unitEdgeLength);
characters[1].setBounds(2*unitEdgeLength, 3*unitEdgeLength, 2*unitEdgeLength, unitEdgeLength);
characters[2].setBounds(unitEdgeLength, 3*unitEdgeLength, unitEdgeLength, 2*unitEdgeLength);
characters[3].setBounds(4*unitEdgeLength, 3*unitEdgeLength, unitEdgeLength, 2*unitEdgeLength);
characters[4].setBounds(unitEdgeLength, unitEdgeLength, unitEdgeLength, 2*unitEdgeLength);
characters[5].setBounds(4*unitEdgeLength, unitEdgeLength, unitEdgeLength, 2*unitEdgeLength);
characters[6].setBounds(unitEdgeLength, 5*unitEdgeLength, unitEdgeLength, unitEdgeLength);
characters[7].setBounds(4*unitEdgeLength, 5*unitEdgeLength, unitEdgeLength, unitEdgeLength);
characters[8].setBounds(2*unitEdgeLength, 4*unitEdgeLength, unitEdgeLength, unitEdgeLength);
characters[9].setBounds(3*unitEdgeLength, 4*unitEdgeLength, unitEdgeLength, unitEdgeLength);
characters[9].requestFocus();

// 曹操字号调大一点
characters[0].reviseFontSize((int)(1.5*0.3*unitEdgeLength));

// 四个边界容器
left = new Borders();
right = new Borders();
above = new Borders();
below = new Borders();

frame.add(left);
frame.add(right);
frame.add(above);
frame.add(below);

left.setBounds(unitEdgeLength-unitWidthLength, unitEdgeLength-unitWidthLength, unitWidthLength, 5*unitEdgeLength+2*unitWidthLength);
right.setBounds(5*unitEdgeLength, unitEdgeLength-unitWidthLength, unitWidthLength, 5*unitEdgeLength+2*unitWidthLength);
above.setBounds(unitEdgeLength, unitEdgeLength-unitWidthLength, 4*unitEdgeLength, unitWidthLength);
below.setBounds(unitEdgeLength, 6*unitEdgeLength, 4*unitEdgeLength, unitWidthLength);

// 验证容器
frame.validate();
}

@Override
public void keyPressed(KeyEvent e) {
if(listenerOver == true) {
return ;
}

step++;

Characters man = (Characters) e.getSource();
if (e.getKeyCode() == KeyEvent.VK_DOWN)
go(man, below);
if (e.getKeyCode() == KeyEvent.VK_UP)
go(man, above);
if (e.getKeyCode() == KeyEvent.VK_LEFT)
go(man, left);
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
go(man, right);
}

public void keyReleased(KeyEvent e) {
}

public void keyTyped(KeyEvent e) {
}


public void mousePressed(MouseEvent e) {

if(listenerOver == true) {
return ;
}

step++;
//System.out.println(step);

Characters man = (Characters) e.getSource();
int x = -1, y = -1;
x = e.getX();
y = e.getY();
int w = man.getBounds().width;
int h = man.getBounds().height;
if (y > h / 2)
go(man, below);
if (y < h / 2)
go(man, above);
if (x < w / 2)
go(man, left);
if (x > w / 2)
go(man, right);
}

public void mouseClicked(MouseEvent e) {
}

public void mouseEntered(MouseEvent e) {
}

public void mouseExited(MouseEvent e) {
}

public void mouseReleased(MouseEvent e) {
}

public void go(Characters man, JButton direction) {

if(listenerOver == true) {
return ;
}

boolean move = true;

Rectangle manRect = man.getBounds();

int x = man.getBounds().x;
int y = man.getBounds().y;

// System.out.println("x:"+x+"y:"+y);

// 检查是否是曹操
if (man.number == 0) {

// 检查曹操是否到达胜利位置,x、y是左侧的中点

// 测试
// if (x == 200 && y == 100) {
// System.out.println("x:"+x+"y:"+y);

//
if (x == 2*unitEdgeLength && y == 4*unitEdgeLength) {
for (int i = 0; i < 10; i++) {
characters[i].setEnabled(false);
}
restart.setEnabled(true);
quitGame.setEnabled(true);

//System.out.println("x:"+x+"y:"+y);

// 结束其他操作
listenerOver = true;

// 到达胜利位置,显示胜利窗口
showVictoryDialog();

// 结束其他操作
listenerOver = true;

// 结束剩余的操作,以防出现意外
return ;
}
}

// 实现坐标移动
if (direction == below) {
y = y + unitEdgeLength;
}
else if (direction == above) {
y = y - unitEdgeLength;
}
else if (direction == left) {
x = x - unitEdgeLength;
}
else if (direction == right) {
x = x + unitEdgeLength;
}

manRect.setLocation(x, y);

Rectangle dirctionRect = direction.getBounds();

for (int k = 0; k < 10; k++) {
Rectangle CharactersRect = characters[k].getBounds();
if ((manRect.intersects(CharactersRect)) && (man.number != k))
move = false;
}

if (manRect.intersects(dirctionRect))
move = false;

if (move == true)
man.setLocation(x, y);

// System.out.println("x:"+x+"y:"+y);
}

private void showVictoryDialog() {
JOptionPane.showMessageDialog(
frame, // 父窗口
"恭喜,您赢了!\n您使用的步骤数为"+step, // 消息内容
"游戏胜利", // 窗口标题
JOptionPane.INFORMATION_MESSAGE // 消息类型
);
}

public void actionPerformed(ActionEvent e) {

if (e.getSource() instanceof QuitGame) {
// 关闭当前窗口
frame.dispose();

// 关闭程序
System.exit(0);
}
else if(e.getSource() instanceof RestartButton) {
// 关闭当前窗口
frame.dispose();

// 创建新的华容道窗口
new HuaRongDao();
}
else if(listenerOver == true) {
return ;
}
}
}

Main.java

1
2
3
4
5
6
7
8
9
10
package huaRongDao;

// 启动程序
public class Main {
public static void main(String[] args) {

// 创建新的华容道程序,开始程序
new HuaRongDao();
}
}

QuitGame.java

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
package huaRongDao;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JButton;

public class QuitGame extends JButton implements FocusListener{
/**
* 序列化版本UID,用于序列化和反序列化
*/
private static final long serialVersionUID = 4L;

Color bgcolor = new Color(255,255,255);

private final int standardFontSize = (int)(0.2*HuaRongDao.unitEdgeLength);


Color fontcolor = Color.red;

// 字体格式
Font font = new Font("仿宋", Font.BOLD, standardFontSize);

QuitGame(String string) {
super(string);

setBackground(bgcolor);

setFont(font);

setForeground(fontcolor);

setBorderPainted(false);

bgcolor = getBackground();
}

@Override
public void focusGained(FocusEvent arg0) {
// TODO Auto-generated method stub
setBackground(Color.lightGray);
}

@Override
public void focusLost(FocusEvent arg0) {
// TODO Auto-generated method stub
setBackground(bgcolor);
}
}

RestartButton.java

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
package huaRongDao;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JButton;

public class RestartButton extends JButton implements FocusListener{

/**
* 序列化版本UID,用于序列化和反序列化
*/
private static final long serialVersionUID = 4L;
private final int standardFontSize = (int)(0.2*HuaRongDao.unitEdgeLength);


Color bgcolor = new Color(255,255,255);

Color fontcolor = Color.red;



// 字体格式
Font font = new Font("仿宋", Font.BOLD, standardFontSize);



RestartButton(String string) {
super(string);

setBackground(bgcolor);

setFont(font);

setForeground(fontcolor);

setBorderPainted(false);

bgcolor = getBackground();
}

@Override
public void focusGained(FocusEvent arg0) {
// TODO Auto-generated method stub
setBackground(Color.lightGray);
}

@Override
public void focusLost(FocusEvent arg0) {
// TODO Auto-generated method stub
setBackground(bgcolor);
}
}

Characters.java

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
package huaRongDao;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;

public class Characters extends JButton implements FocusListener {
/**
* 程序要求加的,暂时还不知道是干嘛的,不加就给warning
*
* 应该是序列化版本UID,用于序列化和反序列化
*/
private static final long serialVersionUID = 2L;

private final int standardFontSize = (int)(0.3*HuaRongDao.unitEdgeLength);
private boolean focused = false;

int number;

// 正常情况下按钮背景颜色
Color bgcolor = new Color(222, 170, 104);

// 焦点时的颜色和鼠标悬浮时的背景颜色
Color focusedandHoverbgColor = new Color(199,110,85);

// 名称颜色
Color fontcolor = new Color(74, 46, 58);

// 字体格式
Font font = new Font("仿宋", Font.BOLD, standardFontSize);

Characters(int number, String string) {
super(string);

this.number = number;

// 背景颜色
setBackground(bgcolor);

// 字体颜色
setForeground(fontcolor);

// 字体格式
setFont(font);

// 角色编号设置
this.number = number;

// 获取背景颜色
bgcolor = getBackground();

// 设置边界显示
setBorderPainted(true);

// 增加焦点监听器
addFocusListener(this);

// 启用鼠标悬停效果
setRolloverEnabled(true);

// 增加鼠标悬浮监听器
addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
setBackground(focusedandHoverbgColor); // 鼠标悬浮时改变背景颜色
}

@Override
public void mouseExited(MouseEvent e) {
if (focused == false)
setBackground(bgcolor); // 鼠标离开时恢复背景颜色
}
});


}

// 修改字体大小的方法,用于提供外界修改字号(这里是方便给曹操增大字号)
void reviseFontSize(int newFontSize) {
font = new Font("仿宋", Font.BOLD, newFontSize);
setFont(font);
}

@Override
public void focusGained(FocusEvent arg0) {
// TODO Auto-generated method stub
focused = true;
setBackground(focusedandHoverbgColor);
}

@Override
public void focusLost(FocusEvent arg0) {
// TODO Auto-generated method stub
focused = false;
setBackground(bgcolor);
}
}

Borders.java

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
package huaRongDao;

import java.awt.Color;
import javax.swing.JButton;

public class Borders extends JButton{

/**
* 序列化版本UID,用于序列化和反序列化
*/
private static final long serialVersionUID = 3L;

Color bgcolor = new Color(255,255,255);
Borders() {
super();

setBorderPainted(true);

setBackground(bgcolor);

bgcolor = getBackground();

}

}

javaGUI练习游戏华容道(横刀立马)
http://example.com/2024/06/19/javaGUI练习游戏华容道(横刀立马)/
作者
John Doe
发布于
2024年6月19日
许可协议