贪吃蛇游戏规则:通过方向控制蛇的移动方向,当蛇头碰到前方食物时,将食物转换为自己的身体。
游戏设定:
1)每吃到n颗食物,移动速度加快
2)每颗食物增加步骤时长限制,蛇在一定步骤内未吃到食物将重新生成新的食物
3)碰到自身或边界游戏结束
按键操作:方向键控制移动方向,A键重新开始
屏幕区域规划:屏幕分辨率240*135,显示分两个区域,左侧为游戏区域(180*135),右侧为分数与等级显示区域(60*135)。蛇身单个节点大小15*15。
具体实现:(数据结及显示屏驱动使用示例工程中的代码)
1)按键扫描,控制蛇的方向,按键是否有抖动不影响蛇的移动,故未做去抖动处理
void key_process(void) { if(!dev_read_key(KEY_UP) && my_eat_snake.snake_dir != S_DOWN) my_eat_snake.snake_dir = S_UP; if(!dev_read_key(KEY_DOWN) && my_eat_snake.snake_dir != S_UP) my_eat_snake.snake_dir = S_DOWN; if(!dev_read_key(KEY_LEFT) && my_eat_snake.snake_dir != S_RIGHT) my_eat_snake.snake_dir = S_LEFT; if(!dev_read_key(KEY_RIGHT) && my_eat_snake.snake_dir != S_LEFT) my_eat_snake.snake_dir = S_RIGHT; if(!dev_read_key(KEY_A)) { score = 0; LCD_1IN3_Clear(GLCD_COLOR_BLACK); snake_reinit(); } if(!dev_read_key(KEY_B)) { music_on = !music_on; } }
2)蛇的移动
void snake_move(){ uint16_t i; //clear last body clear_last_body(my_eat_snake.my_snake_body[my_eat_snake.snake_body_len - 1].iX,my_eat_snake.my_snake_body[my_eat_snake.snake_body_len - 1].iY); for( i = my_eat_snake.snake_body_len - 1; i > 0; i--){ my_eat_snake.my_snake_body[i].iX = my_eat_snake.my_snake_body[i-1].iX; my_eat_snake.my_snake_body[i].iY = my_eat_snake.my_snake_body[i-1].iY; } switch(my_eat_snake.snake_dir) { case S_UP: my_eat_snake.my_snake_body[0].iY -= my_eat_snake.snake_body_width; break; case S_DOWN: my_eat_snake.my_snake_body[0].iY += my_eat_snake.snake_body_width; break; case S_LEFT: my_eat_snake.my_snake_body[0].iX -= my_eat_snake.snake_body_width; break; case S_RIGHT: my_eat_snake.my_snake_body[0].iX += my_eat_snake.snake_body_width; break; } }
如果使用全局刷新界面会有明显的抖动,游戏进行时采用了局部刷新。每移动一步只需绘制新的蛇头,清楚蛇尾即可。
void clear_last_body(int x, int y) { int i,j; for(i=0;i<15;i++) {//row for(j=0;j<15;j++) {//column LCD_1IN3_DisplayPoint(x+j,y+i,GLCD_COLOR_BLACK); } } }
3)判断是否吃上食物
bool snake_eat() { int i; int tempx,tempy; tempx = my_eat_snake.my_snake_body[0].iX; tempy = my_eat_snake.my_snake_body[0].iY; switch(my_eat_snake.snake_dir) { case S_UP: tempy -= my_eat_snake.snake_body_width; break; case S_DOWN: tempy += my_eat_snake.snake_body_width; break; case S_LEFT: tempx -= my_eat_snake.snake_body_width; break; case S_RIGHT: tempx += my_eat_snake.snake_body_width; break; } if(tempx >= W_WIDTH){ tempx = 0; } if(tempx < 0){ tempx = W_WIDTH-B_WIDTH; } if(tempy >= W_HEIGHT) tempy = 0; if(tempy < 0) tempy = W_HEIGHT-B_WIDTH; //eat food judge if(tempy == my_snake_food.food.iY && tempx == my_snake_food.food.iX) { my_eat_snake.snake_body_len += 1; score+=1; for( i = my_eat_snake.snake_body_len - 1; i > 0; i--){ my_eat_snake.my_snake_body[i].iX = my_eat_snake.my_snake_body[i-1].iX; my_eat_snake.my_snake_body[i].iY = my_eat_snake.my_snake_body[i-1].iY; my_eat_snake.my_snake_body[i].img_index = my_eat_snake.my_snake_body[i-1].img_index; } my_eat_snake.my_snake_body[0].iY = my_snake_food.food.iY; my_eat_snake.my_snake_body[0].iX = my_snake_food.food.iX; my_eat_snake.my_snake_body[0].img_index = my_snake_food.food.img_index; my_eat_snake.snake_speed = 800-(my_eat_snake.snake_body_len/3)*50; level = my_eat_snake.snake_body_len/3; //draw_snake(); new_food(); return true; } return false; }
4)游戏结束判断,当蛇头碰到身体或边界游戏结束
bool is_game_over() { int i; for(i=my_eat_snake.snake_body_len-1;i>0;i--) { if(my_eat_snake.my_snake_body[0].iX == my_eat_snake.my_snake_body[i].iX && my_eat_snake.my_snake_body[0].iY == my_eat_snake.my_snake_body[i].iY) return true; } if(my_eat_snake.my_snake_body[0].iX >= W_WIDTH){ return true; } if(my_eat_snake.my_snake_body[0].iX < 0){ return true; } if(my_eat_snake.my_snake_body[0].iY >= W_HEIGHT) return true; if(my_eat_snake.my_snake_body[0].iY < 0) return true; return false; }
5)对蛇身做了渐变色处理,使用HSV颜色转RGB方式
uint16_t convertHSVtoRGB565(float h, float s, float v) { int i; float f, p, q, t; int r, g, b; uint16_t rgb565; if (s == 0) { r = g = b = v * 255; } else { h /= 60; i = (int)h; f = h - i; p = v * (1 - s); q = v * (1 - s * f); t = v * (1 - s * (1 - f)); switch (i) { case 0: r = v * 255; g = t * 255; b = p * 255; break; case 1: r = q * 255; g = v * 255; b = p * 255; break; case 2: r = p * 255; g = v * 255; b = t * 255; break; case 3: r = p * 255; g = q * 255; b = v * 255; break; case 4: r = t * 255; g = p * 255; b = v * 255; break; default: r = v * 255; g = p * 255; b = q * 255; break; } } rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); return rgb565; }
6)主流程
void snake_run(){ static uint16_t ms_count = 0; ms_count += 10; my_snake_food.alivetime += 10; if(ms_count >= my_eat_snake.snake_speed) { if(!is_game_over()) { if(!snake_eat()) snake_move(); draw_snake(); if(my_snake_food.alivetime >= (rand()%15+20)*my_eat_snake.snake_speed) { clear_last_body(my_snake_food.food.iX,my_snake_food.food.iY); new_food(); } draw_snake_food(); draw_record_area(); } else { //game over my_eat_snake.snake_speed = 1000; draw_image(0,0,W_WIDTH,W_HEIGHT,(unsigned char*)gImage_pic1); LCD_DisplayString(0,5,"Press A to Start",16,GLCD_COLOR_MAGENTA); } ms_count = 0; } key_process(); DEV_Delay_ms(10); }
以上为本次DIY的代码。