Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Guangjun Jia
FlappyBird
Commits
5676508a
Unverified
Commit
5676508a
authored
Nov 26, 2020
by
kingyuluk
Browse files
refactor: 简化部分代码
parent
4cc7c4e2
Changes
18
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
5676508a
# Flappy Bird
# Flappy Bird









## Overview
## Overview
...
@@ -12,8 +10,10 @@
...
@@ -12,8 +10,10 @@
具备原版所有功能,相较原版加入了移动型水管、优化了难度梯度。
具备原版所有功能,相较原版加入了移动型水管、优化了难度梯度。
[
RL FlappyBird
](
https://github.com/kingyuluk/RL-FlappyBird
)
基于本项目集成了Amazon的Deep Java Library (DJL),可以使用强化学习(DQN)训练Flappy Bird
## How to play
## How to play
直接运行FlappyBird.jar即可开始游戏。
程序入口:app/GameApp.java
游戏使用空格键操作。
游戏使用空格键操作。
...
@@ -43,11 +43,11 @@
...
@@ -43,11 +43,11 @@
*
图片与音效资源皆来源于网络,仅供学习交流
*
图片与音效资源皆来源于网络,仅供学习交流
## Package Contents
## Package Contents
*
com.bird.app 游戏的入口
*
com.
kingyu.flappy
bird.app 游戏的入口
*
com.bird.
main
游戏的
内容
*
com.
kingyu.flappy
bird.
game
游戏的
主体
*
com.bird.util 自定义的工具
*
com.
kingyu.flappy
bird.util 自定义的工具
## [Change Log](https://github.com/kingyuluk/FlappyBird/blob/master/CHANGELOG.md)
## [Change Log](https://github.com/kingyuluk/FlappyBird/blob/master/CHANGELOG.md)
...
...
src/com/bird/main/GameScore.java
deleted
100644 → 0
View file @
4cc7c4e2
package
com.bird.main
;
import
java.io.DataInputStream
;
import
java.io.DataOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
com.bird.util.Constant
;
import
com.bird.util.MusicUtil
;
/**
* 游戏计时类, 单例类,方便调用
*
* @author Kingyu
*
*/
public
class
GameScore
{
private
static
final
GameScore
GAME_SCORE
=
new
GameScore
();
private
long
score
=
0
;
// 分数
private
long
bestScore
;
// 最高分数
private
GameScore
()
{
bestScore
=
-
1
;
try
{
loadBestScore
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
public
static
GameScore
getInstance
()
{
return
GAME_SCORE
;
}
// 装载最高纪录
private
void
loadBestScore
()
throws
Exception
{
File
file
=
new
File
(
Constant
.
SCORE_FILE_PATH
);
if
(
file
.
exists
())
{
DataInputStream
dis
=
new
DataInputStream
(
new
FileInputStream
(
file
));
bestScore
=
dis
.
readLong
();
dis
.
close
();
}
}
// 保存最高纪录
public
void
saveBestScore
(
long
score
)
throws
Exception
{
File
file
=
new
File
(
Constant
.
SCORE_FILE_PATH
);
DataOutputStream
dos
=
new
DataOutputStream
(
new
FileOutputStream
(
file
));
dos
.
writeLong
(
score
);
dos
.
close
();
}
public
long
getBestScore
()
{
return
bestScore
;
}
public
long
getScore
()
{
return
score
;
}
public
void
setScore
(
Bird
bird
)
{
if
(!
bird
.
isDead
()){
MusicUtil
.
playScore
();
//每次得分播放音效
score
+=
1
;
//小鸟没死时记分
}
}
// 判断是否为最高纪录
public
void
isSaveScore
()
{
long
score
=
getScore
();
if
(
bestScore
<
score
)
bestScore
=
score
;
try
{
saveBestScore
(
bestScore
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
//重置计分器
public
void
reset
()
{
score
=
0
;
}
// private int timeState; // 计时器的状态
// public static final int STATE_READY = 0; // 计时就绪
// public static final int STATE_START = 1; // 计时开始
// public static final int STATE_OVER = 2; // 计时结束
// 以下为游戏计时的相关方法,因改进了记分方式目前无用
// /**
// * 游戏用时,毫秒
// *
// * @return
// */
// public long getTime() {
// if (timeState == STATE_READY) {
// return startTime;
// } else if (timeState == STATE_START) {
// return (System.currentTimeMillis() - startTime);
// } else {
// return (endTime - startTime);
// }
// }
//
// //游戏时间转换为秒
// public long getTimeInSeconds() {
// return getTime() / 1000;
// }
//
// // 计时器是否就绪
// public boolean isReadyTiming() {
// return timeState == STATE_READY;
// }
//
// // 开始计时
// public void startTiming() {
// startTime = System.currentTimeMillis();
// timeState = STATE_START;
// }
//
// // 结束计时
// public void endTiming() {
// endTime = System.currentTimeMillis();
// timeState = STATE_OVER;
// }
//
// private static final int FIRST_SCORE_TIME = 6600; // 从游戏开始到通过第一根水管的所需时间
// private static final int PER_SCORE_TIME = 2900; // 通过后续每一根水管的间隔的所需时间
//
// //将游戏时间转换为通过水管的数量
// public long TimeToScore() {
// long time = getTime();
// long temp = score;
// if (time >= FIRST_SCORE_TIME && time < FIRST_SCORE_TIME + PER_SCORE_TIME) {
// score = 1; //time大于FIRST_SCORE_TIME且未到第二对水管
// } else if (time >= FIRST_SCORE_TIME + PER_SCORE_TIME) {
// score = (int) (time - FIRST_SCORE_TIME) / PER_SCORE_TIME + 1;
// }
// if (score - temp > 0) {
// MusicUtil.playScore(); //每次得分播放音效
// }
// return score;
// }
//
// /**
// * 是否正在计时
// *
// * @return
// */
// public boolean isTiming() {
// return timeState == STATE_START;
// }
}
src/
com/
bird/app/GameApp.java
→
src/
main/java/com/kingyu/flappy
bird/app/GameApp.java
View file @
5676508a
package
com.bird.app
;
package
com.
kingyu.flappy
bird.app
;
import
com.
bird.main.G
ame
Fr
ame
;
import
com.
kingyu.flappybird.g
ame
.G
ame
;
/**
/**
* 程序入口类
* 程序入口类
...
@@ -12,6 +12,6 @@ import com.bird.main.GameFrame;
...
@@ -12,6 +12,6 @@ import com.bird.main.GameFrame;
public
class
GameApp
{
public
class
GameApp
{
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
new
Game
Frame
();
new
Game
();
}
}
}
}
src/
com/
bird/
main
/Bird.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/Bird.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Color
;
import
java.awt.Color
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
import
java.awt.Rectangle
;
import
java.awt.Rectangle
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
import
com.bird.util.GameUtil
;
import
com.
kingyu.flappy
bird.util.GameUtil
;
import
com.bird.util.MusicUtil
;
import
com.
kingyu.flappy
bird.util.MusicUtil
;
/**
/**
* 小鸟类,小鸟的绘制与飞行逻辑都在此类
* 小鸟类,小鸟的绘制与飞行逻辑都在此类
...
@@ -25,26 +25,28 @@ public class Bird {
...
@@ -25,26 +25,28 @@ public class Bird {
// 图片资源
// 图片资源
private
BufferedImage
image
;
// 实时的小鸟图片
private
BufferedImage
image
;
// 实时的小鸟图片
private
BufferedImage
scoreImg
;
// 计分牌
private
BufferedImage
overImg
;
// 结束标志
private
BufferedImage
againImg
;
// 继续标志
// 小鸟的状态
// 小鸟的状态
private
int
state
;
private
int
state
;
public
static
final
int
STATE
_NORMAL
=
0
;
public
static
final
int
BIRD
_NORMAL
=
0
;
public
static
final
int
STATE
_UP
=
1
;
public
static
final
int
BIRD
_UP
=
1
;
public
static
final
int
STATE_DOWN
=
2
;
public
static
final
int
BIRD_FALL
=
2
;
public
static
final
int
STATE
_FALL
=
3
;
public
static
final
int
BIRD_DEAD
_FALL
=
3
;
public
static
final
int
STATE
_DEAD
=
4
;
public
static
final
int
BIRD
_DEAD
=
4
;
private
final
Rectangle
birdRect
;
// 碰撞矩形
private
final
Rectangle
birdRect
;
// 碰撞矩形
public
static
final
int
RECT_DESCALE
=
2
;
// 补偿碰撞矩形宽高的参数
public
static
final
int
RECT_DESCALE
=
2
;
// 补偿碰撞矩形宽高的参数
private
final
GameScore
countScore
;
// 计分器
private
final
ScoreCounter
counter
;
// 计分器
private
final
GameOverAnimation
gameOverAnimation
;
public
static
int
BIRD_WIDTH
;
public
static
int
BIRD_HEIGHT
;
// 在构造器中对资源初始化
// 在构造器中对资源初始化
public
Bird
()
{
public
Bird
()
{
countScore
=
GameScore
.
getInstance
();
// 计分器
counter
=
ScoreCounter
.
getInstance
();
// 计分器
gameOverAnimation
=
new
GameOverAnimation
();
// 读取小鸟图片资源
// 读取小鸟图片资源
birdImages
=
new
BufferedImage
[
STATE_COUNT
][
IMG_COUNT
];
birdImages
=
new
BufferedImage
[
STATE_COUNT
][
IMG_COUNT
];
...
@@ -54,45 +56,47 @@ public class Bird {
...
@@ -54,45 +56,47 @@ public class Bird {
}
}
}
}
assert
birdImages
[
0
][
0
]
!=
null
;
BIRD_WIDTH
=
birdImages
[
0
][
0
].
getWidth
();
BIRD_HEIGHT
=
birdImages
[
0
][
0
].
getHeight
();
// 初始化小鸟的坐标
// 初始化小鸟的坐标
x
=
Constant
.
FRAME_WIDTH
>>
2
;
x
=
Constant
.
FRAME_WIDTH
>>
2
;
y
=
Constant
.
FRAME_HEIGHT
>>
1
;
y
=
Constant
.
FRAME_HEIGHT
>>
1
;
int
ImgWidth
=
birdImages
[
state
][
0
].
getWidth
();
int
ImgHeight
=
birdImages
[
state
][
0
].
getHeight
();
// 初始化碰撞矩形
// 初始化碰撞矩形
int
rectX
=
x
-
ImgWidth
/
2
;
int
rectX
=
x
-
BIRD_WIDTH
/
2
;
int
rectY
=
y
-
ImgHeight
/
2
;
int
rectY
=
y
-
BIRD_HEIGHT
/
2
;
birdRect
=
new
Rectangle
(
rectX
+
RECT_DESCALE
,
rectY
+
RECT_DESCALE
*
2
,
ImgWidth
-
RECT_DESCALE
*
3
,
birdRect
=
new
Rectangle
(
rectX
+
RECT_DESCALE
,
rectY
+
RECT_DESCALE
*
2
,
BIRD_WIDTH
-
RECT_DESCALE
*
3
,
ImgHeight
-
RECT_DESCALE
*
4
);
// 碰撞矩形的坐标与小鸟相同
BIRD_WIDTH
-
RECT_DESCALE
*
4
);
// 碰撞矩形的坐标与小鸟相同
}
}
// 绘制方法
// 绘制方法
public
void
draw
(
Graphics
g
)
{
public
void
draw
(
Graphics
g
)
{
fly
();
movement
();
int
state_index
=
Math
.
min
(
state
,
STATE
_FALL
);
// 图片资源索引
int
state_index
=
Math
.
min
(
state
,
BIRD_DEAD
_FALL
);
// 图片资源索引
// 小鸟中心点计算
// 小鸟中心点计算
int
halfImgWidth
=
birdImages
[
state_index
][
0
].
getWidth
()
>>
1
;
int
halfImgWidth
=
birdImages
[
state_index
][
0
].
getWidth
()
>>
1
;
int
halfImgHeight
=
birdImages
[
state_index
][
0
].
getHeight
()
>>
1
;
int
halfImgHeight
=
birdImages
[
state_index
][
0
].
getHeight
()
>>
1
;
if
(
speed
>
0
)
if
(
velocity
>
0
)
image
=
birdImages
[
STATE
_UP
][
0
];
image
=
birdImages
[
BIRD
_UP
][
0
];
g
.
drawImage
(
image
,
x
-
halfImgWidth
,
y
-
halfImgHeight
,
null
);
// x坐标于窗口1/4处,y坐标位窗口中心
g
.
drawImage
(
image
,
x
-
halfImgWidth
,
y
-
halfImgHeight
,
null
);
// x坐标于窗口1/4处,y坐标位窗口中心
if
(
state
==
STATE
_DEAD
)
if
(
state
==
BIRD
_DEAD
)
drawG
ameOver
(
g
);
g
ameOver
Animation
.
draw
(
g
,
this
);
else
if
(
state
!=
STATE
_FALL
)
else
if
(
state
!=
BIRD_DEAD
_FALL
)
drawScore
(
g
);
drawScore
(
g
);
// 绘制矩形
// 绘制矩形
// g.setColor(Color.black);
// g.setColor(Color.black);
// g.drawRect((int) birdRect.getX(), (int) birdRect.getY(), (int) birdRect.getWidth(), (int) birdRect.getHeight());
// g.drawRect((int) birdRect.getX(), (int) birdRect.getY(), (int) birdRect.getWidth(), (int) birdRect.getHeight());
}
}
public
static
final
int
SPEED_UP
=
32
;
// 小鸟向上的速度
public
static
final
int
ACC_FLAP
=
14
;
// players speed on flapping
public
static
final
double
g
=
9.8
;
// 重力加速度
public
static
final
double
ACC_Y
=
2
;
// players downward acceleration
public
static
final
double
T
=
0.2
;
// 小鸟的下落函数执行的时间
public
static
final
int
MAX_VEL_Y
=
15
;
// max vel along Y, max descend speed
private
double
speed
=
0
;
// 小鸟的初速度
private
int
velocity
=
0
;
// bird's velocity along Y, default same as playerFlapped
private
boolean
keyFlag
=
true
;
// 按键状态,true为已释放,使当按住按键时不会重复调用方法
private
boolean
keyFlag
=
true
;
// 按键状态,true为已释放,使当按住按键时不会重复调用方法
...
@@ -108,81 +112,83 @@ public class Bird {
...
@@ -108,81 +112,83 @@ public class Bird {
return
keyFlag
;
return
keyFlag
;
}
}
private
final
int
BOTTOM_BOUNDARY
=
Constant
.
FRAME_HEIGHT
-
GameBackground
.
GROUND_HEIGHT
-
(
BIRD_HEIGHT
/
2
);
int
TOP_BOUNDARY
=
30
;
// 小鸟的飞行逻辑
// 小鸟的飞行逻辑
private
void
fly
()
{
private
void
movement
()
{
// 翅膀状态,实现小鸟振翅飞行
// 翅膀状态,实现小鸟振翅飞行
wingState
++;
wingState
++;
image
=
birdImages
[
Math
.
min
(
state
,
STATE_FALL
)][
wingState
/
10
%
IMG_COUNT
];
image
=
birdImages
[
Math
.
min
(
state
,
BIRD_DEAD_FALL
)][
wingState
/
10
%
IMG_COUNT
];
// 下方边界: 窗口的高度 - 地面的高度 - 小鸟图片的高度
final
int
bottomBoundary
=
Constant
.
FRAME_HEIGHT
-
Constant
.
GROUND_HEIGHT
-
(
birdImages
[
0
][
0
].
getHeight
()
>>
1
);
final
int
topBoundary
=
-
50
;
switch
(
state
)
{
switch
(
state
)
{
case
STATE_DOWN
:
case
BIRD_FALL
:
// 自由落体
// 自由落体
speed
-=
g
*
T
;
if
(
velocity
<
MAX_VEL_Y
)
double
h
=
speed
*
T
-
g
*
T
*
T
/
2
;
velocity
-=
ACC_Y
;
y
=
Math
.
min
((
int
)
(
y
-
h
),
bottomBoundary
);
y
=
Math
.
min
((
y
-
velocity
),
BOTTOM_BOUNDARY
);
birdRect
.
y
=
Math
.
min
((
int
)
(
birdRect
.
y
-
h
),
bottomBoundary
)
;
birdRect
.
y
=
birdRect
.
y
-
velocity
;
if
(
birdRect
.
y
==
bottomBoundary
)
{
if
(
birdRect
.
y
>
BOTTOM_BOUNDARY
)
{
MusicUtil
.
playCrash
();
MusicUtil
.
playCrash
();
birdDead
();
die
();
}
}
break
;
break
;
case
STATE
_FALL:
case
BIRD_DEAD
_FALL:
// 自由落体
// 自由落体
speed
-=
g
*
T
;
if
(
velocity
<
MAX_VEL_Y
)
h
=
speed
*
T
-
g
*
T
*
T
/
2
;
velocity
-=
ACC_Y
;
y
=
Math
.
min
((
int
)
(
y
-
h
),
bottomBoundary
);
y
=
Math
.
min
((
y
-
velocity
),
BOTTOM_BOUNDARY
);
birdRect
.
y
=
Math
.
min
((
int
)
(
birdRect
.
y
-
h
),
bottomBoundary
);
birdRect
.
y
=
birdRect
.
y
-
velocity
;
if
(
birdRect
.
y
==
bottomBoundary
)
if
(
birdRect
.
y
>
BOTTOM_BOUNDARY
)
{
birdDead
();
die
();
}
break
;
break
;
case
STATE
_DEAD:
case
BIRD
_DEAD:
Game
Frame
.
setGameState
(
Game
Frame
.
STATE_OVER
);
Game
.
setGameState
(
Game
.
STATE_OVER
);
break
;
break
;
case
STATE
_NORMAL:
case
BIRD
_NORMAL:
case
STATE
_UP:
case
BIRD
_UP:
break
;
break
;
}
}
// 控制上方边界
if
(
birdRect
.
y
<
topBoundary
)
{
birdRect
.
y
=
topBoundary
;
y
=
topBoundary
;
}
}
}
// 小鸟振翅
// 小鸟振翅
public
void
bird
U
p
()
{
public
void
bird
Fla
p
()
{
if
(
keyIsReleased
())
{
// 如果按键已释放
if
(
keyIsReleased
())
{
// 如果按键已释放
if
(
state
==
STATE
_DEAD
||
state
==
STATE
_UP
||
state
==
STATE
_FALL
)
if
(
state
==
BIRD
_DEAD
||
state
==
BIRD
_UP
||
state
==
BIRD_DEAD
_FALL
)
return
;
// 小鸟死亡或坠落时返回
return
;
// 小鸟死亡或坠落时返回
MusicUtil
.
playFly
();
// 播放音效
MusicUtil
.
playFly
();
// 播放音效
state
=
STATE_UP
;
state
=
BIRD_UP
;
speed
=
SPEED_UP
;
// 每次振翅将速度改为上升速度
if
(
birdRect
.
y
>
TOP_BOUNDARY
)
{
wingState
=
0
;
// 重置翅膀状态
velocity
=
ACC_FLAP
;
// 每次振翅将速度改为上升速度
wingState
=
0
;
// 重置翅膀状态
}
keyPressed
();
keyPressed
();
}
}
}
}
// 小鸟下降
// 小鸟下降
public
void
bird
Down
()
{
public
void
bird
Fall
()
{
if
(
state
==
STATE
_DEAD
||
state
==
STATE
_FALL
)
if
(
state
==
BIRD
_DEAD
||
state
==
BIRD_DEAD
_FALL
)
return
;
// 小鸟死亡或坠落时返回
return
;
// 小鸟死亡或坠落时返回
state
=
STATE_DOWN
;
state
=
BIRD_FALL
;
}
public
void
die
(){
counter
.
saveScore
();
state
=
BIRD_DEAD
;
Game
.
setGameState
(
Game
.
STATE_OVER
);
}
}
// 小鸟坠落(已死)
// 小鸟坠落(已死)
public
void
b
irdFall
()
{
public
void
deadB
irdFall
()
{
state
=
STATE
_FALL
;
state
=
BIRD_DEAD
_FALL
;
MusicUtil
.
playCrash
();
// 播放音效
MusicUtil
.
playCrash
();
// 播放音效
speed
=
0
;
// 速度置0,防止小鸟继续上升与水管重叠
velocity
=
0
;
// 速度置0,防止小鸟继续上升与水管重叠
// 死后画面静止片刻
// 死后画面静止片刻
try
{
try
{
Thread
.
sleep
(
200
);
Thread
.
sleep
(
200
);
...
@@ -191,85 +197,42 @@ public class Bird {
...
@@ -191,85 +197,42 @@ public class Bird {
}
}
}
}
// 小鸟死亡
public
void
birdDead
()
{
state
=
STATE_DEAD
;
// 加载游戏结束的资源
if
(
overImg
==
null
)
{
overImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
OVER_IMG_PATH
);
scoreImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
SCORE_IMG_PATH
);
againImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
AGAIN_IMG_PATH
);
}
countScore
.
isSaveScore
();
// 判断是否保存纪录
}
// 判断小鸟是否死亡
// 判断小鸟是否死亡
public
boolean
isDead
()
{
public
boolean
isDead
()
{
return
state
==
STATE
_FALL
||
state
==
STATE
_DEAD
;
return
state
==
BIRD_DEAD
_FALL
||
state
==
BIRD
_DEAD
;
}
}
// 绘制实时分数
// 绘制实时分数
private
void
drawScore
(
Graphics
g
)
{
private
void
drawScore
(
Graphics
g
)
{
g
.
setColor
(
Color
.
white
);
g
.
setColor
(
Color
.
white
);
g
.
setFont
(
Constant
.
CURRENT_SCORE_FONT
);
g
.
setFont
(
Constant
.
CURRENT_SCORE_FONT
);
String
str
=
Long
.
toString
(
count
Score
.
ge
tScore
());
String
str
=
Long
.
toString
(
count
er
.
getCurren
tScore
());
int
x
=
Constant
.
FRAME_WIDTH
-
GameUtil
.
getStringWidth
(
Constant
.
CURRENT_SCORE_FONT
,
str
)
>>
1
;
int
x
=
Constant
.
FRAME_WIDTH
-
GameUtil
.
getStringWidth
(
Constant
.
CURRENT_SCORE_FONT
,
str
)
>>
1
;
g
.
drawString
(
str
,
x
,
Constant
.
FRAME_HEIGHT
/
10
);
g
.
drawString
(
str
,
x
,
Constant
.
FRAME_HEIGHT
/
10
);
}
}
private
static
final
int
SCORE_LOCATE
=
5
;
// 位置补偿参数
private
int
flash
=
0
;
// 图片闪烁参数
// 绘制游戏结束的显示
private
void
drawGameOver
(
Graphics
g
)
{
// 绘制结束标志
int
x
=
Constant
.
FRAME_WIDTH
-
overImg
.
getWidth
()
>>
1
;
int
y
=
Constant
.
FRAME_HEIGHT
/
4
;
g
.
drawImage
(
overImg
,
x
,
y
,
null
);
// 绘制计分牌
x
=
Constant
.
FRAME_WIDTH
-
scoreImg
.
getWidth
()
>>
1
;
y
=
Constant
.
FRAME_HEIGHT
/
3
;
g
.
drawImage
(
scoreImg
,
x
,
y
,
null
);
// 绘制本局的分数
g
.
setColor
(
Color
.
white
);
g
.
setFont
(
Constant
.
SCORE_FONT
);
x
=
(
Constant
.
FRAME_WIDTH
-
scoreImg
.
getWidth
()
/
2
>>
1
)
+
SCORE_LOCATE
;
// 位置补偿
y
+=
scoreImg
.
getHeight
()
>>
1
;
String
str
=
Long
.
toString
(
countScore
.
getScore
());
x
-=
GameUtil
.
getStringWidth
(
Constant
.
SCORE_FONT
,
str
)
>>
1
;
y
+=
GameUtil
.
getStringHeight
(
Constant
.
SCORE_FONT
,
str
);
g
.
drawString
(
str
,
x
,
y
);
// 绘制最高分数
if
(
countScore
.
getBestScore
()
>
0
)
{
str
=
Long
.
toString
(
countScore
.
getBestScore
());
x
=
(
Constant
.
FRAME_WIDTH
+
scoreImg
.
getWidth
()
/
2
>>
1
)
-
SCORE_LOCATE
;
// 位置补偿
x
-=
GameUtil
.
getStringWidth
(
Constant
.
SCORE_FONT
,
str
)
>>
1
;
g
.
drawString
(
str
,
x
,
y
);
}
// 绘制继续游戏,使图像闪烁
final
int
COUNT
=
30
;
// 闪烁周期
if
(
flash
++
>
COUNT
)
GameUtil
.
drawImage
(
againImg
,
Constant
.
FRAME_WIDTH
-
againImg
.
getWidth
()
>>
1
,
Constant
.
FRAME_HEIGHT
/
5
*
3
,
g
);
if
(
flash
==
COUNT
*
2
)
// 重置闪烁参数
flash
=
0
;
}
// 重置小鸟
// 重置小鸟
public
void
reset
()
{
public
void
reset
()
{
state
=
STATE
_NORMAL
;
// 小鸟状态
state
=
BIRD
_NORMAL
;
// 小鸟状态
y
=
Constant
.
FRAME_HEIGHT
>>
1
;
// 小鸟坐标
y
=
Constant
.
FRAME_HEIGHT
>>
1
;
// 小鸟坐标
speed
=
0
;
// 小鸟速度
velocity
=
0
;
// 小鸟速度
int
ImgHeight
=
birdImages
[
state
][
0
].
getHeight
();
int
ImgHeight
=
birdImages
[
state
][
0
].
getHeight
();
birdRect
.
y
=
y
-
ImgHeight
/
2
+
RECT_DESCALE
*
2
;
// 小鸟碰撞矩形坐标
birdRect
.
y
=
y
-
ImgHeight
/
2
+
RECT_DESCALE
*
2
;
// 小鸟碰撞矩形坐标
countScore
.
reset
();
// 重置计分器
counter
.
reset
();
// 重置计分器
flash
=
0
;
}
public
long
getCurrentScore
()
{
return
counter
.
getCurrentScore
();
}
public
long
getBestScore
()
{
return
counter
.
getBestScore
();
}
public
int
getBirdX
()
{
return
x
;
}
}
// 获取小鸟的碰撞矩形
// 获取小鸟的碰撞矩形
...
...
src/
com/
bird/
main
/Cloud.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/Cloud.java
View file @
5676508a
package
com.bird.main
;
package
com.kingyu.flappybird.game
;
import
com.kingyu.flappybird.util.Constant
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
...
@@ -25,7 +27,7 @@ public class Cloud {
...
@@ -25,7 +27,7 @@ public class Cloud {
this
.
img
=
img
;
this
.
img
=
img
;
this
.
x
=
x
;
this
.
x
=
x
;
this
.
y
=
y
;
this
.
y
=
y
;
this
.
speed
=
2
;
//云朵的速度
this
.
speed
=
Constant
.
GAME_SPEED
*
2
;
//云朵的速度
// 云朵图片缩放的比例 1.0~2.0
// 云朵图片缩放的比例 1.0~2.0
double
scale
=
1
+
Math
.
random
();
// Math.random()返回0.0~1.0的随机值
double
scale
=
1
+
Math
.
random
();
// Math.random()返回0.0~1.0的随机值
// 缩放云朵图片
// 缩放云朵图片
...
...
src/
com/bird/main/G
ame
Fr
ame.java
→
src/
main/java/com/kingyu/flappybird/g
ame
/G
ame.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
static
com
.
bird
.
util
.
Constant
.
FRAME_HEIGHT
;
import
static
com
.
kingyu
.
flappy
bird
.
util
.
Constant
.
FRAME_HEIGHT
;
import
static
com
.
bird
.
util
.
Constant
.
FRAME_WIDTH
;
import
static
com
.
kingyu
.
flappy
bird
.
util
.
Constant
.
FRAME_WIDTH
;
import
static
com
.
bird
.
util
.
Constant
.
FRAME_X
;
import
static
com
.
kingyu
.
flappy
bird
.
util
.
Constant
.
FRAME_X
;
import
static
com
.
bird
.
util
.
Constant
.
FRAME_Y
;
import
static
com
.
kingyu
.
flappy
bird
.
util
.
Constant
.
FRAME_Y
;
import
static
com
.
bird
.
util
.
Constant
.
GAME_INTERVAL
;
import
static
com
.
kingyu
.
flappy
bird
.
util
.
Constant
.
GAME_INTERVAL
;
import
static
com
.
bird
.
util
.
Constant
.
GAME_TITLE
;
import
static
com
.
kingyu
.
flappy
bird
.
util
.
Constant
.
GAME_TITLE
;
import
java.awt.Frame
;
import
java.awt.Frame
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
...
@@ -22,22 +22,22 @@ import java.awt.image.BufferedImage;
...
@@ -22,22 +22,22 @@ import java.awt.image.BufferedImage;
* @author Kingyu
* @author Kingyu
*/
*/
public
class
Game
Frame
extends
Frame
implements
Runnable
{
public
class
Game
extends
Frame
implements
Runnable
{
private
static
final
long
serialVersionUID
=
1L
;
// 保持版本的兼容性
private
static
final
long
serialVersionUID
=
1L
;
// 保持版本的兼容性
private
static
int
gameState
;
// 游戏状态
private
static
int
gameState
;
// 游戏状态
public
static
final
int
STAT
E_READY
=
0
;
// 游戏未开始
public
static
final
int
GAM
E_READY
=
0
;
// 游戏未开始
public
static
final
int
STAT
E_START
=
1
;
// 游戏开始
public
static
final
int
GAM
E_START
=
1
;
// 游戏开始
public
static
final
int
STATE_OVER
=
2
;
// 游戏结束
public
static
final
int
STATE_OVER
=
2
;
// 游戏结束
private
GameBackground
background
;
// 游戏背景对象
private
GameBackground
background
;
// 游戏背景对象
private
GameForeground
foreground
;
// 游戏前景对象
private
GameForeground
foreground
;
// 游戏前景对象
private
Bird
bird
;
// 小鸟对象
private
Bird
bird
;
// 小鸟对象
private
GameElementLayer
gameElement
;
// 游戏元素对象
private
GameElementLayer
gameElement
;
// 游戏元素对象
private
GameReady
ready
;
// 游戏未开始时对象
private
WelcomeAnimation
welcomeAnimation
;
// 游戏未开始时对象
// 在构造器中初始化
// 在构造器中初始化
public
Game
Frame
()
{
public
Game
()
{
initFrame
();
// 初始化游戏窗口
initFrame
();
// 初始化游戏窗口
setVisible
(
true
);
// 窗口默认为不可见,设置为可见
setVisible
(
true
);
// 窗口默认为不可见,设置为可见
initGame
();
// 初始化游戏对象
initGame
();
// 初始化游戏对象
...
@@ -65,19 +65,19 @@ public class GameFrame extends Frame implements Runnable {
...
@@ -65,19 +65,19 @@ public class GameFrame extends Frame implements Runnable {
public
void
keyPressed
(
KeyEvent
e
)
{
public
void
keyPressed
(
KeyEvent
e
)
{
int
keycode
=
e
.
getKeyChar
();
int
keycode
=
e
.
getKeyChar
();
switch
(
gameState
)
{
switch
(
gameState
)
{
case
STAT
E_READY:
case
GAM
E_READY:
if
(
keycode
==
KeyEvent
.
VK_SPACE
)
{
if
(
keycode
==
KeyEvent
.
VK_SPACE
)
{
// 游戏启动界面时按下空格,小鸟振翅一次并开始受重力影响
// 游戏启动界面时按下空格,小鸟振翅一次并开始受重力影响
bird
.
bird
U
p
();
bird
.
bird
Fla
p
();
bird
.
bird
Down
();
bird
.
bird
Fall
();
setGameState
(
STAT
E_START
);
// 游戏状态改变
setGameState
(
GAM
E_START
);
// 游戏状态改变
}
}
break
;
break
;
case
STAT
E_START:
case
GAM
E_START:
if
(
keycode
==
KeyEvent
.
VK_SPACE
)
{
if
(
keycode
==
KeyEvent
.
VK_SPACE
)
{
//游戏过程中按下空格则振翅一次,并持续受重力影响
//游戏过程中按下空格则振翅一次,并持续受重力影响
bird
.
bird
U
p
();
bird
.
bird
Fla
p
();
bird
.
bird
Down
();
bird
.
bird
Fall
();
}
}
break
;
break
;
case
STATE_OVER:
case
STATE_OVER:
...
@@ -91,7 +91,7 @@ public class GameFrame extends Frame implements Runnable {
...
@@ -91,7 +91,7 @@ public class GameFrame extends Frame implements Runnable {
// 重新开始游戏
// 重新开始游戏
private
void
resetGame
()
{
private
void
resetGame
()
{
setGameState
(
STAT
E_READY
);
setGameState
(
GAM
E_READY
);
gameElement
.
reset
();
gameElement
.
reset
();
bird
.
reset
();
bird
.
reset
();
}
}
...
@@ -113,9 +113,9 @@ public class GameFrame extends Frame implements Runnable {
...
@@ -113,9 +113,9 @@ public class GameFrame extends Frame implements Runnable {
background
=
new
GameBackground
();
background
=
new
GameBackground
();
gameElement
=
new
GameElementLayer
();
gameElement
=
new
GameElementLayer
();
foreground
=
new
GameForeground
();
foreground
=
new
GameForeground
();
ready
=
new
GameReady
();
welcomeAnimation
=
new
WelcomeAnimation
();
bird
=
new
Bird
();
bird
=
new
Bird
();
setGameState
(
STAT
E_READY
);
setGameState
(
GAM
E_READY
);
// 启动用于刷新窗口的线程
// 启动用于刷新窗口的线程
new
Thread
(
this
).
start
();
new
Thread
(
this
).
start
();
...
@@ -139,8 +139,8 @@ public class GameFrame extends Frame implements Runnable {
...
@@ -139,8 +139,8 @@ public class GameFrame extends Frame implements Runnable {
foreground
.
draw
(
bufG
,
bird
);
// 前景层
foreground
.
draw
(
bufG
,
bird
);
// 前景层
// 鸟
// 鸟
if
(
gameState
==
STAT
E_READY
)
{
// 游戏未开始
if
(
gameState
==
GAM
E_READY
)
{
// 游戏未开始
ready
.
draw
(
bufG
);
welcomeAnimation
.
draw
(
bufG
);
}
else
{
// 游戏结束
}
else
{
// 游戏结束
gameElement
.
draw
(
bufG
,
bird
);
// 游戏元素层
gameElement
.
draw
(
bufG
,
bird
);
// 游戏元素层
}
}
...
@@ -148,7 +148,6 @@ public class GameFrame extends Frame implements Runnable {
...
@@ -148,7 +148,6 @@ public class GameFrame extends Frame implements Runnable {
g
.
drawImage
(
bufImg
,
0
,
0
,
null
);
// 一次性将图片绘制到屏幕上
g
.
drawImage
(
bufImg
,
0
,
0
,
null
);
// 一次性将图片绘制到屏幕上
}
}
// TODO: 不建议在while循环中使用sleep
@SuppressWarnings
(
"InfiniteLoopStatement"
)
@SuppressWarnings
(
"InfiniteLoopStatement"
)
@Override
@Override
public
void
run
()
{
public
void
run
()
{
...
@@ -162,8 +161,10 @@ public class GameFrame extends Frame implements Runnable {
...
@@ -162,8 +161,10 @@ public class GameFrame extends Frame implements Runnable {
}
}
}
}
public
static
int
getGameState
(){
return
gameState
;};
public
static
void
setGameState
(
int
gameState
)
{
public
static
void
setGameState
(
int
gameState
)
{
Game
Frame
.
gameState
=
gameState
;
Game
.
gameState
=
gameState
;
}
}
}
}
src/
com/
bird/
main
/GameBackground.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/GameBackground.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
import
com.bird.util.GameUtil
;
import
com.
kingyu.flappy
bird.util.GameUtil
;
/**
/**
* 游戏背景类,绘制游戏背景的内容都在此类
* 游戏背景类,绘制游戏背景的内容都在此类
...
@@ -19,15 +19,19 @@ public class GameBackground {
...
@@ -19,15 +19,19 @@ public class GameBackground {
private
final
int
speed
;
// 背景层的速度
private
final
int
speed
;
// 背景层的速度
private
int
layerX
;
// 背景层的坐标
private
int
layerX
;
// 背景层的坐标
public
static
final
int
GROUND_HEIGHT
;
static
{
BackgroundImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
BG_IMG_PATH
);
assert
BackgroundImg
!=
null
;
GROUND_HEIGHT
=
BackgroundImg
.
getHeight
()
/
2
;
}
// 在构造器中初始化
// 在构造器中初始化
public
GameBackground
()
{
public
GameBackground
()
{
this
.
speed
=
1
;
this
.
speed
=
Constant
.
GAME_SPEED
;
this
.
layerX
=
0
;
this
.
layerX
=
0
;
}
}
static
{
//读取背景图片
BackgroundImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
BG_IMG_PATH
);
}
// 绘制方法
// 绘制方法
public
void
draw
(
Graphics
g
,
Bird
bird
)
{
public
void
draw
(
Graphics
g
,
Bird
bird
)
{
...
...
src/
com/
bird/
main
/GameElementLayer.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/GameElementLayer.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
import
com.bird.util.GameUtil
;
import
com.
kingyu.flappy
bird.util.GameUtil
;
/**
/**
* 游戏中各种元素层的类
* 游戏中各种元素层的类
...
@@ -70,11 +70,14 @@ public class GameElementLayer {
...
@@ -70,11 +70,14 @@ public class GameElementLayer {
}
else
{
}
else
{
// 判断最后一对水管是否完全进入游戏窗口,若进入则添加水管
// 判断最后一对水管是否完全进入游戏窗口,若进入则添加水管
Pipe
lastPipe
=
pipes
.
get
(
pipes
.
size
()
-
1
);
// 获得容器中最后一个水管
Pipe
lastPipe
=
pipes
.
get
(
pipes
.
size
()
-
1
);
// 获得容器中最后一个水管
int
currentDistance
=
lastPipe
.
getX
()
-
bird
.
getBirdX
()
+
Bird
.
BIRD_WIDTH
/
2
;
// 小鸟和最后一根水管的距离
final
int
SCORE_DISTANCE
=
Pipe
.
PIPE_WIDTH
*
2
+
HORIZONTAL_INTERVAL
;
// 小于得分距离则得分
if
(
lastPipe
.
isInFrame
())
{
if
(
lastPipe
.
isInFrame
())
{
if
(
pipes
.
size
()
>=
Constant
.
FULL_PIPE
-
2
)
// 若窗口中可容纳的水管已满,说明小鸟已飞到第一对水管的位置,开始记分
if
(
pipes
.
size
()
>=
PipePool
.
FULL_PIPE
-
2
)
{
GameScore
.
getInstance
().
setScore
(
bird
);
ScoreCounter
.
getInstance
().
score
(
bird
);
}
try
{
try
{
int
currentScore
=
(
int
)
Game
Score
.
getInstance
().
getScore
()
+
1
;
// 获取当前分数
int
currentScore
=
(
int
)
Score
Counter
.
getInstance
().
get
Current
Score
()
+
1
;
// 获取当前分数
// 移动水管刷新的概率随当前分数递增,当得分大于19后全部刷新移动水管
// 移动水管刷新的概率随当前分数递增,当得分大于19后全部刷新移动水管
if
(
GameUtil
.
isInProbability
(
currentScore
,
20
))
{
if
(
GameUtil
.
isInProbability
(
currentScore
,
20
))
{
if
(
GameUtil
.
isInProbability
(
1
,
4
))
// 生成移动水管和移动悬浮水管的概率
if
(
GameUtil
.
isInProbability
(
1
,
4
))
// 生成移动水管和移动悬浮水管的概率
...
@@ -209,7 +212,7 @@ public class GameElementLayer {
...
@@ -209,7 +212,7 @@ public class GameElementLayer {
for
(
Pipe
pipe
:
pipes
)
{
for
(
Pipe
pipe
:
pipes
)
{
// 判断碰撞矩形是否有交集
// 判断碰撞矩形是否有交集
if
(
pipe
.
getPipeRect
().
intersects
(
bird
.
getBirdRect
()))
{
if
(
pipe
.
getPipeRect
().
intersects
(
bird
.
getBirdRect
()))
{
bird
.
b
irdFall
();
// 有交集则小鸟坠落
bird
.
deadB
irdFall
();
return
;
return
;
}
}
}
}
...
...
src/
com/
bird/
main
/GameForeground.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/GameForeground.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
import
com.bird.util.GameUtil
;
import
com.
kingyu.flappy
bird.util.GameUtil
;
/**
/**
* 前景类, 游戏中的遮挡层 包含多朵云
* 前景类, 游戏中的遮挡层 包含多朵云
...
...
src/main/java/com/kingyu/flappybird/game/GameOverAnimation.java
0 → 100644
View file @
5676508a
package
com.kingyu.flappybird.game
;
import
com.kingyu.flappybird.util.Constant
;
import
com.kingyu.flappybird.util.GameUtil
;
import
java.awt.*
;
import
java.awt.image.BufferedImage
;
/**
* 游戏结束界面
*
* @author Kingyu
*
*/
public
class
GameOverAnimation
{
private
final
BufferedImage
scoreImg
;
// 计分牌
private
final
BufferedImage
overImg
;
// 结束标志
private
final
BufferedImage
againImg
;
// 继续标志
public
GameOverAnimation
(){
overImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
OVER_IMG_PATH
);
scoreImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
SCORE_IMG_PATH
);
againImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
AGAIN_IMG_PATH
);
}
private
static
final
int
SCORE_LOCATE
=
5
;
// 计分牌位置补偿参数
private
int
flash
=
0
;
// 图片闪烁参数
public
void
draw
(
Graphics
g
,
Bird
bird
)
{
int
x
=
Constant
.
FRAME_WIDTH
-
overImg
.
getWidth
()
>>
1
;
int
y
=
Constant
.
FRAME_HEIGHT
/
4
;
g
.
drawImage
(
overImg
,
x
,
y
,
null
);
// 绘制计分牌
x
=
Constant
.
FRAME_WIDTH
-
scoreImg
.
getWidth
()
>>
1
;
y
=
Constant
.
FRAME_HEIGHT
/
3
;
g
.
drawImage
(
scoreImg
,
x
,
y
,
null
);
// 绘制本局的分数
g
.
setColor
(
Color
.
white
);
g
.
setFont
(
Constant
.
SCORE_FONT
);
x
=
(
Constant
.
FRAME_WIDTH
-
scoreImg
.
getWidth
()
/
2
>>
1
)
+
SCORE_LOCATE
;
// 位置补偿
y
+=
scoreImg
.
getHeight
()
>>
1
;
String
str
=
Long
.
toString
(
bird
.
getCurrentScore
());
x
-=
GameUtil
.
getStringWidth
(
Constant
.
SCORE_FONT
,
str
)
>>
1
;
y
+=
GameUtil
.
getStringHeight
(
Constant
.
SCORE_FONT
,
str
);
g
.
drawString
(
str
,
x
,
y
);
// 绘制最高分数
if
(
bird
.
getBestScore
()
>
0
)
{
str
=
Long
.
toString
(
bird
.
getBestScore
());
x
=
(
Constant
.
FRAME_WIDTH
+
scoreImg
.
getWidth
()
/
2
>>
1
)
-
SCORE_LOCATE
;
// 位置补偿
x
-=
GameUtil
.
getStringWidth
(
Constant
.
SCORE_FONT
,
str
)
>>
1
;
g
.
drawString
(
str
,
x
,
y
);
}
// 绘制继续游戏,图像闪烁
final
int
COUNT
=
30
;
// 闪烁周期
if
(
flash
++
>
COUNT
)
GameUtil
.
drawImage
(
againImg
,
Constant
.
FRAME_WIDTH
-
againImg
.
getWidth
()
>>
1
,
Constant
.
FRAME_HEIGHT
/
5
*
3
,
g
);
if
(
flash
==
COUNT
*
2
)
// 重置闪烁参数
flash
=
0
;
}
}
src/
com/
bird/
main
/MovingPipe.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/MovingPipe.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Graphics
;
import
java.awt.Graphics
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
/**
/**
* 移动水管类,继承Pipe类
* 移动水管类,继承Pipe类
...
...
src/
com/
bird/
main
/Pipe.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/Pipe.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Graphics
;
import
java.awt.*
;
import
java.awt.Rectangle
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
import
com.bird.util.GameUtil
;
import
com.
kingyu.flappy
bird.util.GameUtil
;
/**
/**
* 水管类
* 水管类
...
@@ -43,14 +42,13 @@ public class Pipe {
...
@@ -43,14 +42,13 @@ public class Pipe {
public
static
final
int
TYPE_HOVER_HARD
=
5
;
public
static
final
int
TYPE_HOVER_HARD
=
5
;
// 水管的速度
// 水管的速度
public
static
final
int
SPEED
=
1
;
int
speed
;
int
speed
;
Rectangle
pipeRect
;
// 水管的碰撞矩形
Rectangle
pipeRect
;
// 水管的碰撞矩形
// 构造器
// 构造器
public
Pipe
()
{
public
Pipe
()
{
this
.
speed
=
SPEED
;
this
.
speed
=
Constant
.
GAME_
SPEED
;
this
.
width
=
PIPE_WIDTH
;
this
.
width
=
PIPE_WIDTH
;
pipeRect
=
new
Rectangle
();
pipeRect
=
new
Rectangle
();
...
@@ -184,25 +182,4 @@ public class Pipe {
...
@@ -184,25 +182,4 @@ public class Pipe {
return
pipeRect
;
return
pipeRect
;
}
}
// 各参数的写入与获取
// public void setX(int x) {
// this.x = x;
// }
//
// public void setY(int y) {
// this.y = y;
// }
//
// public void setType(int type) {
// this.type = type;
// }
//
// public void setHeight(int height) {
// this.height = height;
// }
//
// public void setVisible(boolean visible) {
// this.visible = visible;
// }
}
}
src/
com/
bird/
main
/PipePool.java
→
src/
main/java/com/kingyu/flappy
bird/
game
/PipePool.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
com.bird.util.Constant
;
import
com.
kingyu.flappy
bird.util.Constant
;
/**
/**
* 为了避免反复地创建和销毁对象,使用对象池来提前创建好一些对象,使用时从对象池中获得,使用完后归还
* 为了避免反复地创建和销毁对象,使用对象池来提前创建好一些对象,使用时从对象池中获得,使用完后归还
...
@@ -16,13 +16,14 @@ public class PipePool {
...
@@ -16,13 +16,14 @@ public class PipePool {
private
static
final
List
<
MovingPipe
>
movingPool
=
new
ArrayList
<>();
// 池中对象的容器
private
static
final
List
<
MovingPipe
>
movingPool
=
new
ArrayList
<>();
// 池中对象的容器
public
static
final
int
MAX_PIPE_COUNT
=
30
;
// 对象池中对象的最大个数,自行定义
public
static
final
int
MAX_PIPE_COUNT
=
30
;
// 对象池中对象的最大个数,自行定义
public
static
final
int
FULL_PIPE
=
(
Constant
.
FRAME_WIDTH
/
(
Pipe
.
PIPE_HEAD_WIDTH
+
GameElementLayer
.
HORIZONTAL_INTERVAL
)
+
2
)
*
2
;
// 初始化水管容器,初始化水管的数量的计算方式见常量类中的注释
// 初始化水管容器,初始化水管的数量的计算方式见常量类中的注释
static
{
static
{
for
(
int
i
=
0
;
i
<
Constant
.
FULL_PIPE
;
i
++)
{
for
(
int
i
=
0
;
i
<
PipePool
.
FULL_PIPE
;
i
++)
{
pool
.
add
(
new
Pipe
());
pool
.
add
(
new
Pipe
());
}
}
for
(
int
i
=
0
;
i
<
Constant
.
FULL_PIPE
;
i
++)
{
for
(
int
i
=
0
;
i
<
PipePool
.
FULL_PIPE
;
i
++)
{
movingPool
.
add
(
new
MovingPipe
());
movingPool
.
add
(
new
MovingPipe
());
}
}
}
}
...
...
src/main/java/com/kingyu/flappybird/game/ScoreCounter.java
0 → 100644
View file @
5676508a
package
com.kingyu.flappybird.game
;
import
java.io.DataInputStream
;
import
java.io.DataOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
com.kingyu.flappybird.util.Constant
;
import
com.kingyu.flappybird.util.MusicUtil
;
/**
* 游戏计时类, 单例类,方便调用
*
* @author Kingyu
*
*/
public
class
ScoreCounter
{
private
static
final
ScoreCounter
scoreCounter
=
new
ScoreCounter
();
private
long
score
=
0
;
// 分数
private
long
bestScore
;
// 最高分数
private
ScoreCounter
()
{
bestScore
=
-
1
;
try
{
loadBestScore
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
public
static
ScoreCounter
getInstance
()
{
return
scoreCounter
;
}
// 装载最高纪录
private
void
loadBestScore
()
throws
Exception
{
File
file
=
new
File
(
Constant
.
SCORE_FILE_PATH
);
if
(
file
.
exists
())
{
DataInputStream
dis
=
new
DataInputStream
(
new
FileInputStream
(
file
));
bestScore
=
dis
.
readLong
();
dis
.
close
();
}
}
public
void
saveScore
()
{
bestScore
=
Math
.
max
(
bestScore
,
getCurrentScore
());
try
{
File
file
=
new
File
(
Constant
.
SCORE_FILE_PATH
);
DataOutputStream
dos
=
new
DataOutputStream
(
new
FileOutputStream
(
file
));
dos
.
writeLong
(
bestScore
);
dos
.
close
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
public
void
score
(
Bird
bird
)
{
if
(!
bird
.
isDead
())
{
MusicUtil
.
playScore
();
score
+=
1
;
}
}
public
long
getBestScore
()
{
return
bestScore
;
}
public
long
getCurrentScore
()
{
return
score
;
}
public
void
reset
()
{
score
=
0
;
}
}
\ No newline at end of file
src/
com/bird/main/GameReady
.java
→
src/
main/java/com/kingyu/flappybird/game/WelcomeAnimation
.java
View file @
5676508a
package
com.bird.
main
;
package
com.
kingyu.flappy
bird.
game
;
import
java.awt.Graphics
;
import
com.kingyu.flappybird.util.Constant
;
import
com.kingyu.flappybird.util.GameUtil
;
import
java.awt.*
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
import
com.bird.util.Constant
;
import
com.bird.util.GameUtil
;
/**
/**
* 游戏启动界面类
* 游戏启动界面类
*
*
* @author Kingyu
* @author Kingyu
*
*
*/
*/
public
class
GameReady
{
public
class
WelcomeAnimation
{
private
final
BufferedImage
titleImg
;
private
final
BufferedImage
titleImg
;
private
final
BufferedImage
noticeImg
;
private
final
BufferedImage
noticeImg
;
private
int
flash
=
0
;
// 图像闪烁参数
private
int
flash
Count
=
0
;
// 图像闪烁参数
// 构造器中进行初始化,装载图像资源
public
WelcomeAnimation
()
{
public
GameReady
()
{
titleImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
TITLE_IMG_PATH
);
titleImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
TITLE_IMG_PATH
);
noticeImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
NOTICE_IMG_PATH
);
noticeImg
=
GameUtil
.
loadBufferedImage
(
Constant
.
NOTICE_IMG_PATH
);
}
}
public
void
draw
(
Graphics
g
)
{
public
void
draw
(
Graphics
g
)
{
// 计算title图像的x、y坐标
int
x
=
(
Constant
.
FRAME_WIDTH
-
titleImg
.
getWidth
())
>>
1
;
int
x
=
Constant
.
FRAME_WIDTH
-
titleImg
.
getWidth
()
>>
1
;
//x坐标为窗口中央
int
y
=
Constant
.
FRAME_HEIGHT
/
3
;
int
y
=
Constant
.
FRAME_HEIGHT
/
3
;
//y坐标为游戏窗口的1/3处
g
.
drawImage
(
titleImg
,
x
,
y
,
null
);
g
.
drawImage
(
titleImg
,
x
,
y
,
null
);
// 绘制
// 使notice的图像闪烁
// 使notice的图像闪烁
final
int
C
OUNT
=
30
;
// 闪烁周期
final
int
C
YCLE
=
30
;
// 闪烁周期
if
(
flash
++
>
C
OUNT
)
if
(
flash
Count
++
>
C
YCLE
)
GameUtil
.
drawImage
(
noticeImg
,
Constant
.
FRAME_WIDTH
-
noticeImg
.
getWidth
()
>>
1
,
Constant
.
FRAME_HEIGHT
/
5
*
3
,
g
);
GameUtil
.
drawImage
(
noticeImg
,
Constant
.
FRAME_WIDTH
-
noticeImg
.
getWidth
()
>>
1
,
Constant
.
FRAME_HEIGHT
/
5
*
3
,
g
);
if
(
flash
==
C
OUNT
*
2
)
// 重置闪烁参数
if
(
flash
Count
==
C
YCLE
*
2
)
flash
=
0
;
flash
Count
=
0
;
}
}
}
}
src/
com/
bird/util/Constant.java
→
src/
main/java/com/kingyu/flappy
bird/util/Constant.java
View file @
5676508a
package
com.bird.util
;
package
com.
kingyu.flappy
bird.util
;
import
java.awt.Color
;
import
java.awt.Color
;
import
java.awt.Font
;
import
java.awt.Font
;
import
com.bird.main.GameElementLayer
;
import
com.bird.main.Pipe
;
/**
/**
* 常量类
* 常量类
*
*
...
@@ -55,11 +52,14 @@ public class Constant {
...
@@ -55,11 +52,14 @@ public class Constant {
public
static
final
String
SCORE_FILE_PATH
=
"resources/score"
;
// 分数文件路径
public
static
final
String
SCORE_FILE_PATH
=
"resources/score"
;
// 分数文件路径
// 游戏速度(水管及背景层的移动速度)
public
static
final
int
GAME_SPEED
=
4
;
// 游戏背景色
// 游戏背景色
public
static
final
Color
BG_COLOR
=
new
Color
(
0x4bc4cf
);
public
static
final
Color
BG_COLOR
=
new
Color
(
0x4bc4cf
);
// 游戏刷新率
// 游戏刷新率
public
static
final
int
GAME_INTERVAL
=
1000
/
6
0
;
public
static
final
int
GAME_INTERVAL
=
1000
/
3
0
;
// 标题栏高度
// 标题栏高度
public
static
final
int
TOP_BAR_HEIGHT
=
20
;
public
static
final
int
TOP_BAR_HEIGHT
=
20
;
...
@@ -77,7 +77,4 @@ public class Constant {
...
@@ -77,7 +77,4 @@ public class Constant {
public
static
final
Font
CURRENT_SCORE_FONT
=
new
Font
(
"华文琥珀"
,
Font
.
BOLD
,
32
);
// 字体
public
static
final
Font
CURRENT_SCORE_FONT
=
new
Font
(
"华文琥珀"
,
Font
.
BOLD
,
32
);
// 字体
public
static
final
Font
SCORE_FONT
=
new
Font
(
"华文琥珀"
,
Font
.
BOLD
,
24
);
// 字体
public
static
final
Font
SCORE_FONT
=
new
Font
(
"华文琥珀"
,
Font
.
BOLD
,
24
);
// 字体
// 窗口可容纳的水管数量+2, 由窗口宽度、水管宽度、水管间距算得
public
static
final
int
FULL_PIPE
=
(
Constant
.
FRAME_WIDTH
/
(
Pipe
.
PIPE_HEAD_WIDTH
+
GameElementLayer
.
HORIZONTAL_INTERVAL
)
+
2
)
*
2
;
}
}
src/
com/
bird/util/GameUtil.java
→
src/
main/java/com/kingyu/flappy
bird/util/GameUtil.java
View file @
5676508a
package
com.bird.util
;
package
com.
kingyu.flappy
bird.util
;
import
java.awt.*
;
import
java.awt.*
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.BufferedImage
;
...
...
src/
com/
bird/util/MusicUtil.java
→
src/
main/java/com/kingyu/flappy
bird/util/MusicUtil.java
View file @
5676508a
package
com.bird.util
;
package
com.
kingyu.flappy
bird.util
;
import
java.io.FileInputStream
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.IOException
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment