#LibGDX Introduction LibGDX是一个跨平台的2D/3D的游戏开发框架,它由Java/C/C++语言编写而成。它基于Apache License,Version 2.0协议,对商业使用和非商业使用均免费
##Adventages
##游戏框架概览
libgdx 作为游戏引擎,其框架主要包含输入,逻辑处理,输出三个部分

- 输入,主要有用户的响应事件,如触屏(Touch),点击(Click),长按(Long Touch), 拖拽(Drag)等。输入中的文件一般为图片,声音,视频等
- 逻辑,主要有数学逻辑和物理逻辑,libgdx对于物理上处理是Box2D的封装,可以满足一般需求。对于数学逻辑封装了一些常见的结构和少量算式,可以基于此开发自己需要的算法。libgdx对于图像和声音等文件的处理比较好,可以直接使用。
- 输出,一般是图片,声音,影像等,也有文件或者其他数据(比如网络的存储)
##引擎框架
一般采用模块化结构,便于功能的开发与管理,libgdx游戏开发模块结构如下图

Android 游戏引用(Application)——》 游戏内容(Game)——》各种场景画面切换(Screen)——》各种场景画面的舞台(Stage)——》舞台上的角色(Actor)
#LibGDX模块概述 LibGDX 包括几个模块,对每一个典型的游戏架构步骤提供服务:
- Input - 对所有平台提供一个统一的输入模块并处理。支持键盘,触摸屏,传感器,鼠标等;
- Graphics - 开启屏幕上图像的绘制,支持OpenGL ES;
- Files - 抽象所有平台文件访问为读写操作提供合适的方法;
- Audio - 在所有平台上有利于声音的记录和播放;
- Math - 很实用的模块,对于游戏开发提供最快的数学计算;
- Physics - 对于Box2D的完整封装。
##应用模块(Application) 应用模块负责让你的游戏在特定平台上运行,它将实例化子模块,在桌面PC上创建一个窗口或者在Android上面创建一个Activity,并且显示处理UI线程。你可以通过以下三种方法同应用交互:
- 访问子模块;
- 查询信息,比如当前应用运行的平台信息;
- 注册一个ApplicationListener。
最后一种方法允许你得到生命周期时间的通知以及对这些事件进行反馈,Libgdx应用的生命周期简化了Android Activity生命周期的模型
- ApplicationListener.resume():在应用程序启动或者应用从一个暂停状态恢复的时候被调用一次;
- ApplicationListener.pause():在应用程序被中断或者被一个外部事件暂停,这些外部事件可能是:一个来电,用户按下Home键,应用程序根据用户的操作将会被恢复或者销毁;
- ApplicationListener.destroy():在应用程序将要销毁的时候被调用。
然而,你可能会问到主循环在哪儿?它不在这里,应用程序包装了依赖平台的UI线程,这些线程有基于事件的性质。我们不能在UI线程里面添加一个无限循环,因为这样会冻结整个应用程序,UI线程通常是基于事件的,这意味着当除非有事件需要处理,比如:键被按下或者鼠标点击,操作系统将使UI线程转入休眠,这不是放我们游戏主循环的好地方。信不信由你,游戏具有天生的多线程性质,除了UI线程,libgdx为你生成了第二个线程。但它不属于应用模块,而是属于图像模块,所以接下来,我们来看看它都做了些什么?
##图形模块(Graphics Module) 虽然有的游戏不需要不断的重新绘制屏幕,但是Libgdx假设你想要的游戏需要不间断的绘制屏幕,这是个简单的概念并且你不需要去关注任何脏标记或者去关注在某些游戏状态改变的情况下重新绘制屏幕。
我们已经知道UI线程不是一直不间断的运行的,而是在事件的驱动下有操作系统调度运行的(粗略的认为)。这就是我们为什么实例化第二个线程,也就是我们通常说的渲染线程,这个线程是由Graphics模块所创建,Graphics模块本身由应用模块在程序启动的时候实例化。
渲染线程执行一个无限循环,由于应用程序的生命周期事件,它可能会被暂停或者恢复。作为开发者,你可以通过注册一个RenderListerner将这个线程与图形模块连接起来(是的,我太喜欢回调了...)。与ApplicationListener相似的是,RenderListerner对由图像模块渲染线程触发的特定事件做出回应:
- RenderListener.surfaceCreated():在EGL的绘图界面和上下文被建立,并且我们已经准备通过OpenGL画图的时候被调用,这一般发生在应用第一次启动或者当应用从暂停状态到恢复状态;
- RenderListener.surfaceChanged():在EGL的绘图界面大小发生改变的时候被调用,这一般发生在屏幕方向发生改变或者桌面上的窗口大小改变;
- RenderListener.render():不断的被调用,而且这里是随着游戏的运行实现我们游戏逻辑的最好的地方,每次从这个方法返回时Libgdx会确保你在方法内所绘制的东西得以在屏幕上显示,如果应用程序被暂停,那么渲染线程也将暂停,因此这个方法将不会被调用;
- RenderListener.dispose():在应用程序即将死亡的时候被调用,这里是做一些清理工作,比如记录高分或者保存一些信息的可选择的地方。
libgdx中所有的图片资源都是被托管的,你永远也不需要担心一个EGL的上下文或者绘图表面丢失
###图像资源 Graphics接口提供了一些创建一系列平台依赖图像资源的方法,其他图形资源是平台无关的,可以通过Libgdx中相关的类自由的创建,我们先看一下这些通过图形接口创建的资源:
- Pixmap(像素图):是一个围绕平台相关位图的包装器,像素图可以从文件创建,或者指定宽、高和像素格式,他们存储在普通的RAM中,在EGL上下文丢失的情况下不会被破坏,像素图可以直接被Libgdx渲染.在几乎所有情况下,他们由纹理构造器所创建;
- Texture(纹理):实际上就是显存中的像素图.如同前文所提到的那样,当EGL上下文丢失的时候它将被销毁,纹理可以从像素图中创建,或者指定特定的宽、高和像素格式,或者是指定文件,接下来的案例中,纹理将由libgdx管理,否则,纹理没有管理者,你不得不小心翼翼的重新构造他们当上下文丢失后。非托管型纹理在创建后可以被操作,于此相反,由于托管型是静态的,所以不能被操作,纹理可以直接用于渲染;
- Font(字体):是一个围绕平台相关字体的包装器,字体可以从文件中加载或者通过指定的文字名称。此外,它有宽度,以及格式,比如粗体、斜体等。字体还拥有一个内部纹理,因此它将被EGL上下文丢失所影响,作为一个好的库,libgdx将会自动为你处理此类的丢失。因此字体也是托管资源,可以直接使用于渲染。
以下是可以不使用Graphics接口初始化的资源:
- Mesh(网格):作用是一个以顶点格式保存点、线、三角形集合,网格通常驻留在显存中。因此也受到EGL上下文丢失影响,网格也是托管型图形资源,因此你不必担心。在libgdx中所绘制的每个物体都会被转化为一个网格,平转移到图形处理器渲染,大多数时候,你设置了一个纹理,它将被应用到这个网格的几何形状中,对于你们中的OpenGL专家来说:一个网格上基本上包装了一个(索引)顶点数组,或者一个顶点缓冲对象,这取决于硬件;
- SpriteBatch(精灵组):是渲染二维物体,比如精灵和文字的首选地方,就拿精灵来说,一个精灵简单指定一个纹理,它拥有精灵的形象以及精灵位置和方向属性。libgdx中有一个更好的处理精灵的类Sprite可供选择,在文本的案例中,用户可以指定文本的字体用于文本渲染,该SpriteBatch类相比其他所有开源精灵渲染方案,拥有极高的速度和良好的渲染效果,精灵组在内部使用一个Mesh,因此也是受到上下文影响的。与往常一样,你同样不需要担心;
- BitmapFont(位图字体):是渲染文本的另一种方法,不同于加载一种系统字体或者在从文件中提供一个TTF字体,位图字体使用AngleCode位图字体。你可以通过使用TWL主题编辑器或者一个叫做Hiero的工具创建这样的字体,这种格式将是你渲染文本的首选方式。不久后,我们将会对这种文本渲染有一个详细的介绍,位图字体的内部使用纹理,因此也是托管的;
- ShaderProgram(着色程序):封装了OpenGL ES 2.0的顶点和片段着色器,这是一个方便的类,他简化了在OpenGL ES中管理着色的难度,由于着色器驻留在显存中,它受到上下文丢失的影响,它也是托管的;
- FrameBuffer(帧缓冲器):封装了OpenGL ES2.0的帧缓冲对象,它同样是托管资源,尽管在上下文丢失的情况下它们的内容将会被销毁。鉴于该帧缓冲区通常重绘每一帧,因此这应该不是一个大问题。
如果你想要更底层的操作,你同样可以访问已绑定的OpenGL ES.Graphics接口拥有多个getter方法,它将返回一个如下接口的实现:
- GL10:为您提供所有的OpenGLES1.0的功能;
- GL11:为您提供所有的OpenGLES1.1的功能,它实际上是从GL10上扩展而来,所以你也可以通过调用该接口, 用OpenGL ES1.0的所有功能;
- GL20:为您提供所有的OpenGLES2.0的功能,如果你想要取得所有着色器,这就是你要使用的;
- GLCommon:包含了OpenGL ES1.x和OpenGL ES 2.0所共有的所有功能,例如glTexImage2D等。
在次强调,OpenGL ES 1.x和2.0是不兼容的,在启动的时候就必须决定使用哪个版本,这个通常在构建一个由后端所提供Application实现类的时候完成。Graphics接口提供给你一些方法去检查当前正在运行的平台下可以获得哪个OpenGLES实现,如果你在一个没有OpenGL ES 2.0支持下的环境中指定使用GL20上下文,libgdx将会退回到OpenGL ES 1.x,因此对于一些老的设备,你可以拥有单独的方法渲染。
##声音模块(Audio Module) Libgdx拥有一个专门的音频模块,他提供两种类型的资源:声音和音乐。
- Sound(声音)类旨在播放声音效果,通常你从一个文件中加载声音效果,根据某些事件,例如僵尸脑袋爆炸,调用Sound.play()方法播放它。声音通常很短,在几秒钟的范围内,他们会在内存中加载和解码,如果它们长时间的运行,很可能会占据很大的一些内存;
- Music(音乐)是你所想要使用的为了播放很长事件的声音(或者,好吧,就是背景音乐)的类,音乐是流的形式,那意味它仅仅是部分被装载进入了内存,根据文件格式解码,然后输出到音频设备中。
声音和音乐都是系统资源,如果图形资源一样,你必须在它们不再被使用的时候,通过调用Sound.dispose()和Music.dispose()方法释放它们。
Libgdx支持mp3、Ogg以及Wave文件格式,我建议你在大多数情况下使用Ogg格式。
##文件模块(Files Module) 文件模型有三种不同的文件类型:
- Internal files(内部文件类型):这些文件将和你的应用程序绑定在一起,在桌面PC环境中,它们相对与你的应用程序根目录而存在。在Android上他们存储在assets文件夹下,我们本也可以提供一种方法来访问drawable文件夹下面的数据,但是最终决定放弃这个想法,因为在这个文件夹中的数据有可能在系统载入文件的时候被改变。作为一个游戏开发人员,我们希望对我们的文件完全控制, Internal files是只读的;
- External files(外部文件):这些文件有可能从服务器上下载来的,或者是你创建用来保存高分辨率或者设置,在桌面环境下,它们将相对于当前使用者的home目录存储。在Android下,它们将相对于SD卡根目录存储,External files是可读、可写的;
- Absolute files(绝对文件):如果你想体验一下痛苦,你可以使用绝对文件,它不是平台无关的,如果你使用绝对路径,那么它只能在你的电脑中运行, Absolute files是可读、可写的。
##输出模块(Input Module) 整个体系的最后一个模块是输入模块,顾名思义,它为你提供了访问应用程序运行平台的输入外设的能力,我们把这些东西统一到了一起
<1> Polling access(轮询访问):只是询问Input接口是否有键按下或者触摸屏被触摸;
<2> Event based handlind(事件驱动):你可以使用Input接口注册一个InputListener,它将接收所有的触摸屏和键盘事件,这些事件通常在UI线程中处理。在以前的文章中我们提到的,是在渲染线程中,为了减轻使用的难度,我们设定InputListener只有在渲染线程中才能被调用(事实上是在RenderListerner.render()方法被调用之前)。
最后,Android上面的重力感应设备同样在桌面PC上面是没有的,我们设定的该事件处理方式或许有些愚蠢,因为它总是产生事件,因此你只可以使用轮询方式来访问当前的重力感应设备的状态。
##网络模块(NetWork Module) 我们决定不在Libgdx中包含网络模块,值得庆幸的是Android支持大多数标准Java scoket API
##其他模块(Other Module)
-
math(数学):这个包中有良好的的三角函数查找表,矩阵、四元数、向量类、样条(是指通过一组给定点集来生成平滑曲线的柔性带,此概念源于生产实践,“样条”是绘制曲线的一种绘图工具,是富有弹性的细长条,绘图时用压铁使样条通过指定的形值点(样点),并调整样条使它具有满意的形状,然后沿样条画出曲线),平截头体,多边形三角测量,相交代码,虽然这些方法都很高效,但是碰到如果计算量很大的话,还是考虑一下直接使用本地代码吧(JNI);
-
box2d(一个物理引擎):用Java JNI写了一个完全的Box2D,这样做的原因是:
- 它比用JBox2D快多了;
- 它不会产生让垃圾收集器发疯的垃圾,其他的项目比如:Rokon或者Andengine都使用了这一部分代码。
-
scene2d:一个好的2D场景地图API,它很灵活,适合拿来做UI;
-
utils:包含了一些辅助类,大多数是为了减少垃圾收集器的工作,比如自定义的hashmap实现,对象池等等。包中还把JSON库包含了进来,如果你想要读取或者写这个类型的文件,那你就以他们的格式提供材料。
#开发基础
##AndroidApplication
而 AndroidApplication 又继承Android 基本的Activity并实现了libgdx自定义的接口类 Application

##ApplicationListener接口 An ApplicationListener is called when the Application is created, resumed, rendering, paused or destroyed
- 在create()方法中初始化一下相应的变量,否则会得到空指针;在dispose()方法中不要忘了对变量执行销毁
##Graphics
绘制图形,程序启动(create)——》读取图片(image)——》纹理(texture)绑定——》绘制初始化(sprite.begin)——》绘制(render)——》绘制完处理(sprite.end)——》销毁(dispose)等步骤
###纹理 Texture
该类存放在com.badlogic.gdx.graphics包下,继承自Object,实现了Disposable接口,凡是实现了该接口的类,都应该在程序结束时对该类进行销毁
一个图片从原始格式解码并上传到GPU就被称为纹理。OpenGL要求纹理的高度和宽度都必须是2的n次方大小,只有满足这个条件纹理图片才是有效的;其实就是承装获取到的目的图片的容器
###Pixmap 该类存放在com.badlogic.gdx.graphics包下,继承自Object,实现了Disposable接口。
Libgdx所提供的像素级图像渲染用类,由于Libgdx目前以JNI方式自带图像解码器,所以我们可以直接将Pixmap理解为一个Android中 Bitmap的替代者,两者间实现细节虽有差别,但具体作用却大同小异。Pixmap支持Alpha、LuminanceAlpha、RGB565、 RGBA4444、RGB888、RGBA8888等五种图像彩色模式,支持png、jpg、bmp等三种图像文件的读取和加载。一般来说,Pixmap 必须和Texture混用才能真正显示画面。不过在事实上,Libgdx的Texture里已经内置有Pixmap了
###TextureRegion
该类存放在com.badlogic.gax.graphics.g2d包下,该类的子类有Sprite、TextureAtlas、AtlasRegion
实际操作中我们也经常使用图片的一部分,或者将多个图片资源集合在一个图片文件中。而要显示图片的一部分就可以使用TextureRegion类。其实可以理解为就是截图工具,从左上角开始截图,然后可以定义截图的大小
TextureRegion一般都是截取texture,然后定义截取起点(x,y)随后再定义宽高(width,height),如果宽高是正数,那么就是沿x、y正方向截取,如果是负就是沿x、y负方向截取,方向只和宽高的正负有关
###Sprite 该类在com.badlogic.gdx.graphics.g2d包下,继承自TextureRegion类,它的子类有TextureAtlas、AtlasSprite
TextureRegion的加强版,比TextureRegion多了一些功能,如:可以指定位置、颜色、旋转等。其实Sprite的功能就是以上的集合。但是Sprite更方便,它用一个对象描述了一切,但是同时加入了很多;TextureRegion和Texture没有的东西,如位置、颜色、旋转等等。
###SpriteBatch
该类存放在com.badlogic.gdx.graphics.g2d的包下,也是继承自Object,实现了Disposable接口
SpriteBatch可以把许多相同纹理一起描述并一起送入GPU,同时赋予纹理和坐标以便每个图形的绘制。其实可以把SpriteBatch理解为就是一个画笔,没有画笔是画不了画的
在MainActivity.java类中,把initialize()方法中的useGL2IfAvailable参数改为true就行了,就可以随便任何分辨率图片不必是2的N次方了。不过需要特别注意的是最好在安卓真机上进行调试,模拟器很容易报错不识别
libgdx使用的是笛卡尔坐标系,以左下角为原点,绘制方向是由下向上,由左到右
###TexturePacker-Gui工具与TextureAtlas类
Gdx.files,它是libgdx的文件模块,主要提供以下5大功能:读取文件,写入文件、复制文件、移动文件、列出文件和目录。其中获取文件有几种方法:
- Classpath:路径相对于classpath,文件通常为只读;
- Internal:内部文件路径相对于程序根目录或者android 的assets文件夹;
- External:外部文件路径是相对于SD卡根目录;
- Absolute:assets文件夹本身就是存储资源的文件夹,而且相比resource文件夹,它其中的资源不会生成R中的ID,用来放图片很是合适。
##文字显示
###Hiero


