疯狂java实战演义 弹球游戏代码
分类:
IT文章
•
2025-01-29 10:35:31
1 package org.crazyit.ball;
2
3 import java.awt.Image;
4 import java.io.File;
5 import javax.imageio.ImageIO;
6 import java.io.IOException;
7
8 /**
9 * 小球对象
10 *
11 * @author yangenxiong yangenxiong2009@gmail.com
12 * @author Kelvin Mak kelvin.mak125@gmail.com
13 * @version 1.0
14 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
15 * <br>Copyright (C), 2009-2010, yangenxiong
16 * <br>This program is protected by copyright laws.
17 */
18 public class Ball extends BallComponent {
19 // 定义球的竖向速度
20 private int speedY = 10;
21 // 定义弹球的横向速度
22 private int speedX = 8;
23 // 定义是否在运动
24 private boolean started = false;
25 // 定义是否结束运动
26 private boolean stop = false;
27
28 /**
29 * m 有参数构造器
30 *
31 * @param panelWidth
32 * int 画板宽度
33 * @param panelHeight
34 * int 画板高度
35 * @param offset
36 * int 位移
37 * @param path
38 * String 图片路径
39 */
40 public Ball(int panelWidth, int panelHeight, int offset, String path)
41 throws IOException {
42 // 调用父构造器
43 super(panelWidth, panelHeight, path);
44 // 设置y坐标
45 this.setY(panelHeight - super.getImage().getHeight(null) - offset);
46 }
47
48 /**
49 * 设置横向速度
50 *
51 * @param speed
52 * int 速度
53 * @return void
54 */
55 public void setSpeedX(int speed) {
56 this.speedX = speed;
57 }
58
59 /**
60 * 设置竖向速度
61 *
62 * @param speed
63 * int 速度
64 * @return void
65 */
66 public void setSpeedY(int speed) {
67 this.speedY = speed;
68 }
69
70 /**
71 * 设置是否在运动
72 *
73 * @param b
74 * boolean
75 * @return void
76 */
77 public void setStarted(boolean b) {
78 this.started = b;
79 }
80
81 /**
82 * 设置是否结束运动
83 *
84 * @param b
85 * boolean
86 * @return void
87 */
88 public void setStop(boolean b) {
89 this.stop = b;
90 }
91
92 /**
93 * 返回横向速度
94 *
95 * @return int 速度
96 */
97 public int getSpeedX() {
98 return this.speedX;
99 }
100
101 /**
102 * 返回竖向速度
103 *
104 * @return int 速度
105 */
106 public int getSpeedY() {
107 return this.speedY;
108 }
109
110 /**
111 * 是否在运动
112 *
113 * @return boolean 是否在运动
114 */
115 public boolean isStarted() {
116 return this.started;
117 }
118
119 /**
120 * 是否已经结束运动
121 *
122 * @return boolean 是否已经结束运动
123 */
124 public boolean isStop() {
125 return this.stop;
126 }
127
128 }
Ball
1 package org.crazyit.ball;
2
3 import java.awt.Image;
4 import java.io.File;
5 import javax.imageio.ImageIO;
6 import java.io.IOException;
7
8 /**
9 * 桌面弹球游戏相关组件的父类
10 *
11 * @author yangenxiong yangenxiong2009@gmail.com
12 * @author Kelvin Mak kelvin.mak125@gmail.com
13 * @version 1.0
14 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
15 * <br>Copyright (C), 2009-2010, yangenxiong
16 * <br>This program is protected by copyright laws.
17 */
18 public class BallComponent {
19 // 设置x坐标
20 private int x = -1;
21 // 设置y坐标
22 private int y = -1;
23 // 设置图片
24 private Image image = null;
25 // 设置图片速度
26 private int speed = 5;
27
28 /**
29 * 构造器
30 *
31 * @param path
32 * String 图片路径
33 */
34 public BallComponent(String path) throws IOException {
35 super();
36 this.image = ImageIO.read(new File(path));
37 }
38
39 /**
40 * 构造器
41 *
42 * @param panelWidth
43 * int 画板宽度
44 * @param panelHeight
45 * int 画板高度
46 * @param path
47 * String 图片路径
48 */
49 public BallComponent(int panelWidth, int panelHeight, String path)
50 throws IOException {
51 super();
52 // 读取图片
53 this.image = ImageIO.read(new File(path));
54 // 设置x坐标
55 this.x = (int) ((panelWidth - image.getWidth(null)) / 2);
56 }
57
58 /**
59 * 构造器
60 *
61 * @param x
62 * int 图像的x坐标
63 * @param y
64 * int 图像的y坐标
65 * @param path
66 * String 图片路径
67 */
68 public BallComponent(String path, int x, int y) throws IOException {
69 super();
70 // 读取图片
71 this.image = ImageIO.read(new File(path));
72 this.x = x;
73 this.y = y;
74 }
75
76 /**
77 * 获取x坐标
78 *
79 * @return int x坐标
80 */
81 public int getX() {
82 return this.x;
83 }
84
85 /**
86 * 获取y坐标
87 *
88 * @return int y坐标
89 */
90 public int getY() {
91 return this.y;
92 }
93
94 /**
95 * 获取图片速度
96 *
97 * @return int 图片速度
98 */
99 public int getSpeed() {
100 return this.speed;
101 }
102
103 /**
104 * 设置x坐标
105 *
106 * @param x
107 * int x坐标
108 * @return void
109 */
110 public void setX(int x) {
111 this.x = x;
112 }
113
114 /**
115 * 设置y坐标
116 *
117 * @param y
118 * int y坐标
119 * @return void
120 */
121 public void setY(int y) {
122 this.y = y;
123 }
124
125 /**
126 * 返回图片
127 *
128 * @return Image 图片
129 */
130 public Image getImage() {
131 return this.image;
132 }
133 }
BallComponent
1 package org.crazyit.ball;
2
3 import javax.swing.JFrame;
4 import javax.swing.JPanel;
5 import javax.swing.Timer;
6 import java.awt.Dimension;
7 import java.awt.Image;
8 import java.awt.Graphics;
9 import java.awt.Color;
10 import java.awt.event.KeyAdapter;
11 import java.awt.event.KeyListener;
12 import java.awt.event.KeyEvent;
13 import java.awt.event.ActionListener;
14 import java.awt.event.ActionEvent;
15 import java.io.IOException;
16
17 /**
18 * 游戏界面
19 *
20 * @author yangenxiong yangenxiong2009@gmail.com
21 * @author Kelvin Mak kelvin.mak125@gmail.com
22 * @version 1.0
23 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
24 * <br>Copyright (C), 2009-2010, yangenxiong
25 * <br>This program is protected by copyright laws.
26 */
27 public class BallFrame extends JFrame {
28 // 定义JPanel的宽度
29 private final int BALLPANEL_WIDTH = 307;
30 // 定义JPanel的高度
31 private final int BALLPANEL_HEIGHT = 400;
32 // 定义画板
33 private BallPanel ballPanel = null;
34 // 定义档板
35 // private Image stick = null;
36 // 设置档板x坐标
37 private int stickX = -1;
38 // 创建一个BallService实例
39 private BallService service = null;
40 // 定义一个timer
41 Timer timer = null;
42
43 /**
44 * 默认构造器
45 */
46 public BallFrame() throws IOException {
47 super();
48 // 初始化
49 initialize();
50 }
51
52 /**
53 * 初始化界面
54 *
55 * @return void
56 */
57 public void initialize() throws IOException {
58 // 设置窗口的标题
59 this.setTitle("弹球");
60 // 设置为不可改变大小
61 this.setResizable(false);
62 // 设置背景为黑色
63 this.setBackground(Color.BLACK);
64 // 获取画板
65 ballPanel = getBallPanel();
66 // 创建BallService实例
67 service = new BallService(this, BALLPANEL_WIDTH, BALLPANEL_HEIGHT);
68
69 // 定义每0.1秒执行一次监听器
70 ActionListener task = new ActionListener() {
71 public void actionPerformed(ActionEvent e) {
72 // 开始改变位置
73 service.run();
74 // 刷新画板
75 ballPanel.repaint();
76 }
77 };
78 // 如果timer不为空
79 if (timer != null) {
80 // 重新开始timer
81 timer.restart();
82 } else {
83 // 新建一个timer
84 timer = new Timer(100, task);
85 // 开始timer
86 timer.start();
87 }
88
89 this.add(ballPanel);
90 // 增加事件监听器
91 KeyListener[] klarr = this.getKeyListeners();
92 if (klarr.length == 0) {
93 // 定义键盘监听适配器
94 KeyListener keyAdapter = new KeyAdapter() {
95 public void keyPressed(KeyEvent ke) {
96 // 改变档板的坐标
97 service.setStickPos(ke);
98 }
99 };
100 this.addKeyListener(keyAdapter);
101 }
102 }
103
104 /**
105 * 获取画板
106 *
107 * @return BallPanel 返回BallPanle
108 */
109 public BallPanel getBallPanel() {
110
111 if (ballPanel == null) {
112 // 新建一个画板
113 ballPanel = new BallPanel();
114 // 设置画板的大小
115 ballPanel.setPreferredSize(new Dimension(BALLPANEL_WIDTH,
116 BALLPANEL_HEIGHT));
117 }
118 return ballPanel;
119 }
120
121 // 定义一个JPanel内部类来完成画图功能
122 public class BallPanel extends JPanel {
123 /**
124 * 重写void paint( Graphics g )方法
125 *
126 * @param g
127 * Graphics
128 * @return void
129 */
130 public void paint(Graphics g) {
131 // 画图
132 service.draw(g);
133 }
134 }
135
136 }
BallFrame
1 package org.crazyit.ball;
2
3 import java.io.IOException;
4
5 import javax.swing.JFrame;
6
7 /**
8 * 游戏入口类
9 *
10 * @author yangenxiong yangenxiong2009@gmail.com
11 * @author Kelvin Mak kelvin.mak125@gmail.com
12 * @version 1.0
13 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
14 * <br>Copyright (C), 2009-2010, yangenxiong
15 * <br>This program is protected by copyright laws.
16 */
17 public class BallGame {
18 /**
19 * 开始游戏
20 *
21 * @return void
22 */
23 public static void main(String[] args) throws IOException {
24 BallFrame ballFrame = new BallFrame();
25 ballFrame.pack();
26 ballFrame.setVisible(true);
27 ballFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
28 }
29 }
BallGame
1 package org.crazyit.ball;
2
3 import java.awt.event.KeyEvent;
4 import java.awt.Image;
5 import java.awt.Graphics;
6 import java.io.IOException;
7
8 /**
9 * 处理游戏逻辑的对象
10 *
11 * @author yangenxiong yangenxiong2009@gmail.com
12 * @author Kelvin Mak kelvin.mak125@gmail.com
13 * @version 1.0
14 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
15 * <br>Copyright (C), 2009-2010, yangenxiong
16 * <br>This program is protected by copyright laws.
17 */
18 public class BallService {
19 // 定义一个Stick(档板)
20 private Stick stick = null;
21 // 定义一个弹球
22 private Ball ball = null;
23 // 定义一个游戏结束图片
24 private BallComponent gameOver = null;
25 // 定义一个赢了游戏的图片
26 private BallComponent won = null;
27 // 定义一个砖块图片数组
28 private Brick[][] bricks = null;
29 private int width;
30 private int height;
31 BallFrame ballFrame = null;
32
33 /**
34 * 私有空构造器
35 */
36 private BallService() {
37 super();
38 }
39
40 /**
41 *
42 * @param frame
43 * JFrame JFrame实例
44 * @param width
45 * int 宽
46 * @param height
47 * int 高
48 * @return BallService
49 */
50 public BallService(BallFrame frame, int width, int height)
51 throws IOException {
52 // 初始化变量
53 this.width = width;
54 this.height = height;
55 this.ballFrame = frame;
56 // 创建一个Stick(档板)实例
57 stick = new Stick(width, height, "img/stick.jpg");
58 // 创建一个弹球的实例
59 ball = new Ball(width, height, stick.getImage().getHeight(null),
60 "img/ball.gif");
61 // 游戏结束图片
62 gameOver = new BallComponent("img/over.gif");
63 // 赢图片
64 won = new BallComponent("img/win.gif");
65 // 砖块图片数组
66 bricks = createBrickArr("img/brick.gif", 11, 6);
67 }
68
69 /**
70 * run
71 *
72 * @return void
73 */
74 public void run() {
75 // 弹球坐标改变
76 setBallPos();
77 // 道具坐标改改变
78 setMagicPos();
79 }
80
81 /**
82 * 设置档板图片的位置
83 *
84 * @param ke
85 * KeyEvent 键盘事件
86 * @return void
87 */
88 public void setStickPos(KeyEvent ke) {
89 // 把弹球的运动状态设为true
90 ball.setStarted(true);
91 // 如果是左方向键
92 if (ke.getKeyCode() == KeyEvent.VK_LEFT) {
93 if (stick.getX() - stick.SPEED > 0) {
94 // x坐标向左移动
95 stick.setX(stick.getX() - stick.SPEED);
96 }
97 }
98 // 如果是右方向键
99 if (ke.getKeyCode() == KeyEvent.VK_RIGHT) {
100 if (stick.getX() + stick.SPEED < width - stick.getPreWidth()) {
101 // x坐标向右移动
102 stick.setX(stick.getX() + stick.SPEED);
103 // ballFrame.getBallGame().reStart( ballFrame );
104 }
105 }
106 // 如果是F2键
107 if (ke.getKeyCode() == KeyEvent.VK_F2) {
108 // 初始化ballFrame
109 try {
110 ballFrame.initialize();
111 } catch (IOException e) {
112 System.out.println(e.getMessage());
113 }
114 }
115 }
116
117 /**
118 * 设置小球图片的位置
119 *
120 * @return void
121 */
122 public void setBallPos() {
123 // 正数的数度
124 int absSpeedX = Math.abs(ball.getSpeedX());
125 int absSpeedY = Math.abs(ball.getSpeedY());
126 // 如果游戏已经开始而且没有结束
127 if (ball.isStarted()) {
128 // 如果小球碰到左边界
129 if (ball.getX() - absSpeedX < 0) {
130 // 重新设置x坐标
131 ball.setX(ball.getImage().getWidth(null));
132 // 把x方向的速度设为反方向
133 ball.setSpeedX(-ball.getSpeedX());
134 }
135 // 如果小球碰到右边界
136 if (ball.getX() + absSpeedX > width
137 - ball.getImage().getWidth(null)) {
138 // 重新设置x坐标
139 ball.setX(width - ball.getImage().getWidth(null) * 2);
140 // 把x方向的速度设为反方向
141 ball.setSpeedX(-ball.getSpeedX());
142 }
143 // 如果小球碰到上边界
144 if (ball.getY() - absSpeedY < 0) {
145 // 重新设置y坐标
146 ball.setY(ball.getImage().getWidth(null));
147 // 把y方向的速度设为反方向
148 ball.setSpeedY(-ball.getSpeedY());
149 }
150 // 如果小球碰到下边界
151 if (ball.getY() + absSpeedY > height
152 - stick.getImage().getHeight(null)) {
153 // 如果小球与档板有碰撞
154 if (isHitStick(ball)) {
155 // 重新设置y坐标
156 ball.setY(height - ball.getImage().getHeight(null) * 2);
157 // 把y方向的速度设为反方向
158 ball.setSpeedY(-ball.getSpeedY());
159 }
160 }
161 // 与砖块碰撞后的运动
162 for (int i = bricks.length - 1; i > -1; i--) {
163 for (int j = bricks[i].length - 1; j > -1; j--) {
164 // 如果小球与砖块有碰撞
165 if (isHitBrick(bricks[i][j])) {
166 if (ball.getSpeedY() > 0) {
167 ball.setSpeedY(-ball.getSpeedY());
168 }
169 }
170 }
171 }
172 // 结束游戏
173 if (ball.getY() > height) {
174 ball.setStop(true);
175 }
176
177 // 设置x坐标
178 ball.setX(ball.getX() - (int) (Math.random() * 2)
179 - ball.getSpeedX());
180 // 设置y坐标
181 ball.setY(ball.getY() - (int) (Math.random() * 2)
182 - ball.getSpeedY());
183 }
184 }
185
186 /**
187 * 小球与砖块是否有碰撞
188 *
189 * @return boolean
190 */
191 public boolean isHitBrick(Brick brick) {
192 if (brick.isDisable()) {
193 return false;
194 }
195 // ball的圆心x坐标
196 double ballX = ball.getX() + ball.getImage().getWidth(null) / 2;
197 // ball的圆心y坐标
198 double ballY = ball.getY() + ball.getImage().getHeight(null) / 2;
199 // brick的中心x坐标
200 double brickX = brick.getX() + brick.getImage().getWidth(null) / 2;
201 // brick的中心y坐标
202 double brickY = brick.getY() + brick.getImage().getHeight(null) / 2;
203 // 两个坐标点的距离
204 double distance = Math.sqrt(Math.pow(ballX - brickX, 2)
205 + Math.pow(ballY - brickY, 2));
206 // 如果两个图形重叠,返回true;
207 if (distance < (ball.getImage().getWidth(null) + brick.getImage()
208 .getWidth(null)) / 2) {
209 // 使brick无效
210 brick.setDisable(true);
211 return true;
212
213 }
214 return false;
215 }
216
217 /**
218 * BallComponent是否与档板有碰撞
219 *
220 * @param image
221 * BallComponent 图像
222 * @return boolean
223 */
224 public boolean isHitStick(BallComponent bc) {
225 // 获取图片对象
226 Image tempImage = bc.getImage();
227 // 如果与档板有碰撞
228 if (bc.getX() + tempImage.getWidth(null) > stick.getX()
229 && bc.getX() < stick.getX() + stick.getPreWidth()
230 && bc.getY() + tempImage.getHeight(null) > stick.getY()) {
231 return true;
232 }
233 return false;
234 }
235
236 /**
237 * 设置道具的位置
238 *
239 * @return void
240 */
241 public void setMagicPos() {
242 for (int i = 0; i < bricks.length; i++) {
243 for (int j = 0; j < bricks[i].length; j++) {
244 // 获取magic
245 Magic magic = bricks[i][j].getMagic();
246 if (magic != null) {
247 // 如果这个brick的状态是无效的
248 if (bricks[i][j].isDisable() && magic.getY() < height) {
249 // 设置magic的y坐标向下增加
250 magic.setY(magic.getY() + magic.getSpeed());
251 // 设置档板的宽度
252 setStickWidth(magic);
253
254 }
255 }
256 }
257 }
258 }
259
260 /**
261 * 设置档板的长度
262 *
263 * @param magic
264 * Magic 道具
265 * @return void
266 */
267 public void setStickWidth(Magic magic) {
268 if (isHitStick(magic)) {
269 // 道具的作用
270 magic.magicDo(stick);
271 }
272 }
273
274 /**
275 * 判断是否赢了
276 *
277 * @return boolean
278 */
279 public boolean isWon() {
280 // 如果消了全部砖块,则为赢
281 for (int i = 0; i < bricks.length; i++) {
282 for (int j = 0; j < bricks[i].length; j++) {
283 if (!bricks[i][j].isDisable()) {
284 return false;
285 }
286 }
287 }
288 return true;
289 }
290
291 /**
292 * 创建一个类型为Brick的数组
293 *
294 * @param path
295 * String 图像路径
296 * @param xSize
297 * int
298 * @param ySize
299 * int
300 * @return Brick[][]
301 */
302 public Brick[][] createBrickArr(String path, int xSize, int ySize)
303 throws IOException {
304 // 创建一个Brick[][]
305 Brick[][] bricks = new Brick[xSize][ySize];
306 int x = 0;
307 int y = 0;
308 int random = 0;
309 int imageSize = 28;
310 boolean isDisable = false;
311 // 迭代初始化数组
312 for (int i = 0; i < xSize; i++) {
313 for (int j = 0; j < ySize; j++) {
314 // 创建一个新的砖块
315 random = (int) (Math.random() * 3);
316 x = i * imageSize;
317 y = j * imageSize;
318 // 一定机率没有砖块
319 isDisable = Math.random() > 0.8 ? true : false;
320 if (isDisable) {
321 random = 0;
322 }
323 Brick brick = new Brick(path, random, x, y);
324 brick.setDisable(isDisable);
325 // 设置x坐标
326 brick.setX(x);
327 // 设置y坐标
328 brick.setY(y);
329 bricks[i][j] = brick;
330 }
331 }
332 return bricks;
333 }
334
335 /**
336 * 画图
337 *
338 * @param g
339 * Graphics 用来画图的对象
340 * @return void
341 */
342 public void draw(Graphics g) {
343 // 如果赢了
344 if (isWon()) {
345 // 绘制赢的图片
346 g.drawImage(won.getImage(), won.getX(), won.getY(), width,
347 height - 10, null);
348 } else if (ball.isStop()) {
349 // 绘制游戏结束图像
350 g.drawImage(gameOver.getImage(), gameOver.getX(), gameOver.getY(),
351 width, height - 10, null);
352 } else {
353 // 清除原来的图像
354 g.clearRect(0, 0, width, height);
355 // 绘制档板图像
356 g.drawImage(stick.getImage(), stick.getX(), stick.getY(), stick
357 .getPreWidth(), stick.getImage().getHeight(null), null);
358 // 绘制弹球图像
359 g.drawImage(ball.getImage(), ball.getX(), ball.getY(), null);
360 // 迭代绘制砖块图像
361 for (int i = 0; i < bricks.length; i++) {
362 for (int j = 0; j < bricks[i].length; j++) {
363 BallComponent magic = bricks[i][j].getMagic();
364 // 如果这个砖块图像对像是有效的
365 if (!bricks[i][j].isDisable()) {
366 // 里面的数字1为砖块图像间的间隙
367 g.drawImage(bricks[i][j].getImage(), bricks[i][j]
368 .getX(), bricks[i][j].getY(), bricks[i][j]
369 .getImage().getWidth(null) - 1, bricks[i][j]
370 .getImage().getHeight(null) - 1, null);
371 } else if (magic != null && magic.getY() < height) {
372 g.drawImage(magic.getImage(), magic.getX(), magic
373 .getY(), null);
374 }
375 }
376 }
377 }
378 }
379 }