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
eb44ec32
Unverified
Commit
eb44ec32
authored
Dec 17, 2020
by
kingyuluk
Browse files
refactor: 优化代码
parent
5676508a
Changes
17
Hide whitespace changes
Inline
Side-by-side
FlappyBird.jar
View file @
eb44ec32
No preview for this file type
README.md
View file @
eb44ec32
...
...
@@ -12,8 +12,12 @@
[
RL FlappyBird
](
https://github.com/kingyuluk/RL-FlappyBird
)
基于本项目集成了Amazon的Deep Java Library (DJL),可以使用强化学习(DQN)训练Flappy Bird
## How to play
程序入口:app/GameApp.java
*
通过
```java -jar FlappyBird.jar```
直接运行
*
运行源码中的
```App:main```
方法
游戏使用空格键操作。
...
...
@@ -43,11 +47,11 @@
*
图片与音效资源皆来源于网络,仅供学习交流
## Package Contents
*
com.kingyu.flappybird.app 游戏
的入口
*
com.kingyu.flappybird.app 游戏
主体
*
com.kingyu.flappybird.
game
游戏的
主体
*
com.kingyu.flappybird.
component
游戏的
组件
*
com.kingyu.flappybird.util
自定义的
工具
*
com.kingyu.flappybird.util 工具
包
## [Change Log](https://github.com/kingyuluk/FlappyBird/blob/master/CHANGELOG.md)
...
...
src/main/java/com/kingyu/flappybird/app/
Game
App.java
→
src/main/java/com/kingyu/flappybird/app/App.java
View file @
eb44ec32
package
com.kingyu.flappybird.app
;
import
com.kingyu.flappybird.game.Game
;
/**
*
程序
入口
类
*
游戏
入口
*
* @author Kingyu
*
*/
public
class
GameApp
{
public
class
App
{
public
static
void
main
(
String
[]
args
)
{
new
Game
();
}
...
...
src/main/java/com/kingyu/flappybird/
game
/Game.java
→
src/main/java/com/kingyu/flappybird/
app
/Game.java
View file @
eb44ec32
package
com.kingyu.flappybird.game
;
package
com.kingyu.flappybird.app
;
import
com.kingyu.flappybird.component.GameElementLayer
;
import
com.kingyu.flappybird.component.Bird
;
import
com.kingyu.flappybird.component.GameBackground
;
import
com.kingyu.flappybird.component.GameForeground
;
import
com.kingyu.flappybird.component.WelcomeAnimation
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
FRAME_HEIGHT
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
FRAME_WIDTH
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
FRAME_X
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
FRAME_Y
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
GAME_INTERVAL
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
FPS
;
import
static
com
.
kingyu
.
flappybird
.
util
.
Constant
.
GAME_TITLE
;
import
java.awt.Frame
;
import
java.awt.Graphics
;
import
java.awt.event.KeyEvent
;
import
java.awt.event.KeyListener
;
import
java.awt.event.WindowAdapter
;
import
java.awt.event.WindowEvent
;
import
java.awt.event.*
;
import
java.awt.image.BufferedImage
;
/**
*
主窗口类,游戏
窗口
和
绘制
的相关内容
*
游戏主体,管理游戏的组件和
窗口绘制
*
* @author Kingyu
*/
public
class
Game
extends
Frame
implements
Runnable
{
public
class
Game
extends
Frame
{
private
static
final
long
serialVersionUID
=
1L
;
// 保持版本的兼容性
private
static
int
gameState
;
// 游戏状态
...
...
@@ -118,7 +121,16 @@ public class Game extends Frame implements Runnable {
setGameState
(
GAME_READY
);
// 启动用于刷新窗口的线程
new
Thread
(
this
).
start
();
new
Thread
(()
->{
while
(
true
)
{
repaint
();
// 通过调用repaint(),让JVM调用update()
try
{
Thread
.
sleep
(
FPS
);
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
}
}).
start
();
}
// 项目中存在两个线程:系统线程,自定义的线程:调用repaint()。
...
...
@@ -134,35 +146,17 @@ public class Game extends Frame implements Runnable {
public
void
update
(
Graphics
g
)
{
Graphics
bufG
=
bufImg
.
getGraphics
();
// 获得图片画笔
// 使用图片画笔将需要绘制的内容绘制到图片
background
.
draw
(
bufG
,
bird
);
// 背景层
foreground
.
draw
(
bufG
,
bird
);
// 前景层
// 鸟
if
(
gameState
==
GAME_READY
)
{
// 游戏未开始
welcomeAnimation
.
draw
(
bufG
);
}
else
{
// 游戏结束
gameElement
.
draw
(
bufG
,
bird
);
// 游戏元素层
}
bird
.
draw
(
bufG
);
// 鸟
bird
.
draw
(
bufG
);
g
.
drawImage
(
bufImg
,
0
,
0
,
null
);
// 一次性将图片绘制到屏幕上
}
@SuppressWarnings
(
"InfiniteLoopStatement"
)
@Override
public
void
run
()
{
while
(
true
)
{
repaint
();
// 通过调用repaint(),让JVM调用update()
try
{
Thread
.
sleep
(
GAME_INTERVAL
);
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
}
}
public
static
int
getGameState
(){
return
gameState
;};
public
static
void
setGameState
(
int
gameState
)
{
Game
.
gameState
=
gameState
;
}
...
...
src/main/java/com/kingyu/flappybird/
game
/Bird.java
→
src/main/java/com/kingyu/flappybird/
component
/Bird.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.awt.Color
;
import
java.awt.Graphics
;
import
java.awt.Rectangle
;
import
java.awt.image.BufferedImage
;
import
com.kingyu.flappybird.app.Game
;
import
com.kingyu.flappybird.util.Constant
;
import
com.kingyu.flappybird.util.GameUtil
;
import
com.kingyu.flappybird.util.MusicUtil
;
/**
* 小鸟类,小鸟的绘制与飞行逻辑
都在此类
* 小鸟类,
实现
小鸟的绘制与飞行逻辑
*
* @author Kingyu
*/
...
...
@@ -20,8 +21,7 @@ public class Bird {
private
final
BufferedImage
[][]
birdImages
;
// 小鸟的图片数组对象
private
final
int
x
;
private
int
y
;
// 小鸟的坐标
int
wingState
;
// 翅膀状态
private
int
wingState
;
// 翅膀状态
// 图片资源
private
BufferedImage
image
;
// 实时的小鸟图片
...
...
@@ -34,7 +34,7 @@ public class Bird {
public
static
final
int
BIRD_DEAD_FALL
=
3
;
public
static
final
int
BIRD_DEAD
=
4
;
private
final
Rectangle
birdRect
;
// 碰撞矩形
private
final
Rectangle
bird
Collision
Rect
;
// 碰撞矩形
public
static
final
int
RECT_DESCALE
=
2
;
// 补偿碰撞矩形宽高的参数
private
final
ScoreCounter
counter
;
// 计分器
...
...
@@ -67,7 +67,7 @@ public class Bird {
// 初始化碰撞矩形
int
rectX
=
x
-
BIRD_WIDTH
/
2
;
int
rectY
=
y
-
BIRD_HEIGHT
/
2
;
birdRect
=
new
Rectangle
(
rectX
+
RECT_DESCALE
,
rectY
+
RECT_DESCALE
*
2
,
BIRD_WIDTH
-
RECT_DESCALE
*
3
,
bird
Collision
Rect
=
new
Rectangle
(
rectX
+
RECT_DESCALE
,
rectY
+
RECT_DESCALE
*
2
,
BIRD_WIDTH
-
RECT_DESCALE
*
3
,
BIRD_WIDTH
-
RECT_DESCALE
*
4
);
// 碰撞矩形的坐标与小鸟相同
}
...
...
@@ -86,7 +86,7 @@ public class Bird {
gameOverAnimation
.
draw
(
g
,
this
);
else
if
(
state
!=
BIRD_DEAD_FALL
)
drawScore
(
g
);
// 绘制矩形
// 绘制
碰撞
矩形
// g.setColor(Color.black);
// g.drawRect((int) birdRect.getX(), (int) birdRect.getY(), (int) birdRect.getWidth(), (int) birdRect.getHeight());
}
...
...
@@ -94,76 +94,46 @@ public class Bird {
public
static
final
int
ACC_FLAP
=
14
;
// players speed on flapping
public
static
final
double
ACC_Y
=
2
;
// players downward acceleration
public
static
final
int
MAX_VEL_Y
=
15
;
// max vel along Y, max descend speed
private
int
velocity
=
0
;
// bird's velocity along Y, default same as playerFlapped
private
boolean
keyFlag
=
true
;
// 按键状态,true为已释放,使当按住按键时不会重复调用方法
public
void
keyPressed
()
{
keyFlag
=
false
;
}
public
void
keyReleased
()
{
keyFlag
=
true
;
}
public
boolean
keyIsReleased
()
{
return
keyFlag
;
}
private
final
int
BOTTOM_BOUNDARY
=
Constant
.
FRAME_HEIGHT
-
GameBackground
.
GROUND_HEIGHT
-
(
BIRD_HEIGHT
/
2
);
int
TOP_BOUNDARY
=
30
;
// 小鸟的飞行逻辑
private
void
movement
()
{
// 翅膀状态,实现小鸟振翅飞行
wingState
++;
image
=
birdImages
[
Math
.
min
(
state
,
BIRD_DEAD_FALL
)][
wingState
/
10
%
IMG_COUNT
];
switch
(
state
)
{
case
BIRD_FALL:
// 自由落体
if
(
velocity
<
MAX_VEL_Y
)
velocity
-=
ACC_Y
;
y
=
Math
.
min
((
y
-
velocity
),
BOTTOM_BOUNDARY
);
birdRect
.
y
=
birdRect
.
y
-
velocity
;
if
(
birdRect
.
y
>
BOTTOM_BOUNDARY
)
{
if
(
state
==
BIRD_FALL
||
state
==
BIRD_DEAD_FALL
)
{
freeFall
();
if
(
birdCollisionRect
.
y
>
BOTTOM_BOUNDARY
)
{
if
(
state
==
BIRD_FALL
)
{
MusicUtil
.
playCrash
();
die
();
}
break
;
case
BIRD_DEAD_FALL:
// 自由落体
if
(
velocity
<
MAX_VEL_Y
)
velocity
-=
ACC_Y
;
y
=
Math
.
min
((
y
-
velocity
),
BOTTOM_BOUNDARY
);
birdRect
.
y
=
birdRect
.
y
-
velocity
;
if
(
birdRect
.
y
>
BOTTOM_BOUNDARY
)
{
die
();
}
break
;
case
BIRD_DEAD:
Game
.
setGameState
(
Game
.
STATE_OVER
);
break
;
case
BIRD_NORMAL:
case
BIRD_UP:
break
;
die
();
}
}
}
private
void
freeFall
()
{
if
(
velocity
<
MAX_VEL_Y
)
velocity
-=
ACC_Y
;
y
=
Math
.
min
((
y
-
velocity
),
BOTTOM_BOUNDARY
);
birdCollisionRect
.
y
=
birdCollisionRect
.
y
-
velocity
;
}
private
void
die
()
{
counter
.
saveScore
();
state
=
BIRD_DEAD
;
Game
.
setGameState
(
Game
.
STATE_OVER
);
}
// 小鸟振翅
public
void
birdFlap
()
{
if
(
keyIsReleased
())
{
// 如果按键已释放
if
(
state
==
BIRD_DEAD
||
state
==
BIRD_UP
||
state
==
BIRD_DEAD_FALL
)
return
;
// 小鸟死亡或坠落时返回
if
(
keyIsReleased
())
{
if
(
isDead
()
)
return
;
MusicUtil
.
playFly
();
// 播放音效
state
=
BIRD_UP
;
if
(
bird
Rect
.
y
>
TOP_BOUNDARY
)
{
if
(
bird
CollisionRect
.
y
>
Constant
.
TOP_BAR_HEIGHT
)
{
velocity
=
ACC_FLAP
;
// 每次振翅将速度改为上升速度
wingState
=
0
;
// 重置翅膀状态
}
...
...
@@ -173,28 +143,16 @@ public class Bird {
// 小鸟下降
public
void
birdFall
()
{
if
(
state
==
BIRD_DEAD
||
state
==
BIRD_DEAD_FALL
)
return
;
// 小鸟死亡或坠落时返回
if
(
isDead
()
)
return
;
state
=
BIRD_FALL
;
}
public
void
die
(){
counter
.
saveScore
();
state
=
BIRD_DEAD
;
Game
.
setGameState
(
Game
.
STATE_OVER
);
}
// 小鸟坠落(已死)
public
void
deadBirdFall
()
{
state
=
BIRD_DEAD_FALL
;
MusicUtil
.
playCrash
();
// 播放音效
velocity
=
0
;
// 速度置0,防止小鸟继续上升与水管重叠
// 死后画面静止片刻
try
{
Thread
.
sleep
(
200
);
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
}
// 判断小鸟是否死亡
...
...
@@ -218,11 +176,25 @@ public class Bird {
velocity
=
0
;
// 小鸟速度
int
ImgHeight
=
birdImages
[
state
][
0
].
getHeight
();
birdRect
.
y
=
y
-
ImgHeight
/
2
+
RECT_DESCALE
*
2
;
// 小鸟碰撞矩形坐标
bird
Collision
Rect
.
y
=
y
-
ImgHeight
/
2
+
RECT_DESCALE
*
2
;
// 小鸟碰撞矩形坐标
counter
.
reset
();
// 重置计分器
}
private
boolean
keyFlag
=
true
;
// 按键状态,true为已释放,使当按住按键时不会重复调用方法
public
void
keyPressed
()
{
keyFlag
=
false
;
}
public
void
keyReleased
()
{
keyFlag
=
true
;
}
public
boolean
keyIsReleased
()
{
return
keyFlag
;
}
public
long
getCurrentScore
()
{
return
counter
.
getCurrentScore
();
}
...
...
@@ -236,7 +208,7 @@ public class Bird {
}
// 获取小鸟的碰撞矩形
public
Rectangle
getBirdRect
()
{
return
birdRect
;
public
Rectangle
getBird
Collision
Rect
()
{
return
bird
Collision
Rect
;
}
}
src/main/java/com/kingyu/flappybird/
game
/Cloud.java
→
src/main/java/com/kingyu/flappybird/
component
/Cloud.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
com.kingyu.flappybird.util.Constant
;
...
...
@@ -6,7 +6,7 @@ import java.awt.Graphics;
import
java.awt.image.BufferedImage
;
/**
* 云朵类
* 云朵类
,实现云朵的绘制和运动逻辑
*
* @author Kingyu
*/
...
...
src/main/java/com/kingyu/flappybird/
game
/GameBackground.java
→
src/main/java/com/kingyu/flappybird/
component
/GameBackground.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.awt.Graphics
;
import
java.awt.image.BufferedImage
;
...
...
@@ -7,7 +7,7 @@ import com.kingyu.flappybird.util.Constant;
import
com.kingyu.flappybird.util.GameUtil
;
/**
* 游戏背景类,
绘制
游戏背景的
内容都在此类
* 游戏背景类,
实现
游戏背景的
绘制
*
* @author Kingyu
*
...
...
@@ -51,11 +51,11 @@ public class GameBackground {
if
(
bird
.
isDead
())
{
//小鸟死亡则不再绘制
return
;
}
move
Logic
();
move
ment
();
}
// 背景层的运动逻辑
private
void
move
Logic
()
{
private
void
move
ment
()
{
layerX
+=
speed
;
if
(
layerX
>
BackgroundImg
.
getWidth
())
layerX
=
0
;
...
...
src/main/java/com/kingyu/flappybird/
game
/GameElementLayer.java
→
src/main/java/com/kingyu/flappybird/
component
/GameElementLayer.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.awt.Graphics
;
import
java.util.ArrayList
;
...
...
@@ -8,7 +8,7 @@ import com.kingyu.flappybird.util.Constant;
import
com.kingyu.flappybird.util.GameUtil
;
/**
* 游戏
中各种元素层的类
* 游戏
元素层,目前管理水管的生成逻辑并绘制容器中的水管
*
* @author Kingyu
*/
...
...
@@ -73,7 +73,8 @@ public class GameElementLayer {
int
currentDistance
=
lastPipe
.
getX
()
-
bird
.
getBirdX
()
+
Bird
.
BIRD_WIDTH
/
2
;
// 小鸟和最后一根水管的距离
final
int
SCORE_DISTANCE
=
Pipe
.
PIPE_WIDTH
*
2
+
HORIZONTAL_INTERVAL
;
// 小于得分距离则得分
if
(
lastPipe
.
isInFrame
())
{
if
(
pipes
.
size
()
>=
PipePool
.
FULL_PIPE
-
2
)
{
if
(
pipes
.
size
()
>=
PipePool
.
FULL_PIPE
-
2
&&
currentDistance
<=
SCORE_DISTANCE
+
Pipe
.
PIPE_WIDTH
*
3
/
2
)
{
ScoreCounter
.
getInstance
().
score
(
bird
);
}
try
{
...
...
@@ -211,7 +212,7 @@ public class GameElementLayer {
// 遍历水管容器
for
(
Pipe
pipe
:
pipes
)
{
// 判断碰撞矩形是否有交集
if
(
pipe
.
getPipeRect
().
intersects
(
bird
.
getBirdRect
()))
{
if
(
pipe
.
getPipeRect
().
intersects
(
bird
.
getBird
Collision
Rect
()))
{
bird
.
deadBirdFall
();
return
;
}
...
...
src/main/java/com/kingyu/flappybird/
game
/GameForeground.java
→
src/main/java/com/kingyu/flappybird/
component
/GameForeground.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.awt.Graphics
;
import
java.awt.image.BufferedImage
;
...
...
@@ -9,21 +9,18 @@ import com.kingyu.flappybird.util.Constant;
import
com.kingyu.flappybird.util.GameUtil
;
/**
* 前景
类, 游戏中的遮挡层 包含多朵云
* 前景
层,目前管理云朵的生成逻辑并绘制容器中的云朵
*
* @author Kingyu
*/
public
class
GameForeground
{
private
final
List
<
Cloud
>
clouds
;
// 云朵的容器
private
final
BufferedImage
[]
cloudImages
;
// 图片资源
private
long
time
;
// 控制云的逻辑运算周期
public
static
final
int
CLOUD_INTERVAL
=
100
;
//云朵刷新的逻辑运算的周期
public
GameForeground
()
{
clouds
=
new
ArrayList
<>();
//云朵的容器
// 读入图片资源
cloudImages
=
new
BufferedImage
[
Constant
.
CLOUD_IMAGE_COUNT
];
for
(
int
i
=
0
;
i
<
Constant
.
CLOUD_IMAGE_COUNT
;
i
++)
{
...
...
@@ -34,14 +31,14 @@ public class GameForeground {
// 绘制方法
public
void
draw
(
Graphics
g
,
Bird
bird
)
{
cloudLogic
();
cloud
Born
Logic
();
for
(
Cloud
cloud
:
clouds
)
{
cloud
.
draw
(
g
,
bird
);
}
}
// 云朵的控制
private
void
cloudLogic
()
{
private
void
cloud
Born
Logic
()
{
// 100ms运算一次
if
(
System
.
currentTimeMillis
()
-
time
>
CLOUD_INTERVAL
)
{
time
=
System
.
currentTimeMillis
();
// 重置time
...
...
@@ -74,7 +71,6 @@ public class GameForeground {
i
--;
}
}
}
}
}
src/main/java/com/kingyu/flappybird/
game
/GameOverAnimation.java
→
src/main/java/com/kingyu/flappybird/
component
/GameOverAnimation.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
com.kingyu.flappybird.util.Constant
;
import
com.kingyu.flappybird.util.GameUtil
;
...
...
src/main/java/com/kingyu/flappybird/component/MovingPipe.java
0 → 100644
View file @
eb44ec32
package
com.kingyu.flappybird.component
;
import
java.awt.Graphics
;
import
com.kingyu.flappybird.util.Constant
;
/**
* 移动水管类,继承Pipe类
*
* @author Kingyu
*/
public
class
MovingPipe
extends
Pipe
{
private
int
dealtY
;
// 移动水管的坐标
public
static
final
int
MAX_DELTA
=
50
;
// 最大移动距离
private
int
direction
;
public
static
final
int
DIR_UP
=
0
;
public
static
final
int
DIR_DOWN
=
1
;
// 构造器
public
MovingPipe
()
{
super
();
}
/**
* 设置水管参数
*
* @param x:x坐标
* @param y:y坐标
* @param height:水管高度
* @param type:水管类型
* @param visible:水管可见性
*/
public
void
setAttribute
(
int
x
,
int
y
,
int
height
,
int
type
,
boolean
visible
)
{
super
.
setAttribute
(
x
,
y
,
height
,
type
,
visible
);
dealtY
=
0
;
direction
=
DIR_DOWN
;
if
(
type
==
TYPE_TOP_HARD
)
{
direction
=
DIR_UP
;
}
}
// 绘制方法
public
void
draw
(
Graphics
g
,
Bird
bird
)
{
switch
(
type
)
{
case
TYPE_HOVER_HARD:
drawHoverHard
(
g
);
break
;
case
TYPE_TOP_HARD:
drawTopHard
(
g
);
break
;
case
TYPE_BOTTOM_HARD:
drawBottomHard
(
g
);
break
;
}
// 鸟死后水管停止移动
if
(
bird
.
isDead
())
{
return
;
}
movement
();
// 绘制碰撞矩形
// g.setColor(Color.black);
// g.drawRect((int) pipeRect.getX(), (int) pipeRect.getY(), (int) pipeRect.getWidth(), (int) pipeRect.getHeight());
}
// 绘制移动的悬浮水管
private
void
drawHoverHard
(
Graphics
g
)
{
// 拼接的个数
int
count
=
(
height
-
2
*
PIPE_HEAD_HEIGHT
)
/
PIPE_HEIGHT
+
1
;
// 绘制水管的上顶部
g
.
drawImage
(
imgs
[
2
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
y
+
dealtY
,
null
);
// 绘制水管的主体
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
g
.
drawImage
(
imgs
[
0
],
x
,
y
+
dealtY
+
i
*
PIPE_HEIGHT
+
PIPE_HEAD_HEIGHT
,
null
);
}
// 绘制水管的下底部
int
y
=
this
.
y
+
height
-
PIPE_HEAD_HEIGHT
;
g
.
drawImage
(
imgs
[
1
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
y
+
dealtY
,
null
);
}
// 绘制从上往下的移动水管
private
void
drawTopHard
(
Graphics
g
)
{
// 拼接的个数
int
count
=
(
height
-
PIPE_HEAD_HEIGHT
)
/
PIPE_HEIGHT
+
1
;
// 取整+1
// 绘制水管的主体
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
g
.
drawImage
(
imgs
[
0
],
x
,
y
+
dealtY
+
i
*
PIPE_HEIGHT
,
null
);
}
// 绘制水管的顶部
g
.
drawImage
(
imgs
[
1
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
height
-
Constant
.
TOP_PIPE_LENGTHENING
-
PIPE_HEAD_HEIGHT
+
dealtY
,
null
);
}
// 绘制从下往上的移动水管
private
void
drawBottomHard
(
Graphics
g
)
{
// 拼接的个数
int
count
=
(
height
-
PIPE_HEAD_HEIGHT
)
/
PIPE_HEIGHT
+
1
;
// 绘制水管的主体
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
g
.
drawImage
(
imgs
[
0
],
x
,
Constant
.
FRAME_HEIGHT
-
PIPE_HEIGHT
-
i
*
PIPE_HEIGHT
+
dealtY
,
null
);
}
// 绘制水管的顶部
g
.
drawImage
(
imgs
[
2
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
Constant
.
FRAME_HEIGHT
-
height
+
dealtY
,
null
);
}
/**
* 可动水管的运动逻辑
*/
private
void
movement
()
{
//x坐标的运动逻辑与普通水管相同
x
-=
speed
;
pipeRect
.
x
-=
speed
;
if
(
x
<
-
1
*
PIPE_HEAD_WIDTH
)
{
// 水管完全离开了窗口
visible
=
false
;
}
//水管上下移动的逻辑
if
(
direction
==
DIR_DOWN
)
{
dealtY
++;
if
(
dealtY
>
MAX_DELTA
)
{
direction
=
DIR_UP
;
}
}
else
{
dealtY
--;
if
(
dealtY
<=
0
)
{
direction
=
DIR_DOWN
;
}
}
pipeRect
.
y
=
this
.
y
+
dealtY
;
}
}
src/main/java/com/kingyu/flappybird/
game
/Pipe.java
→
src/main/java/com/kingyu/flappybird/
component
/Pipe.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.awt.*
;
import
java.awt.image.BufferedImage
;
...
...
@@ -7,7 +7,7 @@ import com.kingyu.flappybird.util.Constant;
import
com.kingyu.flappybird.util.GameUtil
;
/**
* 水管类
* 水管类
,实现水管的绘制与运动逻辑
*
* @author Kingyu
*/
...
...
@@ -108,7 +108,7 @@ public class Pipe {
if
(
bird
.
isDead
())
{
return
;
}
pipeLogic
();
movement
();
}
// 绘制从上往下的普通水管
...
...
@@ -155,7 +155,7 @@ public class Pipe {
/**
* 普通水管的运动逻辑
*/
private
void
pipeLogic
()
{
private
void
movement
()
{
x
-=
speed
;
pipeRect
.
x
-=
speed
;
if
(
x
<
-
1
*
PIPE_HEAD_WIDTH
)
{
// 水管完全离开了窗口
...
...
src/main/java/com/kingyu/flappybird/
game
/PipePool.java
→
src/main/java/com/kingyu/flappybird/
component
/PipePool.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -6,6 +6,7 @@ import java.util.List;
import
com.kingyu.flappybird.util.Constant
;
/**
* 水管对象池
* 为了避免反复地创建和销毁对象,使用对象池来提前创建好一些对象,使用时从对象池中获得,使用完后归还
*
* @author Kingyu
...
...
@@ -14,11 +15,10 @@ import com.kingyu.flappybird.util.Constant;
public
class
PipePool
{
private
static
final
List
<
Pipe
>
pool
=
new
ArrayList
<>();
// 池中对象的容器
private
static
final
List
<
MovingPipe
>
movingPool
=
new
ArrayList
<>();
// 池中对象的容器
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
{
for
(
int
i
=
0
;
i
<
PipePool
.
FULL_PIPE
;
i
++)
{
pool
.
add
(
new
Pipe
());
...
...
src/main/java/com/kingyu/flappybird/
game
/ScoreCounter.java
→
src/main/java/com/kingyu/flappybird/
component
/ScoreCounter.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
java.io.DataInputStream
;
import
java.io.DataOutputStream
;
...
...
@@ -10,13 +10,20 @@ 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
static
class
ScoreCounterHolder
{
private
static
final
ScoreCounter
scoreCounter
=
new
ScoreCounter
();
}
public
static
ScoreCounter
getInstance
()
{
return
ScoreCounterHolder
.
scoreCounter
;
}
private
long
score
=
0
;
// 分数
private
long
bestScore
;
// 最高分数
...
...
@@ -30,10 +37,6 @@ public class ScoreCounter {
}
}
public
static
ScoreCounter
getInstance
()
{
return
scoreCounter
;
}
// 装载最高纪录
private
void
loadBestScore
()
throws
Exception
{
File
file
=
new
File
(
Constant
.
SCORE_FILE_PATH
);
...
...
src/main/java/com/kingyu/flappybird/
game
/WelcomeAnimation.java
→
src/main/java/com/kingyu/flappybird/
component
/WelcomeAnimation.java
View file @
eb44ec32
package
com.kingyu.flappybird.
game
;
package
com.kingyu.flappybird.
component
;
import
com.kingyu.flappybird.util.Constant
;
import
com.kingyu.flappybird.util.GameUtil
;
...
...
@@ -7,7 +7,7 @@ import java.awt.*;
import
java.awt.image.BufferedImage
;
/**
* 游戏启动界面
类
* 游戏启动界面
*
* @author Kingyu
*
...
...
src/main/java/com/kingyu/flappybird/game/MovingPipe.java
deleted
100644 → 0
View file @
5676508a
package
com.kingyu.flappybird.game
;
import
java.awt.Graphics
;
import
com.kingyu.flappybird.util.Constant
;
/**
* 移动水管类,继承Pipe类
*
* @author Kingyu
*
*/
public
class
MovingPipe
extends
Pipe
{
private
int
dealtY
;
// 移动水管的坐标
public
static
final
int
MAX_DEALY
=
50
;
// 最大移动距离
private
int
dir
;
public
static
final
int
DIR_UP
=
0
;
public
static
final
int
DIR_DOWN
=
1
;
// 构造器
public
MovingPipe
()
{
super
();
}
/**
* 设置水管参数
*
* @param x:x坐标
* @param y:y坐标
* @param height:水管高度
* @param type:水管类型
* @param visible:水管可见性
*/
public
void
setAttribute
(
int
x
,
int
y
,
int
height
,
int
type
,
boolean
visible
)
{
this
.
x
=
x
;
this
.
y
=
y
;
this
.
height
=
height
;
this
.
type
=
type
;
this
.
visible
=
visible
;
setRectangle
(
this
.
x
,
this
.
y
,
this
.
height
);
dealtY
=
0
;
dir
=
DIR_DOWN
;
if
(
type
==
TYPE_TOP_HARD
)
{
dir
=
DIR_UP
;
}
}
// 绘制方法
public
void
draw
(
Graphics
g
,
Bird
bird
)
{
switch
(
type
)
{
case
TYPE_HOVER_HARD:
drawHoverHard
(
g
);
break
;
case
TYPE_TOP_HARD:
drawTopHard
(
g
);
break
;
case
TYPE_BOTTOM_HARD:
drawBottomHard
(
g
);
break
;
}
// 鸟死后水管停止移动
if
(
bird
.
isDead
())
{
return
;
}
pipeLogic
();
// 绘制碰撞矩形
// g.setColor(Color.black);
// g.drawRect((int) pipeRect.getX(), (int) pipeRect.getY(), (int) pipeRect.getWidth(), (int) pipeRect.getHeight());
}
// 绘制移动的悬浮水管
private
void
drawHoverHard
(
Graphics
g
)
{
// 拼接的个数
int
count
=
(
height
-
2
*
PIPE_HEAD_HEIGHT
)
/
PIPE_HEIGHT
+
1
;
// 绘制水管的上顶部
g
.
drawImage
(
imgs
[
2
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
y
+
dealtY
,
null
);
// 绘制水管的主体
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
g
.
drawImage
(
imgs
[
0
],
x
,
y
+
dealtY
+
i
*
PIPE_HEIGHT
+
PIPE_HEAD_HEIGHT
,
null
);
}
// 绘制水管的下底部
int
y
=
this
.
y
+
height
-
PIPE_HEAD_HEIGHT
;
g
.
drawImage
(
imgs
[
1
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
y
+
dealtY
,
null
);
}
// 绘制从上往下的移动水管
private
void
drawTopHard
(
Graphics
g
)
{
// 拼接的个数
int
count
=
(
height
-
PIPE_HEAD_HEIGHT
)
/
PIPE_HEIGHT
+
1
;
// 取整+1
// 绘制水管的主体
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
g
.
drawImage
(
imgs
[
0
],
x
,
y
+
dealtY
+
i
*
PIPE_HEIGHT
,
null
);
}
// 绘制水管的顶部
g
.
drawImage
(
imgs
[
1
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
height
-
Constant
.
TOP_PIPE_LENGTHENING
-
PIPE_HEAD_HEIGHT
+
dealtY
,
null
);
}
// 绘制从下往上的移动水管
private
void
drawBottomHard
(
Graphics
g
)
{
// 拼接的个数
int
count
=
(
height
-
PIPE_HEAD_HEIGHT
)
/
PIPE_HEIGHT
+
1
;
// 绘制水管的主体
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
g
.
drawImage
(
imgs
[
0
],
x
,
Constant
.
FRAME_HEIGHT
-
PIPE_HEIGHT
-
i
*
PIPE_HEIGHT
+
dealtY
,
null
);
}
// 绘制水管的顶部
g
.
drawImage
(
imgs
[
2
],
x
-
((
PIPE_HEAD_WIDTH
-
width
)
>>
1
),
Constant
.
FRAME_HEIGHT
-
height
+
dealtY
,
null
);
}
/**
* 可动水管的运动逻辑
*/
private
void
pipeLogic
()
{
//x坐标的运动逻辑与普通水管相同
x
-=
speed
;
pipeRect
.
x
-=
speed
;
if
(
x
<
-
1
*
PIPE_HEAD_WIDTH
)
{
// 水管完全离开了窗口
visible
=
false
;
}
//水管上下移动的逻辑
if
(
dir
==
DIR_DOWN
)
{
dealtY
++;
if
(
dealtY
>
MAX_DEALY
)
{
dir
=
DIR_UP
;
}
}
else
{
dealtY
--;
if
(
dealtY
<=
0
)
{
dir
=
DIR_DOWN
;
}
}
pipeRect
.
y
=
this
.
y
+
dealtY
;
}
}
src/main/java/com/kingyu/flappybird/util/Constant.java
View file @
eb44ec32
...
...
@@ -59,7 +59,7 @@ public class Constant {
public
static
final
Color
BG_COLOR
=
new
Color
(
0x4bc4cf
);
// 游戏刷新率
public
static
final
int
GAME_INTERVAL
=
1000
/
30
;
public
static
final
int
FPS
=
1000
/
30
;
// 标题栏高度
public
static
final
int
TOP_BAR_HEIGHT
=
20
;
...
...
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