如何使用libgdx编写一个简单的游戏(三)— 人性化

17 3月

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2013/03/17/libgdx-game-3/

这一篇主要是添加一些让游戏更人性化的东西,比如音效和加载画面,菜单等等。

这其中用到了很多资源,主要出自以下几个网站,大家有需要也可以去上面寻找。

http://www.freesound.org/

添加音效

首先是飞镖发出时候的音效,我希望是类似”bing”的一声,要短小精炼。

我使用的是http://www.freesound.org/people/BMacZero/sounds/96132/

libgdx支持的音频主要是WAV, MP3和OGG,其他的支持需要扩展支持。

libgdx中的音频有两种,一种是sound,一种是music。

一般所谓的音效使用sound,而音乐就使用music。

在DartController中添加属性

Sound bing;

在实例化方法中添加

this.bing = Gdx.audio.newSound(Gdx.files.internal("audio/bing.wav"));

在AddDart方法中添加

bing.play();

 

在怪兽被消灭的时候的音效我选用http://www.freesound.org/people/yottasounds/sounds/174465/

在TargetController中添加

great = Gdx.audio.newSound(Gdx.files.internal("audio/great.wav"));

最后添加一个背景音乐。我使用的是http://www.freesound.org/people/Setuniman/sounds/167453/

大小为5.7M,个人感觉有点大。

而且我需要循环播放,这就意味着末尾的这个部分的我不需要。

使用在线转换器截取并转化成ogg。

转化以后大小变成465kb了。仔细听一下,感觉很多部分是重复,所以再一次截取,只要前4秒的。

转化好以后在主类添加

backgroundMusic = Gdx.audio.newMusic(Gdx.files
.internal("audio/background.ogg"));
backgroundMusic.setLooping(true);//循环播放
backgroundMusic.setVolume(0.4f);//设置音量
backgroundMusic.play();//播放

因为music可以在resume和pause时自动播放和暂停,所以不需要其他的处理。在游戏关闭时需要将其释放掉。

backgroundMusic.dispose();

Game-Screen模式和资源预加载

到目前为止我们的所有操作都在一个界面上,但是一个游戏中可能有很多不同的界面和场景,比如菜单,帮助,关卡1,关卡2等等。

libgdx提供了Game-Screen模式,即只有一个Game,但是Game中有很多Screen。通过setScreen来切换。

这里注意一下Game所提供的切换功能没有任何过渡效果,后面会有添加过多效果的例子。

新建DartsGame类,继承Game类。在darts-shasha-android项目和darts-shasha-desktop项目中分别修改入口代码

package com.cnblogs.htynkn;

import android.os.Bundle;

import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;

publicclass MainActivity extends AndroidApplication {
@Override
publicvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

AndroidApplicationConfiguration cfg =new AndroidApplicationConfiguration();
cfg.useGL20 =false;

initialize(new DartsGame(), cfg);
}
}

package com.cnblogs.htynkn;

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;

publicclass Main {
publicstaticvoidmain(String[] args) {
LwjglApplicationConfiguration cfg =new LwjglApplicationConfiguration();
cfg.title ="darts-shasha";
cfg.useGL20 =false;

cfg.width =480;
cfg.height =320;

new LwjglApplication(new DartsGame(), cfg);
}
}

新建一个类ShaScreen,实现Screen接口,其中的代码基本和原来的主类一样。唯一的区别就是create中的代码需要移动到show中。

在DartsGame中添加代码

package com.cnblogs.htynkn;

import com.badlogic.gdx.Game;
import com.cnblogs.htynkn.screen.ShaScreen;

publicclass DartsGame extends Game {
@Override
publicvoidcreate() {
ShaScreen screen =new ShaScreen();
this.setScreen(screen);
}
}

这样我们就转化到Game-Screen模式。

当我们在游戏中使用了很多资源的时候直接new的话经常会卡顿,比如我们这个demo再加入音效后进入时间明显变长了。

所以我们这里需要一个预加载过程,而libgdx提供的AssetManager可以实现这个功能。

加载中使用一个小图标加文字形式。由于要使用中文,同时文字量很小,所以使用hiero作图。

03

新建一个LoadingScreen类作为加载页面。

因为AssetManager的作用很特殊,很多类都可以要调用它,所以我一般使用单例模式。

在DartsGame添加

publicstatic AssetManager manager;
publicstatic AssetManagergetManager() {
if (manager ==null) {
manager =new AssetManager();
}
return manager;
}

在LoadingScreen中通过

AssetManager manager = DartsGame.getManager();

获取manager。然后通过load方法添加要加载的资源

manager.load("audio/background.ogg", Music.class);
manager.load("audio/bing.wav", Sound.class);
manager.load("audio/great.wav", Sound.class);
manager.load("pack/sha/default.pack", TextureAtlas.class);

这里只是告诉manager要加载什么资源,并没有实际加载。

在render方法中调用

DartsGame.getManager().update()

来启动加载并获取是否加载完成,如果返回值为true那么就表明加载完成。

其他类通过

DartsGame.getManager().get()

来获取资源。

LoadingScreen代码如下:

package com.cnblogs.htynkn.screen;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.cnblogs.htynkn.DartsGame;

publicclass LoadingScreen implements Screen {

Game game;
Stage stage;

@Override
publicvoidrender(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
if (DartsGame.getManager().update()) {
game.setScreen(new ShaScreen());
}
stage.act();
stage.draw();
}

@Override
publicvoidresize(int width,int height) {
// TODO Auto-generated method stub

}

@Override
publicvoidshow() {
AssetManager manager = DartsGame.getManager();
manager.load("audio/background.ogg", Music.class);
manager.load("audio/bing.wav", Sound.class);
manager.load("audio/great.wav", Sound.class);
manager.load("pack/sha/default.pack", TextureAtlas.class);

stage =new Stage(480,320,true);
BitmapFont font =new BitmapFont(
Gdx.files.internal("pack/loading/font.fnt"),false);
LabelStyle labelStyle =new LabelStyle(font, Color.WHITE);
Label label =new Label("游戏加载中...", labelStyle);
label.setPosition(160,150);
stage.addActor(label);
Image image =new Image(
new TextureAtlas(Gdx.files
.internal("pack/loading/default.pack"))
.findRegion("ninja_attack"));
image.setOrigin(image.getWidth() /2, image.getHeight() /2);
image.addAction(Actions.repeat(1000, Actions.rotateBy(360,3f)));
image.setPosition(100,140);
stage.addActor(image);
}

@Override
publicvoidhide() {
// TODO Auto-generated method stub

}

@Override
publicvoidpause() {
// TODO Auto-generated method stub

}

@Override
publicvoidresume() {
// TODO Auto-generated method stub

}

@Override
publicvoiddispose() {
// TODO Auto-generated method stub

}

publicLoadingScreen(Game game) {
this.game = game;
}
}

效果如下:

04

当我们不需要某个资源时通过

manager.unload

来销毁。或者使用

manager.clear();

来清空所有资源。

添加友盟统计

统计功能对于一个应用是必须的。你可以获取到用户的信息,比如分辨率,系统版本,还可以快速获取到错误等等。

libgdx是一个游戏框架,没有自带的统计功能,这里我选用友盟统计。

首先申请key

申请完成以后获取Appkey并下载SDK,拷贝到android项目的libs文件夹中。

在AndroidManifest.xml中添加相关信息。

详细的情况参考友盟的文档。

现在来看一下友盟文档,最常用的是

MobclickAgent.onResume(this);
MobclickAgent.onPause(this);

为了方便开发,我们新建一个接口IStatisticsService。

package com.cnblogs.htynkn.extension;

publicinterface IStatisticsService {
void onResume();
void onPause();
}

然后在DartsGame类添加

publicstatic IStatisticsService statisticsService;

然后在Android项目中添加AndroidStatisticsService

package com.cnblogs.htynkn.extension;

import android.content.Context;

import com.umeng.analytics.MobclickAgent;

publicclass AndroidStatisticsService implements IStatisticsService {

Context context;

publicAndroidStatisticsService(Context context) {
this.context = context;
}

@Override
publicvoidonResume() {
MobclickAgent.onResume(context);
}

@Override
publicvoidonPause() {
MobclickAgent.onPause(context);
}

}

修改入口文件为

package com.cnblogs.htynkn;

import android.os.Bundle;

import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.cnblogs.htynkn.extension.AndroidStatisticsService;

publicclass MainActivity extends AndroidApplication {
@Override
publicvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cfg =new AndroidApplicationConfiguration();
cfg.useGL20 =false;
DartsGame dartsGame =new DartsGame();
DartsGame.setStatisticsService(new AndroidStatisticsService(this));
initialize(dartsGame, cfg);
}
}

同样的,在桌面项目中添加DesktopStatisticsService

package com.cnblogs.htynkn.extension;

import com.badlogic.gdx.Gdx;

publicclass DesktopStatisticsService implements IStatisticsService{

@Override
publicvoidonResume() {
Gdx.app.log("StatisticsService","onResume");
}

@Override
publicvoidonPause() {
Gdx.app.log("StatisticsService","onPause");
}

}

修改入口文件

package com.cnblogs.htynkn;

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.cnblogs.htynkn.extension.DesktopStatisticsService;

publicclass Main {
publicstaticvoidmain(String[] args) {
LwjglApplicationConfiguration cfg =new LwjglApplicationConfiguration();
cfg.title ="飞镖杀杀";
cfg.useGL20 =false;
cfg.width =480;
cfg.height =320;
DartsGame.setStatisticsService(new DesktopStatisticsService());
new LwjglApplication(new DartsGame(), cfg);
}
}

因为桌面项目并没有统计功能,所以以输出log替代。

然后在游戏相应位置调用即可。

其他需要的功能办法基本相同,就是实现相应接口,然后不同的平台传入不同实现。没有实现的就用mock输出。

依照这种方法还可以添加其他第三方功能。

不过很遗憾友盟SDK升级以后我死活用不上了…现在换成百度APP统计了。原理是一样的,具体参考源码。

比如在Android的启动文件中重写onPause和onResume

package com.cnblogs.htynkn;

import android.os.Bundle;

import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.cnblogs.htynkn.extension.AndroidStatisticsService;

publicclass MainActivity extends AndroidApplication {
@Override
publicvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cfg =new AndroidApplicationConfiguration();
cfg.useGL20 =false;
DartsGame dartsGame =new DartsGame();
DartsGame.setStatisticsService(new AndroidStatisticsService(this));
initialize(dartsGame, cfg);
}

@Override
protectedvoidonResume() {
super.onResume();
DartsGame.getStatisticsService().onResume();
}

@Override
protectedvoidonPause() {
super.onPause();
DartsGame.getStatisticsService().onPause();
}
}

统计结果

 


我还实现了其他方法,比如事件记录等等。

说实话,友盟的统计比百度的好很多,但是不知为嘛我用不起了。

写在最后

本来这一篇写好很久了,但是我一直想加入一个菜单和游戏结束的界面,不过最近实在没有时间,先发出来这个部分吧。

如果有时间以后会补上的。

Github仓库地址:https://github.com/htynkn/DartsShaSha 对应的tag是page3。

apk下载地址:http://pan.baidu.com/share/link?shareid=385272&uk=4127624209

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2013/03/17/libgdx-game-3/

发表回复

您的电子邮箱地址不会被公开。