黄金周第一天,将之前开发的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
首先要说的是,在iOS的不同framework中使用着不同的坐标系:
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是将要绘制的UIImage图片,width和height是它的宽高 CGContextTranslateCTM(context, 0, height); CGContextScaleCTM(context, 1.0, -1.0); CGContextDrawImage(context, CGRectMake(0, 0, width, height), uiImage.CGImage);
解决方法二:使用UIImage的drawInRect函数,该函数内部能自动处理图片的正确方向
// uiImage是将要绘制的UIImage图片,width和height是它的宽高 UIGraphicsPushContext( context ); [uiImage drawInRect:CGRectMake(0, 0, width, height)]; UIGraphicsPopContext();
解决方法三:垂直翻转投影矩阵
这种方法通过设置上下颠倒的投影矩阵,使得原本y轴向上的GL坐标系看起来变成了y轴向下,并且坐标原点从屏幕左下角移到了屏幕左上角。如果你习惯使用y轴向下的坐标系进行二维操作,可以使用这种方法,同时原本颠倒的图片经过再次颠倒后回到了正确的方向:
// uiImage是将要绘制的UIImage图片,width和height是它的宽高 // 图片被颠倒的绘制到context CGContextDrawImage(context, CGRectMake(0, 0, width, height), uiImage.CGImage); // 设置上下颠倒的投影矩阵(则原来颠倒的图片回到了正确的方向) glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof( 0, framebufferWidth, framebufferHeight, 0, -1, 1 );
在极其有限的工作日的晚上和周末进行着iOS上game programming的研究,进展非常缓慢,不过还是有必要将过程中的一些问题随时记录下来。
这很有可能是因为在OpenGL ES2的context中使用OpenGL ES1的函数,ES1是固定函数渲染管线 (fixed function pipeline),而ES2是可编程的渲染管线 (programmable pipeline),ES2不再支持这些ES1的固定渲染管线的函数, 比如’glMatrixMode’。所以当ES2遇到这些不支持的ES1函数时,你的程序会收到一个’EXC_BAD_ACCESS’消息并且崩溃。通过gdb查看callstack,显示最后一个函数是gliUnimplemented:
#0 0x0b05c0e5 in gliUnimplemented () #1 0x00a1c6c3 in glMatrixMode ()
如果一定要使用ES1函数, 你只能以ES1来初始化你的GL context:
EAGLContext *aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
需要将资源文件添加到项目的’Groups & Files’中
这可能是因为你启动了GL的某个渲染状态(比如vertex,color,texture coordinate等等,这里有所有可能状态的清单),但是却没有在绘制函数(比如’glDrawArray’)进行之前,设置该状态所对应的数据指针。
比如说:
glEnableClientState( GL_COLOR_ARRAY ); glColorPointer( 4, GL_UNSIGNED_BYTE, 0, youColorArray );
对于上面这两句代码,如果你设置了使用color数组,但是却没有设置color数组指针,在真正的绘制时你的程序就会因为找不到对应的指针而崩溃。同样的, 如果你调用了‘glEnableClientState(GL_TEXTURE_COORD_ARRAY), 则你也需要通过glTexCoordPointer()设置纹理坐标的数组指针,如此类推。
在iPhone上通过OpenGL ES进行2D绘制时,默认的原点位置在屏幕中央,并且屏幕的坐标范围依次是从-1到1,不管是横轴还是纵轴。如下图所示,GL中的默认的单位1分别代表着屏幕长度和宽度的一半。
图片来自book: ‘Learning iOS Game Programming_A Hands-On Guide to Building Your First iPhone Game’
如果希望将原点移动到屏幕左下角,并且绘制时希望以像素为单位,只需要通过glOrthof函数将投影矩阵设置成一个垂直投影矩阵即可,代码如下:
glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof( 0, framebufferWidth, 0, framebufferHeight, -1, 1 );
Recent Comments