寫在前面
技術源於分享,所以今天抽空把自己之前用java做過的小游戲整理貼出來給大家參考學習。java確實不適合寫桌面應用,這里只是通過這個游戲讓大家理解oop面向對象編程的過程,純屬娛樂。代碼寫的很簡單,也很容易理解,並且注釋寫的很清楚了,還有問題,自己私下去補課學習。
完整代碼
敵飛機
|
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
|
import
java.util.Random;
敵飛機: 是飛行物,也是敵人
public
class
Airplane
extends
FlyingObject
implements
Enemy {
private
int
speed =
3
;
//移動步驟
/** 初始化數據 */
public
Airplane(){
this
.image = ShootGame.airplane;
width = image.getWidth();
height = image.getHeight();
y = -height;
Random rand =
new
Random();
x = rand.nextInt(ShootGame.WIDTH - width);
}
/** 獲取分數 */
@Override
public
int
getScore() {
return
5
;
}
/** //越界處理 */
@Override
public
boolean
outOfBounds() {
return
y>ShootGame.HEIGHT;
}
/** 移動 */
@Override
public
void
step() {
y += speed;
}
}
|
分數獎勵
|
1
2
3
4
5
6
7
8
9
|
/**
* 獎勵
*/
public
interface
Award {
int
DOUBLE_FIRE =
0
;
//雙倍火力
int
LIFE =
1
;
//1條命
/** 獲得獎勵類型(上面的0或1) */
int
getType();
}
|
蜜蜂
|
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
|
import
java.util.Random;
/** 蜜蜂 */
public
class
Bee
extends
FlyingObject
implements
Award{
private
int
xSpeed =
1
;
//x坐標移動速度
private
int
ySpeed =
2
;
//y坐標移動速度
private
int
awardType;
//獎勵類型
/** 初始化數據 */
public
Bee(){
this
.image = ShootGame.bee;
width = image.getWidth();
height = image.getHeight();
y = -height;
Random rand =
new
Random();
x = rand.nextInt(ShootGame.WIDTH - width);
awardType = rand.nextInt(
2
);
//初始化時給獎勵
}
/** 獲得獎勵類型 */
public
int
getType(){
return
awardType;
}
/** 越界處理 */
@Override
public
boolean
outOfBounds() {
return
y>ShootGame.HEIGHT;
}
/** 移動,可斜着飛 */
@Override
public
void
step() {
x += xSpeed;
y += ySpeed;
if
(x > ShootGame.WIDTH-width){
xSpeed = -
1
;
}
if
(x <
0
){
xSpeed =
1
;
}
}
}
|
子彈類:是飛行物體
|
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
|
/**
* 子彈類:是飛行物
*/
public
class
Bullet
extends
FlyingObject {
private
int
speed =
3
;
//移動的速度
/** 初始化數據 */
public
Bullet(
int
x,
int
y){
this
.x = x;
this
.y = y;
this
.image = ShootGame.bullet;
}
/** 移動 */
@Override
public
void
step(){
y-=speed;
}
/** 越界處理 */
@Override
public
boolean
outOfBounds() {
return
y<-height;
}
}
|
敵人的分數
|
1
2
3
4
5
6
7
|
/**
* 敵人,可以有分數
*/
public
interface
Enemy {
/** 敵人的分數 */
int
getScore();
}
|
飛行物(敵機,蜜蜂,子彈,英雄機)
|
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
|
import
java.awt.image.BufferedImage;
/**
* 飛行物(敵機,蜜蜂,子彈,英雄機)
*/
public
abstract
class
FlyingObject {
protected
int
x;
//x坐標
protected
int
y;
//y坐標
protected
int
width;
//寬
protected
int
height;
//高
protected
BufferedImage image;
//圖片
public
int
getX() {
return
x;
}
public
void
setX(
int
x) {
this
.x = x;
}
public
int
getY() {
return
y;
}
public
void
setY(
int
y) {
this
.y = y;
}
public
int
getWidth() {
return
width;
}
public
void
setWidth(
int
width) {
this
.width = width;
}
public
int
getHeight() {
return
height;
}
public
void
setHeight(
int
height) {
this
.height = height;
}
public
BufferedImage getImage() {
return
image;
}
public
void
setImage(BufferedImage image) {
this
.image = image;
}
/**
* 檢查是否出界
* @return true 出界與否
*/
public
abstract
boolean
outOfBounds();
/**
* 飛行物移動一步
*/
public
abstract
void
step();
/**
* 檢查當前飛行物體是否被子彈(x,y)擊(shoot)中
* @param Bullet 子彈對象
* @return true表示被擊中了
*/
public
boolean
shootBy(Bullet bullet){
int
x = bullet.x;
//子彈橫坐標
int
y = bullet.y;
//子彈縱坐標
return
this
.x<x && x<
this
.x+width &&
this
.y<y && y<
this
.y+height;
}
}
|
英雄機
|
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
|
import
java.awt.image.BufferedImage;
/**
* 英雄機:是飛行物
*/
public
class
Hero
extends
FlyingObject{
private
BufferedImage[] images = {};
//英雄機圖片
private
int
index =
0
;
//英雄機圖片切換索引
private
int
doubleFire;
//雙倍火力
private
int
life;
//命
/** 初始化數據 */
public
Hero(){
life =
3
;
//初始3條命
doubleFire =
0
;
//初始火力為0
images =
new
BufferedImage[]{ShootGame.hero0, ShootGame.hero1};
//英雄機圖片數組
image = ShootGame.hero0;
//初始為hero0圖片
width = image.getWidth();
height = image.getHeight();
x =
150
;
y =
400
;
}
/** 獲取雙倍火力 */
public
int
isDoubleFire() {
return
doubleFire;
}
/** 設置雙倍火力 */
public
void
setDoubleFire(
int
doubleFire) {
this
.doubleFire = doubleFire;
}
/** 增加火力 */
public
void
addDoubleFire(){
doubleFire =
40
;
}
/** 增命 */
public
void
addLife(){
//增命
life++;
}
/** 減命 */
public
void
subtractLife(){
//減命
life--;
}
/** 獲取命 */
public
int
getLife(){
return
life;
}
/** 當前物體移動了一下,相對距離,x,y鼠標位置 */
public
void
moveTo(
int
x,
int
y){
this
.x = x - width/
2
;
this
.y = y - height/
2
;
}
/** 越界處理 */
@Override
public
boolean
outOfBounds() {
return
false
;
}
/** 發射子彈 */
public
Bullet[] shoot(){
int
xStep = width/
4
;
//4半
int
yStep =
20
;
//步
if
(doubleFire>
0
){
//雙倍火力
Bullet[] bullets =
new
Bullet[
2
];
bullets[
0
] =
new
Bullet(x+xStep,y-yStep);
//y-yStep(子彈距飛機的位置)
bullets[
1
] =
new
Bullet(x+
3
*xStep,y-yStep);
return
bullets;
}
else
{
//單倍火力
Bullet[] bullets =
new
Bullet[
1
];
bullets[
0
] =
new
Bullet(x+
2
*xStep,y-yStep);
return
bullets;
}
}
/** 移動 */
@Override
public
void
step() {
if
(images.length>
0
){
image = images[index++/
10
%images.length];
//切換圖片hero0,hero1
}
}
/** 碰撞算法 */
public
boolean
hit(FlyingObject other){
int
x1 = other.x -
this
.width/
2
;
//x坐標最小距離
int
x2 = other.x +
this
.width/
2
+ other.width;
//x坐標最大距離
int
y1 = other.y -
this
.height/
2
;
//y坐標最小距離
int
y2 = other.y +
this
.height/
2
+ other.height;
//y坐標最大距離
int
herox =
this
.x +
this
.width/
2
;
//英雄機x坐標中心點距離
int
heroy =
this
.y +
this
.height/
2
;
//英雄機y坐標中心點距離
return
herox>x1 && herox<x2 && heroy>y1 && heroy<y2;
//區間范圍內為撞上了
}
}
|
游戲啟動主類
|
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
|
import
java.awt.Font;
import
java.awt.Color;
import
java.awt.Graphics;
import
java.awt.event.MouseAdapter;
import
java.awt.event.MouseEvent;
import
java.util.Arrays;
import
java.util.Random;
import
java.util.Timer;
import
java.util.TimerTask;
import
java.awt.image.BufferedImage;
import
javax.imageio.ImageIO;
import
javax.swing.ImageIcon;
import
javax.swing.JFrame;
import
javax.swing.JPanel;
public
class
ShootGame
extends
JPanel {
public
static
final
int
WIDTH =
400
;
// 面板寬
public
static
final
int
HEIGHT =
654
;
// 面板高
/** 游戲的當前狀態: START RUNNING PAUSE GAME_OVER */
private
int
state;
private
static
final
int
START =
0
;
private
static
final
int
RUNNING =
1
;
private
static
final
int
PAUSE =
2
;
private
static
final
int
GAME_OVER =
3
;
private
int
score =
0
;
// 得分
private
Timer timer;
// 定時器
private
int
intervel =
1000
/
100
;
// 時間間隔(毫秒)
public
static
BufferedImage background;
public
static
BufferedImage start;
public
static
BufferedImage airplane;
public
static
BufferedImage bee;
public
static
BufferedImage bullet;
public
static
BufferedImage hero0;
public
static
BufferedImage hero1;
public
static
BufferedImage pause;
public
static
BufferedImage gameover;
private
FlyingObject[] flyings = {};
// 敵機數組
private
Bullet[] bullets = {};
// 子彈數組
private
Hero hero =
new
Hero();
// 英雄機
static
{
// 靜態代碼塊,初始化圖片資源
try
{
background = ImageIO.read(ShootGame.
class
.getResource(
"background.png"
));
start = ImageIO.read(ShootGame.
class
.getResource(
"start.png"
));
airplane = ImageIO
.read(ShootGame.
class
.getResource(
"airplane.png"
));
bee = ImageIO.read(ShootGame.
class
.getResource(
"bee.png"
));
bullet = ImageIO.read(ShootGame.
class
.getResource(
"bullet.png"
));
hero0 = ImageIO.read(ShootGame.
class
.getResource(
"hero0.png"
));
hero1 = ImageIO.read(ShootGame.
class
.getResource(
"hero1.png"
));
pause = ImageIO.read(ShootGame.
class
.getResource(
"pause.png"
));
gameover = ImageIO
.read(ShootGame.
class
.getResource(
"gameover.png"
));
}
catch
(Exception e) {
e.printStackTrace();
}
}
/** 畫 */
@Override
public
void
paint(Graphics g) {
g.drawImage(background,
0
,
0
,
null
);
// 畫背景圖
paintHero(g);
// 畫英雄機
paintBullets(g);
// 畫子彈
paintFlyingObjects(g);
// 畫飛行物
paintScore(g);
// 畫分數
paintState(g);
// 畫游戲狀態
}
/** 畫英雄機 */
public
void
paintHero(Graphics g) {
g.drawImage(hero.getImage(), hero.getX(), hero.getY(),
null
);
}
/** 畫子彈 */
public
void
paintBullets(Graphics g) {
for
(
int
i =
0
; i < bullets.length; i++) {
Bullet b = bullets[i];
g.drawImage(b.getImage(), b.getX() - b.getWidth() /
2
, b.getY(),
null
);
}
}
/** 畫飛行物 */
public
void
paintFlyingObjects(Graphics g) {
for
(
int
i =
0
; i < flyings.length; i++) {
FlyingObject f = flyings[i];
g.drawImage(f.getImage(), f.getX(), f.getY(),
null
);
}
}
/** 畫分數 */
public
void
paintScore(Graphics g) {
int
x =
10
;
// x坐標
int
y =
25
;
// y坐標
Font font =
new
Font(Font.SANS_SERIF, Font.BOLD,
22
);
// 字體
g.setColor(
new
Color(
0xFF0000
));
g.setFont(font);
// 設置字體
g.drawString(
"SCORE:"
+ score, x, y);
// 畫分數
y=y+
20
;
// y坐標增20
g.drawString(
"LIFE:"
+ hero.getLife(), x, y);
// 畫命
}
/** 畫游戲狀態 */
public
void
paintState(Graphics g) {
switch
(state) {
case
START:
// 啟動狀態
g.drawImage(start,
0
,
0
,
null
);
break
;
case
PAUSE:
// 暫停狀態
g.drawImage(pause,
0
,
0
,
null
);
break
;
case
GAME_OVER:
// 游戲終止狀態
g.drawImage(gameover,
0
,
0
,
null
);
break
;
}
}
public
static
void
main(String[] args) {
JFrame frame =
new
JFrame(
"Fly"
);
ShootGame game =
new
ShootGame();
// 面板對象
frame.add(game);
// 將面板添加到JFrame中
frame.setSize(WIDTH, HEIGHT);
// 設置大小
frame.setAlwaysOnTop(
true
);
// 設置其總在最上
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 默認關閉操作
frame.setIconImage(
new
ImageIcon(
"images/icon.jpg"
).getImage());
// 設置窗體的圖標
frame.setLocationRelativeTo(
null
);
// 設置窗體初始位置
frame.setVisible(
true
);
// 盡快調用paint
game.action();
// 啟動執行
}
/** 啟動執行代碼 */
public
void
action() {
// 鼠標監聽事件
MouseAdapter l =
new
MouseAdapter() {
@Override
public
void
mouseMoved(MouseEvent e) {
// 鼠標移動
if
(state == RUNNING) {
// 運行狀態下移動英雄機--隨鼠標位置
int
x = e.getX();
int
y = e.getY();
hero.moveTo(x, y);
}
}
@Override
public
void
mouseEntered(MouseEvent e) {
// 鼠標進入
if
(state == PAUSE) {
// 暫停狀態下運行
state = RUNNING;
}
}
@Override
public
void
mouseExited(MouseEvent e) {
// 鼠標退出
if
(state == RUNNING) {
// 游戲未結束,則設置其為暫停
state = PAUSE;
}
}
@Override
public
void
mouseClicked(MouseEvent e) {
// 鼠標點擊
switch
(state) {
case
START:
state = RUNNING;
// 啟動狀態下運行
break
;
case
GAME_OVER:
// 游戲結束,清理現場
flyings =
new
FlyingObject[
0
];
// 清空飛行物
bullets =
new
Bullet[
0
];
// 清空子彈
hero =
new
Hero();
// 重新創建英雄機
score =
0
;
// 清空成績
state = START;
// 狀態設置為啟動
break
;
}
}
};
this
.addMouseListener(l);
// 處理鼠標點擊操作
this
.addMouseMotionListener(l);
// 處理鼠標滑動操作
timer =
new
Timer();
// 主流程控制
timer.schedule(
new
TimerTask() {
@Override
public
void
run() {
if
(state == RUNNING) {
// 運行狀態
enterAction();
// 飛行物入場
stepAction();
// 走一步
shootAction();
// 英雄機射擊
bangAction();
// 子彈打飛行物
outOfBoundsAction();
// 刪除越界飛行物及子彈
checkGameOverAction();
// 檢查游戲結束
}
repaint();
// 重繪,調用paint()方法
}
}, intervel, intervel);
}
int
flyEnteredIndex =
0
;
// 飛行物入場計數
/** 飛行物入場 */
public
void
enterAction() {
flyEnteredIndex++;
if
(flyEnteredIndex %
40
==
0
) {
// 400毫秒生成一個飛行物--10*40
FlyingObject obj = nextOne();
// 隨機生成一個飛行物
flyings = Arrays.copyOf(flyings, flyings.length +
1
);
flyings[flyings.length -
1
] = obj;
}
}
/** 走一步 */
public
void
stepAction() {
for
(
int
i =
0
; i < flyings.length; i++) {
// 飛行物走一步
FlyingObject f = flyings[i];
f.step();
}
for
(
int
i =
0
; i < bullets.length; i++) {
// 子彈走一步
Bullet b = bullets[i];
b.step();
}
hero.step();
// 英雄機走一步
}
/** 飛行物走一步 */
public
void
flyingStepAction() {
for
(
int
i =
0
; i < flyings.length; i++) {
FlyingObject f = flyings[i];
f.step();
}
}
int
shootIndex =
0
;
// 射擊計數
/** 射擊 */
public
void
shootAction() {
shootIndex++;
if
(shootIndex %
30
==
0
) {
// 300毫秒發一顆
Bullet[] bs = hero.shoot();
// 英雄打出子彈
bullets = Arrays.copyOf(bullets, bullets.length + bs.length);
// 擴容
System.arraycopy(bs,
0
, bullets, bullets.length - bs.length,
bs.length);
// 追加數組
}
}
/** 子彈與飛行物碰撞檢測 */
public
void
bangAction() {
for
(
int
i =
0
; i < bullets.length; i++) {
// 遍歷所有子彈
Bullet b = bullets[i];
bang(b);
// 子彈和飛行物之間的碰撞檢查
}
}
/** 刪除越界飛行物及子彈 */
public
void
outOfBoundsAction() {
int
index =
0
;
// 索引
FlyingObject[] flyingLives =
new
FlyingObject[flyings.length];
// 活着的飛行物
for
(
int
i =
0
; i < flyings.length; i++) {
FlyingObject f = flyings[i];
if
(!f.outOfBounds()) {
flyingLives[index++] = f;
// 不越界的留着
}
}
flyings = Arrays.copyOf(flyingLives, index);
// 將不越界的飛行物都留着
index =
0
;
// 索引重置為0
Bullet[] bulletLives =
new
Bullet[bullets.length];
for
(
int
i =
0
; i < bullets.length; i++) {
Bullet b = bullets[i];
if
(!b.outOfBounds()) {
bulletLives[index++] = b;
}
}
bullets = Arrays.copyOf(bulletLives, index);
// 將不越界的子彈留着
}
/** 檢查游戲結束 */
public
void
checkGameOverAction() {
if
(isGameOver()==
true
) {
state = GAME_OVER;
// 改變狀態
}
}
/** 檢查游戲是否結束 */
public
boolean
isGameOver() {
for
(
int
i =
0
; i < flyings.length; i++) {
int
index = -
1
;
FlyingObject obj = flyings[i];
if
(hero.hit(obj)) {
// 檢查英雄機與飛行物是否碰撞
hero.subtractLife();
// 減命
hero.setDoubleFire(
0
);
// 雙倍火力解除
index = i;
// 記錄碰上的飛行物索引
}
if
(index != -
1
) {
FlyingObject t = flyings[index];
flyings[index] = flyings[flyings.length -
1
];
flyings[flyings.length -
1
] = t;
// 碰上的與最后一個飛行物交換
flyings = Arrays.copyOf(flyings, flyings.length -
1
);
// 刪除碰上的飛行物
}
}
return
hero.getLife() <=
0
;
}
/** 子彈和飛行物之間的碰撞檢查 */
public
void
bang(Bullet bullet) {
int
index = -
1
;
// 擊中的飛行物索引
for
(
int
i =
0
; i < flyings.length; i++) {
FlyingObject obj = flyings[i];
if
(obj.shootBy(bullet)) {
// 判斷是否擊中
index = i;
// 記錄被擊中的飛行物的索引
break
;
}
}
if
(index != -
1
) {
// 有擊中的飛行物
FlyingObject one = flyings[index];
// 記錄被擊中的飛行物
FlyingObject temp = flyings[index];
// 被擊中的飛行物與最后一個飛行物交換
flyings[index] = flyings[flyings.length -
1
];
flyings[flyings.length -
1
] = temp;
flyings = Arrays.copyOf(flyings, flyings.length -
1
);
// 刪除最后一個飛行物(即被擊中的)
// 檢查one的類型(敵人加分,獎勵獲取)
if
(one
instanceof
Enemy) {
// 檢查類型,是敵人,則加分
Enemy e = (Enemy) one;
// 強制類型轉換
score += e.getScore();
// 加分
}
else
{
// 若為獎勵,設置獎勵
Award a = (Award) one;
int
type = a.getType();
// 獲取獎勵類型
switch
(type) {
case
Award.DOUBLE_FIRE:
hero.addDoubleFire();
// 設置雙倍火力
break
;
case
Award.LIFE:
hero.addLife();
// 設置加命
break
;
}
}
}
}
/**
* 隨機生成飛行物
*
* @return 飛行物對象
*/
public
static
FlyingObject nextOne() {
Random random =
new
Random();
int
type = random.nextInt(
20
);
// [0,20)
if
(type <
4
) {
return
new
Bee();
}
else
{
return
new
Airplane();
}
}
}
|
寫在最后
以上就是這個游戲我整理的完整代碼,因為圖片差不多9張,所以圖片沒上傳,需要圖片的友友請簡信我,最后,我做了一張思維導圖貼出來讓大家更好的理解OOP面向對象編程的過程。
ps:碼字很累,友友們點個贊或者評論,謝謝,么么噠~~資源已上傳(包括圖片),下載地址請戳這里
我有一個微信公眾號,經常會分享一些Java技術相關的干貨。如果你喜歡我的分享,可以用微信搜索“Java團長”或者“javatuanzhang”關注。
