接着上一篇,我们完成后续的扫尾工作:游戏中个物体创建及其碰撞检测,分数保存,音效处理。
1.World类:(加入所有物体,及其碰撞检测,代码里有详细注解)
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
|
package
com.zhf.mylibgdx;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.Random;
import
com.badlogic.gdx.math.Vector2;
/**
* 统一管理世界中各个部分
* @author ZHF
*
*/
public
class
World {
/**世界监听器接口**/
public
interface
WorldListener {
//跳跃
public
void
jump ();
//高跳
public
void
highJump ();
//碰撞
public
void
hit ();
//收集金币
public
void
coin ();
}
//宽和高
public
static
final
float
WORLD_WIDTH =
10
;
public
static
final
float
WORLD_HEIGHT =
15
*
20
;
//状态
public
static
final
int
WORLD_STATE_RUNNING =
0
;
//运行
public
static
final
int
WORLD_STATE_NEXT_LEVEL =
1
;
//下一关
public
static
final
int
WORLD_STATE_GAME_OVER =
2
;
//游戏结束
//世界监听器
public
WorldListener listener;
//重力
public
static
final
Vector2 gravity =
new
Vector2(
0
, -
12
);
//随机数
public
Random rand;
public
float
heightSoFar;
//
public
int
score;
public
int
state;
//游戏中物体
public
final
List<Platform> platforms;
//跳板
public
final
Bob bob;
//主角
public
final
List<Spring> springs;
//弹簧
public
final
List<Squirrel> squirrels;
//会飞的松鼠
public
final
List<Coin> coins;
//金币
public
Castle castle;
//城堡
public
World(WorldListener listener) {
this
.listener = listener;
//初始化游戏中的物体
this
.bob =
new
Bob(
5
,
1
);
this
.platforms =
new
ArrayList<Platform>();
this
.springs =
new
ArrayList<Spring>();
this
.squirrels =
new
ArrayList<Squirrel>();
this
.coins =
new
ArrayList<Coin>();
rand =
new
Random();
generateLevel();
//生成关卡中除了Bob外所有的物体
}
/**生成关卡中除了Bob外所有的物体**/
private
void
generateLevel() {
float
y = Platform.PLATFORM_HEIGHT /
2
;
float
maxJumpHeight = Bob.BOB_JUMP_VELOCITY * Bob.BOB_JUMP_VELOCITY / (
2
* -gravity.y);
while
(y < WORLD_HEIGHT - WORLD_WIDTH /
2
) {
int
type = rand.nextFloat() >
0
.8f ? Platform.PLATFORM_TYPE_MOVING : Platform.PLATFORM_TYPE_STATIC;
float
x = rand.nextFloat() * (WORLD_WIDTH - Platform.PLATFORM_WIDTH) + Platform.PLATFORM_WIDTH /
2
;
//跳板的位置
Platform platform =
new
Platform(type, x, y);
platforms.add(platform);
//弹簧的位置
if
(rand.nextFloat() >
0
.9f && type != Platform.PLATFORM_TYPE_MOVING) {
Spring spring =
new
Spring(platform.position.x, platform.position.y + Platform.PLATFORM_HEIGHT /
2
+ Spring.SPRING_HEIGHT /
2
);
springs.add(spring);
}
//松鼠的位置
if
(y > WORLD_HEIGHT /
3
&& rand.nextFloat() >
0
.8f) {
Squirrel squirrel =
new
Squirrel(platform.position.x + rand.nextFloat(), platform.position.y
+ Squirrel.SQUIRREL_HEIGHT + rand.nextFloat() *
2
);
squirrels.add(squirrel);
}
//金币的位置
if
(rand.nextFloat() >
0
.6f) {
Coin coin =
new
Coin(platform.position.x + rand.nextFloat(), platform.position.y + Coin.COIN_HEIGHT
+ rand.nextFloat() *
3
);
coins.add(coin);
}
//游戏中的物体的位置根据跳板的位置来确定
y += (maxJumpHeight -
0
.5f);
y -= rand.nextFloat() * (maxJumpHeight /
3
);
}
//城堡的位置是确定的
castle =
new
Castle(WORLD_WIDTH /
2
, y);
}
/**刷新界面**/
public
void
update(
float
deltaTime,
float
accelX) {
updateBob(deltaTime, accelX);
//刷新主角
updatePlatforms(deltaTime);
//刷新跳板
updateSquirrels(deltaTime);
//刷新松鼠
updateCoins(deltaTime);
//刷新金币
if
(bob.state != Bob.BOB_STATE_HIT) checkCollisions();
//游戏结束判断
checkGameOver();
}
/**碰撞检测**/
private
void
checkCollisions() {
// TODO Auto-generated method stub
checkPlatformCollisions();
//跳板的碰撞
checkSquirrelCollisions();
//松鼠的碰撞
checkItemCollisions();
//金币和弹簧的碰撞
checkCastleCollisions();
//城堡的碰撞
}
/**跳板碰撞**/
private
void
checkPlatformCollisions() {
if
(bob.velocity.y >
0
)
return
;
int
len = platforms.size();
for
(
int
i =
0
; i < len; i++) {
Platform platform = platforms.get(i);
if
(bob.position.y > platform.position.y) {
//调用工具类中矩形块碰撞检测
if
(OverlapTester.overlapRectangles(bob.bounds, platform.bounds)) {
bob.hitPlatform();
listener.jump();
if
(rand.nextFloat() >
0
.5f) {
platform.pulverize();
}
break
;
}
}
}
}
/**松鼠碰撞**/
private
void
checkSquirrelCollisions () {
int
len = squirrels.size();
for
(
int
i =
0
; i < len; i++) {
Squirrel squirrel = squirrels.get(i);
if
(OverlapTester.overlapRectangles(squirrel.bounds, bob.bounds)) {
bob.hitSquirrel();
listener.hit();
}
}
}
/**金币和弹簧碰撞**/
private
void
checkItemCollisions () {
int
len = coins.size();
for
(
int
i =
0
; i < len; i++) {
Coin coin = coins.get(i);
if
(OverlapTester.overlapRectangles(bob.bounds, coin.bounds)) {
coins.remove(coin);
len = coins.size();
listener.coin();
score += Coin.COIN_SCORE;
//加分
}
}
if
(bob.velocity.y >
0
)
return
;
//若是上升状态不去考虑碰撞检测
len = springs.size();
for
(
int
i =
0
; i < len; i++) {
Spring spring = springs.get(i);
if
(bob.position.y > spring.position.y) {
//弹簧的碰撞检测
if
(OverlapTester.overlapRectangles(bob.bounds, spring.bounds)) {
bob.hitSpring();
listener.highJump();
}
}
}
}
/**城堡的碰撞**/
private
void
checkCastleCollisions () {
if
(OverlapTester.overlapRectangles(castle.bounds, bob.bounds)) {
state = WORLD_STATE_NEXT_LEVEL;
}
}
/**刷新Bob**/
private
void
updateBob(
float
deltaTime,
float
accelX) {
//碰撞跳板
if
(bob.state != Bob.BOB_STATE_HIT && bob.position.y <=
0
.5f) bob.hitPlatform();
//主角x轴方向移动的速度
if
(bob.state != Bob.BOB_STATE_HIT) bob.velocity.x = -accelX /
10
* Bob.BOB_MOVE_VELOCITY;
bob.update(deltaTime);
//竖直最大高度
heightSoFar = Math.max(bob.position.y, heightSoFar);
}
/**刷新跳板**/
private
void
updatePlatforms(
float
deltaTime) {
int
len = platforms.size();
for
(
int
i =
0
; i < len; i++) {
Platform platform = platforms.get(i);
//取出集合中的跳板对象,调用其自身的刷新方法
platform.update(deltaTime);
//若状态为破碎状态,将该跳板对象移除出去
if
(platform.state == Platform.PLATFORM_STATE_PULVERIZING && platform.stateTime > Platform.PLATFORM_PULVERIZE_TIME) {
platforms.remove(platform);
len = platforms.size();
}
}
}
/**刷新松鼠**/
private
void
updateSquirrels (
float
deltaTime) {
int
len = squirrels.size();
for
(
int
i =
0
; i < len; i++) {
Squirrel squirrel = squirrels.get(i);
squirrel.update(deltaTime);
}
}
/**刷新金币**/
private
void
updateCoins (
float
deltaTime) {
int
len = coins.size();
for
(
int
i =
0
; i < len; i++) {
Coin coin = coins.get(i);
coin.update(deltaTime);
}
}
/**游戏结束判断**/
private
void
checkGameOver () {
//目前的Bob的高度小于场景的高度
if
(heightSoFar -
7
.5f > bob.position.y) {
state = WORLD_STATE_GAME_OVER;
}
}
}
|
看着代码挺多,其实就是一个update()和checkCollisions(),还有重要的generateLevel()。接下来就是渲染WorldRenderer类中绘制各个物体
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/**渲染游戏中各种物体(Bob,跳板,松鼠,弹簧,城堡,金币)**/
private
void
renderObjects() {
batch.enableBlending();
batch.begin();
renderPlatforms();
//绘制跳板
renderBob();
//绘制主角
renderItems();
//绘制金币和弹簧
renderSquirrels();
//绘制松鼠
renderCastle();
//绘制城堡
batch.end();
}
|
由于代码过多,这里就不一一贴出来了,大家可以自行参考源码,有注解的哦!
既然添加了游戏中的物体,那自然又得在Asset中加载资源
声明:
1
2
3
4
5
6
7
8
9
10
11
12
|
//游戏中各种物体
public
static
TextureRegion platform;
//跳板
public
static
Animation brakingPlatform;
//破碎的跳板(动画)
//主角
public
static
Animation bobJump;
//跳跃(动画)
public
static
Animation bobFall;
//下落(动画)
public
static
TextureRegion bobHit;
//碰撞图片
public
static
TextureRegion spring;
//弹簧
public
static
TextureRegion castle;
//城堡
public
static
Animation coinAnim;
//金币 (动画)
public
static
Animation squirrelFly;
//飞着的松鼠 (动画)
|
实例化:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//游戏中各个物体
platform =
new
TextureRegion(items,
64
,
160
,
64
,
16
);
//跳板
brakingPlatform =
new
Animation(
0
.2f,
new
TextureRegion(items,
64
,
160
,
64
,
16
),
new
TextureRegion(items,
64
,
176
,
64
,
16
),
new
TextureRegion(items,
64
,
192
,
64
,
16
),
new
TextureRegion(items,
64
,
208
,
64
,
16
));
//破碎的跳板
spring =
new
TextureRegion(items,
128
,
0
,
32
,
32
);
//弹簧
castle =
new
TextureRegion(items,
128
,
64
,
64
,
64
);
//城堡
coinAnim =
new
Animation(
0
.2f,
new
TextureRegion(items,
128
,
32
,
32
,
32
),
new
TextureRegion(items,
160
,
32
,
32
,
32
),
new
TextureRegion(items,
192
,
32
,
32
,
32
),
new
TextureRegion(items,
160
,
32
,
32
,
32
));
//金币
squirrelFly =
new
Animation(
0
.2f,
new
TextureRegion(items,
0
,
160
,
32
,
32
),
new
TextureRegion(items,
32
,
160
,
32
,
32
));
//飞着的松鼠
//主角
bobJump =
new
Animation(
0
.2f,
new
TextureRegion(items,
0
,
128
,
32
,
32
),
new
TextureRegion(items,
32
,
128
,
32
,
32
));
bobFall =
new
Animation(
0
.2f,
new
TextureRegion(items,
64
,
128
,
32
,
32
),
new
TextureRegion(items,
96
,
128
,
32
,
32
));
bobHit =
new
TextureRegion(items,
128
,
128
,
32
,
32
);
|
运行一下代码,我们发现,我们操作者主角向上移动,会遇到弹簧,会破碎的跳板,飞着的松鼠,金币,一切都正常的运行着! 仔细一看,加上金币后分数值没有改变哦!当然还有死亡的判断,音效的加入等等。
效果图:
在此先做一个代码版本,方便初学者能够清楚的了解代码
源码下载:http://down.51cto.com/data/897211
下面我们来完成分值的计算:
在GameScreen中:
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
|
/**游戏运行状态**/
private
void
updateRunning (
float
deltaTime) {
if
(Gdx.input.justTouched()) {
guiCam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(),
0
));
//点击暂停
if
(OverlapTester.pointInRectangle(pauseBounds, touchPoint.x, touchPoint.y)) {
Assets.playSound(Assets.clickSound);
state = GAME_PAUSED;
return
;
}
}
ApplicationType appType = Gdx.app.getType();
// should work also with Gdx.input.isPeripheralAvailable(Peripheral.Accelerometer)
if
(appType == ApplicationType.Android || appType == ApplicationType.iOS) {
world.update(deltaTime, Gdx.input.getAccelerometerX());
}
else
{
float
accel =
0
;
if
(Gdx.input.isKeyPressed(Keys.DPAD_LEFT)) accel = 5f;
if
(Gdx.input.isKeyPressed(Keys.DPAD_RIGHT)) accel = -5f;
world.update(deltaTime, accel);
}
//当前分数(变化)
if
(world.score != lastScore) {
lastScore = world.score;
scoreString =
"SCORE: "
+ lastScore;
}
//本关结束
if
(world.state == World.WORLD_STATE_NEXT_LEVEL) {
state = GAME_LEVEL_END;
}
//游戏结束,分值计算
if
(world.state == World.WORLD_STATE_GAME_OVER) {
state = GAME_OVER;
if
(lastScore >= Settings.highscores[
4
])
scoreString =
"NEW HIGHSCORE: "
+ lastScore;
else
scoreString =
"SCORE: "
+ lastScore;
//获取最后分数
Settings.addScore(lastScore);
//保存分数
Settings.save();
}
}
|
这里我们每次碰到金币就会加上10分,到游戏结束后,将最终得分保存起来,同时更新排行榜。
Settings:
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
|
package
com.zhf.mylibgdx;
import
java.io.BufferedReader;
import
java.io.BufferedWriter;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.OutputStreamWriter;
import
com.badlogic.gdx.Gdx;
/**
* 设置类:三个方法: 1.load()读取声音开关和最高分. 2.save()保存配置 3.addScore()最高分排行榜,对数组赋值。
* @author ZHF
*
*/
public
class
Settings {
//记录声音开起与关闭
public
static
boolean
soundEnabled =
true
;
//默认分数排行榜分数
public
final
static
int
[] highscores =
new
int
[] {
100
,
80
,
50
,
30
,
10
};
//保存的文件名
public
final
static
String file =
".superjumper"
;
/**加载配置文件**/
public
static
void
load () {
BufferedReader in =
null
;
try
{
in =
new
BufferedReader(
new
InputStreamReader(Gdx.files.external(file).read()));
soundEnabled = Boolean.parseBoolean(in.readLine());
for
(
int
i =
0
; i <
5
; i++) {
highscores[i] = Integer.parseInt(in.readLine());
}
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
try
{
if
(in !=
null
) in.close();
}
catch
(IOException e) {
}
}
}
/**保存分值**/
public
static
void
save () {
BufferedWriter out =
null
;
try
{
//声音的开关
out =
new
BufferedWriter(
new
OutputStreamWriter(Gdx.files.external(file).write(
false
)));
out.write(Boolean.toString(soundEnabled));
for
(
int
i =
0
; i <
5
; i++) {
//将分数写入文件
out.write(Integer.toString(highscores[i]));
}
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
try
{
if
(out !=
null
) out.close();
}
catch
(IOException e) {
}
}
}
/**将所得分数与排行榜分数比较,从高到低重新排一下**/
public
static
void
addScore (
int
score) {
for
(
int
i =
0
; i <
5
; i++) {
if
(highscores[i] < score) {
for
(
int
j =
4
; j > i; j--)
highscores[j] = highscores[j -
1
];
highscores[i] = score;
break
;
}
}
}
}
|
再次运行代码,加了几个金币,分值发生变化了,回到主界面分数排行榜也发生变化了!(原先默认:100
,
80
,
50
,
30
,
10
)
接下来就是声音部分:
我们再次回到GameScreen中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//实例化场景
worldListener =
new
WorldListener() {
@Override
public
void
jump () {
Assets.playSound(Assets.jumpSound);
}
@Override
public
void
highJump () {
Assets.playSound(Assets.highJumpSound);
}
@Override
public
void
hit () {
Assets.playSound(Assets.hitSound);
}
@Override
public
void
coin () {
Assets.playSound(Assets.coinSound);
}
};
|
在监听器中给对应方法播放对应的声音,当然少不了在Asset中添加对声音资源的加载:
声明:
1
2
3
4
5
6
7
|
//声音部分
public
static
Sound clickSound;
//按下音效
public
static
Music music;
//背景音乐
public
static
Sound jumpSound;
//跳跃
public
static
Sound highJumpSound;
//高跳
public
static
Sound hitSound;
//碰撞
public
static
Sound coinSound;
//金币
|
实例化:
1
2
3
4
5
6
7
8
9
10
11
12
|
//背景音乐
music = Gdx.audio.newMusic(Gdx.files.internal(
"data/music.mp3"
));
music.setLooping(
true
);
//循环
music.setVolume(
0
.5f);
//大小
if
(Settings.soundEnabled) music.play();
jumpSound = Gdx.audio.newSound(Gdx.files.internal(
"data/jump.ogg"
));
highJumpSound = Gdx.audio.newSound(Gdx.files.internal(
"data/highjump.ogg"
));
hitSound = Gdx.audio.newSound(Gdx.files.internal(
"data/hit.ogg"
));
coinSound = Gdx.audio.newSound(Gdx.files.internal(
"data/coin.ogg"
));
//点击音效
clickSound = Gdx.audio.newSound(Gdx.files.internal(
"data/click.ogg"
));
|
ok!运行一下!貌似没有什么问题,对应的声音都播放出来了!
到此为止,libgdx中demo程序superjumper分版本的学习就结束了,由于本人也是边学边总结,中间肯定有许多地方讲解的不完善,不妥的地方,这里先想大家说声抱歉哈,希望大家发现问题能及时提出来,这样我也能进步么!这里还是那句话,在学习新东西的时候,我们的不求甚解也不失为一种快速掌握的好方法! 希望这一些列学习笔记能帮助到初学者!
完整代码下载:http://down.51cto.com/data/897232 代码里详细注解哦!