1st Day of Golden Week
黄金周第一天,将之前开发的Pacman移植到了iPad上。因为Moai引擎,移植变得很容易,只需要把input层做一些修改。我的第一个iOS上的game demo就此诞生 已经将代码更新到了github – https://github.com/bennychen/Moai-based-Pacman
黄金周第一天,将之前开发的Pacman移植到了iPad上。因为Moai引擎,移植变得很容易,只需要把input层做一些修改。我的第一个iOS上的game demo就此诞生 已经将代码更新到了github – https://github.com/bennychen/Moai-based-Pacman
使用CGContextDrawImage绘制图片上下颠倒 首先要说的是,在iOS的不同framework中使用着不同的坐标系: UIKit - y轴向下 Core Graphics(Quartz) - y轴向上 OpenGL ES - y轴向上 UIKit是iPhone SDK的Cocoa Touch层的核心framework,是iPhone应用程序图形界面和事件驱动的基础,它和传统的windows桌面一样,坐标系是y轴向下的; Core Graphics(Quartz)一个基于2D的图形绘制引擎,它的坐标系则是y轴向上的;而OpenGL ES是iPhone SDK的2D和3D绘制引擎,它使用左手坐标系,它的坐标系也是y轴向上的,如果不考虑z轴,在二维下它的坐标系和Quartz是一样的。 现在回到问题,当通过CGContextDrawImage绘制图片到一个context中时,如果传入的是UIImage的CGImageRef,因为UIKit和CG坐标系y轴相反,所以图片绘制将会上下颠倒。解决方法有以下几种, 解决方法一:在绘制到context前通过矩阵垂直翻转坐标系 解决方法二:使用UIImage的drawInRect函数,该函数内部能自动处理图片的正确方向 解决方法三:垂直翻转投影矩阵 这种方法通过设置上下颠倒的投影矩阵,使得原本y轴向上的GL坐标系看起来变成了y轴向下,并且坐标原点从屏幕左下角移到了屏幕左上角。如果你习惯使用y轴向下的坐标系进行二维操作,可以使用这种方法,同时原本颠倒的图片经过再次颠倒后回到了正确的方向:
在极其有限的工作日的晚上和周末进行着iOS上game programming的研究,进展非常缓慢,不过还是有必要将过程中的一些问题随时记录下来。 OpenGL ES崩溃在函数’glMatrixMode’ 这很有可能是因为在OpenGL ES2的context中使用OpenGL ES1的函数,ES1是固定函数渲染管线 (fixed function pipeline),而ES2是可编程的渲染管线 (programmable pipeline),ES2不再支持这些ES1的固定渲染管线的函数, 比如’glMatrixMode’。所以当ES2遇到这些不支持的ES1函数时,你的程序会收到一个’EXC_BAD_ACCESS’消息并且崩溃。通过gdb查看callstack,显示最后一个函数是gliUnimplemented: 如果一定要使用ES1函数, 你只能以ES1来初始化你的GL context: 函数’pathForResource’返回nil 需要将资源文件添加到项目的’Groups & Files’中 OpenGL ES崩溃在绘制函数’glDrawArrays’ 这可能是因为你启动了GL的某个渲染状态(比如vertex,color,texture coordinate等等,这里有所有可能状态的清单),但是却没有在绘制函数(比如’glDrawArray’)进行之前,设置该状态所对应的数据指针。 比如说: 对于上面这两句代码,如果你设置了使用color数组,但是却没有设置color数组指针,在真正的绘制时你的程序就会因为找不到对应的指针而崩溃。同样的, 如果你调用了‘glEnableClientState(GL_TEXTURE_COORD_ARRAY), 则你也需要通过glTexCoordPointer()设置纹理坐标的数组指针,如此类推。 怎么样通过OpenGL ES以像素为单位来绘制,而不是屏幕比例? 在iPhone上通过OpenGL ES进行2D绘制时,默认的原点位置在屏幕中央,并且屏幕的坐标范围依次是从-1到1,不管是横轴还是纵轴。如下图所示,GL中的默认的单位1分别代表着屏幕长度和宽度的一半。 图片来自book: ‘Learning iOS Game Programming_A Hands-On Guide to Building Your First iPhone Game’ 如果希望将原点移动到屏幕左下角,并且绘制时希望以像素为单位,只需要通过glOrthof函数将投影矩阵设置成一个垂直投影矩阵即可,代码如下:
一年多前,曾经写过一篇关于Game Engine Framework的文章,当时基本上是为了巩固并加深对framework的理解。最近又做了一些关于framework的工作,对于framework的实现方式又有了些新的认识。虽然我现在做的已经完全不是game了,不过方式对于game也同样适用。 这篇文章主要希望通过一些示例性的C++代码介绍game framework的两种实现方式。首先,我还是搬出一年多前的那篇文章里的game流程图,以下的一些代码也主要基于这张图实现。对于图的细节在这里不再赘述,可以再去翻看之前的那篇文章。 1.通过继承 这是一种最传统的方式了,之前我一直使用这种方式。基本上是提供一个基类,基类封装并决定了整个程序控制流,同时基于该控制流,基类提供了一系列的接口(在C++里是虚函数),以供继承类override,并实现定制化的行为。就像下面的这个Game类,run函数决定了整个程序的执行逻辑,同时initialize,update,render等非纯虚函数则提供了接口以供用户定制并实现具体Game想要的行为。 在上面的代码中,我把实现全部写在了类的定义头文件中,在这里只是为了省事,在现实中你最好还是分开在.h和.cpp文件中。而且在这里,Game类还可以做的更多,我这里只是为了说明实现方式,所以依照前面的流程图而尽量让它简单。另外,不要纠结这段代码中的Event,Mouse,Keyboard等几个类和popEvent方法,它们只是我为了将故事说得更圆满一点而假象出来的几个类,我想你应该能猜到它们是用来干嘛的。 基于此framework,一个具体的游戏只需要重写这些虚函数就可以了,像下面的这些代码。 2.通过Delegation模式 前一种方法有一个缺点,就是将程序的控制流和具体行为紧耦合在了一起,而且还必须使用继承,不易于扩展。现代软件设计的一些方法告诉我们,要尽量使用接口,且尽量使用组合而非继承。Delegation模式就可以帮我们达到这一目的。 何为Delegation模式,wiki上的解释一语中的: Delegation is the simple yet powerful concept of handing a task over to another part of the program. Delegation将一些task委托给程序的另外一部分来处理,以达到了行为使用者和具体行为的松耦合。 以下是通过Delegation模式重新实现的framework。 基于此framework,当需要具体实现一个游戏的时候,只需要实现GameDelegation接口即可,然后将Game类的GameDelegation设置为你所实现的具体的ConcreteGameDelegation类,代码如下。 最近我正好做了一些iOS上开发的研究,发现Delegation在iOS框架中被普遍使用。比如,iOS中的每个应用程序对应的是一个UIApplication类,为每一个UIApplication,开发人员必须要实现一个特定的UIApplicationDelegate,并将它指定给当前的应用程序(在main函数中通过UIApplicationMain函数指定,或者是在nib文件中绑定)。在这个UIApplicationDelegate类中,开发人员就需要重写诸如didFinishLaunchingWithOptions,applicationWillTerminate这样的方法,就类似与上面game framework中的initialize,destroy等方法。当然iOS框架要复杂很多,它还用到其它一系列的设计模式,有空研究些这样设计是非常有趣的。 图片来自于这篇苹果官方关于iOS中delegation的介绍:http://developer.apple.com/library/ios/#documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
新买了MBP,在上面下载并安装了Xcode3.2.6,终于算是迈出iOS game development的第一步。由于现在工作已经基本跟game毫不相干,只有周末才有时间搞点自己的研究了:-( 在Xcode里新建第一个项目,基于模板“OpenGL ES Application”。不用写任何一行代码,iOS SDK已经为我们创建了一个可以运行的OpenGL应用程序了。从工具栏上点击“Build and Run”(或者通过command+return快捷键),试图启动运行程序。但诡异的是,无论怎样,程序都是一启动,闪动一下就退出了。 打开console(菜单->Run->Console),报出一大串的错误: LLVM ERROR: Cannot yet select: 0x900cd10: v4i32 = bit_convert 0x9013b50 [ORD=129] [ID=69] …… …… Failed to launch simulated application: Unknown error. 由于完全是个iOS新兵,花了好一段周折才解决,解决办法: 1.从Groups&Files的Targets下选择你的项目的target; 2.从工具栏点击“info”按钮,设置target属性; 3.将Build->Deployment->iOS Deployment Target从iOS 4.3改为iOS 4.2; 4.回到Xcode主界面,从工具栏的Overview下拉列表中,可以发现,多出了simulator 4.2的项(原来只有4.3),勾选iPhone Simulator 4.2或者iPhone Simulator 4.3; 5.再次运行程序,跳动的彩色小方块终于出来了。 在Project的info中也可以设置iOS Deployment Target,但是在target level设置的优先级会更高,且一个项目可以有多个target。 这应该是Apple的一个bug,iOS4.3太新了。不过这个错误只有OpenGLES的程序才会有,普通程序没有这个错误。Apple每更新一个新版本的iOS,对于开发人员来说,我想或多或少都会带来一定程度的pain。