| 网站首页 | 业界新闻 | 小组 | 交易 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
共有 3339 人关注过本帖, 4 人收藏
标题:炒现饭,也来做个贪吃蛇
只看楼主 加入收藏
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:208
帖 子:2003
专家分:11148
注 册:2014-12-6
结帖率:100%
收藏(4)
 问题点数:0 回复次数:26 
炒现饭,也来做个贪吃蛇
  春节期间有一天值班,无所事事,看论坛内有人提相关贪吃蛇问题,心想:这没头没尾的,怎么解答,还不如自己做个,就当练练手。今天添加简单界面和计分功能,就算整个游戏完成,这是我首次在论坛发帖,也是首个c代码练习,如有不到之处,还望各大神不吝赐教!
  本代码有几处可供各坛友借鉴,一是使用数组存储游戏中需要的字符元素,后面通过指针使用,该方法可减少代码量,无需众多的if...printf语句;二是使用两个场景缓冲区,只printf变化的部分,可提高速度,消除闪烁(dos模式下显示很慢的)。本代码在vc++6下编译通过。


//贪吃蛇C代码  Programer:wmf2014  2015.2.27 仅供bbs.bccn.net参考

#include "stdafx.h"//mfc标准头文件,可忽略,在vc里方便通过编译
#include<stdio.h>//基本库
#include<stdlib.h>//系统库
#include<windows.h>//光标定位、字符颜色函数库
#include<time.h>//时间函数库
#include<conio.h>//键值读入函数库
#define width 60
#define height 25
struct ssnake
{
    int f;//蛇身有效标志
    int x;
    int y;//蛇身坐标
};
void color(int b)         //颜色函数
{
    HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
    SetConsoleTextAttribute(hConsole,b) ;
}
void HideCursor()//隐藏光标
{
    HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor_info={1,0};
    SetConsoleCursorInfo(hOut,&cursor_info);
}

void gotoxy(int x,int y)//设置字符显示位置
{
    HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
    COORD loc={x,y};
    SetConsoleCursorPosition(hOut,loc);
}
void drawmap(char *mp,char *omp,ssnake *snp)
{//画场景
    char pel[]="  ◆■●";
    int i,j,k;
    for(i=0;snp[i].f>0;i++)
    {
        j=4;//蛇身
        if(i==0)j=2;//蛇头
        mp[snp[i].x*height+snp[i].y]=j;
    }
    for(k=0;k<width*height;k++)
    {
        if(mp[k]!=omp[k])
        {
            i=k/height;j=k%height;
            color(15);
            if(mp[k]==6)color(13);
            omp[k]=mp[k];
            gotoxy(i,j);
            printf("%c",pel[mp[k]]);
            printf("%c",pel[mp[k]+1]);
        }
    }
}
void rndapple(ssnake *snp,int *px,int *py)
{//产生苹果随机位置
    bool f=false;
    int i,j,k=0,z[1500][2]={0};
    char map[width][height]={0};
    *px=-1;*py=-1;
    for(i=0;snp[i].f>0;i++)map[snp[i].x][snp[i].y]=1;
    for(i=0;i<width;i+=2)
        for(j=0;j<height;j++)
        {
            if(map[i][j]==0)
            {
                z[k][0]=i;
                z[k][1]=j;
                k++;
            }
        }
    if(k>0)
    {
        i=rand()%k;
        *px=z[i][0];
        *py=z[i][1];
    }
}

void main()
{
    char map[width][height]={0},oldmap[width][height]={0};//场景 0:空 2:蛇头 4:蛇身 6:苹果
    int mx=0,my=0;//蛇头移动方向
    int apx=-1,apy=-1;//苹果位置
    int i,j,sc=0,ef=0,sp=210;
    long t1,nt;//计时
    char a;
    bool pf=false;//暂停标志
    ssnake sn[1500]={0};//蛇,最长1500个关节,关节数据结构为ssnake,
    nt=clock();
    t1=nt;
    system("mode con cols=80 lines=25");
    HideCursor();
    for(i=0;i<height;i++){gotoxy(width,i);printf("‖");}
    color(14);
    gotoxy(width+4,12);printf("控制:←↑→↓");
    gotoxy(width+4,14);printf("空格:暂停");
    gotoxy(width+4,16);printf("ESC :退出");
    gotoxy(width+4,18);printf("得分:%d",sc);
    sn[0].f=1;sn[0].x=30;sn[0].y=10;sn[1].f=0;//蛇头位置
    srand((unsigned)time(NULL));
    while(1)
    {
        nt=clock();
        if(kbhit())   //判断击键
        {
            a=getch();
            if(a<0)
            {
                a=getch();
                if(a=='K'&&mx!=2){mx=-2;my=0;}
                if(a=='M'&&mx!=-2){mx=2;my=0;}//左右移动,由于用汉字符号表示,所以步长为2
                if(a=='H'&&my!=1){my=-1;mx=0;}
                if(a=='P'&&my!=-1){my=1;mx=0;}//上下移动
            }
            else
            {
                if(a==27){ef=1;break;}//人为退出
                if(a==32)pf=!pf;
            }
        }
        if(!pf&&nt-t1>sp)
        {
            t1=nt;
            for(i=0;sn[i].f>0;i++);
            for(j=i;j>0;j--){sn[j].x=sn[j-1].x;sn[j].y=sn[j-1].y;}//蛇身前进
            sn[0].x+=mx;sn[0].y+=my;//蛇头前进
            if(sn[0].x<0||sn[0].x>=width||sn[0].y<0||sn[0].y>=height){ef=2;break;}//越界
            for(j=1;sn[j].f>0;j++){if(sn[j].x==sn[0].x&&sn[j].y==sn[0].y)break;}
            if(sn[j].f!=0){ef=3;break;}//判断是否自己吃自己
            if(sn[0].x==apx&&sn[0].y==apy)//吃了苹果
            {
                sn[i].f=1;sn[i+1].f=0;apx=-1;apy=-1;sp--;
                sc=sc+10+i;//成绩累加
                gotoxy(64,18);printf("得分:%d",sc);
            }
        }
        for(i=0;i<width;i++)
            for(j=0;j<height;j++)
                map[i][j]=0;
        if(apx<0&&apy<0)rndapple(sn,&apx,&apy);//获取苹果位置
        if(apx>=0&&apy>=0)
            map[apx][apy]=6;//设置苹果
        else
        {//已经没有空位画苹果位置了,说明蛇足够长,这是不可能的
            gotoxy(62,24);
            printf("厉害,满分!");
            break;
        }
        drawmap(&map[0][0],&oldmap[0][0],sn);
    }
    gotoxy(25,23);
    color(15);
    if(ef==1)printf("不玩了!Game Over!\n");
    if(ef==2)printf("越界死翘翘!Game Over!\n");
    if(ef==3)printf("吃自己死翘翘!Game Over!\n");
}


[ 本帖最后由 wmf2014 于 2015-2-27 15:59 编辑 ]
搜索更多相关主题的帖子: 贪吃蛇 缓冲区 游戏 元素 
2015-02-27 14:23
诸葛欧阳
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:流年
等 级:贵宾
威 望:82
帖 子:2792
专家分:14619
注 册:2014-10-16
收藏
得分:0 
跪拜

一片落叶掉进了回忆的流年。
2015-02-27 17:39
hazer
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2015-3-7
收藏
得分:0 
不错!!!!!!!!!!!!!!
2015-03-07 21:58
a861268448
Rank: 1
等 级:新手上路
帖 子:47
专家分:0
注 册:2014-9-15
收藏
得分:0 
多谢分享,我可以好好学习下了
2015-03-08 00:05
a861268448
Rank: 1
等 级:新手上路
帖 子:47
专家分:0
注 册:2014-9-15
收藏
得分:0 
楼主,可不可以说下sn[0].f=1;sn[0].x=30;sn[0].y=10;sn[1].f=0;//蛇头位置 这个怎么理解
2015-03-08 15:22
a861268448
Rank: 1
等 级:新手上路
帖 子:47
专家分:0
注 册:2014-9-15
收藏
得分:0 
楼主这里我也没有搞懂
a=getch();
                if(a=='K'&&mx!=2){mx=-2;my=0;}
                if(a=='M'&&mx!=-2){mx=2;my=0;}//左右移动,由于用汉字符号表示,所以步长为2
                if(a=='H'&&my!=1){my=-1;mx=0;}
                if(a=='P'&&my!=-1){my=1;mx=0;}//上下移动

这里面的K,M,H,P是什么含义
2015-03-08 15:29
a861268448
Rank: 1
等 级:新手上路
帖 子:47
专家分:0
注 册:2014-9-15
收藏
得分:0 
回复 楼主 wmf2014
楼主
if(a==32)pf=!pf;
if(!pf&&nt-t1>sp)

中pf=!pf是啥意思,还有nt-t1>sp中的sp是啥?为啥要>
2015-03-08 15:43
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:208
帖 子:2003
专家分:11148
注 册:2014-12-6
收藏
得分:0 
回复 7楼 a861268448
嗯,要完全读懂这些代码还是要些基础的。非常感谢你关注我写的这个小程序,下面我针对你的问题一一解答。
1、我是用一个长度为1500的结构体数组来表示蛇的,因为我定义的屏幕为25*60=1500,即蛇最长也就是沾满屏幕,蛇头永远是在0的位置。结构体有3个元素f、x、y,f为有效标志,x、y为蛇身或蛇头所处坐标,初始化状态只有一个蛇头,同时把蛇头放到屏幕中间,所以“sn[0].f=1”就是表示蛇的第一节有效,第一节即蛇头了,“sn[0].x=30;sn[0].y=10;”就是蛇第一节所在位置坐标为(30,10),“sn[1].f=0”表示蛇第二节为无效状态,大致类似于字符串的结束符。
2、if(a=='K'&&mx!=2){mx=-2;my=0;}...,这里的K,M,H,P是光标键的第二个字节键值,这是系统规定的。一般获取的键盘值用一个字节即可,但光标键需要读取2个字节,第一个值为-32,第二个值就是K,M,H,P了,通过识别第二个键值就可以控制蛇的运动方向了。
3、“if(a==32)pf=!pf”,pf是我定义的一个bool类型标志,初始值为false,pf=!pf就好像一个开关,执行一次pf值就反向变化一次,就“false、true、false、true...”变化下去,“if(a==32)”,a是获取的键盘值,32就是空格键,这句的意思就是判断是否敲了空格键,如果是空格键就将pf值变化一次。“if(!pf&&nt-t1>sp)”中nt-t1是过去的时间,用毫秒计,sp是时间比较标准,初始值为210,即时间超过210毫秒就处理蛇移动一次,但是否真的需要处理蛇的移动,还要受pf标志制约,就是敲空格键暂停或继续游戏。sp的值也在变化,蛇越长,sp越小,即时间越短,难度越高。

大致就这样吧,不善言辞,表述不清,还望谅解。

[ 本帖最后由 wmf2014 于 2015-3-8 17:23 编辑 ]

能编个毛线衣吗?
2015-03-08 17:20
a861268448
Rank: 1
等 级:新手上路
帖 子:47
专家分:0
注 册:2014-9-15
收藏
得分:0 
回复 8楼 wmf2014
多谢解答,通过你的程序收获很多,还有不懂的地方希望指点
2015-03-08 23:01
whc19940817
Rank: 1
等 级:新手上路
帖 子:5
专家分:2
注 册:2015-3-8
收藏
得分:0 
还可以,哟,我只能看懂一部分。很多不懂,不过,从看懂的一部分中收货也很多
2015-03-09 14:10
快速回复:炒现饭,也来做个贪吃蛇
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.054175 second(s), 7 queries.
Copyright©2004-2020, BCCN.NET, All Rights Reserved