【平头哥RVB2601创意应用开发】9~11 游戏结束重新开始及优化代码等
<p>9、游戏结束重新开始</p><p>想要游戏结束后重新开始,就需要用一个变量去表示游戏状态:</p>
<pre>
<code>int status=0;//初始状态为 0 游戏中 1 胜利 2 </code></pre>
<p>同时,把游戏部分的lvgl部分提取为一个方法 :</p>
<div class="parsedown-markdown">
<pre>
<code>void game_init(){
for(int i=0;i<size;i++){
objs.label=lv_label_create(lv_scr_act(), NULL);
lv_obj_set_size(objs.label, 20, 20);
lv_obj_add_style(objs.label, LV_LABEL_PART_MAIN, &style);
lv_label_set_text(objs.label, objs.name);
}
}</code></pre>
<p>把数据初始化提取为一个方法,以便于游戏结束后复用,也就是重新开始:</p>
<pre>
<code>void game_start(){
for(int i=0;i<size;i++){
objs.x=20 + rand() % (128-80);
objs.y=-1*(rand() % size)-30;
objs.die=0;
lv_obj_set_pos(objs.label, objs.x, objs.y);
}
for (int i = 0; i < size; ++i){
for (int j = i + 1; j < size; ++j){
if (objs.y < objs.y){
struct Obj temp = objs;
objs = objs;
objs = temp;
}
}
}
for(int i=0;i<size;i++){
objs.y=-1*30*i;
}
lv_label_set_text(text_gameover, "");
score=0;
looptime=0;
enemy_go_home=0;
lv_label_set_text_fmt(score_label,"%d " LV_SYMBOL_OK, score);
lv_label_set_text_fmt(enemy_go_home_label,LV_SYMBOL_WARNING " %d", enemy_go_home);
status=1;
}</code></pre>
<p>第一次执行:</p>
<pre>
<code>game_init();
game_start();</code></pre>
<p>当游戏结束后重新开始执行:</p>
<pre>
<code>game_start();</code></pre>
<p>在游戏的主循环里:</p>
<pre>
<code>while (1) {
lv_task_handler();
if(status==1){
// 游戏中的代码
}
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key1)&&status==3) {
// 重新开始游戏
game_start();
}
aos_msleep(5);
lv_tick_inc(1);
}</code></pre>
<p> </p>
<p>10、摩尔斯电码输入错误时重新计算长度</p>
<p>实际上并不需要判断对错。因为这里用的是超过一定时间就算输入,一旦输入,判断对错是用于游戏计分的。因此,对于重新计算输入的电码长度,就可以忽略了,也就是,对于输入后,只需要把输入清空就可以了。</p>
<pre>
<code>if(nopress_time>30){
// 判断是否击中代码区域开始
...
// 判断是否击中代码区域结束
strcpy(input,""); //强制把输入的摩尔斯电码情况
lv_label_set_text(text_input,"");//输入效果清空
}</code></pre>
<p>11、优化代码:</p>
<p>开机进入一个画面,之后通过按钮进入另外的画面。</p>
<pre>
<code>static void gui_welcome_task(void *arg){
lv_obj_t *title;
lv_obj_t * btn_left;
lv_obj_t * btn_right;
void init_title(void){
title = lv_label_create(lv_scr_act(), NULL);
// lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);不知道这个为什么不好使
lv_obj_set_pos(title, 22, 10);
lv_label_set_text(title,"Morse Code");
}
void buttonInput(void){
lv_obj_t * label;
btn_left = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_pos(btn_left, 0, 30);
lv_obj_set_size(btn_left, 70, 30);
label = lv_label_create(btn_left, NULL);
lv_label_set_text(label,LV_SYMBOL_EDIT " Test");
}
void buttonGame(void){
lv_obj_t * label;
btn_right = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_pos(btn_right, 60, 30);
lv_obj_set_size(btn_right, 70, 30);
label = lv_label_create(btn_right, NULL);
lv_label_set_text(label,LV_SYMBOL_PLAY " Play");
}
void destroy (void){
lv_obj_del(title);
lv_obj_del(btn_left);
lv_obj_del(btn_right);
aos_task_exit(0);
}
init_title();
buttonInput();
buttonGame();
while(1){
lv_task_handler();
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key1)) {
aos_task_new("gui", gui_game_task, NULL, 10 * 1024);
destroy();
break;
}
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key2)) {
aos_task_new("gui", gui_test_task, NULL, 10 * 1024);
destroy();
break;
}
aos_msleep(5);
lv_tick_inc(1);
}
}</code></pre>
<p>可以发现,新增了一个用于自由输入练习的子task:</p>
<pre>
<code>static void gui_test_task(void *arg){
lv_obj_t *text;
void textarea_create(void)
{
text = lv_textarea_create(lv_scr_act(), NULL);
lv_obj_set_size(text, 128, 60);
lv_obj_align(text, NULL, LV_ALIGN_CENTER, 0, 0);
lv_textarea_set_text(text, "");
lv_textarea_set_placeholder_text(text, "Morse Code");
}
void text_append(char* c){
int len = strlen(input);
for(int i=0;i<len;i++){
lv_textarea_del_char(text);
}
lv_textarea_add_text(text, c);
strcpy(input,"");
}
void check_input(void)
{
if(strcmp(input,".-")==0){
text_append("A");
}
if(strcmp(input,"-...")==0){
text_append("B");
}
if(strcmp(input,"-.-.")==0){
text_append("C");
}
if(strcmp(input,"-..")==0){
text_append("D");
}
if(strcmp(input,".")==0){
text_append("E");
}
if(strcmp(input,"..-.")==0){
text_append("F");
}
if(strcmp(input,"--.")==0){
text_append("G");
}
if(strcmp(input,"....")==0){
text_append("H");
}
if(strcmp(input,"..")==0){
text_append("I");
}
if(strcmp(input,".---")==0){
text_append("J");
}
if(strcmp(input,"-.-")==0){
text_append("K");
}
if(strcmp(input,".-..")==0){
text_append("L");
}
if(strcmp(input,"--")==0){
text_append("M");
}
if(strcmp(input,"-.")==0){
text_append("N");
}
if(strcmp(input,"---")==0){
text_append("O");
}
if(strcmp(input,".--.")==0){
text_append("P");
}
if(strcmp(input,"--.-")==0){
text_append("Q");
}
if(strcmp(input,".-.")==0){
text_append("R");
}
if(strcmp(input,"...")==0){
text_append("S");
}
if(strcmp(input,"-")==0){
text_append("T");
}
if(strcmp(input,"..-")==0){
text_append("U");
}
if(strcmp(input,"...-")==0){
text_append("V");
}
if(strcmp(input,".--")==0){
text_append("W");
}
if(strcmp(input,"-..-")==0){
text_append("X");
}
if(strcmp(input,"-.--")==0){
text_append("Y");
}
if(strcmp(input,"--..")==0){
text_append("Z");
}
if(strcmp(input,"-----")==0){
text_append("0");
}
if(strcmp(input,".----")==0){
text_append("1");
}
if(strcmp(input,"..---")==0){
text_append("2");
}
if(strcmp(input,"...--")==0){
text_append("3");
}
if(strcmp(input,"....-")==0){
text_append("4");
}
if(strcmp(input,".....")==0){
text_append("5");
}
if(strcmp(input,"-....")==0){
text_append("6");
}
if(strcmp(input,"--...")==0){
text_append("7");
}
if(strcmp(input,"---..")==0){
text_append("8");
}
if(strcmp(input,"----.")==0){
text_append("9");
}
}
textarea_create();
while (1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_task_handler();
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key1)) {
//当低电平(按下时)
if(button1_pressed==0){
// 如果button1的状态没有被按下,则设为按下
button1_pressed = 1;
}
if(button1_pressed==1){
//如果button1的状态是按下,则计时
time_for_pressed++;
}
}
if(GPIO_PIN_HIGH == csi_gpio_pin_read(&key1)) {
if(button1_pressed==0){
nopress_time++;
if(nopress_time>30){
check_input();
}
}
if(button1_pressed==1){
nopress_time=0;
printf("%d",time_for_pressed);
//通过判断time_for_pressed的大小,得出是长按还是短按
if(time_for_pressed>20){
//长按
printf("-");
strcat(input,"-");
lv_textarea_add_text(text,"-");
}else{
//短按
printf(".");
strcat(input,".");
lv_textarea_add_text(text,".");
}
time_for_pressed=0;//恢复计数
button1_pressed = 0;
}
}
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key2)) {
if(button2_pressed==0){
button2_pressed=1;
}
}
if(GPIO_PIN_HIGH == csi_gpio_pin_read(&key2)) {
if(button2_pressed==1){
printf("\n");
button2_pressed=0;
strcpy(input,"");
lv_textarea_del_char(text);
}
}
aos_msleep(5);
lv_tick_inc(1);
}
}</code></pre>
<p>最后游戏部分全部代码:</p>
<pre>
<code>static void gui_game_task(void *arg){
static lv_style_t style;
lv_style_init(&style);
static int pad_width = 2;
time_t t;
srand((unsigned) time(&t));
int looptime = 0;
int score=0;//分数初始为0
int status=0;//初始状态为 0 游戏中 1 胜利 2 失败 3
lv_obj_t *text_gameover = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_pos(text_gameover, 28, 30);
lv_obj_set_size(text_gameover, 128, 60);
lv_label_set_text(text_gameover, "");
//输入的标签
lv_obj_t *text_input = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_pos(text_input, 100, 50);
lv_obj_set_size(text_input, 80, 20);
lv_label_set_text(text_input, "");
lv_obj_t *score_label = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_pos(score_label, 2, 0);
lv_obj_set_size(score_label, 128, 30);
lv_style_set_bg_color(&style, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_style_set_text_color(&style, LV_STATE_DEFAULT, LV_COLOR_BLACK);
// set padding
lv_style_set_pad_left(&style,LV_STATE_DEFAULT,pad_width);
lv_style_set_pad_right(&style,LV_STATE_DEFAULT,pad_width);
lv_style_set_pad_top(&style,LV_STATE_DEFAULT,pad_width-1);
lv_style_set_pad_bottom(&style,LV_STATE_DEFAULT,pad_width-1);
lv_style_set_value_font(&style,LV_STATE_DEFAULT,LV_FONT_MONTSERRAT_12);
// lv_style_set_text_font(&style, LV_STATE_DEFAULT,LV_FONT_MONTSERRAT_22);
lv_style_set_border_width(&style, LV_STATE_DEFAULT, 1);
lv_style_set_radius(&style, LV_STATE_DEFAULT, 5);
lv_style_set_border_color(&style, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_label_set_text_fmt(score_label,"%d" LV_SYMBOL_OK, score);
int enemy_go_home=0;//没有被击落的字母就是敌人,这是敌人落下(家门口)的数量
// enemy go home count
lv_obj_t *enemy_go_home_label = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_pos(enemy_go_home_label, 95, 0);
lv_obj_set_size(enemy_go_home_label, 30, 30);
lv_label_set_text_fmt(enemy_go_home_label, LV_SYMBOL_WARNING " %d", enemy_go_home);
int size = 36;
struct Obj{
char name;
char code;
lv_obj_t *label;
int x;
int y;
int die;
}objs={
{"A",".-"},
{"B","-..."},
{"C","-.-."},
{"D","-.."},
{"E","."},
{"F","..-."},
{"G","--."},
{"H","...."},
{"I",".."},
{"J",".---"},
{"K","-.-"},
{"L",".-.."},
{"M","--"},
{"N","-."},
{"O","---"},
{"P",".--."},
{"Q","--.-"},
{"R",".-."},
{"S","..."},
{"T","-"},
{"U","..-"},
{"V","...-"},
{"W",".--"},
{"X","-..-"},
{"Y","-.--"},
{"Z","--.."},
{"0","-----"},
{"1",".----"},
{"2","..---"},
{"3","...--"},
{"4","....-"},
{"5","....."},
{"6","-...."},
{"7","--..."},
{"8","---.."},
{"9","----."},
};
void game_init(){
for(int i=0;i<size;i++){
objs.label=lv_label_create(lv_scr_act(), NULL);
lv_obj_set_size(objs.label, 20, 20);
lv_obj_add_style(objs.label, LV_LABEL_PART_MAIN, &style);
lv_label_set_text(objs.label, objs.name);
}
}
void game_start(){
for(int i=0;i<size;i++){
objs.x=20 + rand() % (128-80);
objs.y=-1*(rand() % size)-30;
objs.die=0;
lv_obj_set_pos(objs.label, objs.x, objs.y);
}
for (int i = 0; i < size; ++i){
for (int j = i + 1; j < size; ++j){
if (objs.y < objs.y){
struct Obj temp = objs;
objs = objs;
objs = temp;
}
}
}
for(int i=0;i<size;i++){
objs.y=-1*30*i;
}
lv_label_set_text(text_gameover, "");
score=0;
looptime=0;
enemy_go_home=0;
lv_label_set_text_fmt(score_label,"%d " LV_SYMBOL_OK, score);
lv_label_set_text_fmt(enemy_go_home_label,LV_SYMBOL_WARNING " %d", enemy_go_home);
status=1;
}
game_init();
game_start();
while (1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_task_handler();
if(status==1){
looptime+=1;
if(looptime % 10 ==0){
for(int i=0;i<size;i++){
if(objs.die==0){
objs.y+=1;
lv_obj_set_pos(objs.label, objs.x, objs.y);
//如果没有被击中,而且落下去了
if(objs.y>64){
enemy_go_home+=1;
lv_label_set_text_fmt(enemy_go_home_label, LV_SYMBOL_WARNING " %d", enemy_go_home);
objs.die=1;
}
}
}
if(enemy_go_home>=5){
// for(int i=0;i<size;i++){
// lv_label_set_text(objs.label, "");
// }
lv_label_set_text(text_gameover, "GameOver");
status = 3; //game over
}
}
}
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key1)&&status==3) {
//restart
game_start();
}
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key1)&&status==1) {
//当低电平(按下时)
if(button1_pressed==0){
// 如果button1的状态没有被按下,则设为按下
button1_pressed = 1;
}
if(button1_pressed==1){
//如果button1的状态是按下,则计时
time_for_pressed++;
}
}
if(GPIO_PIN_HIGH == csi_gpio_pin_read(&key1)&&status==1) {
if(button1_pressed==0){
nopress_time++;
if(nopress_time>30){
//check_input();
for(int i=0;i<size;i++){
//如果没有被击中
if(objs.die==0){
if(objs.y>0 && objs.y<64){
//在可视区间
if(strcmp(input,objs.code)==0){
objs.die = 1;//标记被击中
objs.y = 128;
lv_obj_set_pos(objs.label, objs.x, objs.y);
score++;
lv_label_set_text_fmt(score_label,"%d " LV_SYMBOL_OK, score);
}
}
}
}
strcpy(input,"");
lv_label_set_text(text_input,"");//输入效果清空
//check win
//if status == playing
if(score==size){
//status == "win"
}
}
}
if(button1_pressed==1){
nopress_time=0;
printf("%d",time_for_pressed);
//通过判断time_for_pressed的大小,得出是长按还是短按
if(time_for_pressed>20){
//长按
printf("-");
strcat(input,"-");
}else{
//短按
printf(".");
strcat(input,".");
}
lv_label_set_text(text_input,input);//输入效果
time_for_pressed=0;//恢复计数
button1_pressed = 0;
}
}
if(GPIO_PIN_LOW == csi_gpio_pin_read(&key2)&&status==1) {
if(button2_pressed==0){
button2_pressed=1;
}
}
if(GPIO_PIN_HIGH == csi_gpio_pin_read(&key2)&&status==1) {
if(button2_pressed==1){
printf("\n");
button2_pressed=0;
strcpy(input,"");
lv_label_set_text(text_input,"");//输入效果清空
}
}
aos_msleep(5);
lv_tick_inc(1);
}
}</code></pre>
<p> </p>
</div>
<p>摩尔斯电码输入错误时重新计算长度,超过一定时间就算输入,一旦输入,判断对错是用于游戏计分的<br />
那开始的长度是怎么计算的呢</p>
Jacktang 发表于 2022-5-28 07:33
摩尔斯电码输入错误时重新计算长度,超过一定时间就算输入,一旦输入,判断对错是用于游戏计分的
那开始的 ...
<p>在objs(摩尔斯电码结构体数组)中遍历判断:strcmp(input,objs.code)==0</p>
页:
[1]