其实第一次尝试开始制作Bejeweled这个游戏是在年初,安装了这个游戏后发现所有的资源都在安装目录里,所以借clone这个游戏的过程来学习C++和OpenGL。由于之前遇到的阻碍使自己灰心下来,现在我又重新开始了,即使不能完全、完整、完美的把这个游戏给克隆下来,只要在这个过程中能学到新的知识,也是值得铭记的,不是吗?
虽然用到了OpenGL,但是这个游戏本质上还是2D的,其中会有部分特效(虫洞)需要借助于3D环境,起初我总想弄明白,如何调节视场的参数,来达到这样的效果:当我要画一个背景图的时候,使这个背景图的大小正好与当前程序的窗口大小相吻合?也就是说,让这幅图全屏显示。因为当把一幅图作为纹理来画的时候,必须要通过 glTexCoord2f (GLfloat s, GLfloat t);
为他指定图片四个角的坐标,而这里的参数都是float型的空间坐标(虽然有glTexCoord2i (GLint s, GLint t), 但是我还没搞明白是否是对应着像素的),所以,我觉得无法用一个float型的值来使他对应到当前所创建的窗口坐标的(1024 * 768的窗口,怎么对应?)。最后,我还是先把一个背景图先画上去,然后通过慢慢的调节当前镜头的远近,使其正好和当前窗口相吻合来得到的。这时,我也慢慢明白,作为3D坐标系里的物体,他在窗口里的大小,或者能否与窗口完全吻合,其实的确无法事先确定,就好比你拿着一台DV去录一个物体,当物体的位置已经确定的时候,只能通过调节镜头的焦距来调节它在DV显示屏上的大小。
当然,这些都是些细枝末节,整个程序的结构,各个类之间的组织结构、耦合,一句话---设计模式,才是最整棵树的躯干呢。不过,这个问题还真不是我现在能整理清楚的,慢慢来吧,先把今天遇到的几个小问题做下总结:
1、原来在一个程序里,并不是在平行投影和正交投影间二选一的。在程序中,完全可以根据需要进行两者的切换,这样就方便了做一些2D界面上的东西了,比如文本。 但是发现这个秘密的初衷却是在寻找如何画经由MASK雕镂的图片时知道的,对于背景是纯黑色,或者本身需要一张由黑白两色组成的mask图来决定其形状的图片,最开始我认为应该完全可以通过融合glBlendFunc (GLenum sfactor, GLenum dfactor)
来实现,但是我穷绝了这两个参数的所有配对,结果都不能达到预期的效果,后来仔细想想,既然是融合,那么就必须要是当前图片和缓冲里的图进行融合,而我的目的其实是要做到:凡是mask遮住的部分都不画出来,并且画出的部分是不透明的,这其实是做透明处理啊。 虽然,我不知道一个带有透明部分的图片要画出来的OpenGL方法是什么,但我知道,要想做到这样的效果,就必须拿到当前屏幕上的图片数据,再根据mask将相应部分画到屏幕上去。 而要获得当前屏幕上数据,就必须转换到2D坐标下(Beginning OpenGL Game Programming --- chapter 6 )。
2、为了印证在两种投影模式下可以互相切换,我又根据 Beginning 书 ch6 里提到的例子,先在屏幕上以像素为单位画一个数组形式组织数据的位图。结果又遇到两个小问题:
2.1 发现在创建一个图的纹理之后,位图就画不出。原因是这个纹理创建的时用的 是glTexImage2D
,这个函数要求图片的尺寸必须是2的幂 (网上有说必须是64×64、128×128、256×256三种格式, 这个以后待证。),所以当这张图的尺寸小于当前可支持的最大纹理尺寸(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim))时,就要对其进行适当的转换使他变为最接近的那个2的幂的数。 而这张图的长和宽都不是2的幂,纹理创建后,就会出现上述问题,奇怪的是,如果至少有一条边长满足2的幂就不会,而且,两条边都不满足时,当且仅当他最后一个创建纹理才会出上述问题,否则只要最后一个创建纹理图片至少有一条边满足2的幂这个条件,就不会出问题。
2.2 终于搞清楚导致画位图出问题的原因了,但是在画位图时,有条颜色设置函数glColor3f(1.0, 0.0, 1.0),在这之后,整个窗口都蒙上这个颜色了,像雾!你懂我意思吗? 最后也是在网上查到 再做下glColor3f(1.0, 1.0, 1.0)就恢复正常了。