C语言之简单贪吃蛇

前言

本次练习用于巩固C语言数据结构中的链表,实现贪吃蛇的基本功能。

整体思路

  1. 打印边框
  2. 生成食物与蛇身移动
  3. 控制方向
  4. 结束游戏
   while (1)
    {
        Handle_key();   //按键处理
        Frame_Buff(data);   //画边框
        Eat_Food();			//吃食物
        Sleep(100);
        Map_Set_Buff(data);     //缓冲区画蛇的位置
        Sleep(100);

//---------------------- 越界、碰撞退出-------------------
        if (head->next->Frame_X >= 20 || head->next->Frame_Y >= 50 || head->next->Frame_X < 1 || head->next->Frame_Y < 1 || Snake_Collision())
            break;
    }
    return 0;
}

一、画边框

利用一个打印函数生成边框:

void Frame(char a[][LENGTH])    //画边框
{
    int i, j;
    for (i = 0; i < ROW; i++)
    {
        for (j = 0; j < COLUMN; j++)
        {
            if (a[i][j] == '*')		//防止食物被覆盖
                continue;
            if (i == 0 || i == ROW - 1)
            {
                a[i][j] = '*';
            }
            else
                a[i][j] = ' ';
        }
    }
    for (j = 0; j < COLUMN; j++)
    {
        for (i = 1; i < ROW - 1; i++)
        {
            if (a[i][j] == '*')
                continue;
            if (j == 0 || j == COLUMN - 1)
            {
                a[i][j] = '*';
            }
            else
                a[i][j] = ' ';
        }
    }
}

在这里插入图片描述

边框形状的选择可以按自己喜欢的来

二、画蛇并使其移动

1、清屏与休眠

通常我们都会使用system(“cls”) 函数清屏,但由于清屏速度过快会导致闪屏,看起来不舒服,因此采取了双缓冲控制台防闪屏技术,可以打开下面链接进行学习。
https://blog.csdn.net/weixinhum/article/details/72179593

2、蛇身移动

我使用的是链表来存储蛇身。首先是头节点移动,在X、Y上加一(根据蛇移动的方向,之后就是前一个节点的值赋值给后一个节点,最后一个节点留下来内容就清空。为了存储上一节点的蛇的信息,我用了一个数组存储,记住上一个节点的坐标。

//将当前节点的内容赋值给数组
	ago_data_x[i] = p->Frame_X;			//储存上一个节点的值
	ago_data_y[i] = p->Frame_Y;
//将上一个节点的赋值给当前节点
	p->Frame_X = ago_data_x[i - 1];		
	p->Frame_Y = ago_data_y[i - 1];
	data[p->Frame_X][p->Frame_Y] = '*';
	p = p->next;

这样一来就可以让蛇移动起来了。
在这里插入图片描述

三、控制蛇并生成食物

1、键盘输入

到这里了,我们要开始控制蛇了,这个时候我们需要使用到获取输入的函数_kbhit() ,还有和它一起的函数 _getch()负责监听。

	char c;
	if(_kbhit())
		c = _getch();

2、生成食物

使用rand()函数,以及与其配套使用产生随机数种子srand((int)time(NULL))。

	void Creat_Food()
	{
	    food_x = rand() % ROW + 1;
	    food_y = rand() % COLUMN + 1;
	    data[food_x][food_y] = '*';
	}

四、改变方向

蛇身我采用的是链表存储,插入节点的方法我使用的是头插法。我把要移动的方向存储在头节点中,因此只要访问头节点就可以知道蛇是往哪个方向移动的。

//MOVE:获取键盘输入后返回的值
//p->path:移动方向
	p = head->next;
	if (MOVE == 1)				//向上
	{
		if (p->path != 2)		//避免相反可以移动
		{
			p->path = 1;
		}
	}

五、结束语

好了,就写到这里了。其实一步一步去完成还是挺简单的,遇到不懂可以评论以及查找资料。另外,还有很多东西可以扩展,比如界面、加速行驶、以及增加难度…还是那句话,纸上得来终觉浅,绝知此事要躬行。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用easyx库实现的简单贪吃蛇游戏的C语言代码: ```c #include <graphics.h> #include <conio.h> #include <time.h> #define WIDTH 640 // 窗口宽度 #define HEIGHT 480 // 窗口高度 #define SIZE 20 // 贪吃蛇每个正方形的边长 #define MAX_LENGTH (WIDTH / SIZE) * (HEIGHT / SIZE) // 贪吃蛇最大长度 struct Snake { int x, y; // 贪吃蛇头部坐标 int length; // 贪吃蛇长度 int direction; // 贪吃蛇运动方向 int body[MAX_LENGTH][2]; // 贪吃蛇身体各个部分的坐标 } snake; struct Food { int x, y; // 食物坐标 } food; void init(); // 初始化函数 void drawSnake(); // 绘制贪吃蛇 void moveSnake(); // 移动贪吃蛇 void generateFood(); // 生成食物 bool isHitWall(); // 判断是否撞墙 bool isHitBody(); // 判断是否撞身体 bool isEatFood(); // 判断是否吃到食物 int main() { init(); while (1) { moveSnake(); if (isHitWall() || isHitBody()) { break; } if (isEatFood()) { generateFood(); } cleardevice(); drawSnake(); Sleep(100); } closegraph(); return 0; } void init() { initgraph(WIDTH, HEIGHT); setbkcolor(WHITE); setfillcolor(BLACK); setcolor(BLACK); snake.x = WIDTH / 2; snake.y = HEIGHT / 2; snake.length = 3; snake.direction = VK_RIGHT; for (int i = 0; i < snake.length; i++) { snake.body[i][0] = snake.x - i * SIZE; snake.body[i][1] = snake.y; } generateFood(); } void drawSnake() { for (int i = 0; i < snake.length; i++) { fillrectangle(snake.body[i][0], snake.body[i][1], snake.body[i][0] + SIZE, snake.body[i][1] + SIZE); } setfillcolor(RED); fillrectangle(food.x, food.y, food.x + SIZE, food.y + SIZE); setfillcolor(BLACK); } void moveSnake() { for (int i = snake.length - 1; i > 0; i--) { snake.body[i][0] = snake.body[i - 1][0]; snake.body[i][1] = snake.body[i - 1][1]; } switch (snake.direction) { case VK_UP: snake.y -= SIZE; break; case VK_DOWN: snake.y += SIZE; break; case VK_LEFT: snake.x -= SIZE; break; case VK_RIGHT: snake.x += SIZE; break; } snake.body[0][0] = snake.x; snake.body[0][1] = snake.y; } void generateFood() { srand((unsigned int)time(NULL)); bool flag = true; while (flag) { flag = false; food.x = SIZE * (1 + rand() % (WIDTH / SIZE - 2)); food.y = SIZE * (1 + rand() % (HEIGHT / SIZE - 2)); for (int i = 0; i < snake.length; i++) { if (food.x == snake.body[i][0] && food.y == snake.body[i][1]) { flag = true; break; } } } } bool isHitWall() { if (snake.x < SIZE || snake.x > WIDTH - 2 * SIZE || snake.y < SIZE || snake.y > HEIGHT - 2 * SIZE) { return true; } else { return false; } } bool isHitBody() { for (int i = 1; i < snake.length; i++) { if (snake.body[i][0] == snake.x && snake.body[i][1] == snake.y) { return true; } } return false; } bool isEatFood() { if (snake.x == food.x && snake.y == food.y) { snake.length++; snake.body[snake.length - 1][0] = snake.body[snake.length - 2][0]; snake.body[snake.length - 1][1] = snake.body[snake.length - 2][1]; return true; } else { return false; } } ``` 在该代码中,我们使用了`graphics.h`和`conio.h`两个头文件来实现图形界面和键盘输入的功能。其中,`init()`函数负责初始化贪吃蛇和食物的位置、长度、方向等信息,`drawSnake()`函数负责绘制贪吃蛇和食物,`moveSnake()`函数负责移动贪吃蛇,`generateFood()`函数负责随机生成食物,并判断其是否与贪吃蛇身体重叠,`isHitWall()`函数和`isHitBody()`函数分别用于判断贪吃蛇是否撞墙和撞身体,`isEatFood()`函数用于判断贪吃蛇是否吃到了食物。在主函数中,我们使用一个循环不断移动贪吃蛇,并根据不同情况终止游戏。 在编写完代码后,我们需要在编译选项中添加`-lbgi -lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32`这些库文件,才能正常编译和运行程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值