下午真无聊的不知道干什么了,翻翻自己以前写的代码,偶然看到大一时写的这个简单的贪吃蛇,自己玩了几把后还是决定发到博客吧。(实在无聊,打发时间)
注:完全基于VC++6.0环境,不支持Linux 下terminal中运行。并且代码风格基本没有,写的十分扯,一大堆代码都在main()函数中,其中用了switch来搞了两关,一个是撞墙over,另一个当然可以穿墙了。代码复用就别提了,两关由于十分相似,代码基本相同,由于只是玩,就没搞个公用调用接口。唉,现在看着以前的代码,感觉那风格简直是扯淡。
「正文开始」:
代码开始那段,其实是用来装逼的,什么设置用户名,代码最后重新开始游戏,设置速度(通过sleep的时间实现)之类的,准备着以后修改修改,完善完善,但是现在觉得没时间再玩这些东西了,也一直没改。
由于代码中基本我都写了注释以及打印时的英文标注,在这就说下大体的代码实现思路,其实蛇身是基于双向链表实现的,而蛇的移动是通过以非阻塞的方式从缓冲区中读出按键对应的值,从而控制方向(kbhit()函数可以检测键盘是否按下,以非阻塞的方式从缓冲区读取数据),而蛇的移动是通过检测对用的蛇身位置,通过刷屏
(system(”cls“);)的方式不断打印蛇身的位置,从而实现蛇的移动效果(运动时还需要保证蛇身的运动方向与蛇头是一致的)。本身其实一切都是在开始定义的那个数组
int a[20][20]={0};// 定义布局范围大小
中来实现的,控制的关键是这个数组中每个位置的字符样式(有标记),蛇头就打印实体框,蛇身就是虚体框,而食物就是随机产生的英文咯,每当蛇头与食物在同一个坐标是就新建一个节点,添加到蛇身这条链表。而游戏结束的标志其实也是通过检测蛇头与蛇身的坐标关系,还有与边缘的坐标关系,判断是自残而死还是撞墙而死。「废话不多说了」
上代码:
<head.h>
struct Node
{
int x;
int y; //蛇身节点位置的数据类型、
struct Node *pre;
struct Node *next; //双向链表,控制蛇身运动的一致性
};
struct Food
{
int x;
int y;
char c; // 食物种子的数据类型。
};
这是用到的两个简单的struct,总体实现,其实是基于双向链表的。
在者就是需要用到win环境下的头文件:
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h> //key for snake food !
#include <conio.h>
#include "head.h"
由于比较扯,下面实现代码都是在main函数中,我现在也懒得改了,就这么看吧。
int main(int argc,char *argv[])
{
int a[20][20]={0};// 定义布局范围大小。
char user_name[15];
int i,j,flag=0;
int speed; //蛇运行速度的控制,用sleep()实现,其实也是清屏的间歇速度。。
char c='d',c1='d'; //运动方向初始化
char key;
char speed_key,user_key,stage_key;
struct Food food={9,15,'*'}; //食物得初始位置
int stage; //选择关卡
int gameover=0; //key data
struct Node *head,*p,*rear,*pt;
int score;
printf("************************ <! careful !> *****************************\n\n");
puts("\n<*>*<*>every time when you touch foods and you will get five points !<*><*>\n\n when you want to stop at once ,please press ‘t’\n\nwhen you want to have a pause ,please press '0'\n\n ");
puts("Direction control help: ** < UP:w > < DOMN :s > < left :a > < right :d > **\n\n\n ");
printf("*****************************************\n");
printf("please input the speed of this snake ( between 0 ~~ 300 ):");
scanf("%d",&speed);
printf("\n\nplease input your user_name :");
scanf("%s",user_name);
key='y';
printf("\n\nplease choose which stage to start game(input the int value bellow:)?\n\n【(*0*):without the wall to stop game,(*1*): with the wall to stop your touch】\n\n");
flushall();
scanf("%d",&stage);
while(key=='y')
{
score=0;
head=(struct Node *)malloc(sizeof(struct Node));
head->x=10;
head->y=10; // 蛇身头节点的初始位置
head->pre=NULL;
head->next=NULL;
rear=head;
srand((unsigned)time(NULL)); //随机函数的产生:【食物种子】
switch (stage)
{
case 0:
while(1)
{
if(food.x==head->x && food.y==head->y)
{
p=(struct Node *)malloc(sizeof(struct Node)); //产生曾长段。
pt=head;
while(pt->next!=NULL)
pt=pt->next ; //找出蛇体增长位置pt为尾指针
p->pre= pt;
pt->next = p;
p->next=NULL;
rear=p; //尾指针
score+=5; //分数增加
food.x=rand()%20; //食物产生的随机位置算法
food.y=rand()%20;
food.c=65+rand()%26;
flag=1;
}
pt=rear;
if(kbhit()) // key point : 【 检查键盘有无按下。。输入任意字符继续 ,要么,程序只能执行一次,即打一次
{ // kbhit()可以保证循环时可以连续地以非阻塞方式从缓冲区读入字符。。
c1=getch(); // 清除缓存,从缓冲区读入一个字符】
if(c1=='0')
{
system("pause");
}
if(c1=='t')
{
exit(0);
}
if(c!='d' && c1=='a')
c=c1;
else if(c!='a' && c1=='d') //保证运行时当蛇延直线前行时,按下与直线方向相反的键时,出现游戏结束。。
c=c1;
else if(c!='w' && c1=='s')
c=c1;
else if(c!='s' && c1=='w')
c=c1;
}
while(pt!=head)
{ //控制每一节蛇身的运动与头保持一致
pt->x=pt->pre->x;
pt->y=pt->pre->y;
pt=pt->pre;
}
if(c=='d') //方向控制
{
head->y +=1;
if(head->y >=20)
head->y -=20;
}
else if(c=='a')
{
head->y -=1;
if(head->y <0)
head->y +=20;
}
else if(c=='w')
{
head->x -=1;
if(head->x < 0)
head->x +=20;
}
else if(c=='s')
{
head->x+=1;
if(head->x >=20)
head->x -=20;
}
pt=head->next;
while(pt!=NULL)
{
if(head->x==pt->x && head->y==pt->y)
{
gameover=1; //蛇头与身体相遇时退出游戏
break;
}
pt=pt->next ;
}
if(gameover==1)
break;
system("cls"); //每次清屏。。。
printf("************************ <! game start !> *****************************\n\n");
printf("your user_name : %s\n\nthe current speed is %d\n\n",user_name,speed);
printf(" the current stage is %d\n\n",stage);
printf("*****************************************\n");
for(i=0;i<20;i++) //打印循环开始,也是游戏的可视化布局
{
printf("|");
for(j=0;j<20;j++)
{
flag=0;
pt=head;
while(pt!=NULL)
{
if(i==pt->x && j==pt->y)
{
if(pt==head)
printf("■"); //当pt=head 时,在那个位置打出头标,
else
printf("□"); //要么打出身标
flag=1;
break;
}
pt=pt->next;//一直找,直到蛇尾结束打印
}
if(flag==0)
{
if(i==food.x && j==food.y)
{
putchar(food.c); //如果此位置是food的位置,则打印出food的字符,否则打印空格(必须填满方格布局)。
putchar(food.c);
continue; //转去执行下一次循环判断
}
printf(" "); //不是蛇身,则打印空格
}
}
printf("|\n");
}
printf("*****************************************\n");
_sleep(speed);
}
break;
case 1 :
while(1)
{
if(food.x==head->x && food.y==head->y)
{
p=(struct Node *)malloc(sizeof(struct Node)); //产生曾长段。
pt=head;
while(pt->next!=NULL)
pt=pt->next ; //找出蛇体增长位置pt为尾指针
p->pre= pt;
pt->next = p;
p->next=NULL;
rear=p; //尾指针
score+=5; //分数
food.x=rand()%20; //食物产生的随机位置算法
food.y=rand()%20;
food.c=65+rand()%26;
flag=1;
}
pt=rear;
if(kbhit()) // key point : 【 检查键盘有无按下。。输入任意字符继续 ,要么,程序只能执行一次,即打一次
{ // kbhit()可以保证循环时可以连续地以非阻塞方式从缓冲区读入字符。。
c1=getch(); // 清除缓存,从缓冲区读入一个字符】
if(c1=='0')
{
system("pause");
}
if(c1=='t')
{
exit(0);
}
if(c!='d' && c1=='a')
c=c1;
else if(c!='a' && c1=='d') //保证运行时当蛇延直线前行时,按下与直线方向相反的键时,出现游戏结束。。
c=c1;
else if(c!='w' && c1=='s')
c=c1;
else if(c!='s' && c1=='w')
c=c1;
}
while(pt!=head)
{ //控制每一节蛇身的运动与头保持一致
pt->x=pt->pre->x;
pt->y=pt->pre->y;
pt=pt->pre;
}
if(c=='d') //方向控制
{
head->y +=1;
if(head->y >=20)
{
gameover=1;
break;
}
}
else if(c=='a')
{
head->y -=1;
if(head->y <0)
{
gameover=1;
break;
}
}
else if(c=='w')
{
head->x -=1;
if(head->x < 0)
{
gameover=1;
break;
}
}
else if(c=='s')
{
head->x+=1;
if(head->x >=20)
{
gameover=1;
break;
}
}
pt=head->next;
while(pt!=NULL)
{
if(head->x==pt->x && head->y==pt->y)
{
gameover=1; //蛇头与身体相遇时退出游戏
break;
}
pt=pt->next ;
}
if(gameover==1)
break;
system("cls"); //每次清屏。。。
printf("************************ <! game start !> *****************************\n\n");
printf("your user_name : %s\n\nthe current speed is %d\n\n",user_name,speed);
printf("*****************************************\n");
for(i=0;i<20;i++)
{
printf("|");
for(j=0;j<20;j++)
{
flag=0;
pt=head;
while(pt!=NULL)
{
if(i==pt->x && j==pt->y)
{
if(pt==head)
printf("■"); //当pt=head 时,在那个位置打出头标,
else
printf("□"); //要么打出身标
flag=1;
break;
}
pt=pt->next;//一直找,直到蛇尾结束打印
}
if(flag==0)
{
if(i==food.x && j==food.y)
{
putchar(food.c); //如果此位置是food的位置,则打印出food的字符,否则打印空格(必须填满方格布局)。
putchar(food.c);
continue; //转去执行下一次循环判断
}
printf(" "); //不是蛇身,则打印空格
}
}
printf("|\n");
}
printf("*****************************************\n");
_sleep(speed);
}
break;
}
if(gameover==1) {
puts("************************《Now the game over!》*****************************\n\n ********!< _ >!*******\n\n");
printf("\n your score is :%d\n",score);
puts("if you want to continue ? (y/n)\n");
flushall();
scanf("%c",&key);
if(key=='y')
{
gameover=0;
flushall();
printf("\nif you want to change speed ? (y/n):");
scanf("%c",&speed_key);
if(speed_key=='y')
{
printf("input speed value:\n");
scanf("%d",&speed);
}
else
printf("\n");
flushall();
printf("\nif you want to change user_name ? (y/n):");
scanf("%c",&user_key);
if(user_key=='y')
{
flushall();
printf("input new user_name:\n");
scanf("%s",user_name);
}
else
printf("\n");
flushall();
printf("\n if you want to change the stage ? (y/n):");
scanf("%c",&stage_key);
if(stage_key=='y')
{
flushall();
printf("\nplease input the stage value :");
scanf("%d",&stage);
}
else
printf("\n");
continue;
}
else
exit(0);
}
}
return 0;
}
大概就写到这里吧,唉,还是那句话,代码风格惨不忍睹。