C語言—貪喫蛇遊戲

由於使用了一些庫文件,上傳了下載還需要積分,所以我會把所以代碼都上傳,方便日後複習結構設計的方向希望能有所作用,如果有什麼缺點多謝點評

在這裏插入圖片描述

首先是文件的劃分

在這裏插入圖片描述
需要注意的是,在函數命名的時候要注意清晰明瞭,還有就是注意模塊的劃分要清晰,該是哪個模塊的任務就由哪個模塊去做,不要混亂結果,打個比方,如蛇身的繪畫,可以是snake模塊的任務,但是在實際設計上,繪畫並不是蛇本身的屬性,他應該是view模塊的任務,這樣這是爲了保證數據和操作相互隔離,分工明確。所以在整個程序中會有許多的函數去獲得,snake和food的指針,這樣看似麻煩。但卻是在解決問題時得到了方便。
另外還有注意的是,在編寫程序是要注意模塊劃分,儘可能減少全局變量的使用,如果非要用全局變量也要避免該變量被其他模塊直接操作,這樣就會使代碼安全性提升。
當然在後面的程序中有一處變量我使用了extern int去共享,這個設計其實不太好,但是由於那幾個窗口id屬性是庫函數調用的結果,所以我在這偷了個懶,希望大家不要學習

其次一點就是在跟新遊戲數據時,這裏採用了掩碼的方式去比對,選擇跟新的選項,這個技巧還是十分有用的

snake.h

我爲了方便給頭文件加了很多預編譯,這是個極差的方式,請勿模仿。再此只是爲了我調試的時候方便,是一個錯誤的做法
那麼接下來整個程序還是分爲四個模塊,snake,food,view,main

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include<assert.h>
#include<Windows.h>
#include <conio.h>
#include "glConsole.h"

typedef struct body
{
	int x;
	int y;
	struct body *next;
}body;

typedef enum _tagDir
{
	Left,
	Right,
	Up,
	Down
} Movedir;

typedef struct Snake
{
	body* head;
	body* tail;
	Movedir movedir;
	Movedir newmovedir;//改變方向時,新的移動方向
	int     last_tx;                    // 存儲蛇尾最後位置
	int     last_ty;
}Snake;

typedef struct _tagFood
{
	int x;
	int y;
} Food;

//snake
body *body_make(int x, int y, body *next);
Snake* snake_init();
void snake_release();
bool snake_death();
void snake_grow();
void snake_update();
Snake *retrn_snake_info();

//food
void food_make();
bool food_eat_hit();
Food return_food_info();

//view
void window_init();
void window_release();
void window_show_about();
void window_show_gameinfo(int score, int level, int speed);
void window_draw_wall();
void snake_draw();
void snake_tail_empty();
void food_draw();

snake.c

#include"snake.h"

extern int     about_window;         // 關於窗口ID
extern int     score_window;          // 成績窗口ID
extern int     snake_window;          // 遊戲窗口ID

Snake* snake = NULL;//蛇的全局變量


body *body_make(int x, int y, body *next)
{
	body *p = (body*)malloc(sizeof(body));
	p->x = x;
	p->y = y;
	p->next = next;
	return p;
}

Snake* snake_init()
{
	snake = (Snake*)malloc(sizeof(Snake));

	body *sn1 = body_make(17, 10, NULL);
	body *sn2 = body_make(18, 10, sn1);
	body *sn3 = body_make(19, 10, sn2);
	body *sn4 = body_make(20, 10, sn3);

	snake->head = sn4;
	snake->tail = sn1;

	snake->last_tx = sn1->x;
	snake->last_ty = sn1->y;

	snake->movedir = Right;
	snake->newmovedir = Right;

	return snake;
}

void snake_release()
{
	body *p = snake->head;
	while (p != NULL)
	{
		body *tmp = p->next;
		free(p);
		p = tmp;
	}
	free(snake);
}

void snake_update()
{
	snake->movedir = snake->newmovedir;

	snake->last_tx = snake->tail->x;
	snake->last_ty = snake->tail->y;

	body *prev = snake->head;
	body *curr = snake->head->next;

	int x = prev->x;
	int y = prev->y;
	while (curr != NULL)
	{
		int xx = curr->x;
		int yy = curr->y;

		curr->x = x;
		curr->y = y;

		prev = curr;
		curr = curr->next;

		x = xx;
		y = yy;
	}

	int xxx = 0;
	int yyy = 0;

	switch (snake->movedir)
	{
	case Left:xxx = -1; break;
	case Right:xxx = 1; break;
	case Up:yyy = -1; break;
	case Down:yyy = 1;  break;
	default:break;
	}
	snake->head->x += xxx;
	snake->head->y += yyy;
}

void snake_grow()
{
	body *p = (body*)malloc(sizeof(body));
	p->x = snake->last_tx;
	p->y = snake->last_ty;
	snake->tail->next = p;
	p->next = NULL;

	snake->tail = p;
}

bool snake_death()
{
	int x, y, w, h;
	glmxConsole_GetWindowRect(snake_window, &x, &y, &w, &h);

	if (snake->head->x == w || snake->head->x == 1 || snake->head->y == 0 || snake->head->y == h )
		return true;

	body *p = snake->head->next;
	while (p->next != NULL)
	{
		if (snake->head->x == p->x&&snake->head->y == p->y)
			return true;
		else p = p->next;
	}

	return false;
}

Snake *retrn_snake_info()
{
	assert(snake!=NULL);
	return snake;
}


food.c

#include"snake.h"

extern int     about_window;         // 關於窗口ID
extern int     score_window;          // 成績窗口ID
extern int     snake_window;          // 遊戲窗口ID

Food food;

void food_make()
{
	int x, y, w, h;
	glmxConsole_GetWindowRect(snake_window, &x, &y, &w, &h);
	food.x= rand() % (w-1) + 1;
	food.y= rand() % (h-1) + 1;
}

bool food_eat_hit()
{
	Snake *snake = retrn_snake_info();
	if (food.x == snake->head->x&&food.y == snake->head->y)
		return true;
	else return false;
}

Food return_food_info()
{
	return food;
}

view.c

#include"snake.h"

int     about_window = -1;          // 關於窗口ID
int     score_window = -1;          // 成績窗口ID
int     snake_window = -1;          // 遊戲窗口ID

void window_init()
{
	int main_window;
	int bottom_window1;

	main_window = glmxConsole_CreateWindow(60, 30, "Snake");
	glmxConsole_SplitWindow(main_window, 3, WND_SPLIT_HORIZONTAL, '=', 9, &about_window, &bottom_window1);
	glmxConsole_SplitWindow(bottom_window1, 2, WND_SPLIT_HORIZONTAL, '=', 9, &score_window, &snake_window);
}

void window_release()
{
}

void window_show_about()
{
	glmxConsole_WndDrawFormatText(about_window, 0, 0, 12, "Snake Ver1.0", TEXT_ALIGN_CENTER);
	glmxConsole_WndDrawFormatText(about_window, 0, 2, 12, "GLimix Studio - ZYF", TEXT_ALIGN_CENTER);
}

void window_show_gameinfo(int score,int level,int speed)
{
	char buffer[32];
	sprintf_s(buffer, 32, "SCORE: %d", score);
	glmxConsole_WndDrawFormatText(score_window, 0, 0, 6, buffer, TEXT_ALIGN_LEFT);

	sprintf_s(buffer, 32, "LEVEL: %d", level);
	glmxConsole_WndDrawFormatText(score_window, 0, 1, 6, buffer, TEXT_ALIGN_LEFT);

	sprintf_s(buffer, 32, "SPEED: %d", speed);
	glmxConsole_WndDrawFormatText(score_window, 0, 1, 8, buffer, TEXT_ALIGN_RIGHT);
}

void window_draw_wall()
{
	int x, y, w, h;
	glmxConsole_GetWindowRect(snake_window, &x, &y, &w, &h);
	for (int i = 0; i < w; i++)
	{
		glmxConsole_WndDrawTextEx(snake_window, i, 0, 82, " ");
		glmxConsole_WndDrawTextEx(snake_window, i, h, 82, " ");
	}
	for (int i = 0; i < h; i++)
	{
		glmxConsole_WndDrawTextEx(snake_window, 0, i, 82, " ");
		glmxConsole_WndDrawTextEx(snake_window, w, i, 82, " ");
	}

}

void snake_draw()
{
	Snake *snake = retrn_snake_info();
	body *p = snake->head;
	while (p->next != NULL)
	{
		if (p == snake->head)
			glmxConsole_WndDrawTextEx(snake_window, p->x, p->y, 8, "@");
		else
			glmxConsole_WndDrawTextEx(snake_window, p->x, p->y, 8, "=");

		p = p->next;
	}
	glmxConsole_WndDrawTextEx(snake_window, p->x, p->y, 8, "-");
}

void snake_tail_empty()
{
	Snake *snake = retrn_snake_info();
	glmxConsole_WndDrawTextEx(snake_window, snake->last_tx, snake->last_ty, 8, " ");
}

void food_draw()
{
	Food food = return_food_info();
	glmxConsole_WndDrawTextEx(snake_window, food.x, food.y, 4, "*");
}

main.c

#include"snake.h"
extern int     about_window;         // 關於窗口ID
extern int     score_window;          // 成績窗口ID
extern int     snake_window;          // 遊戲窗口ID

//更新掩碼
#define update_none  0x00
#define update_score 0x01
#define update_all   0x08

void update_info(int *score, int *level, int *speed, int update)
{
	switch (update)
	{
	case update_none:break;
	case update_score:*score += 1;break;
	case update_all:
		*score += 1;
		*level += 1;
		*speed += 1;
		break;
	}
}

int main()
{
	system("cls");
	glmxConsole_Init();

	window_init();
	int score = 0;
	int level = 1;
	int speed = 1;
	window_show_about();
	window_show_gameinfo(score, level, speed);
	window_draw_wall();
	
	Snake *snake = NULL;
	snake=snake_init();
	snake_draw();

	int time_count = 20;//畫面更新計時器

	int time = 10;

	int update;
	bool food_existence = false;

	for (;;)
	{
		snake_death();

		if (time_count-- == 0)
		{
			snake_update();
			snake_tail_empty();
			snake_draw();
			glmxConsole_SetCursorPosition(59, 29);
			if (food_eat_hit())
			{
				update_info(&score, &level, &speed, update_score);
				window_show_gameinfo(score, level, speed);
				if (score % 5 == 0)
				{
					update_info(&score, &level, &speed, update_all);
					if (time != 0)
					{
						time -= 1;
					}
					
				}
				food_existence = false;
				snake_grow();
			}

			if (!food_existence)
			{
				food_make();
				food_draw();
				food_existence = true;
			}

			if (snake_death())
			{
				glmxConsole_WndDrawTextEx(snake_window, 25,8, 2, "GAME OVER \n");
				break;

			}


			time_count = 20;
		}

		if (kbhit())
		{
			char move = getch();
			switch (move)
			{
			case 'w':
			case 'W':
				if (snake->movedir != Down)
					snake->newmovedir = Up;
				break;
			case 's':
			case 'S':
				if (snake->movedir != Up)
					snake->newmovedir = Down;
				break;
			case 'd':
			case 'D':
				if (snake->movedir != Left)
					snake->newmovedir = Right;
				break;
			case 'a':
			case 'A':
				if (snake->movedir != Right)
					snake->newmovedir = Left;
				break;
			}
		}


		Sleep(time);

	}
	getch();

	snake_release();

	window_release();

	glmxConsole_Release();

	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章