DIY自己的贪食蛇——用BREW设计游戏菜单
技术与开发
上期我们学会了BREW程序的基本调试方法和常见错误处理,从本期开始,我们将用BREW设计一个属于自己的手机游戏贪吃蛇,是不是很心动呢?下面我们就开始进行设计的第一步:游戏菜单的开发。
贪吃蛇菜单设计思路
整个游戏菜单的流程如下:启动程序后显示游戏主菜单,用户通过选择菜单项进行相应的操作,比如“开始游戏”。操作完后,程序将重新显示主菜单,等待用户的下一次选择。如果用户选择“退出”操作,则释放资源,结束整个程序(图1)。

贪吃蛇菜单接口的选择
BREW SDK的API里面的ImenuCtl(菜单控件)是专门做菜单的接口,使用它可以在设备上显示菜单,用户通过使用“上”、“下”、“左”和“右”键选择菜单,已选择的菜单项将在屏幕上突出显示,按下“选择”键,则激活相应的菜单处理。
菜单控件有以下四种类型:
·标准菜单控件(AEECLSID_MENUCTL):在屏幕上分行显示菜单项。
·列表控件(AEECLSID_LISTCTL):仅在屏幕上显示当前被选中的菜单项。
·软键菜单控件(AEECLSID_SOFTKEYCTL):沿屏幕的底部并排显示的菜单项。
·图标视图菜单控件(AEECLSID_ICONVIEWCTL):使用位图图标表示每个菜单项。
在这个程序中我们用到的是标准菜单控件,其他菜单控件的使用方法比较类似,大家有空可以自己研究。
小提示:使用菜单控件需要在程序里包含头文件“AEEMenu.h”。
贪吃蛇菜单代码是如何编写的
根据流程图,我们要设计了4个菜单:Start(开始游戏)、High Score(最高分数)、Help(帮助)和Exit(退出游戏)。具体的设计步骤介绍如下。
第一步: 全局变量声明
新建工程“snake”,然后打开“snake.c”文件,定义两个枚举类型,用来表示程序的运行状态和菜单项。
enum app_mode{ //程序中各个状态
MODE_MENU,
MODE_GAME,
MODE_HIGH_SCORE,
MODE_HELP,
};
enum menu_item{ //主菜单各个选项
ITEM_MENU_START,
ITEM_MENU_HIGH_SCORE,
ITEM_MENU_HELP,
ITEM_MENU_EXIT,
};
找到结构体_snake,由于BREW程序不能使用全局数据,所有的变量都必须定义在这个结构体里。
typedef struct _snake {
AEEApplet a ;
AEEDeviceInfo DeviceInfo;
//以下是新增的
int Mode;//程序目前处于哪个状态
IMenuCtl *pIMenuCtl; //使用的菜单控件指针
AEERect ScreenRect; //矩形声明
} snake;
第二步: 处理响应事件
在snake_HandleEvent函数中加入代码,处理启动时的初始化和运行中的按键、菜单相应的事件。
//程序启动
case EVT_APP_START:
//将该矩形设置成设备屏幕大小
pMe->ScreenRect.x = 0;
pMe->ScreenRect.y = 0;
pMe->ScreenRect.dx = pMe->DeviceInfo.cxScreen;
pMe->ScreenRect.dy = pMe->DeviceInfo.cyScreen;
if ( !init_Menuctl(pMe) ) return FALSE; //初始化菜单控件
main_Loop(pMe); //启动程序主循环
return(TRUE);
//按键
case EVT_KEY:
// Add your code here...
if(pMe->pIMenuCtl){ //菜单控件激活情况下,按键事件由菜单控件自动处理
return IMENUCTL_HandleEvent(pMe->pIMenuCtl, eCode, wParam, dwParam);
}else{
}
return(TRUE);
//点击菜单
case EVT_COMMAND:
switch (wParam){ //各菜单选择后处理,目前除了退出,其他只打印出调试信息
case ITEM_MENU_START:// 开始游戏
DBGPRINTF(“---------ITEM_MENU_START----------”);
break;
case ITEM_MENU_HIGH_SCORE: //最高分数
DBGPRINTF(“---------ITEM_MENU_HIGH_SCORE----------”);
break;
case ITEM_MENU_HELP:// 帮助
DBGPRINTF(“--------ITEM_MENU_HELP-----------”);
break;
case ITEM_MENU_EXIT: //退出程序
DBGPRINTF(“--------ITEM_MENU_EXIT -----------”);
ISHELL_CloseApplet(pMe->a.m_pIShell, FALSE);
break;
}
return TRUE;
第三步: 实现菜单功能
首先初始化菜单,加入程序准备显示的4个菜单项,代码如下:
boolean init_Menuctl(snake* pMe){
if(SUCCESS == ISHELL_CreateInstance(pMe->a.m_pIShell, AEECLSID_MENUCTL, (void **)&(pMe->pIMenuCtl)) ){
DBGPRINTF(“---create menuctl instance ok---!”);
IMENUCTL_SetRect(pMe->pIMenuCtl, &(pMe->ScreenRect)); // 设置菜单覆盖区域为整个设备屏幕
IMENUCTL_SetTitle(pMe->pIMenuCtl, NULL, NULL, L“Main Menu”); // 设置标题
IMENUCTL_SetProperties (pMe->pIMenuCtl, MP_UNDERLINE_TITLE); //给标题加下划线
IMENUCTL_AddItem(pMe->pIMenuCtl, NULL, NULL, ITEM_MENU_START, L“Start”, NULL); // 添加菜单项
IMENUCTL_AddItem(pMe->pIMenuCtl, NULL, NULL, ITEM_MENU_HIGH_SCORE, L“High Score”, NULL);
IMENUCTL_AddItem(pMe->pIMenuCtl, NULL, NULL, ITEM_MENU_HELP, L“Help”, NULL);
IMENUCTL_AddItem(pMe->pIMenuCtl, NULL, NULL, ITEM_MENU_EXIT, L“Exit”, NULL);
IMENUCTL_SetActive(pMe->pIMenuCtl, TRUE); // 激活菜单控件对象
pMe->Mode = MODE_MENU; // 切换到主菜单状态
return TRUE;
}
return FALSE;
}
然后在程序主循环中调用main_Display函数根据程序状态显示菜单
void main_Display(snake* pMe){
IDISPLAY_FillRect(pMe->a.m_pIDisplay, &(pMe->ScreenRect), MAKE_RGB(0, 0, 0)); /*用纯黑背景刷新屏幕 */
switch (pMe->Mode){
case MODE_MENU:
IMENUCTL_Redraw(pMe->pIMenuCtl); //刷新菜单控件显示
break;
default:
break;
}
在程序退出时一定要记住释放菜单控件,BREW程序通过调用snake_FreeAppData函数执行指定的资源释放函数,在这里加入我们的代码:
void snake_FreeAppData(snake* pMe)
{
release_Menuctl(pMe);
}
void release_Menuctl(snake* pMe){
if ( pMe->pIMenuCtl != NULL ){
IMENUCTL_Release(pMe->pIMenuCtl);
pMe->pIMenuCtl = NULL;
}
}
最后编译代码,按快捷键“Ctrl+F5”启动模拟器执行程序即可(图2)。
