纯C语言实现经典小游戏——贪吃蛇(VS2017)

假期无聊第二季,用C语言实现简单经典小游戏——贪吃蛇。特别适合新手熟悉C语言。(完整程序在文章最后!!!)
主要涉及C语言知识点如下:
结构体,函数的定义及调用,指针变量,指针和数组,逻辑表达式,基本的选择和循环语句,头文件的编写等
可以说是麻雀虽小,五脏俱全,是新手练习C语言的绝佳小项目!
游戏界面如下:
这里写图片描述

基本思路:
蛇每吃一个食物蛇身子就增加一格,用WASD控制蛇头的运动,而蛇身子跟着蛇头走,每后一格蛇身子下一步走到上一格蛇身子的位置,以此类推。

程序主要变量如下:

#define M 20//整个图形界面的长和宽
#define N 60
    struct snake a[(M - 2)*(N - 2)];//蛇身数组
    int snake_x =4;//蛇身的XY坐标
    int snake_y =4;
    int X = 1;//控制蛇头的方向量
    int Y = 0;
    int food_x , food_y ;//食物的XY坐标
    int score = 0;//分数

食物的随机位置产生是通过两个随机数分别代表X,Y坐标实现的。

void food(int *x, int *y,int *fx,int *fy,int *s, struct snake *snake)
{
    int ffx, ffy;//上一次食物的XY坐标
    ffx = *fx;
    ffy = *fy;

    if (*x == *fx && *y == *fy)//如果吃到了食物,产生下一个食物
    { 
        do {
            *fx = 1 + rand() % (N - 3);
            *fy = 1 + rand() % (M - 3);
        } while (ffx == *fx && ffy == *fy);//保证与上次食物位置不同

        for (int i= (*s); i >= 0; i--)
        {
            if ((snake + *s)->snake_x == *fx && (snake + *s)->snake_y == *fy) {
                *fx = 1 + rand() % (N - 3);
                *fy = 1 + rand() % (M - 3);
            }
        }//大概率保证食物与蛇身子的位置不同(不能完全保证)
        (*s)++ ;                          //分数加一!!!!!!!
    }
}

用WASD控制蛇头的运动是通过改变蛇头的X,Y坐标实现的。

void control(int *x,int *y,int *X,int *Y)//xy是蛇头的坐标,XY是控制运动方向的量
{
    if (_kbhit())
    {
        switch (_getch())
        {
        case 'w' :
        case 'W' :
            if(interf[*y - 1][*x]!='@'){   //if语句保证蛇不能倒着走
                *X = 0; *Y = -1;
            }
            break;
        case 'd':
        case 'D':
            if(interf[*y][*x + 1] != '@'){
                *X = 1; *Y = 0;
            }
                break;
        case 's':
        case 'S':
            if (interf[*y + 1][*x] != '@') {
                *X = 0; *Y = 1;
            }
                break;
        case 'a':
        case 'A':
            if (interf[*y][*x - 1] != '@') {
                *X = -1; *Y = 0;
            }
                break;
        default:
            break;
        } 
    }
    *x = *x + *X;//改变一次位置
    *y = *y + *Y;
}

用定义蛇身子的结构体储存身子的XY坐标,然后定义蛇身子结构体数组存储每一节蛇身子。

struct snake
{
    int number;
    int snake_x;
    int snake_y;
    //struct snake *next;
};

struct snake a[(M - 2)*(N - 2)];


void build_snake(struct snake *snake,int s,int *sx,int *sy)//sx,sy蛇头的位置
{
    for (int i = s; i >= 0; i--)
    {
        if (i == 0) {
            (snake + i)->number = i;
            (snake + i)->snake_x = *sx;
            (snake + i)->snake_y = *sy;
        }else{
            (snake + i)->number = i;
            (snake + i)->snake_x = (snake + i - 1)->snake_x;
            (snake + i)->snake_y = (snake + i - 1)->snake_y;
        }
    }
}

有了蛇身子和食物的坐标位置,将它们一起存储在一个表示整个界面的二位数组,然后循环打印整个数组形成动画效果!

char interf[M][N];

void newinterface(struct snake *snake,  int fx, int fy,int s)
{
    int x, y;
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (i == 0 || i == M - 1)
                interf[i][j] = '-';
                //printf("-");
            else if (j == 0)
                interf[i][j] = '|';
                //printf("|");
            else if (j == N - 1)
                interf[i][j] = '|';
                //printf("|\n");
            else if (i == fy && j == fx)
                interf[i][j] = '$';
                //printf("$");
            else  
                interf[i][j] = ' ';
                //printf(" ");
        }
    }
    for (; s >= 0; s--)
    {
            x = (snake + s)->snake_x;
            y = (snake + s)->snake_y;
            interf[y][x] = '@';
    }   
}

完整程序代码!!!

文件 snakemain.cpp

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "interface.h"
#include "snake.h"

int main(void)
{
    struct snake a[(M - 2)*(N - 2)];
    int snake_x =4;
    int snake_y =4;
    int X = 1;
    int Y = 0;
    int food_x , food_y ;
    int score = 0;

    do {
        food_x = 1 + rand() % (N - 3);
        food_y = 1 + rand() % (M - 3);
    } while (food_x == 4 && food_y == 4);

    for (;;)
    {
        system("cls");
        printf("\n                       贪吃蛇小游戏");
        printf("\n作者:xhyang 博客地址:http://blog.csdn.net/weixin_39449570\n");
        printf("按W控制向上运动,按D控制向右运动,按S控制向下运动,按A控制向左运动。\n");
        printf("得分:%d",score);
        printf("\n");

        control(&snake_x, &snake_y,&X,&Y);
        build_snake(a, score, &snake_x, &snake_y);
        death(snake_x, snake_y,score);
        newinterface(a, food_x, food_y, score);
        food(&snake_x, &snake_y, &food_x, &food_y,&score,a);
        draw();
        Sleep(140);
    }
    system("pause");
    return 0;
}
文件 snake.h

#ifndef SNAKE_H
#define SNAKE_H

struct snake
{
    int number;
    int snake_x;
    int snake_y;
    //struct snake *next;
};

void build_snake(struct snake *snake, int s, int *sx, int *sy);

#endif
文件 snake.cpp

#include <stdio.h>
#include <stdlib.h>
#include "snake.h"

void build_snake(struct snake *snake,int s,int *sx,int *sy)
{
    for (int i = s; i >= 0; i--)
    {
        if (i == 0) {
            (snake + i)->number = i;
            (snake + i)->snake_x = *sx;
            (snake + i)->snake_y = *sy;
        }else{
            (snake + i)->number = i;
            (snake + i)->snake_x = (snake + i - 1)->snake_x;
            (snake + i)->snake_y = (snake + i - 1)->snake_y;
        }
    }
}
文件 interface.h

#ifndef INTERFACE_H
#define INTERFACE_H

#define M 20
#define N 60

void control(int *x, int *y, int *X, int *Y);
void snake(int x, int y);
void newinterface(struct snake *snake, int fx, int fy, int s);
void food(int *x, int *y, int *fx, int *fy, int *s, struct snake *snake);
void draw(void);
void death(int x, int y, int s);

#endif
文件 interface.cpp
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include "interface.h"
#include "snake.h"

char interf[M][N];

void newinterface(struct snake *snake,  int fx, int fy,int s)
{
    int x, y;
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (i == 0 || i == M - 1)
                interf[i][j] = '-';
                //printf("-");
            else if (j == 0)
                interf[i][j] = '|';
                //printf("|");
            else if (j == N - 1)
                interf[i][j] = '|';
                //printf("|\n");
            else if (i == fy && j == fx)
                interf[i][j] = '$';
                //printf("$");
            else  
                interf[i][j] = ' ';
                //printf(" ");
        }
    }
    for (; s >= 0; s--)
    {
            x = (snake + s)->snake_x;
            y = (snake + s)->snake_y;
            interf[y][x] = '@';
    }   
}

void food(int *x, int *y,int *fx,int *fy,int *s, struct snake *snake)
{
    int ffx, ffy;//上一次食物的XY坐标
    ffx = *fx;
    ffy = *fy;

    if (*x == *fx && *y == *fy)//如果吃到了食物,产生下一个食物
    { 
        do {
            *fx = 1 + rand() % (N - 3);
            *fy = 1 + rand() % (M - 3);
        } while (ffx == *fx && ffy == *fy);//保证与上次食物位置不同

        for (int i= (*s); i >= 0; i--)
        {
            if ((snake + *s)->snake_x == *fx && (snake + *s)->snake_y == *fy) {
                *fx = 1 + rand() % (N - 3);
                *fy = 1 + rand() % (M - 3);
            }
        }//大概率保证食物与蛇身子的位置不同(不能完全保证)
        (*s)++ ;                          //分数加一!!!!!!!
    }
}


void control(int *x,int *y,int *X,int *Y)//xy是蛇头的坐标,XY是控制运动方向的量
{
    if (_kbhit())
    {
        switch (_getch())
        {
        case 'w' :
        case 'W' :
            if(interf[*y - 1][*x]!='@'){   //if语句保证蛇不能倒着走
                *X = 0; *Y = -1;
            }
            break;
        case 'd':
        case 'D':
            if(interf[*y][*x + 1] != '@'){
                *X = 1; *Y = 0;
            }
                break;
        case 's':
        case 'S':
            if (interf[*y + 1][*x] != '@') {
                *X = 0; *Y = 1;
            }
                break;
        case 'a':
        case 'A':
            if (interf[*y][*x - 1] != '@') {
                *X = -1; *Y = 0;
            }
                break;
        default:
            break;
        } 
    }
    *x = *x + *X;//改变一次位置
    *y = *y + *Y;
}


void draw(void)
{
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++)
        {
            printf("%c", interf[i][j]);
        }
        printf("\n");
    }
}


void death(int x,int y,int s)
{
    if (x == 0 || x == N-1 || y  == 0 || y == M-1 || interf[y][x] == '@') {
        for (;;)
        {
            system("cls");
            printf("\n              游戏结束!\n");
            printf("              最终得分:%d \n", s);
            Sleep(140);
        //system("pause");
        }

    }
}
  • 104
    点赞
  • 501
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
### 回答1: 好的,这里是一个简单的带有三条命的贪吃蛇C语言程序。这个程序使用了Windows API,所以只能在Windows系统上运行。 ```c #include <stdio.h> #include <stdlib.h> #include <windows.h> #include <conio.h> #define WIDTH 50 #define HEIGHT 20 #define SNAKE_MAX_LENGTH 100 int score = 0; // 得分 int life = 3; // 生命值 int speed = 200; // 蛇的移动速度 // 定义蛇的结构体 struct Snake { int x, y; } snake[SNAKE_MAX_LENGTH]; // 定义食物的结构体 struct Food { int x, y; } food; // 初始化蛇 void init_snake() { snake[0].x = 20; snake[0].y = 10; snake[1].x = 19; snake[1].y = 10; snake[2].x = 18; snake[2].y = 10; } // 初始化食物 void init_food() { srand((unsigned)time(NULL)); food.x = rand() % (WIDTH - 2) + 1; food.y = rand() % (HEIGHT - 2) + 1; } // 显示游戏界面 void draw() { int i, j; system("cls"); printf("Score: %d Life: %d\n", score, life); for(i = 0; i < WIDTH; i++) { printf("#"); } printf("\n"); for(i = 0; i < HEIGHT; i++) { for(j = 0; j < WIDTH; j++) { if(j == 0 || j == WIDTH - 1) { printf("#"); } else if(snake[0].x == j && snake[0].y == i) { printf("@"); } else if(food.x == j && food.y == i) { printf("$"); } else { int k; for(k = 1; k < SNAKE_MAX_LENGTH; k++) { if(snake[k].x == j && snake[k].y == i) { printf("*"); break; } } if(k == SNAKE_MAX_LENGTH) { printf(" "); } } } printf("\n"); } for(i = 0; i < WIDTH; i++) { printf("#"); } printf("\n"); } // 移动蛇 void move() { int i; for(i = SNAKE_MAX_LENGTH - 1; i > 0; i--) { snake[i].x = snake[i - 1].x; snake[i].y = snake[i - 1].y; } if(kbhit()) { char ch = getch(); switch(ch) { case 'w': case 'W': snake[0].y--; break; case 's': case 'S': snake[0].y++; break; case 'a': case 'A': snake[0].x--; break; case 'd': case 'D': snake[0].x++; break; default: break; } } else { snake[0].x++; } } // 判断是否吃到食物 void eat_food() { if(snake[0].x == food.x && snake[0].y == food.y) { score++; if(score % 5 == 0) { life++; } int i; for(i = SNAKE_MAX_LENGTH - 1; i > 0; i--) { if(snake[i].x == 0 && snake[i].y == 0) { snake[i].x = snake[i - 1].x; snake[i].y = snake[i - 1].y; break; } } init_food(); } } // 判断是否死亡 void check_dead() { if(snake[0].x == 0 || snake[0].x == WIDTH - 1 || snake[0].y == 0 || snake[0].y == HEIGHT - 1) { life--; if(life == 0) { exit(0); } snake[0].x = 20; snake[0].y = 10; snake[1].x = 19; snake[1].y = 10; snake[2].x = 18; snake[2].y = 10; } int i; for(i = 1; i < SNAKE_MAX_LENGTH; i++) { if(snake[0].x == snake[i].x && snake[0].y == snake[i].y) { life--; if(life == 0) { exit(0); } snake[0].x = 20; snake[0].y = 10; snake[1].x = 19; snake[1].y = 10; snake[2].x = 18; snake[2].y = 10; } } } int main() { init_snake(); init_food(); while(1) { draw(); move(); eat_food(); check_dead(); Sleep(speed); } return 0; } ``` 这个程序使用了简单的ASCII字符来表示蛇、食物和游戏界面。按下W、A、S、D键可以控制蛇的移动方向,蛇碰到游戏边界或自己的身体就会死亡,每吃到一个食物得分加一,每得五分生命值加一,最多有三条命。 ### 回答2: 贪吃蛇是一款经典游戏,玩家操控蛇头移动,不断吃食物以增长长度,直到蛇头碰撞到自己的身体或墙壁为止。我将用C语言编写一个带有三条命的贪吃蛇。 首先,我会定义蛇的数据结构,包括蛇头的坐标和身体的长度。接着,我会设置游戏界面,初始化蛇的位置和初始长度。 游戏开始后,我会使用循环来实现蛇的不断移动。根据玩家的输入,我会改变蛇头的坐标,使其向上、下、左或右移动。然后,我会更新蛇的身体坐标,使其跟随蛇头的移动。 在游戏过程中,我会设置食物的随机生成。当蛇头与食物的坐标重合时,蛇的长度将增加,得分也会增加。我会在每次蛇吃到食物后检查蛇的长度是否达到了目标长度。如果达到了,蛇将进入下一关,长度会重新设置。 当蛇头碰撞到自己的身体或墙壁时,玩家将失去一条命。我会设置一个全局变量来表示玩家的生命值,初始设为3。碰撞后,我会根据玩家的生命值判断是否继续游戏。如果生命值大于0,游戏将继续,蛇将回到初始位置,并且生命值会减一。如果生命值为0,游戏将结束。 在游戏中,我还会实现得分的显示和计算。每次蛇吃到食物后,得分会增加。我会将得分显示在游戏界面的一角,让玩家时刻了解自己的成绩。 综上所述,我会使用C语言编写一个带有三条命的贪吃蛇游戏。玩家可以操控蛇头移动,吃食物增长身体,同时要避免碰撞到自己的身体或墙壁。游戏将根据玩家的生命值判断是否结束,并实时显示得分。游戏将通过循环不断更新蛇的位置和食物的生成,以实现游戏的持续进行。 ### 回答3: 贪吃蛇是一款经典的游戏,玩家操纵一条长度不断增加的蛇,目标是吃掉尽可能多的食物。在传统的贪吃蛇游戏中,一旦蛇头碰到自己身体或者墙壁,游戏就会结束。 为了增加游戏的趣味性和挑战性,可以给贪吃蛇增加三条命。这样,玩家在蛇头碰到障碍物或者蛇身体时,并不会立即导致游戏结束,而是扣除一条命。 实现这个功能的方法有很多。首先,可以在程序的全局变量中设置一个表示剩余生命的整型变量,初值为3。然后,在游戏主循环中,每次更新蛇的位置后,检测是否发生了碰撞。如果发生了碰撞,剩余生命减1,并重新设置蛇的位置,继续下一轮游戏。 当剩余生命大于0时,游戏不会立即结束,而是继续进行。只有当剩余生命为0时,游戏最终结束。 在游戏界面上,可以显示当前剩余生命的信息,让玩家清楚地知道自己还有几条命。当剩余生命减少时,可以播放一段音效或者显示相应的提示信息,提醒玩家注意生命的消耗。 通过添加三条命的功能,贪吃蛇游戏更具挑战性,玩家需要更加谨慎地操作蛇的移动,避免碰到障碍物。这样的设计可以增加游戏的乐趣,让玩家更有动力挑战更高的分数。同时,在程序设计上也可以锻炼编程能力,提高对游戏开发的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值