Snake games (C language)

Posted by Motionographer on Thu, 10 Feb 2022 21:45:00 +0100

Write before:

Greedy snake, I believe everyone has played it. After learning the C language, I also want to write a greedy Snake game myself. Then I checked some materials. Finally, based on a video of station B, I added my own thinking, design and improvement, and created my own greedy Snake game, which I share with you here. (original video link: https://www.bilibili.com/video/BV1oW411G7Ag)

I believe many students (I mean Xiaobai) will have a doubt after learning the C language course: the programs learned and practiced in the course run in a black box (that is, the console), and they are all text, which is more than a little worse than the software we usually use. How can we write a visual interface in the same C language? I had the same doubts at that time, and then I checked some materials to understand what GUI is. To get down to business, for C language, to write a visual interface, you need to use the corresponding function library: EasyX Library (I don't know much about these, and there are similar function libraries officially, but I only introduce what I use here, which is also used by the teacher in the above video).

Introduction to EasyX Library:

EasyX is a graphics library for C + +, which can help C/C + + beginners get started with graphics and game programming quickly. For example, you can quickly draw a house or a mobile car with geometric graphics based on EasyX graphics library, write Tetris, snake, black and white chess and other small games, and practice various algorithms of graphics, etc. EasyX library provides many functions, such as drawing window, drawing various graphics, text output, image processing, mouse capture and so on. Secondly, the help document of EasyX library makes detailed explanations on the installation instructions, basic concepts, function instructions and common problems of EasyX, which is more convenient to use and friendly to Xiaobai.

EasyX library official website (free download): https://easyx.cn/

EasyX library Baidu cloud: easyX library Baidu cloud Extraction code: easx

Game design overview:

When I was writing this game, I was not familiar with EasyX library and C language programming at the beginning, so I wrote it with the video teacher at the beginning, so the idea was similar to that in the video. With the gradual learning, and then added their own design, the main ideas are as follows:

1. I hope my game can have different maps (walls) as I have played before

2. I hope my game can have different difficulty choices

3. I hope the game can have different background music and can be switched randomly; It also has sound effects when snakes eat food

4. I hope to apply the C language file operation I learned and add a function to refresh new records

Part code:

1. All structures, enumeration type definitions

#ifndef HEAD_H
#define HEAD_H
#endif

struct Coor      //10 * 10 small grid
{
	int x;
	int y;
};

typedef enum ch   //The direction of the snake, whether to pause
{
	up = 119,
	down = 115,
	left = 97,
	right = 100,
	space = 32,
	enter = 13
}CH;

struct Snake       //snake
{
	struct Coor scr[2464];     //Contains up to 100 cells
	int n;                    //Total number of snakes
	CH ch;                    //Snake direction
};

struct Food         //food
{
	int x;
	int y;
};

struct Wall
{
	struct Coor wall[2400];
	int n;
};

typedef struct record
{
	int sleep;
	int mapnumber;
	int score;
	struct record* next;
}Record;

2. Control Snake Movement and pause game function

void ChangeCh()
{
	int input;
	int input1;
	input=_getch();
	switch (input)
	{
	case up:
		if (snake.ch != down)
		{
			snake.ch = up;
			rotateimage(&head, &snakehead, 0, RGB(167, 225, 225));
		}
		break;
	case down:
		if (snake.ch != up)
		{
			snake.ch = down;
			rotateimage(&head, &snakehead, PI, RGB(167, 225, 225));
		}
		break;
	case left:
		if (snake.ch != right)
		{
			snake.ch = left;
			rotateimage(&head, &snakehead, PI / 2, RGB(167, 225, 225));
		}
		break;
	case right:
		if (snake.ch != left)
		{
			snake.ch = right;
			rotateimage(&head, &snakehead, 3 * PI / 2, RGB(167, 225, 225));
		}
		break;
	case enter:             //Pause or resume the game
		setcolor(RED);    //Set color
		settextstyle(40, 0, L"Blackbody");   //Set font style
		setbkmode(OPAQUE);               //Set background
		outtextxy(150, 180, L"Pause!");      //Output text
		settextstyle(30, 0, L"Blackbody");   //Set font style
		outtextxy(150, 230, L"enter: Continue the game");
		outtextxy(150, 260, L"Space: restart");
		do
		{
			input1 = _getch();
			if (input1 == enter)
			{
				clearrectangle(20,20,580,460);
				DrawMap();
				DrawSnake();
				DrawFood();
				break;
			}
			if (input1 == space)
			{
				for (int i = 0; i < snake.n; i++)
				{
					snake.scr[i].x = 20;
					snake.scr[i].y = 20;
				}
				clearcliprgn();
				closegraph();
				CloseMusic();
				Game();
				break;
			}
		} while (1);
		break;
	default:
		break;
	}
}

3. File operation

#include<stdio.h>  
#include<stdlib.h>
#include<string.h>
#include<graphics. h> / / graphics library header file
#include<mmsystem. h> / / multimedia device interface
#include<time.h>
#include<conio.h>
#pragma comment(lib,"winmm.lib")    
#include"head.h"

#pragma comment(lib,"winmm.lib")  

#define pPath "record.txt"

#define FALSE 0
#define TRUE 1
#define TXTNUMBER 12
 
Record*Head;
int Mn;

int IfChangeRecord(int sleep, int mapnumber, int score)
{
	Record* head;
	head = (Record*)malloc(sizeof(Record));
	if (head != NULL)
	{
		head->next = NULL;
		Head = head;
	}
	Record*r;
	FILE* fp = NULL;
	errno_t err = 0;
	char aBuf[TXTNUMBER];
	//Open file
	err = fopen_s(&fp, pPath, "r");
	if (fp == NULL)
	{
		return FALSE;
	}
	//read file
	while (feof(fp) == 0)
	{
		memset(aBuf, 0, TXTNUMBER);
		if (fgets(aBuf, TXTNUMBER, fp) != NULL)
		{
			if (strlen(aBuf) > 0)
			{
				const char* delims = "##";
				char* str[4];
				char* p = NULL;
				int i = 0;
				str[0] = strtok_s(aBuf, delims, &p);
				while (str[i])
				{
					i++;
					str[i] = strtok_s(NULL, delims, &p);
				}
				r = (Record*)malloc(sizeof(Record));
				if (r == NULL)
				{
					return FALSE;
				}
				r->sleep=atoi(str[0]);
				r->mapnumber = atoi(str[1]);
				r->score = atoi(str[2]);
				head->next = r;
				r->next = NULL;
				head = r;
				r = r->next;
			}
		}
	}
	//Close file
	fclose(fp);
	//Judge and update records
	int n=0;
	head = Head->next;
	while (head != NULL)
	{
		if (sleep == head->sleep && mapnumber == head->mapnumber&&score>head->score)
		{
			head->score = score;
			n = 1;
		}
		head = head->next;
	}
	if (n == 1)
	{
		//Delete all original information in the file
		err = fopen_s(&fp, pPath, "w");
		if (fp == NULL)
		{
			return FALSE;
		}
		fclose(fp);
		//Write updated record to file
		err = fopen_s(&fp, pPath, "a");
		if (fp == NULL)
		{
			return FALSE;
		}
		head = Head->next;
		while (head != NULL)
		{
			fprintf(fp, "%d##%d##%d\n", head->sleep, head->mapnumber, head->score);
			head = head->next;
		}
		//Close file
		fclose(fp);
	}
	return n;
}

/*
	MA:All Falls Down.mp3
	MB:All The Things She Said.mp3
	MC:Alone.mp3
	MD:(Swallowing sound effect)
	ME:Faded.mp3
	MF:Ignite.mp3
	MH:Reality.mp3
	MI:YELLOW.mp3
	MJ:YYCY.mp3  (Clouds and smoke become rain)
	*/

void SetBackgroundMusic()
{
	mciSendString(L"open MD.mp3 alias MD", 0, 0, 0);
	srand((unsigned)(time(NULL)));
	Mn = rand() % 8;
	switch (Mn)
	{
	case 0:
		mciSendString(L"open MA.mp3 alias MA", 0, 0, 0);
		mciSendString(L"play MA repeat", 0, 0, 0);
		break;
	case 1:
		mciSendString(L"open MB.mp3 alias MB", 0, 0, 0);
		mciSendString(L"play MB repeat", 0, 0, 0);
		break;
	case 2:
		mciSendString(L"open MC.mp3 alias MC", 0, 0, 0);
		mciSendString(L"play MC repeat", 0, 0, 0);
		break;
	case 3:
		mciSendString(L"open ME.mp3 alias ME", 0, 0, 0);
		mciSendString(L"play ME repeat", 0, 0, 0);
		break;
	case 4:
		mciSendString(L"open MF.mp3 alias MF", 0, 0, 0);
		mciSendString(L"play MF repeat", 0, 0, 0);
		break;
	case 5:
		mciSendString(L"open MH.mp3 alias MH", 0, 0, 0);
		mciSendString(L"play MH repeat", 0, 0, 0);
		break;
	case 6:
		mciSendString(L"open MI.mp3 alias MI", 0, 0, 0);
		mciSendString(L"play MI repeat", 0, 0, 0);
		break;
	case 7:
		mciSendString(L"open MJ.mp3 alias MJ", 0, 0, 0);
		mciSendString(L"play MJ repeat", 0, 0, 0);
		break;
	}
}

void CloseMusic()
{
	mciSendString(L"close MD", 0, 0, 0);
	switch (Mn)
	{
	case 0:
		mciSendString(L"close MA", 0, 0, 0);
		break;
	case 1:
		mciSendString(L"close MB", 0, 0, 0);
		break;
	case 2:
		mciSendString(L"close MC", 0, 0, 0);
		break;
	case 3:
		mciSendString(L"close ME", 0, 0, 0);
		break;
	case 4:
		mciSendString(L"close MF", 0, 0, 0);
		break;
	case 5:
		mciSendString(L"close MH", 0, 0, 0);
		break;
	case 6:
		mciSendString(L"close MI", 0, 0, 0);
		break;
	case 7:
		mciSendString(L"close MJ", 0, 0, 0);
		break;
	}
}

void ChangeMidMusic()
{
	mciSendString(L"play MD from 0", 0, 0, 0);
}

Complete source code:

Complete source code: https://pan.baidu.com/s/1OdZDuyTQBvCKl3bwkaHLuA Extraction code: tcs1

Entire project file: https://pan.baidu.com/s/1XVGd59jmMy-aJhceFktWaw Extraction code: tcs2

Game installation package: https://pan.baidu.com/s/1pD7dlNfl4SWpNdOorK1ZZw Extraction code: tcs3

Final effect display of the game:

Snake 2.0

Supplementary questions:

Make a sharing supplement to the "how to obtain the key value of computer keyboard" encountered in the process of writing this game:

When I encountered this problem, I also went to various baidu searches, and then found that the search results were different. It was really uncomfortable, but finally let me find a good thing: a C language code that can obtain key values. I think it's very useful. I'll share it with you here

#include <stdio.h>

#include <windows.h>

#include <conio.h>

int main()

{
    int ch;//Save the value read from the keyboard
    char c;//Save the value read from the keyboard
    while (1)

    {
        if (_kbhit())//There are keystrokes

        {
            c= ch = _getch();//Get the keyboard value without entering

            printf("%c The key value is:%d\n",c, ch);

        }

        Sleep(100);//Avoid busy waiting

    }
}

But it's been a long time (I wrote this little game around October 2020). I didn't think too much at that time. I forgot the source of the code. Long live the understanding. Thank the original author!

Topics: C C++ Programming Visualization Game Development