设计思路:
- 界面设置:采用system()函数来调整界面的大小,背景颜色
- 绘制地图:采用库函数获取坐标(下面具体介绍)
- 蛇的设计:采用链式结构实现蛇
- 食物设计:rand()随机产生食物坐标
- 蛇的移动:蛇移动实现采用链表相关操作,下面具体介绍
- 方向控制:采用GetAsyncKeyState()函数,通过键盘操作蛇移动的方向
- 蛇移动速度:采用Sleep()函数控制蛇移动速度
具体功能:
- 增加自身速度:分数每增加5分,进行加速
- 人为加速:按shift键进行加速
- 人为减速:按Ctrl键进行减速
- 暂停:游戏中按空格键可暂停,在按一次可继续游戏
- 退出:游戏过程中按Esc键可退出游戏
几个函数:
1.system
(这里只说明游戏中所用到的命令,详细请点击链接http://blog.csdn.net/s200820212/article/details/32695369)
功 能: 发出一个DOS命令
用 法: int system(char *command);
system函数已经被收录在标准c库中,可以直接调用
程序例:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
printf("About to spawn command.com and run a DOS command\n"); system("dir");
return 0;
}
system(“pause”)
用冻结屏幕,便于观察程序的执行结果;
system(“CLS”)
实现清屏操作。
system调用color函数可以改变控制台的前景色和背景,具体参数在下面说明。
例,用 system(“color 0A”); 其中color后面的0是背景色代号,A是前景色代号。各颜色代码如下:
0=黑色
1=蓝色
2=绿色
3=湖蓝色
4=红色
5=紫色
6=黄色
7=白色
8=灰色
9=淡蓝色
A=淡绿色
B=淡浅绿色
C=淡红色
D=淡紫色
E=淡黄色
F=亮白色
2.SetConsoleCursorPosition
解释:设置控制台光标坐标,参数就是设备句柄,坐标,那么把标准输出的句柄传给函数,就可以把光标定位在对应的位置了(左上角位置是0,0然后向左 向下延伸)
CROOD:
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;
很明显这个结构可以用来记录坐标
HANDLE:
一个句柄,用来接收GetHandle()返回的句柄
3.GetStdHandle
函数声明如下 :
HANDLE GetStdHandle(
DWORD nStdHandle
);
GetStdHandle()返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕缓冲区的句柄。
其参数nStdHandle的值为下面几种类型的一种:
值 含义
STD_INPUT_HANDLE 标准输入的句柄
STD_OUTPUT_HANDLE 标准输出的句柄
STD_ERROR_HANDLE 标准错误的句柄
4.GetAsyncKeyState()
具体点击下面链接
http://blog.csdn.net/fengfengfengmy/article/details/5570330
游戏代码:
Snake.h
#ifndef __SNAKE_H__
#define __SNAKE_H__
#define FOOD "■"
#define INIT_X 24//蛇的初始位置
#define INIT_Y 4
#define STARTSPEED 500//开始速度
#define SPEDGRADE 5//加速分数
#define STARTLENTH 5//开始蛇的长度
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<time.h>
//蛇走的方向
enum DIRECTION
{
UP = 1,//上
DOWN,//下
LEFT,//左
RIGHT,//右
};
//蛇的状态
enum Status
{
OK,//活的
KILL_BY_WALL,//撞墙
KILL_BY_SELF,//自己咬死
};
//蛇身节点
typedef struct Node
{
int x;
int y;
struct Node* next;
}SnakeNode;
//蛇本身
typedef struct snake
{
SnakeNode* _pSnake;//蛇头指针
SnakeNode* _food;//蛇的食物
enum DIRECTION _Dir;//行走方向
enum Status _Status;//当前状态
int _SleepTime;//每走一步停留的时间
int _Length;//蛇的长度
}Snake;
void StartMenu();//开始界面
void DrawMap();//地图
void SetPos(int x, int y);//设置光标
void InitSnake(Snake* ps);//初始化蛇结构体
void InitFood(Snake* ps);//初始化食物
int IsFood(SnakeNode* ps, SnakeNode* NewSnake);//判断是否有食物
void SnakeMove(Snake* ps);//蛇的移动
void EatFood(Snake* ps, SnakeNode* NewSnake);//吃食物
void NoFood(Snake* ps, SnakeNode* NewSnake);//没食物
void SnakeRun(Snake* ps);//方向选择
int KillBySelf(Snake* ps);//判断是否撞到自己身上
int KillByWALL(Snake* ps);//判断是否撞墙
#endif //__SNAKE_H__
Snake.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"
//设置光标位置
void SetPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { 0 };
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}
//开始界面
void StartMenu()
{
system("COLOR f3");//设置背景颜色
system("mode con cols=120 lines=35");//设置显示框大小
SetPos(33, 10);
printf("******************************");
SetPos(33, 12);
printf("* 欢迎来到贪吃蛇游戏! *");
SetPos(33, 14);
printf("******************************");
SetPos(33, 18);
system("pause");
system("cls");
SetPos(33, 10);
printf("************************************");
SetPos(33, 12);
printf("* 选项:1->开始游戏 0->退出 *");
SetPos(33, 14);
printf("* 操作:↑ ↓ ← →控制方向 *");
SetPos(33, 16);
printf("* 按空格暂停/继续,ESC退出 *");
SetPos(33, 18);
printf("* 按shift加速,Ctrl减速 *");
SetPos(33, 20);
printf("************************************");
SetPos(33, 22);
system("pause");
system("cls");
}
//地图
void DrawMap()
{
int i;
//上面边框
for (i = 0; i < 70; i += 2)
{
SetPos(i, 0);
printf(FOOD);
}
//下面边框
for (i = 0; i < 70; i += 2)
{
SetPos(i, 30);
printf(FOOD);
}
//左边边框
for (i = 0; i < 30; i++)
{
SetPos(0, i);
printf(FOOD);
}
//右边边框
for (i = 0; i <= 30; i++)
{
SetPos(70, i);
printf(FOOD);
}
printf("\n");
SetPos(76, 5);
printf(" 计分:");
SetPos(85, 5);
printf("%d ", 0);//每次吃完食物更新分数
}
//初始化蛇结构体
void InitSnake(Snake* ps)
{
SnakeNode* cur = NULL;
int i = 0;
cur = (SnakeNode*)malloc(sizeof(SnakeNode));
memset(cur, 0, sizeof(SnakeNode));
cur->x = INIT_X;
cur->y = INIT_Y;
for (i = 1; i <= 4; i++)
{
ps->_pSnake = malloc(sizeof(SnakeNode));
ps->_pSnake->next = cur;
ps->_pSnake->x = INIT_X + i * 2;
ps->_pSnake->y = INIT_Y;
cur = ps->_pSnake;
}
while (cur != NULL)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
ps->_Status = OK;
ps->_SleepTime = STARTSPEED;
ps->_Dir = RIGHT;
ps->_Length = STARTLENTH;
}
//初始化食物
void InitFood(Snake* ps)
{
SnakeNode* food = NULL;
food = (SnakeNode*)malloc(sizeof(SnakeNode));
flag:
memset(food, 0, sizeof(SnakeNode));
do
{
food->x = rand() % 70 + 2;
} while (food->x % 2 != 0);
food->y = rand() % 29 + 1;
SnakeNode* cur = ps->_pSnake;
while (cur != NULL)
{
if (cur->x == food->x&&cur->y == food->y)
{
goto flag;
}
cur = cur->next;
}
ps->_food = food;
SetPos(food->x, food->y);
printf(FOOD);
}
//蛇的移动
int IsFood(SnakeNode* food, SnakeNode* NewSnake)
{
if (food->x == NewSnake->x && food->y == NewSnake->y)
return 1;
return 0;
}
//吃食物
void EatFood(Snake* ps, SnakeNode* NewSnake)
{
int sum = SPEDGRADE;//加速分数,每增加5加速
//头插
SnakeNode* cur = ps->_pSnake;
NewSnake->next = cur;
cur = NewSnake;
ps->_pSnake = NewSnake;
while (cur != NULL)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
++ps->_Length;
int grade = ps->_Length-STARTLENTH;//分数
SetPos(85, 5);
printf("%d ", grade);//每次吃完食物更新分数
if (grade == sum)
{
//分数每增加5分,加速
ps->_SleepTime -= 100;
sum += SPEDGRADE;
}
InitFood(ps);
}
//没食物
void NoFood(Snake* ps, SnakeNode* NewSnake)
{
//先头插,后尾删
SnakeNode* cur = ps->_pSnake;
NewSnake->next = cur;
ps->_pSnake = NewSnake;
cur = NewSnake;
while (cur->next->next != NULL)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;
}
//蛇移动
void SnakeMove(Snake* ps)
{
Sleep(ps->_SleepTime);
SnakeNode* NewSnake = (SnakeNode*)malloc(sizeof(SnakeNode));
memset(NewSnake, 0, sizeof(SnakeNode));
NewSnake->x = ps->_pSnake->x;
NewSnake->y = ps->_pSnake->y;
switch (ps->_Dir)
{
case UP:
NewSnake->y--;
break;
case DOWN:
NewSnake->y++;
break;
case LEFT:
NewSnake->x -= 2;
break;
case RIGHT:
NewSnake->x += 2;
break;
default:
break;
}
int ret = IsFood(ps->_food, NewSnake);
if (ret == 1)
{
//有食物
EatFood(ps, NewSnake);
}
else
{
NoFood(ps, NewSnake);
}
}
//控制方向
void SnakeRun(Snake* ps)
{
do
{
if (GetAsyncKeyState(VK_LEFT) && ps->_Dir != LEFT)
{
ps->_Dir = LEFT;
}
else if (GetAsyncKeyState(VK_RIGHT) && ps->_Dir != RIGHT)
{
ps->_Dir = RIGHT;
}
else if (GetAsyncKeyState(VK_UP) && ps->_Dir != UP)
{
ps->_Dir = UP;
}
else if (GetAsyncKeyState(VK_DOWN) && ps->_Dir != DOWN)
{
ps->_Dir = DOWN;
}
else if (GetAsyncKeyState(VK_ESCAPE))//esc键正常退出
{
exit(0);
}
else if (GetAsyncKeyState(VK_SPACE))//空格暂停或继续
{
while (1)
{
Sleep(300);
if (GetAsyncKeyState(VK_SPACE)) //按空格键继续
{
break;
}
}
}
else if (GetAsyncKeyState(VK_CONTROL))//Ctrl键减速
{
ps->_SleepTime += 100;
}
else if (GetAsyncKeyState(VK_SHIFT))//shift键加速
{
ps->_SleepTime -= 100;
}
SnakeMove(ps);
if (KillBySelf(ps) == 1)
{
ps->_Status = KILL_BY_SELF;
}
if (KillByWALL(ps) == 2)
{
ps->_Status = KILL_BY_WALL;
}
} while (ps->_Status == OK);
}
//判断是否撞到自己身上
int KillBySelf(Snake* ps)
{
SnakeNode* cur = ps->_pSnake->next;
while (cur != NULL)
{
if (ps->_pSnake->x == cur->x&&ps->_pSnake->y == cur->y)
{
return 1;
}
cur = cur->next;
}
return 0;
}
//判断是否撞墙
int KillByWALL(Snake* ps)
{
SnakeNode* cur = ps->_pSnake;
if (cur->x == 0 || cur->x == 70 || cur->y == 0 || cur->y == 30)
return 2;
return 0;
}
test.c
#include<stdio.h>
#include"snake.h"
void play()
{
Snake snake = { 0 };
DrawMap();//地图
InitSnake(&snake);//初始化蛇
InitFood(&snake);//初始化食物
while (snake._Status == OK)
{
SnakeMove(&snake);
SnakeRun(&snake);
}
int grade = snake._Length - STARTLENTH;//获取游戏结束后的分数
if (snake._Status == KILL_BY_SELF)
{
SetPos(34, 10);
printf("Game Over\n");
SetPos(34, 12);
printf("本次得分为:%d\n",grade);
SetPos(34, 14);
system("pause");
}
if (snake._Status == KILL_BY_WALL)
{
SetPos(34, 10);
printf("Game Over\n");
SetPos(34, 12);
printf("本次得分为:%d\n", grade);
SetPos(34, 14);
system("pause");
}
}
void game()
{
while (1)
{
StartMenu();
int input = 0;
SetPos(77, 5);
printf("请选择:");
scanf("%d", &input);
system("cls");
if (1 == input)
{
play();
}
else if (0 == input)
{
exit(0);
}
}
}
int main()
{
game();
return 0;
}
效果展示:
开始界面:
撞墙而死,游戏结束:
撞到自己,游戏结束: