Margoo

...?

舒尔特方格小游戏

游戏介绍

学校的心理课上介绍了舒尔特方格这个东西,能锻炼自己的专注力,回家以后写了 300 来行代码实现了这个舒尔特方格小游戏。

玩法就是按照 1~25 的顺序去点击数字,时间越短越好。

更新日志 (2021/11/27) : 对游戏进行大改,重写 UI,加入计分系统

游戏截图

游戏源码下载

这里直接上源码,同学们可以自行复制到自己的编译器里编译。

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

#include <fstream>

#include <vector>
#include <algorithm>
#include <string>

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

void putimage(IMAGE* image, int x, int y, IMAGE* target = nullptr, int transparency = 255)
{
	HDC target_dc = GetImageHDC(target);
	HDC image_dc = GetImageHDC(image);

	int width = image->getwidth();
	int height = image->getheight();

	BLENDFUNCTION blend_function = { AC_SRC_OVER, 0, static_cast<BYTE>(transparency), AC_SRC_ALPHA };
	AlphaBlend(target_dc, x, y, width, height,
		image_dc, 0, 0, width, height,
		blend_function);
}

struct game_data_head
{
	int data_index;
};

struct game_save
{
	int second;

	time_t clock;
};

void settextheight(int px)
{
	LOGFONT font;

	gettextstyle(&font);

	font.lfHeight = px;

	settextstyle(&font);
}

std::vector<game_save> saves;

void menu_ui()
{
	settextheight(34);

	settextcolor(RGB(30, 30, 30));

	setbkcolor(RGB(244, 245, 249));

	cleardevice();

	outtextxy(200, 110, L"舒尔特方格");

	setfillcolor(RGB(93, 103, 251));

	solidrectangle(162, 278, 217 + 163, 40 + 278);
	solidrectangle(163, 343, 217 + 163, 40 + 343);

	settextcolor(RGB(251, 251, 251));

	settextheight(30);

	outtextxy(223, 283, L"开始游戏");
	outtextxy(223, 348, L"本地排名");

	settextheight(23);

	wchar_t* text = new wchar_t[1024];

	settextcolor(RGB(30, 30, 30));

	if (saves.empty() == false)
	{
		wsprintf(text, L"历史最高纪录 %d s", saves[0].second);
	}
	else
	{
		std::ofstream init_data("./game.dat");

		game_data_head write_head;

		write_head.data_index = 0;

		init_data.write((char*)&write_head, sizeof(&write_head));

		init_data.close();

		wsprintf(text, L"还没有记录哦~");
	}

	outtextxy(9, 630, text);
}

void init_game()
{
	initgraph(540, 660);

	SetWindowText(GetHWnd(), L"舒尔特方格");

	// Read game save
	std::ifstream game_dat("./game.dat");

	game_data_head head;
	game_save	   save;

	game_dat.read((char*)&head, sizeof(&head));

	for (int count = 0; count < head.data_index; ++count)
	{
		game_dat.read((char*)&save, sizeof(&save));

		saves.push_back(save);
	}

	game_dat.close();

	std::sort(saves.begin(), saves.end(), [](game_save r, game_save l) -> bool { return r.second < l.second; });

	LOGFONT font;

	gettextstyle(&font);

	font.lfQuality = PROOF_QUALITY;

	_tcscpy_s(font.lfFaceName, L"微软雅黑");

	setbkmode(TRANSPARENT);

	settextstyle(&font);

	menu_ui();
}

void free_game()
{
	closegraph();
}

// Grid's map
int map[5][5];

// Every number's button
struct map_button
{
	int x;
	int y;
};

map_button button[5][5];

COLORREF   button_color[5][5] = { { RGB(245, 248, 251) } };

time_t start_time;

// Init grid
void init_map()
{
	srand((unsigned int)time(NULL));

	int x = 31;
	int y = 61;

	for (int i = 0, count = 0; i < 5; ++i)
	{
		for (int j = 0; j < 5; ++j)
		{
			button_color[i][j] = RGB(245, 248, 251);

			++count;

			map[i][j] = count;

			button[i][j].x = x;
			button[i][j].y = y;

			x += 81 + 13;
		}

		x = 31;

		y += 81 + 16;
	}

	int temp_x;
	int temp_y;

	for (int i = 4; i >= 0; --i)
	{
		for (int j = 4; j >= 0; --j)
		{
			temp_x = rand() % (i + 1);
			temp_y = rand() % (j + 1);

			int temp = map[temp_x][temp_y];

			map[temp_x][temp_y] = map[i][j];

			map[i][j] = temp;
		}
	}
}

void draw_map(bool show_number = true)
{
	int x = 31;
	int y = 61;

	settextheight(32);

	settextcolor(RGB(30, 30, 30));

	outtextxy(200, 11, L"舒尔特方格");

	for (int i = 0, count = 0; i < 5; ++i)
	{
		for (int j = 0; j < 5; ++j)
		{
			std::wstring text = std::to_wstring(map[i][j]);

			setfillcolor(button_color[i][j]);

			solidrectangle(x, y, x + 81, y + 81);

			if (show_number == true)
			{
				outtextxy(x + (81 / 2 - textwidth(text.c_str()) / 2), y + (81 / 2 - textheight(text.c_str()) / 2), text.c_str());
			}

			x += 81 + 13;
		}

		x = 31;

		y += 81 + 16;
	}

	setfillcolor(RGB(93, 103, 251));

	settextheight(28);

	solidrectangle(183, 599, 183 + 175, 599 + 40);

	settextcolor(RGB(251, 251, 251));

	outtextxy(230, 603, L"重新开始");
}

// Accurate delay
void sleep(unsigned long long dealy)
{
	static time_t old_clock = clock();

	old_clock += dealy;

	while (clock() < old_clock)
	{
		Sleep(1);
	}
}

void rank_ui()
{
	cleardevice();

	settextcolor(RGB(30, 30, 30));

	settextheight(32);

	outtextxy(540 / 2 - textwidth(L"本地排名") / 2, 110, L"本地排名");

	wchar_t* rank_text = new wchar_t[1024];

	if (saves.empty() == false)
	{
		settextheight(36);

		wsprintf(rank_text, L"TOP 1 : %d\0", saves[0].second);

		outtextxy(540 / 2 - textwidth(rank_text) / 2, 170, rank_text);

		if (saves.size() >= 2)
		{
			settextheight(28);

			wsprintf(rank_text, L"TOP 2 : %d\0", saves[1].second);

			outtextxy(540 / 2 - textwidth(rank_text) / 2, 170 + 38, rank_text);
		}

		if (saves.size() >= 3)
		{
			settextheight(26);

			wsprintf(rank_text, L"TOP 3 : %d", saves[2].second);

			outtextxy(540 / 2 - textwidth(rank_text) / 2, 170 + 38 + 28, rank_text);
		}
	}
	else
	{
		outtextxy(540 / 2 - textwidth(L"暂无记录") / 2, 207, L"暂无记录");
	}

	setfillcolor(RGB(93, 103, 251));

	fillrectangle(195, 494, 195 + 175, 494 + 40);

	settextheight(34);

	settextcolor(RGB(251, 251, 251));

	outtextxy(235, 498, L"返回菜单");

	ExMessage message;

	while (true)
	{
		getmessage(&message);

		if (message.message == WM_LBUTTONDOWN)
		{
			if (message.x >= 195 && message.x <= 195 + 175 &&
				message.y >= 494 && message.y <= 498 + 40)
			{
				return;
			}
		}
	}
}

void start_game()
{
	cleardevice();

	init_map();

	draw_map(false);

	int last_number = 0;

	ExMessage message;

	BeginBatchDraw();

	settextheight(19);

	settextcolor(RGB(30, 30, 30));

	outtextxy(208, 569, L"点击任意方块开始");

	FlushBatchDraw();

	bool game_started = false;

	wchar_t* used_time = new wchar_t[1024];

	while (true)
	{
		draw_map();

		while (peekmessage(&message))
		{
			if (game_started == true)
			{
				if (message.message == WM_MOUSEMOVE)
				{
					for (int i = 0, count = 0; i < 5; ++i)
					{
						for (int j = 0; j < 5; ++j)
						{
							button_color[i][j] = RGB(245, 248, 251);
						}
					}

					for (int i = 0, count = 0; i < 5; ++i)
					{
						for (int j = 0; j < 5; ++j)
						{
							if (message.x >= button[i][j].x && message.y >= button[i][j].y &&
								message.x <= button[i][j].x + 81 && message.y <= button[i][j].y + 81)
							{
								button_color[i][j] = RGB(183, 215, 251);

								cleardevice();

								draw_map();

								break;
							}
						}
					}
				}
				if (message.message == WM_LBUTTONDOWN)
				{
					for (int i = 0, count = 0; i < 5; ++i)
					{
						for (int j = 0; j < 5; ++j)
						{
							if (message.x >= button[i][j].x && message.y >= button[i][j].y &&
								message.x <= button[i][j].x + 81 && message.y <= button[i][j].y + 81)
							{
								if (last_number + 1 == map[i][j])
								{
									++last_number;

									char* file_path = new char[1024];
									char* home_drive = nullptr;

									size_t size = 0;

									_dupenv_s(&home_drive, &size, "HOMEDRIVE");

									mciSendStringA("close clicked", NULL, 0, NULL);

									sprintf_s(file_path, 1024, "open \"%s/Windows/Media/tada.wav\" alias clicked", home_drive);

									mciSendStringA(file_path, NULL, 0, NULL);
									mciSendStringA("play clicked", NULL, 0, NULL);
								}

								break;
							}
						}
					}
				}
			}

			if (message.message == WM_LBUTTONDOWN)
			{
				if (message.x >= 183 && message.x <= 183 + 175 &&
					message.y >= 599 && message.y <= 599 + 40)
				{
					start_game();
				}
			}
		}

		if (game_started == false)
		{
			draw_map(false);

			settextcolor(RGB(30, 30, 30));
			settextheight(20);

			outtextxy(208, 569, L"点击任意方块开始");

			if (message.message == WM_LBUTTONDOWN)
			{
				for (int i = 0, count = 0; i < 5; ++i)
				{
					for (int j = 0; j < 5; ++j)
					{
						if (message.x >= button[i][j].x && message.y >= button[i][j].y &&
							message.x <= button[i][j].x + 81 && message.y <= button[i][j].y + 81)
						{
							start_time = clock();

							game_started = true;

							break;
						}
					}
				}
			}
		}

		if (game_started == true)
		{
			settextcolor(RGB(30, 30, 30));

			settextheight(20);

			wsprintf(used_time, L"所用时间 %ds\0", int((clock() - start_time) / 1000));

			outtextxy(540 / 2 - textwidth(used_time) / 2, 569, used_time);

			settextheight(16);

			wsprintf(used_time, L"下一个数字:%d", last_number + 1);

			outtextxy(540 / 2 - textwidth(used_time) / 2, 43, used_time);
		}

		if (last_number == 25)
		{
			cleardevice();

			draw_map();

			settextcolor(RGB(30, 30, 30));

			settextheight(20);

			if (saves.empty() == true)
			{
				wsprintf(used_time, L"游戏结束, 所用时间 %ds, 点击\"重新开始\"按钮再次游玩\0", int((clock() - start_time) / 1000));
			}
			else
			{
				if (int((clock() - start_time) / 1000) < saves[0].second)
				{
					wsprintf(used_time, L"恭喜你打破原有记录 %ds, 新记录 %ds\0", saves[0].second, int((clock() - start_time) / 1000));
				}

				if (int((clock() - start_time) / 1000) == saves[0].second)
				{
					wsprintf(used_time, L"差一秒就能打破记录 %ds 了! 加油 (本局游戏用时 : %ds)\0", saves[0].second, int((clock() - start_time) / 1000));
				}

				if (int((clock() - start_time) / 1000) > saves[0].second)
				{
					wsprintf(used_time, L"差%d s 就能打破记录 %ds 了! 加油 (本局游戏用时 : %ds)\0", int((clock() - start_time) / 1000) - saves[0].second,
						saves[0].second, int((clock() - start_time) / 1000));
				}
			}

			outtextxy(540 / 2 - textwidth(used_time) / 2, 569, used_time);

			FlushBatchDraw();

			game_data_head temp_head;
			game_save      new_save;

			temp_head.data_index = saves.size() + 1;
			new_save.second = int((clock() - start_time) / 1000);

			std::ofstream save("./game.dat");

			saves.push_back(new_save);

			std::sort(saves.begin(), saves.end(), [](game_save r, game_save l) -> bool { return r.second < l.second; });

			save.write((char*)&temp_head, sizeof(&temp_head));

			for (auto& item : saves)
			{
				save.write((char*)&item, sizeof(&item));
			}

			save.close();

			while (true)
			{
				getmessage(&message);

				if (message.message == WM_LBUTTONDOWN)
				{
					if (message.x >= 183 && message.x <= 183 + 175 &&
						message.y >= 599 && message.y <= 599 + 40)
					{
						start_game();
					}
				}
			}
		}

		FlushBatchDraw();

		cleardevice();

		sleep(10);
	}

	EndBatchDraw();
}

int main()
{
	init_game();

	ExMessage message;

	while (true)
	{
		getmessage(&message);

		if (message.message == WM_LBUTTONDOWN)
		{
			if (message.x >= 162 && message.y >= 278 &&
				message.x <= 162 + 217 && message.y <= 278 + 40)
			{
				start_game();
			}
			if (message.x >= 162 && message.y >= 343 &&
				message.x <= 162 + 217 && message.y <= 343 + 40)
			{
				rank_ui();

				cleardevice();

				menu_ui();
			}
		}
	}

	_getch();

	free_game();

	return 0;
}
分享到

评论 (3) -

  • 重新开始后,之前点的数字没有清楚记录

添加评论