1 文档简介
背景
2012年5月2日,Research In Motion(RIM)与其子公司QNX在2012黑莓世界大会上宣布,将面向中国广大高校学生举办基于BlackBerry操作系统平台的应用开发竞赛。那一年,我也是参赛者。
内容
此文档主要介绍在BB10(BlackBerry10)平台上的二维开发,适合黑莓初开发者,能让初学者快速入门以不走弯路。内容包括开发平台简介、BB10程序开发流程概述、BB10二维界面开发的关键技术、往程序中添加音效及应用程序签名。
2 开发环境
开发平台
调试、应用平台
开发语言
说明
(1)如果采用“SDK+ Playbook”搭配,在建立第一个工程项目时则需要配置好开发环境,具体包括“Device Setup”,”SigningRegistration”,”Debug Tokens”配置,这些只要按照提示一步一步往下做即可。配置好后就可以调试、运行程序了。
(2)如果采用“SDK +BlackBerryPlayBookSimulator”搭配,在安装模拟器之前需要安装java虚拟机,如果使用模拟器调试则需要安装“BlackBerryPlayBookSimulator”版本与“BlackBerryNativeSDK”保持一致(我的是2.0.1),这样二者才会保持正常的通信。
(3)BlackBerry NativeSDK与BlackBerryPlayBookSimulator下载地址为:软件下载地址:http://bdsc.webapps.blackberry.com/native/download/
3 BB10程序执行流程
概述
由于我选的开发工具为C语言,所以main函数是整个程序运行的入口点。在main函数中主要分为“系统初始化”,“主消息循环”,“程序释放”三个部分。程序开始运行后,首先进行“系统初始化”,包括开启“系统(平板)接收导航器和屏幕事件”、“系统(平板)接收导航事件”、“系统(平板)接收导航定位”等,这是在程序正式呈现界面之前需要做的初始化操作;然后程序才真正的步入用户程序,包括“事件检测和事件响应”、“数据更新”及“界面呈现”等;在事件检测中包含了是否“退出程序”这个事件,如果检测到了这个事件,则退出程序;在退出程序后,系统会自动的运行“程序释放”部分,包括“动态内存释放”、“停止事件请求”、“关闭bps库”、“关闭系统屏幕环境初始化”,释放顺序不可颠倒。否则可能会造成内存泄露。
(1)程序运行整流程图
图1.黑莓BB10程序执行流程 流程图
(2)平板支持事件包含图
根据自己程序需要,需要屏幕支持的事件为:
图2.屏幕事件包含图
4 黑莓BB10程序开发的关键技术
概述
此次黑莓移动应用开发是选用二维来展现图形界面,主要思想是载入已经存在的图片到内存中,然后再通过此段内存把图像按照需求显示出来。在这个过程中,采用黑莓特有的绘制图形的方法来展现图片---------顶点数组法。
顶点数组法的主要步骤为:
(1) 编写图片解析函数,把图片载到内存之中,返回图片句柄等信息。
(2) 指定已初始化的用来绘制图片的“顶点数组”与“纹理数组”。
(3) 调用OpenGL函数绘制图片。
(1) 解析图片
为了提升开发速度,请原谅我调用了样例中自带的图片解析函数:int bbutil_load_texture (const char *filename, int *width,int *height, float *tex_x, float *tex_y, unsignedint *tex);。
函数功能
载入一张png格式的图片。
参数:
filename是指图片的路径和图片名。
width,height用来返回图片的宽和高,使用时可设置为NULL。
tex_x, tex_y用来返回对纹理数组进行初始化的值。
tex是指向图片的句柄。
返回值
如果纹理图片被载成功返回EXIT_SUCCESS否则返回EXIT_FAILURE。
调用此工具函数载入一张图片后,我们用到的数据是tex_x,tex_y及tex,在调用OpenGL函数绘制图片时会涉及到。我们也可以自己编写函数来载入其它格式的图片,我们只需要知道对应格式图片的格式就可以了。类似的工具函数还有载入字体显示的函数,用户都是可以根据需求对其加以应用的。
(2) 初始化顶点数组和纹理数组
我们需要把顶点数组和纹理数组定义成全局变量,因为我们在其它函数中还要用到这两个重要的数据结构。然后在初始化全局变量函数中初始化这两个数据结构如下:
纹理数组初始化。
//初始化纹理数组
tex_coord[0]= 0.0f;
tex_coord[1]= 0.0f; tex_coord[2]= tex_x;
tex_coord[3]= 0.0f; tex_coord[4]= 0.0f;
tex_coord[5]= tex_y; tex_coord[6]= tex_x;
tex_coord[7]= tex_y;
顶点坐标数组初始化
//初始化顶点坐标数组
f_background_vertices[0]= 0.0f;
f_background_vertices[1]= 0.0f;f_background_vertices[2]=width;
f_background_vertices[3]= 0.0f;f_background_vertices[4]= 0.0f;
f_background_vertices[5]=height;f_background_vertices[2]=width;
f_background_vertices[5]=height;
纹理数组中的tex_x及tex_y是从bbutil_load_texture函数返回来的值,width和height是获取到的屏幕的宽度和高度,分别为640,1024。
(3) 顶点数组法绘制图形
采用顶点数组法绘制图形遵循这样的步骤:
<1> 开启二维纹理、顶点数组绘制法和纹理功能。
<2> 指定顶点数组和纹理数组。
<3> 绘制图片。
<4> 关闭顶点数组绘制法和纹理功能,关闭二维纹理。
下面分别来展示这4个步骤。
<1> 开启二维纹理、顶点数组绘制法和纹理功能
完成这一步需要三个函数来完成
//1>.-----------------------------//To support 2D texturing//Enable Vertex dreaw//Enable Texture coorddraw//1>.--------------------------------glEnable(GL_TEXTURE_2D);glEnableClientState(GL_VERTEX_ARRAY);GlEnableClientState(GL_TEXTURE_COORD_ARRAY);
三个函数的参数代表开启对应的模式。
<2> 指定顶点数组,纹理数组和图片
完成这一步需要三个函数来完成
//2>.-----------------------------// Point vertex array// Point texture coord array//2>.-------------------------------glVertexPointer (2, GL_FLOAT, 0, vertex_array);glTexCoordPointer (2, GL_FLOAT, 0, tex_coord);glBindTexture (GL_TEXTURE_2D, handle);
//2>.-----------------------------// Point vertex array// Point texture coord array//2>.-------------------------------glVertexPointer (2, GL_FLOAT, 0, vertex_array);glTexCoordPointer (2, GL_FLOAT, 0, tex_coord);glBindTexture (GL_TEXTURE_2D, handle);
函数原型参数解释
size :指定了每个顶点对应的坐标个数,只能是2,3,4中的一个,默认值是4。
type :指定了数组中每个顶点坐标的数据类型,可取常量:GL_BYTE,GL_SHORT,GL_FIXED,GL_FLOAT。
stride:指定了连续顶点间的字节排列方式,如果为0,数组中的顶点就会被认为是按照紧凑方式排列的,默认值为0。
pointer:制订了数组中第一个顶点的首地址,默认值为0,一般给一个IntBuffer就可以了。
size:纹理顶点坐标的分量个数。
type:纹理坐标的数据类型。
stride:位图的宽度,可以理解为相邻的两个纹理之间跨多少个字节,一般为0,因为一般不会在纹理中再添加其他的信息。
pointer:存放纹理坐标的数组。
target :纹理被绑定的目标,它只能取值GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D或者GL_TEXTURE_CUBE_MAP。
texture :纹理的名称即bbutil_load_texture函数返回的tex参数,并且,该纹理的名称在当前的应用中不能被再次使用。
<3> 绘制图片
//3>.-----------------------------// Draw texture//3>.-------------------------------glDrawArrays ( GL_TRIANGLE_STRIP, 0, 4);
函数解释
glDrawArrays (GLenum mode,GLint first,GLsizei count);
mode,绘制方式,OpenGL2.0以后提供以下参数:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
first,从数组缓存中的哪一位开始绘制,一般为0。
count,数组中顶点的数量。
<4>关闭顶点数组绘制法和纹理功能,关闭二维纹理
跟开启这些功能时相对应,我们需要按照对应顺序关闭这些功能:
glDisableClientState(GL_VERTEX_ARRAY);glDisableClientState(GL_TEXTURE_COORD_ARRAY);glDisable(GL_TEXTURE_2D);
函数参数含义为对应的模式。
顶点数组法总述
掌握了顶点数组法绘制图片之后,需要将这几个步骤放在“主消息循环”中才能显示图像。为体现程序模块化,我们将顶点数组法绘制图片这一部分放在“重新绘制屏幕”函数中。
根据顶点数组法各函数参数的含义,我们可以领悟到“顶点数组”是一个很重要的数据结构,当我们利用代码不断改变顶点数组元素的值时就能产生动画,图片就能在屏幕上面移动了!这个发现无疑能让用户通过事件来触发界面切换的结果。然后再利用标志变量就可以控制多张图片在界面上显示,就能形成多个界面。
5 往程序中增添音效
对于音效这一块,首先不得不惭愧一下,在开发二维游戏界面时就已经花费了很多的时间,包括搭建平台和探索黑莓程序的执行流程(请原谅我大二是第一次做这样的开发,那个时候连主消息循环是什么样的概念都不清楚)。所以,对于往程序中添加音效这一块并没有收获太多的东西,但是兴许是我们的勤劳精神感动了上帝,我们学校另一同学“抽象”出了可以播放音效的程序模型,但不是游戏背景音乐那样子的。只能把歌曲播放完之后才能继续运行下面的程序,所以我们采用播放一段很短的音效来增添应用程序的一点小乐趣。鉴于后来上了大三之后时间较紧,没有回头过去将音效播放研究一番,所以在此就介绍一下怎么在程序中播放一段甚短的音效。
步骤1
在样例程序中找到包含工具函数int Play(char*input_file)的文件。
步骤2
在此文件中添加如下类似的代码:
int playwav()
{char input_file[PATH_MAX];char cwd[PATH_MAX];getcwd(cwd, PATH_MAX);snprintf(input_file, PATH_MAX, "%s%s", cwd, WAV_RELATIVE_PATH);Play(input_file);return 0;
}
步骤3
把int playwav()函数声明在工程的头文件中,保证此头文件被包含mian函数的文件所包含。
步骤4
在main函数中调用playwav()函数,然后就可以播放WAV_RELATIVE_PATH这个音效了,这个音效是playwav()函数中snprintf函数的最后一个参数。
如此以来,我们就可以播放多个音效了,只需要再定义类似于playwav()的函数,然后按照以上步骤调用即可。此函数内snprintf的最后一个参数就是需要播放的音效的路径和音效名。如将某个音效用于当有触屏事件发生时我们调用“播放叮一声这个音效”,当有划屏操作时我们调用另一个函数“播放划屏音效”,当然音效的时间不能过长,不然会给平板界面带来停滞的画面。
6 应用程序签名
在提交应用的过程中,我们最开始没有“应用程序签名”的意识。后来得到反馈说我们的程序不能够被安装到平板之上,经过讨论和探索才知道是需要应用程序签名。作为一个新的意识,当时我就将“应用程序签名记载到了博客之上”,博客中有介绍“应用程序签名”的由来,应用程序签名详情参见:应用签名地址:http://blog.csdn.net/misskissc/article/details/7997432
此次笔记记录完毕。