DIY自己的贪食蛇——用BREW设计游戏菜单

技术与开发

上期我们学会了BREW程序的基本调试方法和常见错误处理,从本期开始,我们将用BREW设计一个属于自己的手机游戏贪吃蛇,是不是很心动呢?下面我们就开始进行设计的第一步:游戏菜单的开发。

贪吃蛇菜单设计思路

整个游戏菜单的流程如下:启动程序后显示游戏主菜单,用户通过选择菜单项进行相应的操作,比如“开始游戏”。操作完后,程序将重新显示主菜单,等待用户的下一次选择。如果用户选择“退出”操作,则释放资源,结束整个程序(图1)。

31-f14-1.jpg
图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)。

31-f14-2.jpg
图2