Android游戏引擎之LibGdx介绍及各模块概述

转自http://blog.csdn.net/zccjscsdn/article/details/7571528

TheArchitecture

Libgdx是一个跨平台(Windows,Linux,Android)的游戏开发框架,它主要是用Java写的,其中也参杂了一些C/C++代码,这些代码是为了处理一些对性能要求很高的操作,比如物理引擎或者音频处理.作为用户,你只需要关注Java端就可以了,它已经把所有的本地代码封装好了.

Libgdx允许你使用Android上面同样的代码在桌面PC上面编写,测试,调试你的应用(也就是说,你可以不需要打开Android模拟器,就可以调试用Libgdx引擎写的游戏应用),把剥离了常见的Windows之间/ Linux应用程序和一个Android应用程序的区别.一般的开发过程是尽可能的在停留桌面PC上,同时周期性的检查你的当前代码是否仍然能在Android运行.

 

Libgdx将尽力提供一个统一的架构你的工作,以保证在所有平台上相同的行为.可悲的是这个崇高的目标肯定达不到.最大的不同点在于桌面PC和Android设备在于Android设备通常比桌面PC要慢得多.这意味着你的应用在PC上面运行的极快,但在Android运行的就像蜗牛在爬.在本教程中,我们将会遇到很多能做的和不能做的规则,你应该遵守这些规则,为了保证即使在低端Android,你的应用都拥有良好的运行效果.

 

作为游戏开发人员,我们需要一系列的系统组件是我们能够制作是我们梦中的游戏:

·应用程序框架,处理我们应用程序的主循环和生命周期(创建,暂停,恢复,销毁).

·图形模块,它提供了一种方法让我们在屏幕上画一些东西.

·音频模块,播放音乐和声音效果.

·输入模块接收来自鼠标,键盘,触摸屏,重力感应设备等用户输入.

·文件I / O模块读写数据例如:纹理,地图或配置文件中的数据.

libgdx包含上述名单涉及到的所有模块.对于每一个模块存在一个或多个为每个平台实现的Java接口.这些实现被称为后端.目前有一个桌面后端一个applet后端和android后端.

作为一个程序员,你不需要关心你的后端与实际工作.你只工作在每个后端实现公共接口.唯一的平台特定的代码,你只需要写libgdx的一个具体的应用实施实例,如一个用于台式机和一个用于Android.所以,这里是一个愚蠢的小图:

在图中的那些名字实际上就是那些你在写基于Libgdx应用所要用到的公共接口的名字.Application负责管理每一个子模块.有可能只有一个应用,也有可能所有子模块的都有一个实例.让我们仔细看看这些不同的模块.

 

TheApplication

应用模块负责让你的游戏在特定平台上运行.它将实例化子模块,在桌面PC上创建一个窗口或者在Android上面创建一个Activity,并且显示处理UI线程.你通过一下三种方法同应用交互:

·访问子模块

·查询信息,比如当前应用运行的平台信息

·注册一个ApplicationListener

最后一种方法允许你得到生命周期时间的通知以及对这些事件进行反馈.Libgdx应用的生命周期简化了Android Activity生命周期的模型:

是的,3种方法对于任何人来说都足够了.每次这些事件一发生,Application将会调用该注册ApplicationListener的指定方法.因此,在何时这些事件发生了呢.

·ApplicationListener.resume()在应用程序启动或者应用从一个暂停状态恢复的时候被调用一次.

    ·ApplicationListener.pause()在应用程序被中断或者被一个外部事件暂停,这些外部事件可能是:一个来电,用户按下Home键.应用程序根据用户的操作将会被恢复或者销毁.

    ·ApplicationListener.destroy()在应用程序将要销毁的时候被调用

显然,在桌面PC上面没有暂停事件,但是如果我们想要在Android设备上面运行应用程序,我们仍然要准备好暂停事件.

注册一个ApplicationListener不是强制的,然而这样做可以帮助你更好的处理一些事情,比如:在程序开始的时候读取配置文件,在程序销毁的时候销毁程序所使用的一切资源.暂停事件在图像模块中有着重要的作用.接下来我们将会涉及到它.需要记住的是:暂停可能会发生.

然而,你可能会问到主循环在哪儿.它不在这里:).应用程序包装了依赖平台的UI线程,这些线程有基于事件的性质.我们不能在UI线程里面添加一个无限循环,因为这样会冻结整个应用程序.UI线程通常是基于事件的,这意味着当除非有事件需要处理,比如:键被按下或者鼠标点击,操作系统将使UI线程转入休眠.这不是放我们游戏主循环的好地方.

信不信由你,游戏具有天生的多线程性质.除了UI线程,libgdx为你生成了第二个线程.但它不属于应用模块,而是属于图像模块.所以接下来,我们来看看它都做了些什么.

TheGraphics Module

虽然有的游戏不需要不断的重新绘制屏幕,但是Libgdx假设你想要的游戏需要不间断的绘制屏幕.这是个简单的概念并且你不需要去关注任何脏标记或者去关注在某些游戏状态改变的情况下重新绘制屏幕.

    我们已经知道UI线程不是一直不间断的运行的,而是在事件的驱动下有操作系统调度运行的(粗略的认为 :p).这就是我们为什么实例化第二个线程,也就是我们通常说的渲染线程.这个线程是由Graphics模块所创建, Graphics模块本身由应用模块在程序启动的时候实例化.

渲染线程执行一个无限循环,由于应用程序的生命周期事件,它可能会被暂停或者恢复.作为开发者,你可以通过注册一个RenderListerner将这个线程与图形模块连接起来(是的,我太喜欢回调了...).与ApplicationListener相似的是,RenderListerner对由图像模块渲染线程触发的特定事件做出回应:


在我们进入这些方法的详解之前,我先给你介绍一些细节:libgdx使用OpenGl ES,这个是移动设备上硬件加速图像渲染的工业标准.OpenGL ES同一个叫做EGL的东西一起使用,EGL负责设立一个窗口系统和图像硬件的链接.它创建一个渲染表面,用户可以添加一个用户界面组件到上面,图形硬件可以不通过使用UI工具包直接渲染.OpenGL ES自身额外的添加了一个叫做图形上下文的东西,他用于管理驻留在显存中的图形资源.举个例子,这些资源可以是一个纹理,它从本质上来说就是一张位图.OpenGLES将其建立在EGL的表面和背景,通过图形处理处理器获得高质量的图片.

通过以上信息,对于RenderListerner方法,我们有了一些感性的认识,接下来,我们将详细的介绍它.

·RenderListener.surfaceCreated()在EGL的绘图界面和上下文被建立,并且我们已经准备通过OpenGL画图的时候被调用.这一般发生在应用第一次启动或者当应用从暂停状态到恢复状态.

·RenderListener.surfaceChanged()在EGL的绘图界面大小发生改变的时候被调用.这一般发生在屏幕方向发生改变或者桌面上的窗口大小改变.

·RenderListener.render()不断的被调用,而且这里是随着游戏的运行实现我们游戏逻辑的最好的地方.每次从这个方法返回时Libgdx会确保你在方法内所绘制的东西得以在屏幕上显示.如果应用程序被暂停,那么渲染线程也将暂停,因此这个方法将不会被调用.

·RenderListener.dispose()在应用程序即将死亡的时候被调用.这里是做一些清理工作,比如记录高分或者保存一些信息的可选择的地方.

现在,所有的都看起来很棒和清晰.我们知道在哪里放置游戏主逻辑循环(RenderListener.render())并且我们也知道其它的那些方法的意思,但是仍然还有一些疑惑没有得到解答.

 

请记住,EGL上下文负责管理显存里面所有的图片资源,主要是纹理和几何单元.现在,每一次一个OpenGL ES Android应用程序暂停,上下文和绘图界面的东西都会被销毁.这也意味着在显存中的所有图片资源也要被销毁.当程序再被回复的时候,一对新的EGL上下文和绘图表面显示的被创建,然而我们的资源已经消失,在下一次RenderListerner.render()方法被调用后,我们很可能会看到一个空白或者白色的画面.

    通常情况下,你因此需要了解哪些资源当前在显存中,当应用程序暂停的时候,你必须标志那些被销毁的资源.当程序回复,RenderListerner.surfaceCreated()方法再次被调用的时候,你必须重新加载那些被销毁的资源,以便下次RenderListerner.render()方法调用的时候使用.这是令人相当讨厌的.

    这就是为什么libgdx将自动重新加载所有图片资源的原因.这些资源成为被管理者,这意味着libgdx将会管理他们,使他们永远不会被销毁,除非你希望销毁它们.管理资源不耗费额外的内存,所以使用它们不费吹灰之力.

    然而,有一种情况,你想要使用非托管的图形资源,如果你想在程序运行的时候操作纹理的内容,你将不能使用一个托管的纹理.我们将在以后详细的介绍这点.现在你只需要记住在libgdx中所有的图片资源都是被托管的,你永远也不需要担心一个EGL的上下文或者绘图表面丢失.

    那些拥有OpenGL ES经验的人或许已经在怀疑我是不是吃错药了.显然,在桌面环境下没有通过Java使用的OpenGL ES实现.但是,现在有了.Libgdx通过Windows和Linux上的标准OpenGL API模拟了OpenGL ES.几乎支持所有的特性,比如定点数学等等.现在唯一不支持的只有固定的顶点缓冲对象和一些小的getter方法.我们将在后面详细介绍这一问题.

    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 1.0,1.1和2.0兼容的.着色程序和帧缓冲器只有在使用OpenGLES 2.0的时候才可以用,因为OpenGL ES 2.0 API和OpenGL ES 1.x是不兼容的.像素图同OpenGL ES没有联系,因此可以在任何版本中使用.

在整个libgdx中反复出现的主题围绕着释放和处理不使用的资源.在移动设备中内存很小,因此我们努力的去减少内存或者显存的使用,释放那些不在使用的资源.所有的图形资源都拥有dispose()方法,一旦你不再使用这个资源,你应该调用它.对于资源内存的显示管理的另一个原因是,其中的一些对于虚拟机来说是不可见的,因此这些不可能被当做垃圾收集.拿像素图来说,它的像素存储在本地堆中,而本地堆不是由虚拟机所管理的.所有的垃圾收集器看到的只是一个很小的占据了几个自己的类的实例,垃圾收集器可能会因此推迟收集此类的实例,导致我们在本地堆中的内存溢出.对于在显存中的OpenGL ES资源来说,道理是一样的.因此,一定要记住:始终要释放不再需要的资源.

 

如果你想要更底层的操作,你同样可以访问已绑定的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,因此对于一些老的设备,你可以拥有单独的方法渲染.

Graphics包为了你的图形编程需求提供了很多有用的类,比如纹理地图,精灵,摄像机,3D格式文件装载器等等.我们将会在以后的章节中讨论这些.如果你对所有这些都很感兴趣,那请下载SVN源码.

 

TheAudio Module

我们的视觉效果应该由一些效果很好的重金属音乐(或者科技舞曲如果你是这种类型的)支持.爆炸是任何一款卖的很好的游戏的一部分.因此Libgdx拥有一个专门的音频模块,他提供两种类型的资源:声音和音乐.

Sound(声音)类旨在播放声音效果.通常你从一个文件中加载声音效果,根据某些事件,例如僵尸脑袋爆炸,调用Sound.play()方法播放它.声音通常很短,在几秒钟的范围内.他们会在内存中加载和解码.如果它们长时间的运行,很可能会占据很大的一些内存.

Music(音乐)是你所想要使用的为了播放很长事件的声音(或者,好吧,就是背景音乐)的类.音乐是流的形式,那意味它仅仅是部分被装载进入了内存,根据文件格式解码,然后输出到音频设备中.

声音和音乐都是系统资源.如果图形资源一样,你必须在它们不再被使用的时候,通过调用Sound.dispose()和Music.dispose()方法释放它们.

Libgdx支持mp3,Ogg以及Wave文件格式,我建议你在大多数情况下使用Ogg格式.

 

如果你需要对音频设备更多的控制,那么你可以使用AudioDevice和AudioRecorder类,这两个类可以从Audio接口得到.这些类允许你从物理音频设备输出PCM音频样本,也允许你使用麦克风记录PCM样本.不要忘记清理它们.

 

如果你想要做一个音频分析游戏,假如你想做下一代音乐战机,在这个特殊情况下,这里有一些类很可能会派上用场.在做任何事情之前,你需要取到音频文件的PCM样本,因此libgdx封装了libmpg123和Tremor的本地代码.Libmpg123是一个浮点数解码器,能从mp3文件中返回PCM数据.Java类是Mpg123Decoder.Tremor是一个有Xiph提供的高效率的固定点Ogg解码库,可以通过VorbisDecoder类使用它.最后,还有一个对轻量级和优秀的kissfft本地库的封装,它让你拥有进行一系列fourier音频变换的能力.封装本地代码库的类是KissFFT.像往常一样,在这些类的实例不再使用的时候释放掉.

 

音频包以及子包中有很多帮助类,他们可以减轻你编写音频处理类的痛苦.

 

TheFiles Module

有时,你需要装载你的图片或者音频文件,这时就该文件模块出场了.现在,如果你曾经做过任何Android开发,那么你就会知道标准的Java规则不总是适用.特别是那些没有将数据存储在应用的asset文件夹下的情况.在Android中,你有多个预定义的文件夹,比如assets,drawables等,你可以将文件放置在其中.然而,你也可以使用Java的类路径(例如getResourceAsStream()),Android也支持,不过有点不稳定.我们因此决定采用别的方法来读取或者写入文件.输入文件类型.

文件模型有三种不同的文件类型:

·Internal files(内部文件类型).这些文件将和你的应用程序绑定在一起.在桌面PC环境中,它们相对与你的应用程序根目录而存在.在Android上他们存储在assets文件夹下,我们本也可以提供一种方法来访问drawable文件夹下面的数据,但是最终决定放弃这个想法,因为在这个文件夹中的数据有可能在系统载入文件的时候被改变.作为一个游戏开发人员,我们希望对我们的文件完全控制. Internal files是只读的.

·External files(外部文件).这些文件有可能从服务器上下载来的,或者是你创建用来保存高分辨率或者设置.在桌面环境下,它们将相对于当前使用者的home目录存储.在Android下,它们将相对于SD卡根目录存储. External files是可读,可写的.

·Absolute files(绝对文件).如果你想体验一下痛苦,你可以使用绝对文件,它不是平台无关的,如果你使用绝对路径,那么它只能在你的电脑中运行. Absolute files是可读,可写的.

文件接口为你提供多种方法去获取FileHandles,文件读写,列出目录等等.同其它模块的交互也经常使用FileHandles.有时,输入/输出留也是可以做到的.

标准Java规则适用于处理文件,你需要关闭任何一个你打开的输入/输出流.如果其它模块占用着FileHandle,它将为你自行处理所有的清理工作,因此你不必担心这些.

 

TheInput Module

整个体系的最后一个模块是输入模块.顾名思义,它为你提供了访问应用程序运行平台的输入外设的能力,我们把这些东西统一到了一起.

    鼠标和触摸屏是相似的外设.我们采用触摸屏模式,所以在输入模块中没有鼠标事件,有的只是拖动,按下和弹起.在触摸屏中经典的鼠标事件(比如,你没有按下一个按钮,只是光标在上面滑过)是不存在的,因为把手指悬停坐在屏幕上空并且滑过整个屏幕不产生任何输入事件.基于同样的原因,我们不区分鼠标按钮.在这个模块中仅有一个单键的鼠标按钮,但是我们识别触摸屏上的多点触摸事件.在桌面PC环境中,显然只有单个触摸.在Android上面,这个问题有点复杂:很多老的设备不支持多点触摸.但是,虽然一些新的设备比如 Motorola Droid或者是Nexus One 支持多点触摸,却没有多手指追踪.(是的,这是真的),你可以通过Files接口查询是否支持多点触摸.如果是支持,那么这个设备要么支持多点触摸手势,要么是支持多手指追踪.记住这一点区别.

    多数Android设备同样没有专门的键盘,不要担心,我们没有去掉键盘支持,但是我们是这样做的:我们认为你在所有设备上只需要处理一套键码,然后有一些键只能在特定设备中才有,比如Android的 back,home,search,menu键在桌面PC上是见不到的.轨迹球事件也被当作键盘事件处理.

我们将触摸屏事件和键盘事件归为两类:

·Polling access(轮询访问).只是询问Input接口是否有键按下或者触摸屏被触摸.

·Event based handlind(事件驱动).你可以使用Input接口注册一个InputListener,它将接收所有的触摸屏和键盘事件.这些事件通常在UI线程中处理.在以前的文章中我们提到的,是在渲染线程中.为了减轻使用的难度,我们设定InputListener只有在渲染线程中才能被调用(事实上是在RenderListerner.render()方法被调用之前).

最后,Android上面的重力感应设备同样在桌面PC上面是没有的,我们设定的该事件处理方式或许有些愚蠢,因为它总是产生事件,因此你只可以使用轮询方式来访问当前的重力感应设备的状态.

注意,我们处理多点触摸的方法略逊于Android的多点触摸API,在Input接口中处理所有与处理InputListenner接口中触点索引的触摸事件是一样的.第一个触摸到屏幕的手指标记为触点0,第二个触点为1...以此类推.某个手指的触点索引将与其在触摸屏上停留的时间相同. No bit-masking, no other mojo involved.

给使用多点触摸的人一句话:小心使用.如果你准备在只提供多点触摸手势检测的设备上实现在其屏幕上利用自定义的按钮做一个屏幕方向键盘,这将会导致莫名其妙的结果(这句话的意思就是不要在只支持多点手势检测的设备上做多点手势追踪的事情).在设备上测试你的输入方法,看看是不是有上述问题,确保它们以你预计的方式工作.用户将会感谢你的.

 

TheNetwor... Wait, What?

我们决定不在Libgdx中包含网络模块.值得庆幸的是Android支持大多数标准Java scoket API(有一些轻微的偏差,如果你偶然碰到,你也很少会去注意).如果你想创建一个多人游戏,目前你只能自己编写网络代码.我们将会在未来某个时间加入一些,但是别抱太大希望.在网上找一些兼容的Java游戏网络库吧!(可以看LGame里面的网络库,那个里面有的)

NotReally Modules but Still Useful

在Libgdx中除了一些标准模型外,也包含一些对你游戏编程很有用的包:

·math(数学).这个包中有良好的的三角函数查找表,矩阵,四元数,向量类,样条(是指通过一组给定点集来生成平滑曲线的柔性带.此概念源于生产实践,“样条”是绘制曲线的一种绘图工具,是富有弹性的细长条.绘图时用压铁使样条通过指定的形值点(样点),并调整样条使它具有满意的形状,然后沿样条画出曲线.),平截头体,多边形三角测量,相交代码.虽然这些方法都很高效,但是碰到如果计算量很大的话,还是考虑一下直接使用本地代码吧(JNI).

·box2d(一个物理引擎).是的,我们有点疯狂,用Java JNI写了一个完全的Box2D.这样做的原因是:1.它比用JBox2D快多了.2.它不会产生让垃圾收集器发疯的垃圾.其他的项目,比如,Rokon或者Andengine都使用了我们的这一部分代码:).

·scene2d.一个好的2D场景地图API,它很灵活,适合拿来做UI.

·utils.包含了一些辅助类,大多数是为了减少垃圾收集器的工作.比如自定义的hashmap实现,对象池等等.我们还把JSON库包含了进来,如果你想要读取或者写这个类型的文件,那你就以他们的格式提供材料

 

 

TextDict:纹理字典用于跟踪你使用的Texture并提供一个访问Texture资源的支点.它存储TextureRef,如果你需要在你APP的不同位置加载相同的Texture,那么它将只被该类加载进内存一次.—缓存

public class Spriteextends TextureRegion:因此能把Sprite当成是TextureRegion来使用

SpriteBatch:本质上是OpenGL的简易封装体.用于绘制引用Texture(region)的2D矩形.该类将批处理绘画命令并优化他们然后交给GPU处理;该类也是managed,在这种情况下OpenGL上下文丢失时那么SpriteBatch所使用的OpenGL资源都将会变成无效.当用户切换到另外的APP或者接听一个电话时上下文将被丢失.当OpenGL上下文恢复时该类会被自动重新加载;该类是个非常重量级的对象,因此在程序中尽量只存在一个实例;该类能运行在GL1.x和GL2.0上,当在2.0的情况下它会使用2.0自定义的着色来绘画提供的精灵.你所指定的着色将不起作用.

Sprite:持有几何形状,颜色,Texture信息以使用SpriteBatch来绘制2D精灵.每个Sprite有一个位置以及大小(width,height).位置是相对坐标系统原点

Texture:包装一个标准OpenGLES的纹理,该类也可以被managed.它通过Texture.bind()函数来适用到几何形状上.该对象会被绑定到当前活动的Texture单元通过指定GLCommon.glActiveTexture();你可以在任意时刻绘制Pixmap到Texture.这变化会被自动的更新到Texture内存.这是非常快的因此使用它时要非常小心.它只使用于unManagedTexture;不使用Texture必须释放掉.

Gdx:环境类持有Application,Graphics,Audio,Files,Input的引用.由于这些字段是static的,所以不要乱用.这基本上可以让你对谁有子系统进行访问.不要在非渲染线程中使用Graphics;还有持有GLCommon,GL10,GL11,GL20和GLU的引用,与上述规则相同,不要乱用或者打破规则.

interface GLCommon:定义GL1.X,GL2.0的公共函数

BitmapFont:渲染位图字体.字体由两个文件组成:一个图像文件或者包含字形和一个构造在AndleCode BMFont文字格式中的描述每个字形在图片中的位置的TextureRegion.目前只支持单个字体图片.文字被通过SpriteBatch绘制.文字可以被通过BitmapFontCache缓存以更快的渲染出静态文本(从而节省需要计算每个字体的每一帧位置).在使用完时需要及时释放资源.

 

 

游戏相关度较高的包为Graphics,它包含着LibGdx进行OpenGL渲染所提供的功能实现,以及一个Scenes包,它包含着LibGdx所提供的可以直接使用到游戏中的游戏组件,分别为Scenes2D和Scenes3D两部分(3D部分暂无内容),2D部分核心在Actor类,LibGdx的2D组件基本上是围绕着Actor展开的

Libgdx由audio,files,graphics,math,physics,scenes,utils等主要类库组成,分别对应Libgdx的音频操作,文件操作,2D/3D渲染,绘图相关运算,Box2D封装,2D/3D游戏组件,内置工具类.

 

 

 

SpriteBitch:

Binding一个Texture是一个开销很大的操作.由于这原因,它通常存储很多小图到一个大图里去,然后再绘制大图的区域并避免Texture发生变化.更多信息参考TexturePacker

Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT)以清除屏幕.

所有的绘画操作的调用必须在begin和end函数之间.并且她们之间不能存在非SpriteBatch绘画的操作

 

Texture

它解码图像文件并加载到GPU内存,图片文件应该存放到assets文件夹下,图片的像素应该是2的幂

 

TextureRegion

描述了一个在Texture内的矩形,并是对于画一个存在于Texture中的部分非常有用.

 

Sprite

描述Texture的包括区域,将要绘制到的几何以及将要绘制的颜色.

 

Blending

混合默认情况下是启用的.这意味着,当一个Texture绘制的时候,它的透明部分与像素会在屏幕的对应位置被合并.当禁用该属性时,已经在屏幕的该位置上的将被Texture代替.

 

Viewport

SpriteBatch管理它自己的投影和变换矩阵.当一个SpriteBatch被创建的时候,它使用当前程序的大小并设置它的正投影使用Y坐标系统,当begin被调用时,它设置了ViewPort

 

Performancetuning

SpriteBatch有一个构造函数以用来设置在发送到GPU之前的最大可缓冲精灵数.如果这数字太小,会导致额外的GPU调用.如果太大,SpriteBatch将会须要更多的内存.

SpriteBatch有个公共的int型字段MaxSpriteInBatch,它表示在生命中最大的可以发送到GPU中的精灵数.设置一个非常大的SpriteBatch大小并检查该字段可以帮助确定最佳的SpriteBatch大小.它应该是大于等于或略高于maxSpritesInBatch一些.该字段在任何时刻可以被设置为0以重置它.

它有一个公共的int字段renderCalls.在end调用之后,改字段表示在最后一次调用begin和end之间多少次的几何被发送到GPU.当不同的Texture被bound时,或者SpriteBatch缓冲了足够多的精灵,如果SpriteBatch是适合大小的并且renderCall是大的(超过15-20),这时候表明许多Texture正在进行bind.

SpriteBatch有一个额外的构造函数以携带一个size和一个缓冲区大小的number.这是一个高级的功能将触发VBO被使用来代替正常的VA.缓冲的列表被保持,并且每个渲染调用使用列表中的下一个缓冲(循环).当maxSpritesInBatch低而renderCalls是高.这可能会提供一个小的性能提升.

 

scene2d

Scene2d包是一个用来管理层次的Actor组的2D场景图表.它提供了支持持有输入和在坐标系统中的相对于父Actor的图形选择和缩放.它通常提供一个随着时间的推移(渐变)的Actor操作的行为框架.该包提供用于构建GUI的Actor.

 

Importantclasses

Stage类有一个root组的以用来APP可以增加他们的Actor.Stage有一个Camera和一个SpriteBatch.该Camera的Viewport是屏幕的大小.当Stage被绘制,该SpriteBatch也被传输给root组.Stage是一个InputProcessor并传递input事件到root组.

组里的类是一个包含其他Actors的Actor.组中的旋转和缩放将会影响到它的子元素.组委托画图和input处理到合适的子元素.组转换坐标所以子元素在它自己的坐标系统中接受坐标.

Actor类提供在场景图中节点的所有基本功能.位置,大小,缩放,旋转,起点,颜色.它有一个可选的名字以用来允许Acttor去通过名字寻找它

 

Stagesetup

一个Stage有个viewport大小.这可以在构造函数中指定,这通常是一个好主意去设置Stage的viewport当APP重置大小时.该构造函数一般携带一个boolean值的’stretch’.如果true,Stage将被拉伸到设备的分辨率,如果false,Stage的更大分辨率会被拉伸到适应设备的分辨率.如果在resized函数中设置Viewport对于设备的分辨率,那么stretch设置将不会产生作用.

Stage有个’act’函数,它携带一个最后一帧的时间差.这将导致act函数在场景中的每个Actor被调用,允许Actors在一定时间内进行一些行为.Stage调用act是可选的.

 

Actors

继承抽象类Actor去绘制,碰撞检测,以及在场景图表中持有input

 

Drawing

当Stage的draw被调用,它在root组里调用draw.组在它的子元素中调用draw.绘制一个actor,实现draw函数:

SpriteBatch拿到的Actor是以及被父组转换了的,因此.Actor的位置,大小,旋转,缩放是从左下角开始计算.这使得在正确的地方使用SpriteBatch绘制很容易.

如果Actor的visible被设置成false,组不会调用该Actor的draw.

SpriteBatch的begin被完成调用当Actor的draw函数被调用.如果一个Actor需要执行draw以其他方式,例如携带ShapeRenderer,该batch需要被end然后重新开始begin.当然,这将导致该batch被刷新,所以要小心使用.

 

Hitdetection

当在Stage中hit被调用,它在组中调用hit.组在它的子元素中调用hit.第一次调用hit返回Stage中的一个Actor.要做hit检测,实现hit函数:

Hit函数返回hit了的Actor,如果没有hit则返回null.坐标系统被赋予给Actor的坐标系统.

 

Inputhandling

为了处理touches,实现touchDown, touchDragged, andtouchUp函数:

当touchDown发生在Stage,它在root组上调用touchDown.组在子元素上调用hit.touchDown函数在通过调用hit时返回的第一个Actor上发生.如果touchDown返回false,这意味着Actor选择区忽略该事件而处理器继续把它送达到下一个Actor.如果返回true,该Actor变成聚焦Actor.这意味着它将会受到touchDragged和touchUp调用,即使它们没有发生在该Actor上.当touchUp被调用,该Actor会失焦.

组的touchDown函数重写时,如果不调用super函数,那么子元素不会收到任何touch事件.

如果Actor的touchable被设置成false,组将不会对该Actor调用touch

要处理键盘输入,重写keyDown,keyUp,以及keyTyped函数.这些只会在Actor获得键盘焦点时调用(通过对Stage调用keyboardFocus)

 

MeshColorTexture

Mesh:

构造函数:第一个指定是否是静态.如果true将启用OpenGL有益的优化.第二,三个参数指定顶点和索引的数目.由于Mesh代表一个三角形,它有三个顶点.每个顶点在渲染时使用一次,所以Mesh需要三个顶点.最后我们传递一个VertexAttribute对象到指定参数.在VertexAttribute构造函数中,我们传递表示位置信息的Usage常数.然后传递一个整形数的代表每个位置的组件.由于位置由3个点构成(x,y,z)我们传递3个.最后我们设置VertexAttribute的别名.

创建Mesh之后,通过float数组指定它的顶点.第一个3个float是x,y,z的.下一个3个float构成顶点1,最后一个3个float构成顶点2.然后设置索引,以用来给三角形经过.

Mesh. render(int primitiveType, int offset,int type):参数一指定基本形态的类型.参数二如果Mesh代表一个顶点缓冲区时指定偏移量.顶点缓冲区将在以后教程中提到,这里只有0.最后一个参数指定Mesh使用的索引.

 

Texture

在Mesh上增加一个Texture,我们需要把一张图片放到我们的工作空间,创建一个Texture对象到代码中并引用那张图片,然后增加一个TextureAttribute到我们的Mesh

 

ProjectionViewportCamera

Camera.update():重新计算Camera的正投影和视图矩阵.

Camera.apply():设置当前Camera的投影和模型视图矩阵.仅适用于GL10和GL11.确保在调用它之前先调用update()函数.

Projection

一直在使用的OrthographicCamera只能用于制作2D效果,3D效果需要使用透视投影(perspective projection).

Camera.rotate():基于给定的旋转轴进行旋转.

Camera.translate():在给定的旋转轴移动相机

 

你可能感兴趣的:(android,android,游戏,引擎,图形,平台,java)