libgdx游戏引擎开发笔记(十三)SuperJumper游戏例子的讲解(篇七)----各个物体的创建及其碰撞检测

接着上一篇,我们完成后续的扫尾工作:游戏中个物体创建及其碰撞检测,分数保存,音效处理。


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  代码里详细注解哦!



你可能感兴趣的:(游戏,开发,检测)