应天论坛

 找回密码
 参与我们

QQ登录

只需一步,快速开始

搜索
查看: 1029|回复: 0

C语言实现贪吃蛇

[复制链接]

276

主题

303

帖子

3187

积分

管理员

湘南小侠客

Rank: 9Rank: 9Rank: 9

积分
3187

优质服务勋章论坛元老

QQ
发表于 2017-5-25 08:20:03 | 显示全部楼层 |阅读模式
贪吃蛇实现原理:
贪吃蛇游戏在理论上是可以无限的进行下去的(除了撞墙和咬到自己),那么游戏主体就一定是个循环。
蛇是如何动起来的?在这里就是通过不断改变蛇的坐标,然后根据蛇的坐标不断刷新屏幕在视觉上形成蛇的移动效果。
食物出现在随机位置(当然不能出现在障碍物和蛇身上)。
蛇能吃到食物其实就是蛇头的坐标与食物的坐标重合时。
当蛇咬到自己或者撞到墙的时候游戏结束(坐标判断)

[mw_shl_code=c,true]#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>

//72,80,75,77是方向键对应的键值

#define UP 72

#define DOWN 80

#define LEFT 75

#define RIGHT 77

#define SNAKE 1     //蛇的坐标标识

#define FOOD 2      //食物的坐标标识

#define BAR 3       //墙的坐标标识


//初始化地图 17*17

char map[17][17] = {0};

//初始化蛇头坐标

unsigned char snake[50] = {77};

//初始化食物坐标

unsigned char food = 68;

//蛇长

char len = 1;


//存储坐标数字与x、y的转换函数

void tran(unsigned char num,unsigned char * x,unsigned char * y);

//打印游戏

void print_game(void);

//获取方向函数(注意当蛇身长度超过一节时不能回头)

int get_dir(int old_dir);

//移动蛇身函数(游戏大部分内容在其中)

void move_snake(int dir);

//生产食物的函数

unsigned char generate_food(void);

//判断蛇死活的函数(判断了蛇是否撞到边界或者自食)

int isalive(void);


int main(void){

    int dir = UP;   //初始方向默认向上,UP是我们定义的宏

    //按道理该游戏是可以无限继续下去的,因此是个循环

    while(1){

        print_game();   //打印游戏

        dir = get_dir(dir);     //获取方向(我们摁下的方向)

        move_snake(dir);    //移动蛇身

        if(!isalive()){     //判断蛇的生命状态

            break;

        }

    }


    printf("Game Over!\n");

    return 0;

}

//

void tran(unsigned char num,unsigned char * x,unsigned char * y){

    *x = num >> 4;

    *y = (unsigned char)(num << 4) >> 4;    //注意这里要做个强制类型转换

                                            //根据汇编,如果不做强制转换,y的值与num的值相同

}


void print_game(void){

    int i,j;

    //根据地图上每点的情况绘制游戏( i 表示 x 轴,j 表示 y 轴),按行打印,j表示行,i表示列

    for(j = 0;j < 17;j ++){

        for(i = 0;i < 17;i ++){

            //空白地方

            if(map[j] == 0){

                putchar(' ');

            }

            //蛇身

            else if(map[j] == SNAKE){

                putchar('*');

            }

            //围栏

            else if(map[j] == BAR){

                putchar('#');

            }

            //食物

            else if(map[j] == FOOD){

                putchar('$');

            }

        }

        putchar('\n');

    }

    Sleep(500);     //休眠函数 将进程挂起500ms,包含在window.h(在linux下用 sleep(),#include <unistd.h>)

    system("cls");  //清屏函数 配合下一次 print_game() 起到刷新作用,包含在stdlib.h中

}

int get_dir(int old_dir){

    int new_dir = old_dir;

    //用kbhit()与getch()组合实现键盘响应

    //kbhit() 检查当前是否有键盘输入,若有则返回一个非0值,否则返回0

    //getch() 用ch=_getch();会等待你按下任意键之后,把该键字符所对应的ASCII码赋给ch,再执行下面的语句。

    if(_kbhit()){

        _getch();               //第一次输出的方向键的扩展值,第二次是方向键的实际值,只有方向键上下左右这样

        new_dir = _getch();     //getch()函数要使用两次,原因是因为第一次返回的值指示该键扩展的字符,第二次调用才返回实际的键代码


        //如果蛇身长度大于1,则不能回头,如果摁回头方向,则按原来方向走

        //abs(new_dir - old_dir) == 2 表示 |LEFT-RIGHT|

        //abs(new_dir - old_dir) == 8 表示 |UP-DOWN|

        if(len > 1 && (abs(new_dir - old_dir) == 2 || abs(new_dir - old_dir) == 8)){

            new_dir = old_dir;

        }

    }

    return new_dir;

}

void move_snake(int dir){

    int last = snake[0],current;    //last与current用于之后蛇坐标的更新

    int i,j;

    int grow=0;     //判断是否要长身体

    unsigned char x, y,fx,fy;       //蛇坐标与食物坐标

    tran(food, &fx, &fy);   //食物坐标

    tran(snake[0], &x, &y); //蛇头坐标

    switch (dir){           //更新蛇头坐标(坐标原点是左上角)

        case UP:

            y--;

            break;

        case DOWN:

            y++;

            break;

        case LEFT:

            x--;

            break;

        case RIGHT:

            x++;

            break;

    }

    //按位抑或(妙!)

   //http://www.bianceng.cn

    snake[0] = ((x ^ 0) << 4) ^ y;      //将x,y换回一个数

//x与0抑或保留原值

       //将x与y重新合成一个值


    //蛇吃到了食物

    if (snake[0] == food) {

        grow = 1;

        food = generate_food();     //产生新食物

    }


/*******************************************************************************************************************************/

    for (i = 0; i<len; i++) {       //蛇移动的关键,通过将蛇头原来的坐标赋给第二节,原来的第二节赋给第三节,依次下去,完成蛇坐标的更新

        if (i == 0)                //如果只有头,跳过,因为前面已更新蛇头坐标

            continue;

        current = snake;       //将当前操作的蛇节坐标存储到current里

        snake = last;         //完成当前操作蛇节坐标的更新

        last = current;         //last记录的是上一次操作蛇节的坐标,这次操作已经结束,故把current赋给last

}

/*******************************************************************************************************************************/
   

//如果蛇边长了

    if (grow) {

        snake[len] = last;

        len++;

    }


    for (j = 0; j < 17; j ++){      //将边界与食物加到地图里去(i,j 对应 x轴和y轴)

        for (i = 0; i < 17; i ++){

            if (i == 0 || i == 16 || j == 0 || j == 16){

                map[j] = BAR;

            }

            else if (i == fx&&j == fy){

                map[j] = FOOD;

            }

            else{

                map[j] = 0;

            }

        }


    for (i = 0; i < len; i++) {     //将蛇加到地图里去

        tran(snake, &x, &y);

        if (snake > 0){

            map[x][y] = SNAKE;

        }

    }

}

}

unsigned char generate_food(void)

{

    unsigned char food_,fx,fy;

    int in_snake=0,i;

    //以当前时间为参数提供种子供rand()函数生成更为随机的数

    srand((unsigned int)time(NULL));

    //循环产生在边界内且不在蛇身上的食物

    do {

        food_ = rand() % 255;//产生一个0--255的随机数

        tran(food_, &fx, &fy);

        for (i = 0; i < len; i++){

            if (food_ == snake){

            //在不在蛇身上

                in_snake = 1;

            }

        }

    } while (fx == 0 || fx == 16 || fy == 0 || fy == 16 || in_snake);

    return food_;

}

int isalive(void)

{

    int self_eat = 0;

int i;

    unsigned char x, y;

    tran(snake[0], &x, &y);

    for (i = 1; i < len; i++){

        if (snake[0] == snake){

            self_eat = 1;

        }

    }

    //蛇头撞边界或者吃到自己 ,则死掉

    return (x == 0 || x == 16 || y == 0 || y >= 16 || self_eat) ? 0 : 1;

}[/mw_shl_code]
每次见你穿短裤打领带,还穿个拖鞋,下次再这样穿不要从我家门口过了!
http://gsh.yzqz.cn/CassettePlayer/index.html

天之道,损有余而补不足.人之道则不然,损不足以奉有余.孰能有余以奉天下,唯有道者.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 参与我们

本版积分规则

QQ|Archiver|手机版|小黑屋|应天社区 ( 湘ICP备17015224号 )

GMT+8, 2024-4-19 15:30 , Processed in 0.374990 second(s), 31 queries .

Powered by Discuz!

© 2001-2017 Comsenz Inc.


免责声明:
本站所发布的第三方软件及资源(包括但不仅限于文字/图片/音频/视频等仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢某程序或某个资源,请支持正版软件及版权方利益,注册或购买,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To: admin@yzqz.cn

快速回复 返回顶部 返回列表