[参考C3程序员] - C语言贪吃蛇(二维数组)

感谢C3程序员的课程,讲的很详细。下面是贪吃蛇的具体代码,与视频教程相比略有改动,大部分子程序都加了详细的注释。

#include <stdio.h>

#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <mmsystem.h>
#include <time.h>
#include <string.h>
char arr_block[20][48] = {"■■■■■■■■■■■■■■■■■■■■■■■\n",                        //字符串数组,一个■占两个字节,要显示20*23的边框
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■                                          ■\n",
                            "■■■■■■■■■■■■■■■■■■■■■■■\n"};




int arr_snack[20][3]={0};                                   //蛇身的每一节需要横纵坐标以及移动方向3个值,用二维数组存放
                                                            //arr_snack[n][0]存放第n-1节蛇身的纵坐标
                                                            //arr_snack[n][1]存放第n-1节蛇身的横坐标
                                                            //arr_snack[n][2]存放第n-1节蛇身的移动方向
                                                            //蛇身可以很多节,在此使用20节,代表蛇身最长为20节


enum{to_east = 2,to_west = -2,to_south = 1,to_north = -1};  //枚举四个方向,东西方向移动一次是一个■所以是2


int snackdirection = to_west;                               //蛇第一次出现时默认方向是向西
typedef int bool;
#define false 0
#define true  1
bool foodflag = true; //为1时调用food函数生成食物,为0时跳过该函数
int row ;    //食物所在的行
int col ;    //食物所在的列
int length = 2;//初始化时蛇为三节,代表蛇尾数组下标,用于growup函数


void welcome();
void music();
void stopmusic();
void start();
void block();
void randomposition();
void displaysnack();
void dropsnack();
void move();
void direction();
bool gameover();
void food();
void growup();


int main()
{
    welcome();//显示游戏操作提示

    music(); //播放背景音乐

    start(); //按空格键开始游戏

    stopmusic(); //停止播放音乐

    randomposition(); //随机生成一个三节蛇的位置

    while(1)
    {
    system("cls");//清屏
    direction();
    growup();
    food();
    if(gameover() == false)
    {
        printf("game over\n");
        break;
    }
    move();
    block();
printf("\t\tscore:%d",10*(length-2));
    Sleep(500);
    }

    system("pause");
    return 0;
}






/**************************
welcome
显示欢迎界面和操作说明
**************************/
void welcome()
{
    printf("\t welcome\n");
    printf("\t 上下左右\n   \tWSAD    \t按space开始游戏");
}


/**************************
music(stopmusic)
播放(停止播放)音乐
绝对地址与相对地址问题
**************************/
void music()
{
    PlaySound("F:\\C_review\\贪吃蛇\\动漫原声-哀歌(《犬夜叉-TV版》日本动漫主题曲).wav",NULL,SND_FILENAME|SND_ASYNC);
}
void stopmusic()
{
    PlaySound(NULL,0,0);
}
/**************************
start
按' '开始游戏
**************************/
void start()
{
    char s;
    while(1)
    {
        s = _getch();
        if(s == ' ')
        {
            break;
        }
    }
}


/**************************
block
显示■障碍物
打印字符串数组,displaysnack和dropsnack都是改变字符串数组中的元素,并不显示
**************************/
 void block()//显示四周障碍物,■占两个字节
{
     int i=0;
     for(i = 0;i < 20;i ++)
     {
         printf("%s",arr_block[i]);
     }
}
/**************************
randomposition
在■障碍里随机生成一条三节蛇
生成横纵坐标的随机数并初始化其方向为西
从西向东依次为第一节,第二节,第三节
**************************/
 void randomposition()//只在游戏刚开始时调用一次= -1
 {
    int X ;
    int Y ;
    srand((unsigned int)time(NULL));
    X = rand()%19 + 1;  //蛇第一次出现有三节,X坐标范围1-19
    Y = rand()%18 + 1;  //Y坐标范围1-18
    //第一节
    arr_snack[0][0] = Y;
    arr_snack[0][1] = X * 2; //■占两个字节
    arr_snack[0][2] = to_west;
    //第二节
    arr_snack[1][0] = Y;
    arr_snack[1][1] = (X + 1) * 2;
    arr_snack[1][2] = to_west;
    //第三节
    arr_snack[2][0] = Y;
    arr_snack[2][1] = (X + 2) * 2;
    arr_snack[2][2] = to_west;


    displaysnack();
 }


/**************************
displaysnack
显示蛇
即在原本显示障碍的字符串数组中,在蛇的横纵坐标处用"■"替换原有的"  "
**************************/
 void displaysnack()
 {
     int i;
     for(i = 0;arr_snack[i][0] != 0;i++)//有值的时候复制
     {
         strncpy(&arr_block[arr_snack[i][0]][arr_snack[i][1]],"■",2);
     }
 }


/**************************
dropsnack
显示蛇
即在原本显示障碍和蛇身的字符串数组中,在蛇的横纵坐标处用"  "替换原有的"■"
**************************/
 void dropsnack()
 {
     int i;
     for(i = 0;arr_snack[i][0] != 0;i++)//有值的时候复制
     {
         strncpy(&arr_block[arr_snack[i][0]][arr_snack[i][1]],"  ",2);
     }
 }


/**************************
move
让蛇移动
若不处理蛇头,只相当于蛇所有的值向后移动一节,蛇头的值不变
**************************/
 void move()
{
    dropsnack();
    int i;
    for(i = 19;i >= 1;i --)
    {
        if(arr_snack[i][0] == 0)  //遍历过于浪费,过滤空的节
            continue;
        arr_snack[i][0] = arr_snack[i-1][0];//将蛇身前一节的三个元素分别赋给该节蛇身的后一节
        arr_snack[i][1] = arr_snack[i-1][1];
        arr_snack[i][2] = arr_snack[i-1][2];
    }

    arr_snack[0][2] = snackdirection;

    if(arr_snack[0][2] == to_west || arr_snack[0][2] == to_east)
    {
        arr_snack[0][1] += arr_snack[0][2];
    }
    else
    {
        arr_snack[0][0] += arr_snack[0][2];
    }
    displaysnack();
}


/**************************
direction
检测按键输入,控制蛇头方向
控制蛇头的方向就能通过move里的赋值改变整个蛇身的方向
蛇不能按照原方向掉头,所以要另加判断
**************************/
void direction()
{
    if(GetAsyncKeyState('W'))
    {
        if(arr_snack[0][2] != to_south)
        snackdirection = to_north;
    }
    if(GetAsyncKeyState('S'))
    {
        if(arr_snack[0][2] != to_north)
        snackdirection = to_south;
    }
    if(GetAsyncKeyState('A'))
    {
        if(arr_snack[0][2] != to_east)
        snackdirection = to_west;
    }
    if(GetAsyncKeyState('D'))
    {
        if(arr_snack[0][2] != to_west)
        snackdirection = to_east;
    }
}


/**************************
gameover
如果蛇头再走一步碰到■就跳出
**************************/
bool gameover()
{
    if(arr_snack[0][2] == to_west || arr_snack[0][2] == to_east)
    {
        if(strncmp(&arr_block[arr_snack[0][0]][arr_snack[0][1] + arr_snack[0][2]],"■",2) == 0)
        return false;
    }
    else
    {
        if(strncmp(&arr_block[arr_snack[0][0] + arr_snack[0][2]][arr_snack[0][1]],"■",2) == 0)
        return false;
    }
    return true;
}
/**************************
food
随机产生食物,要避免与蛇身和障碍重合
**************************/
void food()
{
    int i;
    int temp = false;
    if(foodflag == true)
    {
        srand((unsigned int)time(NULL));
        while(1)
        {
            row = rand()%18 + 1;  //row坐标范围1-19
            col = rand()%20 + 1;  //col坐标范围1-21
            for(i = 0;arr_snack[i][0] != 0;i++)//有值的时候复制
            {
                if(arr_snack[i][0] != row && arr_snack[i][1] != col * 2)
                {
                   temp = true;
                }
            }
            if(temp == true)
                break;
        }


        strncpy(&arr_block[row][col * 2],"★",2);


    }
    foodflag = false;
}


void growup()
{
    if(arr_snack[0][0] == row && arr_snack[0][1] == col*2)//蛇头和食物重合就变长
    {
        if(arr_snack[length][2] == to_east)
        {
            arr_snack[length+1][0] = arr_snack[length][0];
            arr_snack[length+1][1] = arr_snack[length][1] - 2;
            arr_snack[length+1][2] = arr_snack[length][2];
        }
        if(arr_snack[length][2] == to_west)
        {
            arr_snack[length+1][0] = arr_snack[length][0];
            arr_snack[length+1][1] = arr_snack[length][1] + 2;
            arr_snack[length+1][2] = arr_snack[length][2];
        }
        if(arr_snack[length][2] == to_north)
        {
            arr_snack[length+1][0] = arr_snack[length][0] + 1;
            arr_snack[length+1][1] = arr_snack[length][1];
            arr_snack[length+1][2] = arr_snack[length][2];
        }
        if(arr_snack[length][2] == to_south)
        {
            arr_snack[length+1][0] = arr_snack[length][0] - 1;
            arr_snack[length+1][1] = arr_snack[length][1];
            arr_snack[length+1][2] = arr_snack[length][2];
        }
        length ++;
        foodflag = true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值