贪吃蛇---C语言实现
感想
大一刚放寒假,用了两天时间终于将贪吃蛇写好了。第一次写项目,虽然小了点,但是在这过程中遇到的问题都让我有所收获。
实现
贪吃蛇各函数关系图。如下图:
有了各功能关系图之后就可以开工写代码了。
写代码过程中遇到最多的问题,还是编译器的问题。最开始使用dev c++编译源代码,代码不多时,编译器工作还没什么问题。代码多了之后,编译器直接将我写好的源代码打乱了。大概是原先在函数体中的代码都跑到函数体外边。函数就剩下一个完整函数体。还有出现一些奇怪的括号,夹杂在代码中间。经过漫长的修改和重写代码。《这次备份了一份》。第一次无法过编译。第二次竟然过了。前后两次无任何代码改动。于是将代码移到vs2015上运行,出现如下错误:
几经寻求解决之法不得之后,毅然放弃vs2015,转到eclipse平台。幸好,eclipse c++可用。
----------------------------------------------------------------------------------------------------------------------------------
代码实现思路:
不得不提这个思路借鉴了别人的想法,二维数组----游戏界面。
二维数组通过四个数字来分辨空、墙、食物、蛇,对应为0、1、2、3.
游戏界面,就按照二维数组中的数字输出对应的字符即可。<这很简陋-->
代码
/*
============================================================================
Name : 0.c
Author : 陈致和
Version :
Copyright : 学习之用
Description : Snake in C, Ansi-style
============================================================================
*/
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
/*全局变量*/
int flag = 1;//在初始位置绘制贪吃蛇的状态标志
int MapAndSnake[25][25] = { 0 };/*存储地图边界、贪吃蛇、食物----清零
0代表空
1代表地图元素
2代表食物
3代表贪吃蛇
例如:0000
0000
0000
0000
1111
1201
1331
1111*/
int x = 0, y = 0;//食物坐标
char direction = 'D';//初始--向右
const int nVirtKeyA = 65;/*A*/
const int nVirtKeyD = 68;
const int nVirtKeyS = 83;
const int nVirtKeyW = 87;
int headX,
headY;//当前蛇头所在位置
int tailX,
tailY;//当前蛇尾所在位置
int steeringKeyX,
steeringKeyY;//转向标记点
int score;//分数
//time_t time;//存活时间
int snakeLength = 2;//初始长度为2
//time_t starttime
/*函数预申明*/
void createFood();
void iniMap(int x, int y);
void gamestart();
void reVector(int x, int y);
void reScore();
void exitGame();
DWORD WINAPI checkDirection(void *lpParameter);
void checkCollide();
/*函数区*/
void printfmun() {
int i, j;
for (i = 0; i<25; i++)
{
for (j = 0; j<25; j++)
printf("%d ", MapAndSnake[i][j]);
printf("\n");
}
}
void reScore() {
//time_t nowtime;
//time(&nowtime);
//time=nowtime-starttime;
score=snakeLength*10;
printf("当前分数为:%d\n",score);
//printf("你当前存活时间为: %d秒\n",time);
printf("贪吃蛇长度:%d\n",snakeLength);
}
void exitGame() {
printf("Game Over !");
exit(0);
}
DWORD WINAPI checkDirection(void *lpParameter) {//按键检测函数*
int key;
key=getch();
while(1){
key=getch();
if(key==nVirtKeyA)
direction=(char)key;
else if(key==nVirtKeyD)
direction=(char)key;
else if(key==nVirtKeyS)
direction=(char)key;
else if(key==nVirtKeyW)
direction=(char)key;
}
}
void checkCollide(){
if(x==headX && y==headY)//蛇头与食物正常碰撞
{
snakeLength++;
switch(direction){
case 'A':{
MapAndSnake[x][y-1]=3;
headY--;
break;
}
case 'D':{
MapAndSnake[x][y+1]=3;
headY++;
break;
}
case 'S':{
MapAndSnake[x+1][y]=3;
headX++;
break;
}
case 'W':{
MapAndSnake[x-1][y]=3;
headX--;
break;
}
}
createFood();
}
}
void reVector(int x,int y){
int time=200;//更新时间
//更新二维数组值
/*方向键*/
switch(direction){
/*左右*/
case 'A':{
steeringKeyX=headX;steeringKeyY=headY;
if(tailX>steeringKeyX){
MapAndSnake[headX][headY-1]=3;
headY--;
MapAndSnake[tailX][tailY]=0;
tailX--;
}
else if(tailX<steeringKeyX){
MapAndSnake[headX][headY-1]=3;
headY--;
MapAndSnake[tailX][tailY]=0;
tailX++;
}
else if(tailX==steeringKeyX){
MapAndSnake[headX][headY-1]=3;
headY--;
MapAndSnake[tailX][tailY]=0;
tailY--;
}
break;
}
case 'D':{
steeringKeyX=headX;steeringKeyY=headY;
if(tailX>steeringKeyX){
MapAndSnake[headX][headY+1]=3;
headY++;
MapAndSnake[tailX][tailY]=0;
tailX--;
}
else if(tailX<steeringKeyX){
MapAndSnake[headX][headY+1]=3;
headY++;
MapAndSnake[tailX][tailY]=0;
tailX++;
}
else if(tailX==steeringKeyX){
MapAndSnake[headX][headY+1]=3;
headY++;
MapAndSnake[tailX][tailY]=0;
tailY++;
}
break;
}
/*上下*/
case 'S':{
steeringKeyX=headX;steeringKeyY=headY;
if(tailY>steeringKeyY){
MapAndSnake[headX+1][headY]=3;
headX++;
MapAndSnake[tailX][tailY]=0;
tailY--;
}
else if(tailY<steeringKeyY){
MapAndSnake[headX+1][headY]=3;
headX++;
MapAndSnake[tailX][tailY]=0;
tailY++;
}
else if(tailY==steeringKeyY){
MapAndSnake[headX+1][headY]=3;
headX++;
MapAndSnake[tailX][tailY]=0;
tailX++;
}
break;
}
case 'W':{
steeringKeyX=headX;steeringKeyY=headY;
if(tailY>steeringKeyY){
MapAndSnake[headX-1][headY]=3;
headX--;
MapAndSnake[tailX][tailY]=0;
tailY--;
}
else if(tailY<steeringKeyY){
MapAndSnake[headX-1][headY]=3;
headX--;
MapAndSnake[tailX][tailY]=0;
tailY++;
}
else if(tailY==steeringKeyY){
MapAndSnake[headX-1][headY]=3;
headX--;
MapAndSnake[tailX][tailY]=0;
tailX--;
}
break;
}
}
checkCollide();
if(x!=0 && y!=0)//食物坐标不为零时刷新食物
{
MapAndSnake[x][y]=2;
}
if(headY==24||headX==24||headX==0||headY==0)
exitGame();
Sleep(time);
system("cls");//
//printfmun();
gamestart();
}
void createFood() {
/*随机产生食物坐标*/
int high = 23, low = 1;
srand(time(NULL));
x = rand() % (high - low + 1) + low;
y = rand() % (high - low + 1) + low;
if(flag==1){
iniMap(x, y);
flag=0;
}
else
reVector(x,y);
}
void iniMap(int x, int y) {
//time(&starttime);
/*初始化二维数组*/
int i, j;
for (i = 0; i<25; i++)
for (j = 0; j<25; j++)
{
if (i == 0 || i == 24)
MapAndSnake[i][j] = 1;
else if (i>0 && i<25)
if (j == 0 || j == 24)
MapAndSnake[i][j] = 1;/*填充地图边界*/
else if (x == i && y == j)
MapAndSnake[x][y] = 2;/*填入食物*/
else if (i == 23)
if (j == 2 || j == 3)
MapAndSnake[i][j] = 3;
}
headX = 23; headY = 3;//初始条件下蛇头位置
tailX = 23; tailY = 2;//初始条件下蛇尾位置
}
void gamestart() {//绘制地图、食物、贪吃?
int i, j;
for (i = 0; i<25; i++)
{
for (j = 0; j<25; j++)
{
if (MapAndSnake[i][j] == 1 ||
MapAndSnake[i][j] == 2 ||
MapAndSnake[i][j] == 3)
printf("■");
else
printf(" ");
}
printf("\n");
}
reScore();
//printfmun();
reVector(x, y);
}
int main() {
/**键盘按键检测线程*/
DWORD ThreadId;
HANDLE threadOne;
INT parameter;
threadOne = CreateThread(NULL,
0,
checkDirection,
¶meter,
0,
&ThreadId);
/**/
createFood();
gamestart();
getchar();
return 0;
}
理想效果
主要是代码写得太渣,导致蛇连续转弯会断了身子。大概这个意思
操作键需要大写键盘锁定----然后W A S D
接下来打算实现一个GUI版贪吃蛇,设置难度系数,优化那些渣代码,实现贪吃蛇自己找食物的功能。