一、问题描述和解决思路
问题描述:贪吃蛇游戏,玩家用w、s、a、d分别代表上、下、左、右,以此来控制贪吃蛇的运动方向。当贪吃蛇吃到食物时身体会增加一段,同时也会使分数加一。如果贪吃蛇撞到它的身体或是游戏边框时,屏幕便会冻结,游戏便会失败。
解决思路: 首先,要初始化游戏,将边框和贪吃蛇画出来,并且随机产生一个食物(利用rand来产生两个随机数,并将其放到二维数组中,使其可以在画布中随机产生食物)。然后,让贪吃蛇的蛇头和身体一开始被赋的值都加一,同时将旧的蛇头蛇身的坐标记录下来,让旧的蛇头变为新的蛇身。再根据玩家输入的字符来判断方向,同时以旧的蛇头和蛇身的坐标为依据来为新的蛇头赋新的值。接下来判断新的蛇头所在位置之前是否有食物(利用if语句进行判断,让新的蛇头的所在的位置的二维数组的值和食物的值进行比较),如果有食物(两个值相同),就使分数加一,同时再随机产生一个新的食物,旧的食物消失。如果没有食物,就依据之前记录的旧的蛇尾的坐标来使蛇尾去掉一段。同时也要判断蛇头是否撞向边框或者撞向自己(利用一个if语句来判断新的蛇头的值是否等于边框的值或者是蛇身的值),如果撞到了,就使屏幕冻结,否则游戏继续。
二、功能模块划分
功能划分:
流程图:
三、遇到问题和解决措施
问题:游戏的边框不是一个矩形,边框只有三边。
解决方法:查看二维数组对边框的赋值,发现最右侧的边框没有赋值。
问题:贪吃蛇的食物随机产生的次数是有限的,无法一直产生食物。
解决方法:查看食物产生随机数的函数,发现食物的x y赋值反啦。
四、源程序
//贪吃蛇游戏
#include<stdio.h>
#include<stdlib.h> //可以产生随机数
#include<conio.h> //控制光标的移动
#include<windows.h> //用来冻结屏幕和延迟时间
#define HIGH 20 //画布尺寸 宽
#define WIDTH 30 // 长
int drection,count; //全局变量(方向和分数)
int food_x,food_y; //全局变量(产生食物的随机数)
int canvas[WIDTH][HIGH]={0}; //刚开始都初始化为零,全是空白
void gotoxy(int x,int y) //用于控制屏幕上的光标的移动 //需要conio.h函数的使用
{
HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE); //调用
COORD pos; //定义一个坐标
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(handle,pos);
}
void start() //画出边框和蛇头及蛇身
{
int i,j //0代表空格 1代表蛇头 大于1代表蛇身 -1代表边框 -2代表食物
for(i=0;i<WIDTH;i++) //画出边框
{
canvas[i][0]=-1;
canvas[i][HIGH-1]=-1;
}
for(j=0;j<HIGH;j++)
{
canvas[0][j]=-1;
canvas[WIDTH-1][j]=-1; //画出边框
}
canvas[WIDTH/2][HIGH/2]=1; //画出蛇头
for(i=1;i<5;i++)
{
canvas[WIDTH/2-i][HIGH/2]=1+i; //画出蛇身
}
drection=4; //让小蛇刚开始朝右移动
food_x=rand()%(27)+2;
food_y=rand()%(17)+2;
canvas[food_x][food_y]=-2; //随机在边框内产生食物
}
void drect() //让贪吃蛇按照既定的方向前进一步,同时判断贪吃蛇是否吃到了食物,玩家可以改变贪吃蛇前进的方向
{
int i,j,k;
for(i=1;i<HIGH-1;i++) //使贪吃蛇朝着原来的方向运动
{
for(j=1;j<WIDTH-1;j++)
{
if(canvas[j][i]>0) //让贪吃蛇的蛇头和蛇身的数值都增加一,使原来的蛇头变成蛇身
{
canvas[j][i]++;
}
}
}
int oldend_i,oldend_j,oldhead_i,oldhead_j,newhead_i,newhead_j; //旧的蛇头和蛇尾的坐标以及新的蛇头的坐标
int max=0;
for(i=1;i<HIGH-1;i++)
{
for(j=1;j<WIDTH-1;j++)
{
if(canvas[j][i]>0)
{
if(max<canvas[j][i]) //记录下蛇尾的坐标
{
max=canvas[j][i]; //引用 max的原因是尾巴会改变,不能使用canvas[i][j]==6
oldend_i=i;
oldend_j=j;
}
if(canvas[j][i]==2)
{
oldhead_i=i;
oldhead_j=j; //将旧的蛇头的坐标记录下来,便于对新的蛇头进行赋值
}
}
}
}
if(drection==1) //根据方向,对新的蛇头进行赋值
{
newhead_i=oldhead_i-1;
newhead_j=oldhead_j; //向上移一个单位
}
if(drection==2)
{
newhead_i=oldhead_i+1;
newhead_j=oldhead_j; //向下移一个单位
}
if(drection==3)
{
newhead_i=oldhead_i;
newhead_j=oldhead_j-1; //向左移一个单位
}
if(drection==4)
{
newhead_i=oldhead_i;
newhead_j=oldhead_j+1; //向右移一个单位
}
if(canvas[newhead_j][newhead_i]==-2) //贪吃蛇吃到食物时
{
count++;
canvas[food_x][food_y]=0; //旧的食物消失
food_x=(rand()%(27))+2;
food_y=(rand()%(17))+2;
printf(" 得分为:%d\n",count); //记录分数
canvas[food_x][food_y]=-2 //随机在边框内产生新的食物
}
else
{
canvas[oldend_j][oldend_i]=0; //贪吃蛇没吃到食物时,将旧的蛇尾去掉
}
if((canvas[newhead_j][newhead_i]==-1)||(canvas[newhead_j][newhead_i]>0)) //贪吃蛇撞墙或者是撞向自己时
{
printf("游戏结束!\n");
system("pause"); //屏幕冻结 (需要使用windows.h)
exit(0);
}
else
{
canvas[newhead_j][newhead_i]=1; //为新的蛇头赋值
}
}
void show() //根据start函数来使画面展示在屏幕上
{
gotoxy(0,0); //调用光标函数
int i,j;
for(i=0;i<HIGH;i++)
{
for(j=0;j<WIDTH;j++)
{
if(canvas[j][i]==-1)
{
printf("#"); //边框
}
else if(canvas[j][i]==1)
{
printf("@"); //蛇头
}
else if(canvas[j][i]==0)
{
printf(" "); //空白部分
}
else if(canvas[j][i]>1)
{
printf("*"); //蛇身
}
else if(canvas[j][i]==-2)
{
printf("F"); //食物
}
}
printf("\n"); //使边框更好的展示出来
}
Sleep(100); //延迟时间为100秒 (要用到头文件 windows.h同时S要大写)
}
void input() //用来控制贪吃蛇运动的方向
{
char ch;
if(kbhit() //判断是否有从键盘输入的内容 (需要使用 conio.h头文件)
{
ch=getch(); //得到输入的内容,但不显示在屏幕上
if(ch=='w') //分别用w,s,a,d来表示上,下,左,右
{
drection=1; //上
drect();
}
if(ch=='s') //下
{
drection=2;
drect();
}
if(ch=='a') //左
{
drection=3;
drect();
}
if(ch=='d') //右
{
drection=4;
drect();
}
}
}
int main()
{
char ch;
system("color F5"); //背景和字体颜色(F为白色背景,5为紫色字体)
printf("\n");
printf(" 欢迎开始贪吃蛇游戏\n");
printf("\n");
printf( " 请按p进入游戏界面\n");
scanf("%c",&ch);
if(ch=='p')
{
start(); //画面函数的调用
while(1)
{
show(); //将画面展示在屏幕上
drect(); //主要操作
input(); //根据键盘的输入来调节方向
}
}
return 0;
}