贪吃蛇
效果演示:
操作说明:
-
、W
、S
、A
控制 上 、下、左、右 方向,D
暂停,按下任意键继续空格
- 每吃掉一个食物长度加1,界面下方显示当前长度
- 蛇头撞到自身或边界后显示
2秒(时间可更改),任意键退出game over!
- 由于上下字符间隔与左右字符间隔不一致,纵向移动时移动速度会超过横向移动速度。
- 画面显示:游戏画面信息存入二维数组:数组下标映射游戏中位置坐标,数组元素的值(0,1…)分别表示游戏场景中不同的对象(空白处,蛇头…),遍历数组根据不同的值输出游戏画面。每次输出前将光标调至首行首列处,覆盖之前的输出画面,达到刷新游戏画面的效果。
- 小蛇移动与成长:根据方向变量的值(1,2,3,4)来向某一方向(上,下,左,右)持续前进,当方向按键按下时,修改方向变量的值以改变方向。蛇头对应的数组元素的数值为1,从头到尾,数值递增(2,3,4,5…),每次更新画面,使数组中大于0的数组元素(蛇头蛇身)的值加一,蛇头的值变为2,根据行进方向在新方向上生成新的蛇头(数值为1),未吃到食物的情况下,将蛇尾变为空白。即通过向目标方向生成一个新蛇头,去掉蛇尾,来达到移动的效果,而吃掉食物时生成新蛇头而不去掉蛇尾,使长度加一。
- 食物生成:当食物被吃掉后,随机生成一个处于空白处的坐标,改变该坐标的值为新的食物。
以下为带注释的完整源代码:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define high 25 //画布高
#define width 60 //画布宽
#define border -1 //边界
#define blank 0 //空白
#define head 1 //蛇头
#define food -2 //食物
int canvas[high+1][width+1]; //画布数组
int direction; //行进方向
int head_h,head_w; //蛇头坐标
int tail_h,tail_w; //蛇尾坐标
int food_h,food_w; //食物坐标
int length; //贪吃蛇长度(包括蛇头)
int Isover; //游戏结束标志
void Startup(); //游戏数值初始化
void Show(); //游戏界面输出
void UpdateInput(); //因输入导致的游戏状态更新
void UpdateNormal(); //与输入无关的游戏状态更新
int main()
{
Startup();
while(Isover){
Show();
UpdateInput();
UpdateNormal();
}
printf("\ngame over!\n");
Sleep(2000);
system("pause");
return 0;
}
void Startup(){
/*设置边界值*/
for(int i=0;i<=width;i++){
canvas[0][i]=border;
canvas[high][i]=border;
}
for(int i=0;i<=high;i++){
canvas[i][0]=border;
canvas[i][width]=border;
}
/*设置贪吃蛇初始位置*/
head_h=high/2;
head_w=width/2;
canvas[head_h][head_w]=head;
/*贪吃蛇初始长度*/
length=6;
for(int i=1;i<length;i++){ //设置蛇身,应与初始移动方向相反
canvas[head_h][head_w-i]=i+1;
}
/*设置初始方向*/
direction=4;
/*设置食物位置,随机出现*/
srand(time(NULL));
do{
food_h=rand()%high;
food_w=rand()%width;
}while(canvas[food_h][food_w]!=blank);
canvas[food_h][food_w]= food;
/*设置游戏结束条件*/
Isover=1;
}
void Show(){
HideCursor(); //隐藏光标
gotoxy(1,1); //回调光标位置,刷新画面
for(int i=0;i<=high;i++){ //输出游戏界面
for(int j=0;j<=width;j++){
if(canvas[i][j] == border){ //边界
printf("#");
}
else if(canvas[i][j] == head ){ //蛇头
printf("@");
}
else if(canvas[i][j]== blank){ //空白处
printf(" ");
}
else if(canvas[i][j]== food){ //食物
printf("O");
}
else if(canvas[i][j]> 0){ //蛇身
printf("*");
}
}
printf("\n");
}
printf("\nLength of the snake:%2d",length);
}
void UpdateInput(){
char key_W=GetKeyState('W'), //监测 W 键是否按下
key_S=GetKeyState('S'), //监测 S 键是否按下
key_A=GetKeyState('A'), //监测 A 键是否按下
key_D=GetKeyState('D'), //监测 D 键是否按下
key_BS=GetKeyState(' '); //监测 空格 键是否按下
if(kbhit()){ //当有键按下时
if(key_BS<0){ //当按下 空格键 时,游戏暂停
printf("\n游戏暂停!");
system("pause");
system("cls");
}
if(key_W<0 && direction!=2){ //当按下 W 键,且原方向不为下时,上移
direction=1;
}
if(key_S<0 && direction!=1){ //当按下 S 键,且原方向不为上时,下移
direction=2;
}
if(key_A<0 && direction!=4){ //当按下 A 键,且原方向不为右时,左移
direction=3;
}
if(key_D<0 && direction!=3){ //当按下 D 键,且原方向不为左时,右移
direction=4;
}
}
}
void UpdateNormal(){
int max=0;
for(int i=1;i<high;i++){ //遍历画布
for(int j=1;j<width;j++){
if(canvas[i][j] > 0){ //使蛇身的值自增
canvas[i][j]++;
if(canvas[i][j]>max){ //定位数值最大点,即蛇尾处
max=canvas[i][j];
tail_h=i;
tail_w=j;
}
}
}
}
switch(direction){ //蛇头位置向当前方向移动
case 1:head_h--;break;
case 2:head_h++;break;
case 3:head_w--;break;
case 4:head_w++;break;
}
if(canvas[head_h][head_w] == blank){ //新蛇头在空白处
canvas[head_h][head_w] = head;
canvas[tail_h][tail_w] = blank;
}
else if(canvas[head_h][head_w] == food){ //新蛇头在食物处
length++;
canvas[head_h][head_w] = head;
do{ //随机出现食物,且食物只能刷新在空白处
food_h=rand()%high;
food_w=rand()%width;
}while(canvas[food_h][food_w]!=blank);
canvas[food_h][food_w]= food;
}
else{ //新蛇头在边界处或蛇身处
Isover=0;
}
}
void gotoxy(int x,int y){ //回调光标
COORD pos;
pos.X=x-1;
pos.Y=y-1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void HideCursor(){ //隐藏光标函数
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = sizeof(cursor);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(handle, &cursor);
}
以上内容在观看河海大学童晶老师的C语言游戏课程的基础上总结改进完成。