贪吃蛇游戏程序目前我写了两种。一种运用了二维数组记录全部数据,另一种用结构体记录蛇和食物的数据。
下面我详细介绍第一种方法:二维数组记录全部数据。
后面附上两种方法的完整代码
首先了解一个小知识。如果全局变量与局部变量同名,则在局部变量的作用域内访问的是局部变量,全局变量将被“屏蔽”。
写好游戏框架:#include数组记录游戏数据#include #include #define BLOCK_SIZE 20; #define HEIGH 30; #define WIDTH 40; void startup() //初始化函数 { } void show() //绘制函数 { } void updateWithoutInput() //与输入无关的更新 { } void updateWithInput() //与输入有关的更新 { } int main() { startup(); //初始化函数 while (1) { show(); //进行绘制 updateWithoutInput(); //输入无关的更新 updateWithInput(); //输入有关的更新 } return 0; }
下面是数组记录数据的简单例子
原理:把数据全部放进二维数组中储存,通过改变数组元素的数据来达到控制贪吃蛇。
这个方法的运用在于理解数组定义的坐标
贪吃蛇的绘制是在定义的坐标元素下赋予颜色来达到显示蛇的效果
贪吃蛇的移动 1.获取键盘_kbhit()函数是判断键盘是否按下
_getch()函数是获取按下的键盘信息
#include2.控制蛇的运动:#include #include #include int main() { cout << "你好" << endl; while (1) { if (_kbhit())//当按键时 { char input = _getch(); if (input == ('s')) //当按下s { cout << "你好" << endl; } } } system("pause"); return 0; }
假设小蛇初始元素值为54321,其中1为蛇头、5432为蛇身、最大值5为蛇尾。首先将二维数组中所有大于0的元素加1,得到65432;然后将最大值6变为0,即去除了原来的蛇尾;最后将2右边的元素由0变成1,即实现了小蛇向右移动。
代码:
3.时间控制
Sleep()函数运行时,整个程序都会暂停,包括用户输入模块。用户会感觉到卡顿,明明按了键,小蛇却没有反应。
为了解决这个问题,我用了静态变量。
static修饰的变量称为静态变量,即程序开始运行时就为其分配内存空间,直到程序运行完收回。
动态变量如果不赋初值,其初值为随机数;静态变量如果不赋初值,其初值为0
4.游戏失败的判断当小蛇碰到画面边界时,则认为游戏失败。由于每次只有蛇头是新生成的位置,所以在moveSnake()函数中只需判断蛇头是否越过边界:
当最后运行游戏时会出现一个bug ,当运行代码时,输入法发生了转换导致键盘消息无法获取。此时可以快速转换输入法就可以获取键盘消息了
第一种方法完整代码:
#include第二种方法完整代码:#include #include #define BLOCK_SIZE 20 // 每个小格子的长宽大小 #define HEIGHT 30 // 高度上一共30个小格子 #define WIDTH 40 // 宽度上一共40个小格子 // 全局变量定义 int Blocks[HEIGHT][WIDTH] = { 0 }; // 二维数组,用于记录所有的游戏数据 char moveDirection; // 小蛇移动方向 int food_i, food_j; // 食物的位置 int isFailure = 0; // 是否游戏失败 int speed = 40; void moveSnake() // 移动小蛇及相关处理函数 { int i, j; for (i = 0; i < HEIGHT; i++) // 对行遍历 for (j = 0; j < WIDTH; j++) // 对列遍历 if (Blocks[i][j] > 0) // 大于0的为小蛇元素 Blocks[i][j]++; // 让其+1 int oldTail_i, oldTail_j, oldHead_i, oldHead_j; // 定义变量,存储旧蛇尾、旧蛇头坐标 int max = 0; // 用于记录最大值 for (i = 0; i < HEIGHT; i++) // 对行列遍历 { for (j = 0; j < WIDTH; j++) { if (max < Blocks[i][j]) // 如果当前元素值比max大 { max = Blocks[i][j]; // 更新max的值 oldTail_i = i; // 记录最大值的坐标,就是旧蛇尾的位置 oldTail_j = j; } if (Blocks[i][j] == 2) // 找到数值为2 { oldHead_i = i; // 数值为2恰好是旧蛇头的位置 oldHead_j = j; } } } int newHead_i = oldHead_i; // 设定变量存储新蛇头的位置 int newHead_j = oldHead_j; // 根据用户按键,设定新蛇头的位置 switch (moveDirection) { case 'w': case 'W': case 72: newHead_i = oldHead_i - 1; break; case 'S': case 's': newHead_i = oldHead_i + 1; break; case 'D': case 'd': newHead_j = oldHead_j + 1; break; case 'A': case 'a': newHead_j = oldHead_j - 1; break; } // 如果蛇头超出边界,或者蛇头碰到蛇身,游戏失败 if (newHead_i >= HEIGHT || newHead_i < 0 || newHead_j >= WIDTH || newHead_j < 0|| Blocks[newHead_i][newHead_j]>0) { isFailure = 1; // 游戏失败 return; // 函数返回 } Blocks[newHead_i][newHead_j] = 1; // 新蛇头位置数值为1 if (newHead_i == food_i && newHead_j == food_j) // 如果新蛇头正好碰到食物 { food_i = rand() % (HEIGHT - 5) + 2; // 食物重新随机位置 food_j = rand() % (WIDTH - 5) + 2; // 不对旧蛇尾处理,相当于蛇的长度+1 } else // 新蛇头没有碰到食物 Blocks[oldTail_i][oldTail_j] = 0; // 旧蛇尾变成空白,不吃食物时 蛇的长度保持不变 } void startup() // 初始化函数 { //画蛇 int i; Blocks[HEIGHT / 2][WIDTH / 2] = 1; // 画面中间画蛇头,数字为1 for (i = 1; i <= 4; i++) // 向左依次4个蛇身,数值依次为2、3、4、5 Blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1; moveDirection = 'd'; // 初始向右移动 food_i = rand() % (HEIGHT - 5) + 2; // 初始化随机食物位置 food_j = rand() % (WIDTH - 5) + 2; initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE); // 新开画面 setlinecolor(RGB(200, 200, 200)); // 设置线条颜色 BeginBatchDraw(); // 开始批量绘制 } void show() // 绘制函数 { cleardevice(); // 清屏 int i, j; for (i = 0; i < HEIGHT; i++) // 对二维数组所有元素遍历 { for (j = 0; j < WIDTH; j++) { if (Blocks[i][j] > 0) // 元素大于0表示是蛇, setfillcolor(RGB(0, 128, 255)); else setfillcolor(RGB(34,177,76)); // 元素为0表示为空,颜色为灰色 // 在对应位置处,以对应颜色绘制小方格 fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); } } setfillcolor(RGB(0, 255, 0)); // 食物颜色为绿色 // 绘制食物小方块 fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE); if (isFailure) // 如果游戏失败 { setbkmode(TRANSPARENT); // 文字字体透明 settextcolor(RGB(255, 0, 0));// 设定文字颜色 settextstyle(80, 0, _T("宋体")); // 设定文字大小、样式 outtextxy(240, 220, _T("游戏失败")); // 输出文字内容 } FlushBatchDraw(); // 批量绘制 } void updateWithoutInput() // 与输入无关的更新函数 { if (isFailure) // 如果游戏失败,函数返回 return; static int waitIndex = 1; // 静态局部变量,初始化时为1 waitIndex++; // 每一帧+1 if (waitIndex == 10) // 如果等于10才执行,这样小蛇每隔10帧移动一次 { moveSnake(); // 调用小蛇移动函数 waitIndex = 1; // 再变成1 } } void updateWithInput() // 和输入有关的更新函数 { if (_kbhit()) // 如果有按键输入,并且不失败 { if (isFailure == 0) { char input = _getch(); //获得按键输入 moveDirection = input; // 设定移动方向 moveSnake(); // 调用小蛇移动函数 } } } int main() // 主函数 { startup(); // 初始化函数,仅执行一次 while (1) // 一直循环 { show(); // 进行绘制 updateWithoutInput(); // 和输入无关的更新 updateWithInput(); // 和输入有关的更新 } return 0; }
#include#include #include #include #define SNAKE_NUM 500//蛇的最大节数 enum DIR { up, down, LEFt, RIGHT, }; struct snake { int size;//蛇的节数 int dir;//蛇的方向 int speed;//蛇的速度 POINT coor[SNAKE_NUM];//蛇的坐标 }snake; //数据的初始化 struct food //定义食物 { int x; int y; int r;//食物半径 bool flay;//判断食物是否被吃 DWORD collor;//食物的颜色 }food; void GameInit() { srand(GetTickCount()); //做界面,创建一个窗口 //init 初始化 graph 图片 initgraph(640, 480); //初始化食物,以食物为随机数组的种子。 //GetTickCount 获取系统开机到现在所经过的时间,以毫秒为单位。 //初始化蛇,一开始有三节 snake.size = 3; snake.speed= 10; snake.dir = RIGHT; for (int i =0; i food.y = rand() % 480; food.collor = RGB(rand() % 256, rand() % 256, rand() % 256); food.r = rand() % 10 + 5; food.flay = true; } void GameDraw() { //双缓冲绘图 BeginBatchDraw(); //设置背景颜色。 setbkcolor(RGB(28, 115, 119)); cleardevice(); //绘制蛇 定义蛇的坐标 setfillcolor(GREEN); for (int i = 0; i < snake.size; i++) { solidcircle(snake.coor[i].x ,snake.coor[i].y, 5);//solidcirle 绘制圆。 } EndBatchDraw(); if (food.flay) { solidcircle(food.x, food.y, food.r); } } void snakemove() { //改变蛇的坐标,用蛇头移动 for (int i =snake.size-1;i>0;i--) { snake.coor[i] = snake.coor[i - 1]; } //snake.coor[i].x++; switch (snake.dir)//蛇移动时,方向改变坐标。 { case up: snake.coor[0].y-=snake.speed; if (snake.coor[0].y + 10 <= 0) { snake.coor[0].y = 640; } break; case down: snake.coor[0].y+=snake.speed; if (snake.coor[0].y - 10 >= 640) { snake.coor[0].y = 0; } break; case LEFt: snake.coor[0].x-=snake.speed; if (snake.coor[0].x + 10 <= 0) { snake.coor[0].x =640; } break; case RIGHT: snake.coor[0].x+=snake.speed; if (snake.coor[0].x - 10 >=640) { snake.coor[0].x = 0; } break; } } void keycontrol() { if (_kbhit())//判断有没有按键 键盘。函数 {//72 80 75 77 上下左右的按键数值。 W S A D switch (_getch())//getch()函数是阻塞函数,,如果没有判断,只有按键,蛇才会动。 { case 'w': case 'W': case 72: if(snake.dir !=down) snake.dir = up; break; //改变蛇的方向 case 's': case 'S': case 80: if (snake.dir != up) snake.dir = down; break; case 'a': case 'A': case 75: if (snake.dir != RIGHT) snake.dir = LEFt; break;; case 'd': case 'D': case 77: if (snake.dir != LEFt) snake.dir = RIGHT; break; } } } void eatfood() { if (food.flay&&snake.coor[0].x >= food.x-food.r && snake.coor[0].x<=food.x+food.r&& snake.coor[0].y <= food.y+food.r &&snake.coor[0].y>=food.y-food.r) { food.flay = false; snake.size++; } if (!food.flay) { food.x = rand() % 640;//rand()随机数组,随机数要头文件 food.y = rand() % 480; food.collor = RGB(rand() % 256, rand() % 256, rand() % 256); food.r = rand() % 10 + 5; food.flay = true; } } int main() { GameInit(); GameDraw(); while(1) { eatfood(); Sleep(10); GameDraw(); snakemove(); keycontrol(); Sleep(100); } return 0; }



