目录
-
项目介绍
1.项目简介
我们的项目依据诺基亚手机当年附带的小游戏贪吃蛇进行书写。使用竖线与下划线作为边界,使用简单的“@”字符与“*”字符与“#”字符分别构成蛇头蛇身体与食物.蛇,同时蛇具有不同的速度。
2.主要问题
1.如何保存蛇的位置与食物的位置?
2.如何更新页面?
3.如何随机生成食物?
4如何移动光标,以便更新蛇?
5.如何移动蛇?形成移动效果?
-
系统设计
1.框架设计
- 定义蛇对象、食物对象,用于保存它们的坐标
- 初始化蛇、初始化食物
3.控制流程:
1)蛇头和墙壁的碰撞
2)蛇头和蛇身体的碰撞
(如果蛇头碰到墙壁或者身体,蛇会死亡)
3)蛇头和食物的碰撞
1>蛇身增长
2>食物消失 -- 新食物产生
3>分数累加
4> 移动速度增大
4)蛇的移动
1>自动移动
2>手动控制移动:ASWD---左下上右
5)显示分数
2函数设计
1>主函数与各个函数分离,主函数保证代码逻辑,各个辅助函数实现具体功能,通过多次的函数调用来实现所需功能。
2>函数分类:将出了main函数外的函数分为辅助函数,和主要函数
3>函数命名 使用body,snake,wall等具体描述,前缀使用init等
3.函数运行
1>开始 在开始界面呈现菜单,使用do while 进入循环,同时选择模式或者退出,由switch case 语句进入
2>中途 使用wasd与程序进行交互
3结束游戏 结束游戏后返回,由相应函数呈现分数
- 关键技术介绍
头文件有
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>
- 使用结构体与数组使用向右向下的x.y坐标的方式确定蛇对象与食物对象的位置
- 使用while()循环的嵌套以及相应语句实现对蛇头是否和墙壁的碰撞,蛇头和蛇身体的碰撞,蛇头和食物的碰撞的判断,若蛇与身体或者墙壁碰撞则会break,跳出循环
3.使用 srand(time(NULL)),使用时间来生成随机数种子,从而随机生成食物的坐标
4.使用COORD结构体以及
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
移动光标到coord所储存的位置,并且进行判断,以此来画蛇的头部与身体,以及食物
5.使用
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cci);
设置光标不可见
6 使用do while循环来实现重复游戏,使得玩家可以先进入菜单页面进行判断,再通过交互输入指令
7.kbhit()非阻塞地响应键盘输入事件,判断键盘是否进行输入,如果输入则返回true,未输入则返回false
8.getch()不回显地接收输入的字符,接收玩家从键盘输入的指令,同时不显示在控制台
9.控制Sleep(),控制程序的休眠时间来呈现贪吃蛇的速度,并且通过相应变量控制贪吃蛇的速度
10.system(“cls”)实现清屏操作
代码实现
头文件,宏,全局变量与结构体定义
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>
#define WIDE 60 //宽
#define HIGH 20 //高
//一个身体的对象
typedef struct BODY
{
int X;
int Y;
}BODY;
//定义蛇对象
struct SNAKE
{
BODY body[WIDE * HIGH];//蛇头body【0】
int size;
}snake;
//定义食物对象
struct FOOD
{
int X;
int Y;
}food;
int score = 0;
int kx = 0;
int ky = 0; //用户按下键得到的坐标值
int lastX = 0;//蛇尾坐标
int lastY = 0;
int sleeptime = 260;
初始化函数 与分数展示函数
void initsnake()//蛇初始化
{
snake.size = 2;
snake.body[0].X = WIDE / 2;//初始化蛇头
snake.body[0].Y = HIGH / 2;
snake.body[1].X = WIDE / 2 - 1;
snake.body[1].Y = HIGH / 2;
}
void initfood()
{
food.X = rand() % WIDE;
food.Y = rand() % HIGH;
return;
}
void initui(void)
{
//画蛇
COORD coord;
for(int i = 0; i < snake.size; i++)
{
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord); //光标移动的位置
if(i ==0)putchar('@');
else putchar('*');
}
//去除蛇尾
coord.X = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
putchar(' ');
//画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
putchar('#');
}
void initwall(void)
{
for(int i = 0; i <= HIGH; i++)
{
for(int j = 0; j <= WIDE;j++)
{
if(j == WIDE)
{
printf("|");
}
else if(i == HIGH)
{
printf("_");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void showScore()
{
//把光标移动到不妨碍的地方
COORD coord;
coord.X = 0;
coord.Y = HIGH + 2;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
printf("Game Over!!!\n");
printf("你的成绩为: %d\n",score);
}
游戏逻辑函数和主函数
void playgame(void)
{
char key = 'd';
//撞墙
while(snake.body[0].X >= 0 && snake.body[0].X < WIDE
&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH)
{
initui(); //更新蛇
//接收用户按键输入awds
if(kbhit())
{
key = getch();
}
switch(key)
{
case'w':kx = 0; ky = -1;break;
case's':kx = 0; ky = +1;break;
case'd':kx = +1; ky = 0;break;
case'a':kx = -1; ky = 0;break;
default:
break;
}
//撞身体
for(int i = 1; i < snake.size; i++)
{
if(snake.body[0].X == snake.body[i].X
&& snake.body[0].Y == snake.body[i].Y)
{
return;
}
}
//撞食物
if(snake.body[0].X == food.X && snake.body[0].Y == food.Y)
{
//食物消失
initfood();
//身体增长
snake.size++;
//加分
score+= 10;
//加速
if(sleeptime > 100)
{
sleeptime -= 20;
}
}
lastX = snake.body[snake.size - 1].X;
lastY = snake.body[snake.size - 1].Y;
//蛇移动,后一节赋给前一节
for(int i = snake.size - 1; i > 0; i--)
{
snake.body[i].X = snake.body[i-1].X;
snake.body[i].Y = snake.body[i-1].Y;
}
snake.body[0].X += kx;
snake.body[0].Y += ky;
Sleep(sleeptime);
//清屏
//system("cls");
}
}
int main()
{
CONSOLE_CURSOR_INFO cci;//设置光标不可见
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cci);
srand(time(NULL));//随机数种子
initsnake();//初始化蛇
initfood();//初始化食物
initwall();//画墙
initui();//画蛇和食物
playgame();//启动游戏
showScore();
system("pause");
return 0;
}
整体呈现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>
#define WIDE 60 //宽
#define HIGH 20 //高
//一个身体的对象
typedef struct BODY
{
int X;
int Y;
}BODY;
//定义蛇对象
struct SNAKE
{
BODY body[WIDE * HIGH];//蛇头body【0】
int size;
}snake;
//定义食物对象
struct FOOD
{
int X;
int Y;
}food;
int score = 0;
int kx = 0;
int ky = 0; //用户按下键得到的坐标值
int lastX = 0;//蛇尾坐标
int lastY = 0;
int sleeptime = 260;
void initsnake()//蛇初始化
{
snake.size = 2;
snake.body[0].X = WIDE / 2;//初始化蛇头
snake.body[0].Y = HIGH / 2;
snake.body[1].X = WIDE / 2 - 1;
snake.body[1].Y = HIGH / 2;
}
void initfood()
{
food.X = rand() % WIDE;
food.Y = rand() % HIGH;
return;
}
void initui(void)
{
//画蛇
COORD coord;
for(int i = 0; i < snake.size; i++)
{
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord); //光标移动的位置
if(i ==0)putchar('@');
else putchar('*');
}
//去除蛇尾
coord.X = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
putchar(' ');
//画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
putchar('#');
}
void playgame(void)
{
char key = 'd';
//撞墙
while(snake.body[0].X >= 0 && snake.body[0].X < WIDE
&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH)
{
initui(); //更新蛇
//接收用户按键输入awds
if(kbhit())
{
key = getch();
}
switch(key)
{
case'w':kx = 0; ky = -1;break;
case's':kx = 0; ky = +1;break;
case'd':kx = +1; ky = 0;break;
case'a':kx = -1; ky = 0;break;
default:
break;
}
//撞身体
for(int i = 1; i < snake.size; i++)
{
if(snake.body[0].X == snake.body[i].X
&& snake.body[0].Y == snake.body[i].Y)
{
return;
}
}
//撞食物
if(snake.body[0].X == food.X && snake.body[0].Y == food.Y)
{
//食物消失
initfood();
//身体增长
snake.size++;
//加分
score+= 10;
//加速
if(sleeptime > 100)
{
sleeptime -= 20;
}
}
lastX = snake.body[snake.size - 1].X;
lastY = snake.body[snake.size - 1].Y;
//蛇移动,后一节赋给前一节
for(int i = snake.size - 1; i > 0; i--)
{
snake.body[i].X = snake.body[i-1].X;
snake.body[i].Y = snake.body[i-1].Y;
}
snake.body[0].X += kx;
snake.body[0].Y += ky;
Sleep(sleeptime);
//清屏
//system("cls");
}
}
void initwall(void)
{
for(int i = 0; i <= HIGH; i++)
{
for(int j = 0; j <= WIDE;j++)
{
if(j == WIDE)
{
printf("|");
}
else if(i == HIGH)
{
printf("_");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void showScore()
{
//把光标移动到不妨碍的地方
COORD coord;
coord.X = 0;
coord.Y = HIGH + 2;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
printf("Game Over!!!\n");
printf("你的成绩为: %d\n",score);
}
int main()
{
CONSOLE_CURSOR_INFO cci;//设置光标不可见
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cci);
srand(time(NULL));//随机数种子
initsnake();//初始化蛇
initfood();//初始化食物
initwall();//画墙
initui();//画蛇和食物
playgame();//启动游戏
showScore();
system("pause");
return 0;
}