思澈科技solution井字棋游戏【外置应用】
文章目录一、简介参考文档二、应用介绍三、应用开发1、应用文件夹创建2、文件目录结构说明3、配置图片资源3.1 图标放置3.2 应用内游戏资源3.3 图片资源说明4、编写代码文件4.1 主体函数说明on_starton_resumeon_pauseon_stop4.2 on_start 初始化4.3 on_resume 激活配置4.4 on_pause 暂停4.5 on_stop4.6 初始化时完成游戏代码配置5、编译下载5.1 编译5.2 下载5.3 显示一、简介学习思澈科技solution开发外置C应用这里以开发一个井字棋游戏为例。参考文档应用APP图形应用框架创建一个新APP二、应用介绍solution 应用分为两种 1、内置应用 2、外置应用1、内置应用\open_source_solution_v2.4.1\solution\examples\xxx\application2、外置应用\open_source_solution_v2.4.1\solution\examples\_dynamic_app其中C应用在\open_source_solution_v2.4.1\solution\examples\_dynamic_app\c\app下三、应用开发优先参考创建一个新APP文档1、应用文件夹创建直接复制粘贴sport文件夹并重命名为game此时在butterfli下点击刷新可以看到game出现在C app中,选中预置即可将其编译到工程中2、文件目录结构说明目录下包含resource和src两个目录resource:资源目录存放APP使用到的各种资源src源代码目录存放应用C源代码readme.ini 编译依赖配置文件 SConscript 编译连接脚本其中resource下包含font_bitmapimageslangthumbnailsfont_bitmapbitmap字体images图片资源文件包括gif等lang多语言表thumbnailsAPP图标图片名称需为tn.png3、配置图片资源3.1 图标放置图标名称需为tn.png 当需要不同风格的图标时依次命名为 tn.png\tn2.png\tn3.png ,图标风格可以是方形圆形等。在应用切换列表显示或者宫格显示时会切换不同风格的图标显示。3.2 应用内游戏资源这里井字棋游戏的显示可以完全使用C代码画图实现这样可以不在这里加任何其他图片资源。也可以使用LVGL图片控件显示img图片资源。将需要的图片资源替换掉原有的图片资源其中empty为透明图片用于清空棋盘显示。3.3 图片资源说明可以看到图片资源目录下 如image下还有很多个目录。这些都有各自的用途。可以参考图片资源说明文档包括如何在solution使用获取图片文件4、编写代码文件应用APP文档动态应用指南创建 game_main.c ,并删除刚刚复制的其他资源文件然后添加代码代码#defineDYN_APP/* 声明此为外置APP资源通过外置方式获取 */#includertthread.h#includelvgl.h#includeglobal.h#includelvsf_multobj.h#includelvsf_multswipe.h#includelvsf_scrollbar.h#includelvsf_bg_db.h/* 定义模块名称必须与动态应用APP_ID相同模拟器调试使用且需要在 #include app_module.h 之前 */#define_MODULE_NAME_game/* 模块名称为 game */#includeapp_module.htypedefstruct{lv_obj_t*bg_cont;}game_main_t;staticvoidon_start(void){/*从框架获取申请的内存必须要注册的时候填入需要的内存大小*/p_lane_playAPP_GET_PAGE_MEM_PTR;}staticvoidon_resume(void){}staticvoidon_pause(void){}staticvoidon_stop(void){}/* 注册应用 *//* app_get_strid为应用名称设置 NULL:第二个参数为 缩略图设置可以填NULL game: 应用名称,必须与对应的应用ID 相同 size应用全局内存大小,该内存由框架申请释放,页面可以直接使用 */APPLICATION_REGISTER(app_get_strid(key_sport,Game),NULL,game,sizeof(game_main_t));4.1 主体函数说明设置APP文档前置代码文件编辑设置完成后后面就是应用主体的编写应用主体分为4个函数on_start\on_resume\on_pause\on_stopon_start页面初始化仅调用一次on_resume页面激活每次显示时调用on_pause页面暂停被切换至后台时调用on_stop页面销毁退出时调用4.2 on_start 初始化初始化 获取框架申请的内存,全局指针所对应的结构体大小一定要和申请的大小一致APP_GET_PAGE_MEM_PTR是框架提供的接口用于获取预先申请的内存指针game static game_main_t *game NULL;staticvoidon_start(void){game(game_main_t*)APP_GET_PAGE_MEM_PTR;RT_ASSERT(game);jingziqi_app_gui_init();//自定义页面初始化函数在这里编写游戏的初始化相关代码}4.3 on_resume 激活配置staticvoidon_resume(void){/* 井字棋游戏中只有简单的触摸事件激活启动时也不需要额外的配置或刷新定时器因此这个函数为NULL。 */}4.4 on_pause 暂停staticvoidon_pause(void){/* 同on_resume函数。 */}4.5 on_stopstaticvoidon_stop(void){/* 将全局指针变量置空防止其他地方使用时非空判断出现异常,该指针指向的内存会在框架执行完stop消息后释放 */gameNULL;}4.6 初始化时完成游戏代码配置因此一个非常简单的的外置应用只需要配置好on_start中的初始化代码即可完成。接下来就是在初始化时就完成井字棋游戏的代码编写。【完整C代码】/********************* * INCLUDES *********************/#defineDYN_APP#includertthread.h#includelvgl.h#includeglobal.h#includelvsf_multobj.h#includelvsf_multswipe.h#includelvsf_scrollbar.h#includelvsf_bg_db.h#define_MODULE_NAME_game#includeapp_module.htypedefenum{PLAYER_X_TURN,// X玩家回合PLAYER_O_TURN,// O玩家回合PLAYER_X_WIN,// X玩家获胜PLAYER_O_WIN,// O玩家获胜GAME_DRAW// 平局}GameState;// 棋盘状态typedefenum{EMPTY,PLAYER_X,PLAYER_O}CellState;typedefstruct{CellState board[3][3];// 3x3棋盘GameState current_state;// 当前游戏状态lv_obj_t*cell_btns[3][3];// 按钮对象数组lv_obj_t*status_label;// 状态显示标签lv_obj_t*restart_btn;// 重新开始按钮lv_obj_t*game_board;// 游戏棋盘对象lv_obj_t*bg_cont;}game_main_t;staticgame_main_t*gameNULL;/** * 检查是否有获胜者 * return 获胜者(PLAYER_X, PLAYER_O)或EMPTY */staticCellStatecheck_winner(void){// 检查行for(inti0;i3;i){if(game-board[i][0]!EMPTYgame-board[i][0]game-board[i][1]game-board[i][1]game-board[i][2]){returngame-board[i][0];}}// 检查列for(intj0;j3;j){if(game-board[0][j]!EMPTYgame-board[0][j]game-board[1][j]game-board[1][j]game-board[2][j]){returngame-board[0][j];}}// 检查对角线if(game-board[0][0]!EMPTYgame-board[0][0]game-board[1][1]game-board[1][1]game-board[2][2]){returngame-board[0][0];}if(game-board[0][2]!EMPTYgame-board[0][2]game-board[1][1]game-board[1][1]game-board[2][0]){returngame-board[0][2];}returnEMPTY;}/** * 检查是否平局 * return true如果平局 */staticboolcheck_draw(void){for(inti0;i3;i){for(intj0;j3;j){if(game-board[i][j]EMPTY){returnfalse;}}}returntrue;}/** * 更新按钮显示 */staticvoidupdate_cell_display(introw,intcol){lv_obj_t*btngame-cell_btns[row][col];lv_obj_t*imglv_obj_get_child(btn,0);switch(game-board[row][col]){caseEMPTY:lv_img_set_src(img,APP_GET_IMG(empty));break;casePLAYER_X:lv_img_set_src(img,APP_GET_IMG(cha));break;casePLAYER_O:lv_img_set_src(img,APP_GET_IMG(gou));break;}}// /**// * 处理单元格点击// */staticvoidcell_click_cb(lv_event_t*e){//如果游戏已经结束不处理点击if(game-current_statePLAYER_X_WIN||game-current_statePLAYER_O_WIN||game-current_stateGAME_DRAW){return;}// 获取点击的按钮lv_obj_t*btnlv_event_get_target(e);// 找到按钮对应的行列introw-1,col-1;for(inti0;i3;i){for(intj0;j3;j){if(game-cell_btns[i][j]btn){rowi;colj;break;}}if(row!-1)break;}// 如果单元格不为空不处理if(game-board[row][col]!EMPTY){return;}// 根据当前玩家设置单元格if(game-current_statePLAYER_X_TURN){game-board[row][col]PLAYER_X;update_cell_display(row,col);//检查游戏状态CellState winnercheck_winner();if(winnerPLAYER_X){game-current_statePLAYER_X_WIN;lv_label_set_text(game-status_label,玩家 X 获胜!);}elseif(check_draw()){game-current_stateGAME_DRAW;lv_label_set_text(game-status_label,平局!);}else{game-current_statePLAYER_O_TURN;lv_label_set_text(game-status_label,玩家 O 回合);}}elseif(game-current_statePLAYER_O_TURN){game-board[row][col]PLAYER_O;update_cell_display(row,col);//检查游戏状态CellState winnercheck_winner();if(winnerPLAYER_O){game-current_statePLAYER_O_WIN;lv_label_set_text(game-status_label,玩家 O 获胜!);}elseif(check_draw()){game-current_stateGAME_DRAW;lv_label_set_text(game-status_label,平局!);}else{game-current_statePLAYER_X_TURN;lv_label_set_text(game-status_label,玩家 X 回合);}}}voidgame_init(void){// 清空棋盘for(inti0;i3;i){for(intj0;j3;j){game-board[i][j]EMPTY;}}// 设置初始状态为X玩家回合game-current_statePLAYER_X_TURN;// 更新状态显示lv_label_set_text(game-status_label,玩家 X 回合);}/** * 重新开始游戏回调 */staticvoidrestart_click_cb(lv_event_t*e){(void)e;// 未使用参数game_init();// 清空所有按钮显示for(inti0;i3;i){for(intj0;j3;j){update_cell_display(i,j);}}}staticvoidjingziqi_app_gui_init(){lv_obj_t*parentlv_scr_act();lv_obj_t*bg_contlv_obj_create(parent);lv_obj_set_size(bg_cont,390,390);lv_obj_set_pos(bg_cont,0,0);lv_obj_set_style_bg_color(bg_cont,LV_COLOR_BLACK,LV_PART_MAIN);/* 棋盘 */lv_obj_t*game_boardlv_img_create(bg_cont);lv_img_set_src(game_board,APP_GET_IMG(qipan));lv_obj_set_size(game_board,390,390);lv_obj_set_pos(game_board,0,0);/* 状态标签 */lv_obj_t*labellv_label_create(parent);lv_label_set_text(label,玩家 X 回合);// 初始状态lv_obj_set_style_text_color(label,lv_color_white(),0);lv_obj_set_pos(label,50,400);game-game_boardgame_board;game-status_labellabel;// 创建3x3棋盘按钮for(inti0;i3;i){// 创建行容器lv_obj_t*row_contlv_obj_create(bg_cont);//lv_obj_remove_style_all(row_cont);lv_obj_set_size(row_cont,300,100);lv_obj_set_style_bg_opa(row_cont,0,0);lv_obj_set_pos(row_cont,45,45i*100);for(intj0;j3;j){// 创建单元格按钮lv_obj_t*btnlv_btn_create(row_cont);lv_obj_set_size(btn,100,100);lv_obj_set_style_bg_opa(btn,0,0);lv_obj_set_pos(btn,j*100,0);// 创建按钮标签lv_obj_t*imglv_img_create(btn);lv_img_set_src(img,NULL);lv_obj_center(img);// 存储按钮引用game-cell_btns[i][j]btn;// 添加点击事件lv_obj_add_event_cb(btn,cell_click_cb,LV_EVENT_CLICKED,NULL);}}/* 重新开始按钮 */lv_obj_t*restart_btnlv_btn_create(parent);lv_obj_set_size(restart_btn,100,40);lv_obj_set_pos(restart_btn,240,400);lv_obj_t*restart_labellv_label_create(restart_btn);lv_label_set_text(restart_label,重新开始);lv_obj_center(restart_label);lv_obj_add_event_cb(restart_btn,restart_click_cb,LV_EVENT_CLICKED,NULL);game-restart_btnrestart_btn;game_init();lv_obj_update_layout(parent);}staticvoidon_start(void){game(game_main_t*)APP_GET_PAGE_MEM_PTR;RT_ASSERT(game);jingziqi_app_gui_init();}staticvoidon_resume(void){}staticvoidon_pause(void){}staticvoidon_stop(void){}APPLICATION_REGISTER(app_get_strid(key_sport,Game),NULL,game,sizeof(game_main_t));5、编译下载5.1 编译C应用中勾选对应应用为预置如果你和我一样只修改过C应用部分代码且之前有关编译可以选择部分编译否则需要进行全编译5.2 下载选中对应的COM口并下载5.3 显示