转自:http://www.apkbus.com/android-59654-1-1.html
本讲源代码下载(我第一次居然忘了传,囧)
edu.nju.wsj.libgdx.rar(3.78 MB, 下载次数: 358)
本讲是
Libgdx游戏教程的第十八篇,我将其作为外篇三来讲。大家都知道,被我作为外篇的某一讲,一定是一个新的部分的引子。今天我们来讲一讲libgdx中的另一个控件:Window类,随后我们在实战篇中将用到这个控件。
我们先来看看官方文档中对Window是如何解释的:
java.lang.Object
|com.badlogic.gdx.scenes.scene2d.Actor
|com.badlogic.gdx.scenes.scene2d.Group
|com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup
|com.badlogic.gdx.scenes.scene2d.ui.tablelayout.Table
|
com.badlogic.gdx.scenes.scene2d.ui.Window
我们可以看到,其实Window就是一个Actor,也就是我们非常熟悉的演员类,但是这个演员类似乎又和一般的Actor不太一样,我们来看看Window这个类的不同之处(注意,这里的Window乃是com.badlogic.gdx.scenes.scene2d.ui.Window,而不是SDK中的Window类,请大家注意一下)
我们从以上的继承树从上往下看,最初的继承是从Actor继承而来的Group,其实Group很好理解,就是一个Actor的集合,那为什么有了Actor类又要写一个Group类呢?其实很简单,在演员类Actor实例很多的情况下我们可以通过一个Group统一管理这个Group里所有Actor的行为,其实就是把整个Group看作一个Actor,集合里的所有Actor的某一行为都根据这个Group来统一制定。
这里给大家科普一下,其实我们很早以前就接触了这个Group类,大家能猜到是在哪里吗?我们先来看看Group类的方法吧,当然,时刻牢记Group也是继承自Actor的,那么对于Group的一些行为和属性就很好理解了,我们下面来看它的比较特别的一些属性。
官方文档中Group的方法有一个我们很是熟悉:
是不是明白了?我们在舞台类Stage中添加新的演员Actor用的也是addActor()方法。其实很简单,Stage中就封装了一个Group来统一管理加入该舞台中的众多Actor。其实不光是这里,我们从Actor类的成员变量中也可以看到Group的踪影:
画出红线的部分,大家可以看到,我们对于某一个Actor取得其成员变量parent,就可以得到一个Group,其实就是代表这个Actor所在的Group。
我们再从继承树的位置往下看,接下来是WidgetGroup,这个就不做过多解释了,其实也就是一个Group,一般用来装libgdx中的Widget小组件,当然这里的Widget也是继承自Actor,所以WigetGroup和Group也是一个意思,相信大家能够理解。
接下来的Table和Window也是一样的。对于Table,我们可以用SDK中的概念来理解,大家都知道Android SDK中有布局Layout的概念,大家对比一下TableLayout的概念就可以知道这里的Table大概的作用了,当然和TableLayout还是有本质的区别的,但是相同的就是libgdx中的Table和SDK 中的TableLayout都是用来装控件的!
至于Window和Table的区别也不大,只是做了一些更具体的封装,更适合某些场合的使用。
现在我们做一个总结,Window继承自Group,也就是说它既可以单独作为一个控件显示在stage中,也可以在其中添加别的Actor然后一起显示出来,Window可以对它们做统一的管理。
我们接下来就在第九讲的基础上继续修改源代码,并且用我们刚才说到的Window类写一个类似于SDK中的Dialog的对话框。
这里插一句话,事实上在Libgdx写的游戏中也是可以使用SDK中的AlertDialog,我这里就不在给出代码演示了,和我们用SDK编写程序时的使用方法是一样的,都在在需要弹出对话框的地方新建一个AlertDialog并弹出即可,下面我给大家看看我在我新写的一个游戏中就使用了AlertDialog作为弹出的对话框:
我解释一下,被对话框遮住的部分是一个Screen,我们在这个Screen实现了InputProcessor,也就是我们在第八和第九讲中提到了的输入监听。然后我们按下Back键,就弹出一个对话框提示用户是否退出。这是一个SDK和libgdx混用的典型例子,我们在前面还提到过一个SDK和libgdx的混用的例子,就是Activity和AndroidApplication的混用。我们从这里可以看到,SDK和libgdx的混用并不是不可以的,而且有些地方会产生很不错的效果。
接下来我们尝试用libgdx中的Window类来实现相同的效果。代码在第九讲的基础上进行修改,目的是用Window实现一个对话框并且实现退出提示的功能。
我们在Game.java类里新建一个Window对象:
- Window dialog;
我们把需要的素材放到assets文件夹下,
dialog.png,ok.png.cancle.png:
我们首先在show()函数中对dialog进行初始化:
- TextureRegion txr=new TextureRegion(new Texture(Gdx.files.internal("dialog.png")), 512, 256);
- dialog=new Window("dialog",new Window.WindowStyle(bf, new Color(), new NinePatch(txr)));
- //做一个简单的适配,乘以1.2是为了让图片显示出来的时候大一点
- dialog.width=512*1.2f*Gdx.graphics.getWidth()/800f;
- dialog.height=256*1.2f*Gdx.graphics.getWidth()/800f;
- //为了让图片保持居中
- dialog.x=(Gdx.graphics.getWidth()-dialog.width)/2;
- dialog.y=(Gdx.graphics.getHeight()-dialog.height)/2;
其中的构造函数也很简单,大家可以参见官方文档。
我们再将这个dialog在按下BACK键的时候加入舞台,这样在render()函数中调用stage.draw()的时候才能将其一并绘制出来。
- @Override
- public boolean keyDown(int arg0) {
- // TODO Auto-generated method stub
- if(arg0==Input.Keys.BACK){
- if(!hasdialog){
- stage.addActor(dialog);
- hasdialog=true;
- }
- else{
- stage.removeActor(dialog);
- hasdialog=false;
- }
- }
- return false;
- }
我们将这个功能添加在回调函数KeyDown中,这个函数是我们通过继承InputProcessor得来的。
这里我们用了一个boolean变量hasdialog标记当前是否有对话框dialog显示出来,防止重复添加,并且在没有对话框显示的时候按下返回键Back时对话框弹出,再按下Back时对话框消失,代码也很简单,相信大家能看懂。
我们来看看效果:
进入程序界面:
到达这个界面后,我们按下Back返回键
这样对话框算是出来了,我们再按一下BACK键,对话框消失。那么我们初步的Window的实现是没有问题的了,我们进行下一步的操作,添加对应的按钮,并做出相应的操作,比如确定并退出程序或者取消继续游戏。
还记得我们在这一讲的开始特意介绍了Window是从Group继承下来的,因此我们可以直接在这个Window里面添加其他的Actor,这里我们直接在这个dialog中添加两个Button(我们可以从官方文档中看出Libgdx中的Button也是继承自Actor的)。
我们先在Game.java中添加两个按钮:
- //对话框上的两个按钮
- Button ok;
- Button cancle;
我们在show()函数中对它们进行初始化,当然我们这里为了简单起见,先只初始化了一个确定按钮并将其加入dialog这个Window内。
- ok=new Button(new TextureRegion(new Texture(Gdx.files.internal("ok.png")), 160, 80));
- dialog.addActor(ok);
然后我们运行一下,并让对话框弹出。
我们看到按钮已经被加在了Dialog里,不过好像还有一个问题,位置不太对?
这里还有一个很有意思的事情,大家可以看一看。
左下角的按钮我们也是没有设置过位置直接添加进stage的。所以这个按钮的位置应该是(0,0),我们可以看到位置确实是在(0,0)处:
然后我们新建的一个Button ok,我们也没有指定它的位置,也就是说它的位置也应该是(0,0),那么为什么不在屏幕的左下角呢?我们再看下面这张图:
现在大家应该明白了,所谓的初始位置(0,0)应该是相对持有这个Actor的父控件而言的,刚才说到的那个Button它的父控件是整个stage,因此它是在父控件的(0,0)处,而上面那个蓝色的确定按钮,它的父控件是dialog这个Window的实例,所以它的(0,0)是相对于这个dialog而言的。
这些东西其实也不难理解。我们接下来就直接一些,直接把两个按钮都添加上去,并摆好位置(这里我偷了个懒,只对800*480的分辨率进行了适配,用的是绝对坐标,大家可以在不同的分辨率上做出不同的适配,让显示起来更好看一点),并且设置相应的监听函数,这样可以让程序做出相应的响应。
直接贴代码了:
- ok=new Button(new TextureRegion(new Texture(Gdx.files.internal("ok.png")), 160, 80));
- ok.x=160;
- ok.y=60;
- //给ok这个按钮添加监听器
- ok.setClickListener(new ClickListener() {
- @Override
- public void click(Actor arg0, float arg1, float arg2) {
- // TODO Auto-generated method stub
- //关闭程序
- activity.finish();
- android.os.Process.killProcess(android.os.Process.myPid());
- }
- });
- cancel=new Button(new TextureRegion(new Texture(Gdx.files.internal("cancel.png")), 160, 80));
- cancel.x=360;
- cancel.y=60;
- cancel.setClickListener(new ClickListener() {
- @Override
- public void click(Actor arg0, float arg1, float arg2) {
- // TODO Auto-generated method stub
- //移除对话框
- stage.removeActor(dialog);
- hasdialog=false;
- }
- });
- dialog.addActor(ok);
- dialog.addActor(cancel);
来看看运行的结果(这次只对800*480分辨率做了一个适配,其他的机型可能显示不太正确)
对话框显示后按下确定程序退出,按下取消对话框消失,一切正常,这个对话框就算完成了今后我们就可以直接用它在Libgdx游戏中使用了。