手把手教你写蛇蛇大作战(四)

这篇我们主要 添加 摇杆 、加速按钮 还有音效

首先我们看看这章完成的效果图
效果图

在移动设备上只能通过触控板来控制蛇的移动 所以我们要添加一个TouchPad和加速按钮
LibGdx中已经有了这个控件 但是默认的皮肤太丑了。所以我自己用Sketch画了一个。

摇杆

背景图片
background.png

摇杆图片
knob

图片准备好了开始打包图片

修改DesktopLauncher.java文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class DesktopLauncher {
private static boolean rebuildAtlas = true;
private static boolean drawDebugOutline = false;

public static void main(String[] arg) {
if (rebuildAtlas) {
TexturePacker.Settings settings = new TexturePacker.Settings();
settings.maxHeight = 1024;
settings.maxWidth = 1024;
settings.duplicatePadding = false;
settings.debug = drawDebugOutline;
TexturePacker.process(settings, "../../desktop/images",
"../../android/assets/images", "snake");
//添加打包 摇杆皮肤
TexturePacker.process(settings, "../../desktop/images-ui",
"../../android/assets/images", "touchpad-ui");
}
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.width = 800;
config.height = 480;
config.samples = 3;
new LwjglApplication(new SnakeIo(), config);
}
}

运行下DesktopLauncher ,就会在android/assets/images 目录下生成皮肤文件
然后我们新建文件 touchpad-ui.json 内容如下

1
2
3
4
5
6
7
8
{
com.badlogic.gdx.scenes.scene2d.ui.Touchpad$TouchpadStyle: {
default: {
background: background,
knob: knob
}
}
}

添加TouchPad

WorldRenderer.java添加以下属性

1
2
3
4
private Skin touchPadSkin;//摇杆皮肤
public Stage stage;//舞台
private Touchpad touchpad;//摇杆
private ImageButton btnSpeed;//加速按钮

init()方法下面添加初始化代码

1
2
3
4
5
6
stage = new Stage(new ExtendViewport(Constants.VIEWPORT_GUI_WIDTH,
Constants.VIEWPORT_GUI_HEIGHT));
touchPadSkin = new Skin(Gdx.files.internal(Constants.SKIN_TOUCHPAD_UI),new TextureAtlas(Constants.TEXTURE_ATLAS_TOUCHPAD_UI));
stage.addActor(buildSpeed());
stage.addActor(buildTouchPad());
worldController.touchProcessor = stage;//touchpad 监听

buildSpeed()buildTouchPad()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private ImageButton buildSpeed() {
Drawable drawable = new TextureRegionDrawable(Assets.instance.ui.lightning);
btnSpeed = new ImageButton(drawable);
btnSpeed.setBounds(stage.getWidth() - 150, 50, 100, 100);
btnSpeed.addListener(new ClickListener() {
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
worldController.snake.speedUp();
return super.touchDown(event, x, y, pointer, button);
}

@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
worldController.snake.speedDown();
}
});
return btnSpeed;
}
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
private Touchpad buildTouchPad() {
Skin skin = touchPadSkin;
touchpad = new Touchpad(20, skin);
touchpad.setBounds(50, 50, 100, 100);
touchpad.addListener(new InputListener() {
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}

@Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
super.touchDragged(event, x, y, pointer);
// knob相对touchpad左下角的位置
float knobX = touchpad.getKnobX();
float knobY = touchpad.getKnobY();
// knob依touchpad的中心点向右水平线,
float knobPercentX = touchpad.getKnobPercentX(); // 手指离开中心向左趋于-1,向右趋于1
float knobPercentY = touchpad.getKnobPercentY(); // 手指离开中心向下趋于1,向上趋于-1
if (knobPercentX == 0 && knobPercentY == 0) return;
double angle = Math.atan2(knobPercentY, knobPercentX);
if (angle < 0) {
angle += Math.PI * 2;
}
worldController.snake.setDirection(angle);
}

@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
}
});
return touchpad;
}

修改render()方法

1
2
3
4
5
6
public void render() {
renderBackground(shapeRenderer);
renderWorld(spriteBatch);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}

修改resize()方法

1
2
3
4
5
6
public void resize(int width, int height) {
camera.viewportWidth = Constants.VIEWPORT_WIDTH; // Viewport of 30 units!
camera.viewportHeight = Constants.VIEWPORT_HEIGHT * height / width; // Lets keep things in proportion.
camera.update();
stage.getViewport().update(width, height);
}

可以运行看看效果了。

添加声音

bm.mp3

这个声音上传不上去,请到我的github去下载吧

把声音拷贝到assets下的sounds目录下

然后编写代码
修改Assets.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
public AssetSounds sounds;
...
public void init(AssetManager assetManager) {
this.assetManager = assetManager;
assetManager.setErrorListener(this);
assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);
//load sounds
assetManager.load("sounds/bm.mp3", Music.class);
assetManager.load("sounds/live_lost.wav", Sound.class);
assetManager.finishLoading();
...
sounds = new AssetSounds(assetManager);
}

public class AssetSounds {
public final Music bm;
public final Sound liveLost;

public AssetSounds(AssetManager manager) {
this.bm = manager.get("sounds/bm.mp3", Music.class);
this.liveLost = manager.get("sounds/live_lost.wav", Sound.class);
}
}

LigbGdx 提供了Sound.javaMusic.java
来播放声音
我们这边的背景音乐是mp3格式的所以用Musice.java

在这个之前我们先添加我们的声音播放类AudioManager.java

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
public class AudioManager {
public static final AudioManager instance = new AudioManager();
private Music playingMusic;

// singleton: prevent instantiation from other classes
private AudioManager() {

}

public void play(Sound sound) {
play(sound, 1);
}

public void play(Sound sound, float volume) {
play(sound, volume, 1);
}

public void play(Sound sound, float volume, float pitch) {
play(sound, volume, pitch, 0);
}

public void play(Sound sound, float volume, float pitch,
float pan) {
if (!GamePreferences.instance.sound) return;
sound.play(GamePreferences.instance.volSound * volume,
pitch, pan);
}

public void play(Music music) {
stopMusic();
playingMusic = music;
if (GamePreferences.instance.music) {
music.setLooping(true);
music.setVolume(GamePreferences.instance.volMusic);
music.play();
}
}

public void stopMusic() {
if (playingMusic != null) playingMusic.stop();
}

public void onSettingsUpdated() {
if (playingMusic == null) return;
playingMusic.setVolume(GamePreferences.instance.volMusic);
if (GamePreferences.instance.music) {
if (!playingMusic.isPlaying()) playingMusic.play();
} else {
playingMusic.pause();
}
}


}

这边为了方便我们直接把设置方法也写进去了,GamePreferences 提供游戏菜单设置声音大小 的方法 在这里我们省略可以去github 看代码

播放声音

修改SnakeIo.java

1
2
3
4
5
6
7
8
9
@Override
public void create() {
GamePreferences.instance.load();
Assets.instance.init(new AssetManager());
worldController = new WorldController();
worldRenderer = new WorldRenderer(worldController);
Gdx.input.setInputProcessor(worldController);
AudioManager.instance.play(Assets.instance.sounds.bm);
}

dispose()中添加暂停方法

1
2
3
4
5
6
7
@Override
public void dispose() {
AudioManager.instance.stopMusic();
worldRenderer.dispose();
worldController.dispose();
Assets.instance.dispose();
}

这篇文章就ok了,基本功能实现了。还有未实现的功能

  • 判断游戏的结束
  • 添加机器蛇
  • 添加游戏菜单

代码已经放在GITHUB
可以切换到tag3 来查看本篇文章代码

使用 git checkout tag3

文章作者: zhangman523
文章链接: http://blog.zhangman523.cn/2018/09/24/snake_fourth/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zhangman523
支付宝打赏
微信打赏