C/C++使用EasyX 图形库做一个见缝插针的小游戏

游戏简介

见缝插针是一个经典的休闲小游戏,操作简单,图形简洁,写起来也十分容易。试试就逝世

本文介绍使用 C++ 的 Easyx图形库来实现见缝插针。思路如下:

1. 初始化

2. 插入新的针(顺带判断游戏失败)

3. 移动针

4. 绘制屏幕

5. 主页界面

6. 扩展功能:音效、调整速度

因为这个游戏比较简单,所以步骤也比较少。

开始编写
1 预编译
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <graphics.h>
#pragma comment(lib, "winmm.lib")
#define HEIGHT 800
#define WIDTH 900
#define PI 3.1415926
#define PIN_L 120.0
#define RADIO 120

stdio.h用 sprintf_s 函数进行格式化字符数组;

conio.h 用来接受用户键盘输入;

math.h 调用 sin 和 cos 函数计算针末端的坐标;

graphics.h EasyX 图形库的头文件;

pragma 这行指令用于加载播放音乐的静态库;

HEIGHTWIDTH 分别表示窗口的高和宽;

PI 表示圆周率的常量;

PIN_L 表示针的长度(用小数是因为它要和小数运算);

RADIO 表示圆的半径。

2 初始化
全局变量
float pin_angle[1000];
int pin_num = 0;
float speed = PI / 360;

pin_angle 所有针的角度;

pin_num 针的数量;

speed 旋转速度。

初始化函数 

每一局游戏开始的时候调用就行了

void Init()
{
	pin_num = 0;
	speed = PI / 360;
}
3 插入新的针
检测键盘

利用 _kbhit()_getch()函数检测用户是否按下了空格键 (speed != 0 是判断游戏有没有结束)

if (_kbhit() && speed != 0)
{
	char input = _getch();
	if (input == ' ')
	{
		// 按下空格键
	}
}
新的针

把这根针的角度设为 PI

// 增加一根针
pin_num++;
pin_angle[pin_num - 1] = PI;
判断游戏失败

简单说,就是判断新的针跟任何其他针的角度差是否小于一定的值,这里的标准是 PI / 40

// 是否重合
for (int i = 0; i < pin_num - 1; i++)
{
	if (absent(pin_angle[i], pin_angle[pin_num - 1]) < (PI / 40))
	{
		speed = 0;
		return;
	}
}

这里的 absent 函数需要自己定义,因为角度都是浮点数类型,所以不能用 abs 函数取差。

/ 取差的绝对值
float absent(float a, float b)
{
	if (a > b) return a - b;
	else return b - a;
}
CreatePin 函数
// 发射针
void CreatePin()
{
	if (_kbhit() && speed != 0)
	{
		char input = _getch();
		if (input == ' ')
		{
			// 增加一根针
			pin_num++;
			pin_angle[pin_num - 1] = PI;
			
			// 是否重合
			for (int i = 0; i < pin_num - 1; i++)
			{
				if (absent(pin_angle[i], pin_angle[pin_num - 1]) < (PI / 40))
				{
					speed = 0;
					return;
				}
			}
		}
	}
}
4 移动针

很简单,每根针的角度增加速度,如果转了一圈,角度重新归零。

// 移动针
void MovePin()
{
	for (int i = 0; i < pin_num; i++)
	{
		pin_angle[i] += speed;
		if (pin_angle[i] > 2 * PI)
		{
			pin_angle[i] -= 2 * PI;
		}
	}
}
5 绘制屏幕

直接上重点——

F811539E-DC0F-EF6C-84BC-BF77CCCBA66C.png

endx, endy 所表示的量如图,是直角三角形的直角边。

根据三角几何:

endy = sin(角度)(邻边除以斜边)× 斜边

endx = cos(角度)(对边除以斜边) × 斜边

然后再根据坐标绘制线

// 针
setlinecolor(RGB(20, 130, 255));
line(0, HEIGHT / 2, PIN_L, HEIGHT / 2);
for (int i = 0; i < pin_num; i++)
{
	float endx = (PIN_L + RADIO) * cos(-pin_angle[i]) + WIDTH / 2;
	float endy = (PIN_L + RADIO) * sin(-pin_angle[i]) + HEIGHT / 2;
	setlinecolor(RGB(20, 130, 255));
	setfillcolor(RGB(20, 130, 255));
	if (i == pin_num - 1)
	{
		setlinecolor(RED);
		setfillcolor(RED);
	}
	line(WIDTH / 2, HEIGHT / 2, endx, endy);
	fillcircle(endx, endy, 10);
}

其实真的绘制并不复杂,只需要亿点数学知识。

没什么好说的……

// 圆
setlinecolor(RGB(20, 130, 255));
setfillcolor(RGB(70, 180, 255));
setlinestyle(PS_SOLID, 3);
fillcircle(WIDTH / 2, HEIGHT / 2, RADIO);
得分

这里要用一个函数:sprintf_s

它的作用就是格式化输出一串东西,只不过是打印到字符数组里面,跟 printf 一个样。

// 得分
char text[20];
sprintf_s(text, "%d", pin_num);
setbkcolor(RGB(70, 180, 255));
settextcolor(WHITE);
settextstyle(50, 20, "宋体");
outtextxy(WIDTH / 2 - 20, HEIGHT / 2 - 15, text);
按钮

我在游戏界面设置了两个按钮,分别是 返回主页退出游戏

实现方法:

1. 画出长方形以及文字;

2. 检测鼠标按下并且坐标在按钮范围中。

在绘制屏幕的这一部分,只需要实现第一步就行了。

// 按钮
setlinecolor(RGB(20, 130, 255));
roundrect(180, 10, 290, 60, 10, 10);
settextstyle(30, 13, "楷体");
outtextxy(185, 20, "返回主页");
roundrect(300, 10, 410, 60, 10, 10);
outtextxy(305, 20, "退出游戏");
Draw 函数
void Draw()
{
	// 针
	setlinecolor(RGB(20, 130, 255));
	line(0, HEIGHT / 2, PIN_L, HEIGHT / 2);
	for (int i = 0; i < pin_num; i++)
	{
		float endx = (PIN_L + RADIO) * cos(-pin_angle[i]) + WIDTH / 2;
		float endy = (PIN_L + RADIO) * sin(-pin_angle[i]) + HEIGHT / 2;
		setlinecolor(RGB(20, 130, 255));
		setfillcolor(RGB(20, 130, 255));
		if (i == pin_num - 1)
		{
			setlinecolor(RED);
			setfillcolor(RED);
		}
		line(WIDTH / 2, HEIGHT / 2, endx, endy);
		fillcircle(endx, endy, 10);
	}

	// 圆
	setlinecolor(RGB(20, 130, 255));
	setfillcolor(RGB(70, 180, 255));
	setlinestyle(PS_SOLID, 3);
	fillcircle(WIDTH / 2, HEIGHT / 2, RADIO);

	// 得分
	char text[20];
	sprintf_s(text, "%d", pin_num);
	setbkcolor(RGB(70, 180, 255));
	settextcolor(WHITE);
	settextstyle(50, 20, "宋体");
	outtextxy(WIDTH / 2 - 20, HEIGHT / 2 - 15, text);

	// 标题
	settextcolor(RGB(20, 130, 255));
	setbkcolor(RGB(150, 230, 255));
	settextstyle(45, 20, "隶书");
	outtextxy(10, 10, "见缝插针");

	// 按钮
	setlinecolor(RGB(20, 130, 255));
	roundrect(180, 10, 290, 60, 10, 10);
	settextstyle(30, 13, "楷体");
	outtextxy(185, 20, "返回主页");
	roundrect(300, 10, 410, 60, 10, 10);
	outtextxy(305, 20, "退出游戏");
}
主页界面

显示一行字“见缝插针”,再放两个按钮。

// 主页
void Home()
{
	BeginBatchDraw();
	while (true)
	{
		setbkcolor(RGB(150, 230, 255));
		cleardevice();

		settextcolor(RGB(20, 130, 255));
		settextstyle(130, 55, "隶书");
		outtextxy(230, 150, "见缝插针");

		setlinecolor(RGB(20, 130, 255));
		setlinestyle(PS_SOLID, 3);
		roundrect(350, 350, 550, 420, 10, 10);
		settextstyle(45, 20, "楷体");
		outtextxy(370, 360, "开始游戏");
		roundrect(350, 460, 550, 530, 10, 10);
		outtextxy(370, 470, "退出游戏");

		MOUSEMSG msg = GetMouseMsg();
		if (msg.uMsg == WM_LBUTTONDOWN)
		{
			if (msg.x >= 350 && msg.x <= 550)
			{
				if (msg.y >= 350 && msg.y <= 420)
				{
					break;
				}
				if (msg.y >= 460 && msg.y <= 530)
				{
					closegraph();
					exit(0);
				}
			}
		}
		FlushBatchDraw();
	}
	EndBatchDraw();
}
Main 函数
int main()
{
	initgraph(WIDTH, HEIGHT);
	while (true)
	{
		Home();
		Init();
		BeginBatchDraw();
		while (true)
		{
			setbkcolor(RGB(150, 230, 255));
			cleardevice();
			CreatePin();
			MovePin();
			Draw();
			if (MouseHit())
			{
				MOUSEMSG msg = GetMouseMsg();
				if (msg.uMsg == WM_LBUTTONDOWN)
				{
					if (msg.y >= 10 && msg.y <= 60)
					{
						if (msg.x >= 180 && msg.x <= 290)
						{
							break;
						}
						if (msg.x >= 300 && msg.x <= 410)
						{
							closegraph();
							exit(0);
						}
					}
				}
			}
			FlushBatchDraw();
			Sleep(10);
            if (speed == 0)
            {
                break;
            }
		}
		EndBatchDraw();
	}
	return 0;
}
扩展功能
音效

上一篇文章我讲过,这里我懒得讲了

ready go音效_站长素材ready go音效_站长素材https://sc.chinaz.com/yinxiao/150112584240.htmgame over游戏声_站长素材game over游戏声_站长素材https://sc.chinaz.com/yinxiao/130130363410.htm speed == 0 判断处加入:

PlaySound(".\\Game Over.wav", NULL, SND_ASYNC | SND_FILENAME);
Sleep(1000);

Init 函数调用的后面,即游戏开始前,加入:

cleardevice();
Draw();
PlaySound(".\\Ready Go.wav", NULL, SND_ASYNC | SND_FILENAME);
Sleep(1000);
调整速度

根据得分,速度不断增加

// 调整速度
void ChangeSpeed()
{
	if (speed == 0) return;
	if (pin_num <= 10) speed = PI / 360;
	else if (pin_num <= 30) speed = PI / 240;
	else if (pin_num <= 50) speed = PI / 180;
	else if (pin_num <= 70) speed = PI / 120;
	else if (pin_num <= 100) speed = PI / 60;
	else speed = PI / 50;
}

文章最后有完整代码!

效果截图

B8F56820-C1E8-0F4A-B83A-9CEA965C0EB9.png

45C62F61-E519-DE66-7843-6865F28AFFDD.png

完整代码
/*
* 项目名称:见缝插针
* 开发环境:vs2022 + Easyx
* 作者:轩
* 代码长度:232 行
* 完成时间:2023.1.8
* 用时:2 小时
*/

#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <graphics.h>
#pragma comment(lib, "winmm.lib")
#define HEIGHT 800
#define WIDTH 900
#define PI 3.1415926
#define PIN_L 120.0
#define RADIO 120

float pin_angle[1000];
int pin_num = 0;
float speed = PI / 360;


// 取差的绝对值
float absent(float a, float b)
{
	if (a > b) return a - b;
	else return b - a;
}

// 主页
void Home()
{
	BeginBatchDraw();
	while (true)
	{
		setbkcolor(RGB(150, 230, 255));
		cleardevice();

		settextcolor(RGB(20, 130, 255));
		settextstyle(130, 55, "隶书");
		outtextxy(230, 150, "见缝插针");

		setlinecolor(RGB(20, 130, 255));
		setlinestyle(PS_SOLID, 3);
		roundrect(350, 350, 550, 420, 10, 10);
		settextstyle(45, 20, "楷体");
		outtextxy(370, 360, "开始游戏");
		roundrect(350, 460, 550, 530, 10, 10);
		outtextxy(370, 470, "退出游戏");

		MOUSEMSG msg = GetMouseMsg();
		if (msg.uMsg == WM_LBUTTONDOWN)
		{
			if (msg.x >= 350 && msg.x <= 550)
			{
				if (msg.y >= 350 && msg.y <= 420)
				{
					break;
				}
				if (msg.y >= 460 && msg.y <= 530)
				{
					closegraph();
					exit(0);
				}
			}
		}
		FlushBatchDraw();
	}
	EndBatchDraw();
}

void Init()
{
	pin_num = 0;
	speed = PI / 360;
}

// 调整速度
void ChangeSpeed()
{
	if (speed == 0) return;
	if (pin_num <= 10) speed = PI / 360;
	else if (pin_num <= 30) speed = PI / 240;
	else if (pin_num <= 50) speed = PI / 180;
	else if (pin_num <= 70) speed = PI / 120;
	else if (pin_num <= 100) speed = PI / 60;
	else speed = PI / 50;
}

// 移动针
void MovePin()
{
	for (int i = 0; i < pin_num; i++)
	{
		pin_angle[i] += speed;
		if (pin_angle[i] > 2 * PI)
		{
			pin_angle[i] -= 2 * PI;
		}
	}
}

// 绘制
void Draw()
{
	// 针
	setlinecolor(RGB(20, 130, 255));
	line(0, HEIGHT / 2, PIN_L, HEIGHT / 2);
	for (int i = 0; i < pin_num; i++)
	{
		float endx = (PIN_L + RADIO) * cos(-pin_angle[i]) + WIDTH / 2;
		float endy = (PIN_L + RADIO) * sin(-pin_angle[i]) + HEIGHT / 2;
		setlinecolor(RGB(20, 130, 255));
		setfillcolor(RGB(20, 130, 255));
		if (i == pin_num - 1)
		{
			setlinecolor(RED);
			setfillcolor(RED);
		}
		line(WIDTH / 2, HEIGHT / 2, endx, endy);
		fillcircle(endx, endy, 10);
	}

	// 圆
	setlinecolor(RGB(20, 130, 255));
	setfillcolor(RGB(70, 180, 255));
	setlinestyle(PS_SOLID, 3);
	fillcircle(WIDTH / 2, HEIGHT / 2, RADIO);

	// 得分
	char text[20];
	sprintf_s(text, "%d", pin_num);
	setbkcolor(RGB(70, 180, 255));
	settextcolor(WHITE);
	settextstyle(50, 20, "宋体");
	outtextxy(WIDTH / 2 - 20, HEIGHT / 2 - 15, text);

	// 标题
	settextcolor(RGB(20, 130, 255));
	setbkcolor(RGB(150, 230, 255));
	settextstyle(45, 20, "隶书");
	outtextxy(10, 10, "见缝插针");

	// 按钮
	setlinecolor(RGB(20, 130, 255));
	roundrect(180, 10, 290, 60, 10, 10);
	settextstyle(30, 13, "楷体");
	outtextxy(185, 20, "返回主页");
	roundrect(300, 10, 410, 60, 10, 10);
	outtextxy(305, 20, "退出游戏");
}

// 发射针
void CreatePin()
{
	if (_kbhit() && speed != 0)
	{
		char input = _getch();
		if (input == ' ')
		{
			// 增加一根针
			pin_num++;
			pin_angle[pin_num - 1] = PI;
			
			// 是否重合
			for (int i = 0; i < pin_num - 1; i++)
			{
				if (absent(pin_angle[i], pin_angle[pin_num - 1]) < (PI / 40))
				{
					speed = 0;
					return;
				}
			}
		}
	}
}

int main()
{
	initgraph(WIDTH, HEIGHT);
	while (true)
	{
		Home();
		Init();
		cleardevice();
		Draw();
		PlaySound(".\\Ready Go.wav", NULL, SND_ASYNC | SND_FILENAME);
		Sleep(1000);
		BeginBatchDraw();
		while (true)
		{
			setbkcolor(RGB(150, 230, 255));
			cleardevice();
			CreatePin();
			MovePin();
			ChangeSpeed();
			Draw();
			if (MouseHit())
			{
				MOUSEMSG msg = GetMouseMsg();
				if (msg.uMsg == WM_LBUTTONDOWN)
				{
					if (msg.y >= 10 && msg.y <= 60)
					{
						if (msg.x >= 180 && msg.x <= 290)
						{
							break;
						}
						if (msg.x >= 300 && msg.x <= 410)
						{
							closegraph();
							exit(0);
						}
					}
				}
			}
			FlushBatchDraw();
			Sleep(10);
			if (speed == 0)
			{
				PlaySound(".\\Game Over.wav", NULL, SND_ASYNC | SND_FILENAME);
				Sleep(1000);
				break;
			}
		}
		EndBatchDraw();
	}
	return 0;
}
收藏 (0)
评论列表
正在载入评论列表...
我是有底线的