C语言结构数组实现贪吃蛇小游戏

yizhihongxing

C语言结构数组实现贪吃蛇小游戏攻略

前言

贪吃蛇是一种经典的小游戏,类似于蛇果子等。在游戏中,玩家需要控制蛇吃掉食物,并不断地变长,直到撞墙或撞到自己的身体为止。这个游戏对于程序员来说是一个很好的练手项目,也是锻炼从事编程工作所需的基本能力必不可少的一步。在本文中,我们将详细讲解如何使用C语言结构数组实现贪吃蛇小游戏。

开发环境准备

在实现这个小游戏前,我们需要一些开发环境的准备。首先需要安装Code::Blocks和Dev-C++两个IDE,以及游戏需要的Windows库文件。

  • Code::Blocks下载地址:https://www.codeblocks.org/downloads/binaries/
  • Dev-C++下载地址:https://sourceforge.net/projects/orwelldevcpp/
  • Windows库文件下载地址:https://www.mediafire.com/file/zh4adh6l1msthz5/windows_lib_files.zip/file

下载完之后解压缩到C盘根目录下。

完整代码

以下是实现贪吃蛇小游戏的完整代码。代码注释翻译如下:

#include<graphics.h>
#include<conio.h>
#include<time.h>

#define DELAY 100
#define HEIGHT 30
#define WIDTH 30
#define SNAKE_LEN_MAX (HEIGHT-2)*(WIDTH-2)


/*结构体:坐标位置*/
struct point {
    int x;
    int y;
};

/*枚举类型:方向*/
enum direction {
    UP,
    DOWN,
    LEFT,
    RIGHT,
    STOP
};

/*全局变量*/
int HEIGHT_PIXEL;
int WIDTH_PIXEL;
int CELL_SIZE;
int DELAY_TIME;
int MOVE_SPEED;
int SCORE;
int SNAKE_LEN;
struct point snake[SNAKE_LEN_MAX+1];
struct point food;
enum direction dir;

/*函数原型*/
void init();                /*初始化*/
void add_a_food();          /*添加一个食物*/
void move();                /*蛇移动*/
void change_dir();          /*改变蛇的移动方向*/
int is_snake_hit_wall();    /*判断蛇是否撞墙*/
int is_snake_hit_food();    /*判断蛇是否撞到食物*/
int is_snake_hit_self();    /*判断蛇是否撞到自己*/
void game_over();           /*游戏结束*/
void draw_score();          /*画分数*/
void draw_food();           /*画食物*/
void draw_snake_head();     /*画蛇头*/
void draw_snake_tail();     /*画蛇尾*/
void draw_snake_body();     /*画蛇身*/
void draw_snake();          /*画整条蛇*/
void draw_string();         /*画字符串*/

int main()
{
    init();
    while(1) {
        add_a_food();
        while(!kbhit()) {
            move();
            delay(DELAY_TIME);
        }
        change_dir();
        if(is_snake_hit_wall() || is_snake_hit_self()) {
            game_over();
            break;
        }
        if(is_snake_hit_food()) {
            SCORE++;
            SNAKE_LEN++;
            if(SNAKE_LEN > SNAKE_LEN_MAX) {
                game_over();
                break;
            }
            add_a_food();
        }
        cleardevice();
        draw_snake();
        draw_food();
        draw_score();
    }
    getch();
    return 0;
}

void init()
{
    int mousex, mousey;

    /*初始化图形库*/
    initgraph(&mousex, &mousey, "C:\\WINDOWS\\system32\\msimg32.dll");  /*此处是Windows基础库文件,需要判断文件位置*/

    /*设置窗口大小*/
    HEIGHT_PIXEL = 500;
    WIDTH_PIXEL = 500;
    setaspectratio(1,1);
    setbkcolor(BLACK);
    cleardevice();

    /*设置游戏速度*/
    MOVE_SPEED = 6;
    DELAY_TIME = 1000/MOVE_SPEED;

    /*初始化蛇身*/
    SNAKE_LEN = 1;
    snake[1].x = WIDTH/2;
    snake[1].y = HEIGHT/2;

    /*初始化方向*/
    dir = LEFT;
}

void add_a_food()
{
    struct point temp;

    /*随机生成一个食物坐标(不能在蛇身上)*/
    while(1) {
        temp.x = 1 + rand() % (WIDTH-2);
        temp.y = 1 + rand() % (HEIGHT-2);
        for(int i =1; i <= SNAKE_LEN; i++) {
            if(snake[i].x == temp.x && snake[i].y == temp.y) {
                temp.x = 0;
                temp.y = 0;
                break;
            }
        }
        if(temp.x != 0) {
            break;
        }
    }

    /*将随机生成的食物坐标赋值给全局变量*/
    food.x = temp.x;
    food.y = temp.y;
}

void move()
{
    /*将蛇尾设为蛇头*/
    for(int i = SNAKE_LEN; i > 0; i--) {
        snake[i] = snake[i-1];
    }

    /*根据方向改变蛇头位置*/
    switch(dir) {
        case UP:
            snake[1].y--;
            break;
        case DOWN:
            snake[1].y++;
            break;
        case LEFT:
            snake[1].x--;
            break;
        case RIGHT:
            snake[1].x++;
            break;
        case STOP:
            break;
        default:
            break;
    }
}

void change_dir()
{
    /*改变移动方向*/
    if(kbhit()) {
        int input = getch();
        switch(input) {
            case 'w':
            case 'W':
            case 72:    /*方向键上*/
                if(dir != DOWN)
                    dir = UP;
                break;
            case 's':
            case 'S':
            case 80:    /*方向键下*/
                if(dir != UP)
                    dir = DOWN;
                break;
            case 'a':
            case 'A':
            case 75:    /*方向键左*/
                if(dir != RIGHT)
                    dir = LEFT;
                break;
            case 'd':
            case 'D':
            case 77:    /*方向键右*/
                if(dir != LEFT)
                    dir = RIGHT;
                break;
            case 27:
                dir = STOP;
                break;
            default:
                break;
        }
    }
}

int is_snake_hit_wall()
{
    /*判断是否撞墙*/
    if(snake[1].x == 0 || snake[1].x == (WIDTH-1) || snake[1].y == 0 || snake[1].y == (HEIGHT-1)) {
        return 1;
    }
    return 0;
}

int is_snake_hit_food()
{
    /*判断是否吃到食物*/
    if(snake[1].x == food.x && snake[1].y == food.y) {
        return 1;
    }
    return 0;
}

int is_snake_hit_self()
{
    /*判断是否撞到自己*/
    for(int i=2; i <= SNAKE_LEN; i++) {
        if(snake[1].x == snake[i].x && snake[1].y == snake[i].y) {
            return 1;
        }
    }
    return 0;
}

void game_over()
{
    draw_string("Game Over", WIDTH/2, HEIGHT/2);
    getch();
}

void draw_score()
{
    char score_str[10];
    sprintf(score_str, "Score:%d", SCORE);
    draw_string(score_str, 1, 1);
}

void draw_food()
{
    setfillstyle(SOLID_FILL, YELLOW);
    setcolor(YELLOW);
    fillellipse(food.x * CELL_SIZE, food.y * CELL_SIZE, CELL_SIZE/2, CELL_SIZE/2);
}

void draw_snake_head()
{
    setfillstyle(SOLID_FILL, GREEN);
    setcolor(GREEN);
    fillellipse(snake[1].x * CELL_SIZE, snake[1].y * CELL_SIZE, CELL_SIZE/2, CELL_SIZE/2);
}

void draw_snake_tail()
{
    setfillstyle(SOLID_FILL, BLACK);
    setcolor(BLACK);
    bar(snake[SNAKE_LEN].x * CELL_SIZE, snake[SNAKE_LEN].y * CELL_SIZE, (snake[SNAKE_LEN].x+1) * CELL_SIZE, (snake[SNAKE_LEN].y+1) * CELL_SIZE);
}

void draw_snake_body(int i)
{
    setfillstyle(SOLID_FILL, GREEN);
    setcolor(GREEN);
    bar(snake[i].x * CELL_SIZE, snake[i].y * CELL_SIZE, (snake[i].x+1) * CELL_SIZE, (snake[i].y+1) * CELL_SIZE);
}

void draw_snake()
{
    draw_snake_head();
    for(int i = 2; i < SNAKE_LEN; i++) {
        draw_snake_body(i);
    }
    draw_snake_tail();
}

void draw_string(char *str, int x, int y)
{
    outtextxy(x*CELL_SIZE, y*CELL_SIZE, str);
}

整体思路

本篇文章使用结构体数组来实现贪吃蛇小游戏。在游戏中,使用全局变量来存储对游戏状态的控制和存储蛇的位置、食物的位置、本局游戏得分等信息。在每一个游戏循环内,我们需要判断以下几个事项:

  1. 是否添加了食物
  2. 是否需要移动蛇的位置
  3. 是否撞到了墙或自己,如果是,则游戏结束
  4. 是否撞到了食物

对于以上每一个判断条件,我们都可以为之定义一个函数。同时,使用图形处理库来绘制游戏界面。当蛇移动时,会先把蛇尾的位置删除,再新生成一条蛇头。

示例说明

示例1

下面是一个简单的实例,当蛇移动时,它的头部始终向右:

void move()
{
    /*将蛇尾设为蛇头*/
    for(int i = SNAKE_LEN; i > 0; i--) {
        snake[i] = snake[i-1];
    }

    /*改变蛇头位置*/
    snake[1].x++;
}

示例2

下面是一个更复杂的示例,当蛇头受到用户控制改变方向时,蛇会按照改变后的方向移动:

void change_dir()
{
    /*改变移动方向*/
    if(kbhit()) {
        int input = getch();
        switch(input) {
            case 'w':
            case 'W':
            case 72:    /*方向键上*/
                if(dir != DOWN)
                    dir = UP;
                break;
            case 's':
            case 'S':
            case 80:    /*方向键下*/
                if(dir != UP)
                    dir = DOWN;
                break;
            case 'a':
            case 'A':
            case 75:    /*方向键左*/
                if(dir != RIGHT)
                    dir = LEFT;
                break;
            case 'd':
            case 'D':
            case 77:    /*方向键右*/
                if(dir != LEFT)
                    dir = RIGHT;
                break;
            case 27:
                dir = STOP;
                break;
            default:
                break;
        }
    }
}

void move()
{
    /*将蛇尾设为蛇头*/
    for(int i = SNAKE_LEN; i > 0; i--) {
        snake[i] = snake[i-1];
    }

    /*根据方向改变蛇头位置*/
    switch(dir) {
        case UP:
            snake[1].y--;
            break;
        case DOWN:
            snake[1].y++;
            break;
        case LEFT:
            snake[1].x--;
            break;
        case RIGHT:
            snake[1].x++;
            break;
        case STOP:
            break;
        default:
            break;
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言结构数组实现贪吃蛇小游戏 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Python警察与小偷的实现之一客户端与服务端通信实例

    首先介绍一下”Python警察与小偷”这个项目的背景和概念。 “Python警察与小偷”是一种基于Python编程语言实现的网络安全技术,它通过客户端与服务端的通信方式,让警察在远程主机上对小偷进行操作和控制,从而达到保护计算机安全的目的。 下面我们来介绍一下客户端与服务端通信的实现过程。 选择通信协议 在客户端与服务端之间进行通信时,我们需要选择一种通信协…

    other 2023年6月27日
    00
  • mysql通过@变量实现递归详细实例

    下面我将详细讲解 “MySQL 通过 @ 变量实现递归的详细实例”。 什么是 MySQL 递归 MySQL 递归是指在一个查询中,通过引用查询自身来实现对层级型数据的遍历操作。递归查询通常需要用到 MySQL 的 @ 变量。 通常的实现原理是在查询过程中,将一些中间结果存入一个 @ 变量中,并在之后的查询中引用这些变量。通过这些变量可以实现递归操作。 递归的…

    other 2023年6月27日
    00
  • Python递归实现打印多重列表代码

    下面是详细讲解“Python递归实现打印多重列表代码”的完整攻略: 什么是递归 在计算机科学中,递归(recursion)是指在运行过程中调用自身的函数或方法。递归通常用于解决具有重复性质的问题或定义在数据结构上递归的函数。 要想实现递归打印多重列表数据,首先要理解递归思想。递归其实就是方法自己调用自己,每次调用时传入不同的变量,一直到满足条件为止。在递归过…

    other 2023年6月27日
    00
  • 如何写好css系列之button

    以下是关于“如何写好CSS系列之Button”的完整攻略,包括基本概念、步骤和两个示例。 基本概念 Button是网页常用的交互元素之一,用于触发事件或提交表单。CSS(Cascading Sheets)是一种用于描述网页样的语言,可以用于美化Button的外观和交互效果。 步骤 以下是使用CSS美化Button的步骤: Button元素:使用CSS选择器选…

    other 2023年5月7日
    00
  • Python深入学习之闭包

    Python深入学习之闭包攻略 什么是闭包? 在Python中,闭包是指一个函数对象,它可以访问并修改其作用域外的变量。换句话说,闭包是一个函数和与其相关的引用环境的组合。 闭包的特点 闭包函数可以访问外部函数的变量,即使外部函数已经执行完毕。 闭包函数可以修改外部函数的变量的值。 闭包函数可以将外部函数的变量作为返回值。 闭包的应用场景 闭包在Python…

    other 2023年8月20日
    00
  • 在idea中使用JaCoCo插件统计单元测试覆盖率的实现

    以下是关于在IDEA中使用JaCoCo插件统计单元测试覆盖率的完整攻略,包含两个示例说明: 1. 安装JaCoCo插件 首先,在IDEA中安装JaCoCo插件。打开IDEA,点击\”File\” -> \”Settings\” -> \”Plugins\”,搜索并安装\”JaCoCo\”插件。 2. 配置JaCoCo插件 在项目的pom.xml文…

    other 2023年10月19日
    00
  • Android实现网易新闻客户端首页效果

    Android实现网易新闻客户端首页效果攻略 在 Android 开发中实现类似网易新闻客户端首页的效果,主要需要涉及以下知识点:ListView,ViewPager,Fragment,自定义View以及网络请求等等。 1. 布局设计 在实现类似网易新闻客户端首页的效果时,我们可以将布局分为两部分:新闻分类导航栏和新闻内容区域。 新闻分类导航栏可以使用 Li…

    other 2023年6月25日
    00
  • Android Tablayout 自定义Tab布局的使用案例

    Android Tablayout 自定义Tab布局的使用案例 Tablayout是Android Material Design库中的一部分,它提供了一个用于展示多个页面的标签栏,很多应用程序都使用它来实现这个功能。默认情况下,Tablayout会使用系统提供的样式来展示标签。但是有时候我们可能需要自定义Tab布局,来满足一些特殊的需求。 本文将介绍如何使…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部