转自:http://www.apkbus.com/android-57991-1-1.html
今天是#Testin杯#Mkey libgdx教程的第六讲,在第二讲我就曾经对大家承诺过写一个关于Libgdx内多屏幕显示的内容,可是我脑子一时糊涂竟然忘了这事,这里向大家道歉,从第五到第七讲我们就来八一八libgdx中的多游戏容器的实现。我在我的Libgdx教程中尽量给大家介绍一些实用的功能,至于那些libgdx API基本的使用方法则不过多侧重,想来大家通过查询API文档也能掌握。这里再提醒一下大家,API文档可以在官网上看到,也可以在下载下来的libgdx包中的docs下的index.html中查看。
至于多容器,简单的理解就是多个游戏界面,那么大家一定联想到
SDK 中的多界面是用Activity实现的,通过Intent跳转来实现多界面之间的切换。
在今天上午的第五讲中,我们已经尝试了用
SDK API和libgdx混用的办法实现了libgdx中的多界面的切换。这相当于一个Activity(SDK)和一个AndroidApplication(libgdx,继承自Activity)相互跳转,也就是我们直接利用了AndroidApplication继承自Activity这一特点,用Intent进行Activity之间的跳转。那么两个AndroidApplication之间可以不可以用Intent进行跳转呢?毫无疑问也是可以的,这里就不再演示了。道理都是一样的。
但是我们更不会用两个
AndroidApplication之间进行相互跳转,这样做比一个普通Activity和一个AndroidApplication之间切换要来的更慢,因为每次AndroidApplication都要调用initialize()方法,而我在第五讲中曾经提到过,initialize()方法的作用是启动Gdx,将需要的文件载入。这样一来,两个AndroidApplication就会载入两次,更慢就是显然的了。
言归正传,我们重新回到第五讲最后说到的内容。我们已经实现了游戏结构的转变,从一个
AndroidApplication直接启动一个ApplicationListener到令AndroidApplication持有一个继承了虚类Game(Game本身实现了ApplicationListener接口),再由Game持有一个Screen从而进行显示。
其实接下来的工作很简单,就是设计不同的
Screen,然后根据不同的事件触发让Game调用setScreen()方法并传入不同的Screen实例,就能在各个界面之间切换了。当然,这也没有想起来那么简单,很多问题我一一提到。
我们不必再重新设计一个
Screen,还记得我们在第二讲中有一个类MyGame实现了ApplicationActivity吗,我们这里做一下和上一讲以后将Progress适配成Screen一样的工作,我们将MyGame这个类也重写一下,让它改为实现Screen接口的版本。
先给大家看一看修改过后的代码:
- public class MyGame implements Screen {
- SpriteBatch batch;
- BitmapFont bf;
- ParticleEffect particle;
- ParticleEffect tem;
- ParticleEffectPool particlepool;
- ArrayList<ParticleEffect> particlelist;
- Texture tx1;
- Texture tx2;
- Texture tx3;
- LibgdxActivity activity;
- //这里的Button是com.badlogic.gdx.scenes.scene2d.ui.Button,注意区分
- Button button;
- //Button继承自Actor,因此我们也需要一个舞台,stage
- Stage stage;
- public MyGame(LibgdxActivity activity) {
- super();
- this.activity = activity;
- }
- public void resize (int width, int height) {
- // STUB
- }
- public void pause () {
- // STUB
- }
- public void resume () {
- // STUB
- }
- public void dispose () {
- // STUB
- batch.dispose();
- bf.dispose();
- //千万别忘了释放内存
- particle.dispose();
- if(tem!=null)
- tem.dispose();
- particlepool.clear();
- }
- @Override
- public void hide() {
- // TODO Auto-generated method stub
- }
- @Override
- public void render(float arg0) {
- // TODO Auto-generated method stub
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- Gdx.gl.glClearColor(0f,0f,0f,0f);
- stage.act(Gdx.graphics.getDeltaTime());
- stage.draw();
- batch.begin();
- bf.draw(batch, "Testin Mkey libgdx(6)",Gdx.graphics.getWidth()*0.4f, Gdx.graphics.getHeight()/2);
- batch.end();
- if(true){
- if(Gdx.input.isTouched()){
- //当此触摸点与上一触摸点距离大于一定值的时候触发新的粒子系统,由此减小系统负担
- tem=particlepool.obtain();
- tem.setPosition(Gdx.input.getX(),Gdx.graphics.getHeight()-Gdx.input.getY());
- particlelist.add(tem);
- }
- batch.begin();
- for(int i=0;i<particlelist.size();i++){
- particlelist.get(i).draw(batch, Gdx.graphics.getDeltaTime());
- }
- batch.end();
- //清除已经播放完成的粒子系统
- ParticleEffect temparticle;
- for(int i=0;i<particlelist.size();i++){
- temparticle=particlelist.get(i);
- if(temparticle.isComplete()){
- particlelist.remove(i);
- }
- }
- }
- }
- @Override
- public void show() {
- // TODO Auto-generated method stub
- stage=new Stage(Gdx.graphics.getWidth(),Gdx.graphics.getHeight(), true);
- tx2 = new Texture(Gdx.files.internal("button1_480.png"));
- tx1 = new Texture(Gdx.files.internal("button2_480.png"));
- tx3 = new Texture(Gdx.files.internal("button3_480.png"));
- NinePatch n1 = new NinePatch(tx1, 14, 14, 18, 18);
- NinePatch n2 = new NinePatch(tx2, 14, 14, 18, 18);
- NinePatch n3 = new NinePatch(tx3, 14, 14, 18, 18);
- button = new Button( new ButtonStyle(n1, n2, n3, 0f, 0f, 0f, 0f), "Start");
- button.setClickListener(new ClickListener() {
- @Override
- public void click(Actor arg0, float arg1, float arg2) {
- // TODO Auto-generated method stub
- activity.ag.setScreen(activity.progress);
- }
- });
- stage.addActor(button);
- batch=new SpriteBatch();
- bf=new BitmapFont();
- //初始化粒子变量
- particle = new ParticleEffect();
- particle.load(Gdx.files.internal("particle.p"), Gdx.files.internal(""));
- particlepool=new ParticleEffectPool(particle, 5, 10);
- particlelist=new ArrayList<ParticleEffect>();
- //只有加入这条语句,stage中的Button()
- Gdx.input.setInputProcessor(stage);
- }
- }
老规矩,我会对其中的改动一一做出解释。其中最明显的改动就是添加了一个Button,而Button的构造需要三张纹理图片(Textrue)代表按钮按下和弹起时的状态,从而可以显示出不同的效果。
具体的Button的构造方法和使用方法可以参见巴士内教程
android游戏开发框架libgdx的使用(四)--舞台和演员
其中有具体的舞台和演员的介绍以及Button的构造,
不过有一点要注意,帖子中的
Button是按照0.9.2的版本来构造的,在0.9.4的版本中对Button的构造函数做了大幅度的修改,我的代码中是按0.9.4来写的,请大家注意一下。
既然Button继承自演员类Actor,那么它也需要加载一个stage中一起进行绘制。设置stage的大小为屏幕大小(分别用Gdx.graphics.getHeight()和Gdx.graphics.getWidth()或者当前屏幕的长和宽,注意这里的长和宽是根据横屏还是竖屏决定的)。Button构造完成后,给其设定一个监听器,在按下按钮后屏幕跳转到Progress中去。另外我们在MyGame的构造函数中传入了LibgdxActivity(即持有Game的AndroidApplication)的引用,这样就可以在Button的监听器中使用setSreen()进行屏幕的跳转了。
另外还需对LibgdxActivity做少许修改,加入一个MyGame(它是一个Screen)的实例,和原先的Progress一起,这就是有两个屏幕了。
- public class LibgdxActivity extends AndroidApplication {
- Progress progress;
- MyGame mg;
- ApplicationGame ag;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- progress=new Progress();
- mg=new MyGame(this);
- ag=new ApplicationGame(mg);
- initialize(ag, false);
- }
- }
然后我们直接运行,看看效果
界面的切换是不是变得快的多了?我们可以看到,整个过程基本没有卡顿,用户体验就这样得到了满足。我们尝试着按返回键,希望能回到上一个屏幕。诶?程序退出了?!仔细想一想其实也不难找到原因,
Android系统对应用的相应是按活动Activity来相应的,虽然我们在libgdx中设置的是两个Screen,但对于Android而言只有一个Activity,即LibgdxActivity(其实是一个AndroidApplication),那么在只有一个Activity的程序中按返回键,当然程序就直接退出了。那么怎么解决呢?这就是我们第七讲要介绍的问题。
这里向大家道个歉,原本承诺是今天一直更新到第七讲,可是今天在电脑面前写了一天的教程肩膀实在疼得不行,无奈只有放在明天再写了,十分抱歉!
另外预告一下,第七讲之后我决定暂时不继续进行主干内容的介绍转而写几篇外篇,介绍我曾经用一天时间写出的一个很简单的俄罗斯方块的游戏,我将把源代码完全放出来,并且一步步地将这个基于SDK API的程序移植到libgdx下,毕竟我们学了这么多,终于可以实战了,也增加大家的一些信心。两部分的源码都将公开,请大家继续支持Testin杯Mkey libgdx游戏引擎系列教程。
源码在这里:
edu.nju.wsj.libgdx.rar(3.57 MB, 下载次数: 919)
Testin ID:ilovemkey@gmail.com 总的而言这个平台真的非常好用!我正是用这个平台发现了现在写的这个应用的一些内存管理方面的问题。另外建议能够在测试报告中看到某一台机型在整个执行过程中的cpu和内存占用的变化情况,这样可以更快地锁定问题。感谢Itestin让测试变得轻松了太多太多!