C++ Getting Started - Implementing the Sew and Pin Game

Reference resources

  1. C and C++ Game Fun Programming Kid Crystal

To make use of every bit of time

"Pin in Seam" Game: Press the space bar and send a pin onto the disc. All the pins turn counterclockwise. If a new pin hits an existing pin, the game ends

Draw discs and needles

Draw a circle to represent a disc, a line segment to represent a needle, and the coordinates of the center of the circle and the starting point of the segment are (width/2, height/2)

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

int main()
{
	int width = 800;
	int height = 600;
	initgraph(width, height);
	setbkcolor(RGB(255, 255, 255));
	cleardevice();

	setlinestyle(PS_SOLID, 3);								   // Line width 3
	setlinecolor(RGB(0, 0, 0));
	line(width / 2, height / 2, width / 2 + 160, height / 2);  // Draw a needle

	setlinecolor(HSVtoRGB(0, 0.9, 0.8));                       // Set the disc line color to red
	circle(width / 2, height / 2, 60);

	_getch();
	closegraph();
	return 0;
}

Rotation of needle

The start coordinate of the needle is the center of the picture (width/2, height/2). Assuming the length of the needle is lineLength and the rotation angle of the needle is angle, the end coordinate of the needle (xEnd, yEnd) can be calculated by the trigonometric function. Then, the rotation effect of the needle can be achieved by increasing the angle of the needle gradually.

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

int main()
{
	float PI = 3.1415926;
	int width = 800;
	int height = 600;
	initgraph(width, height);
	setbkcolor(RGB(255, 255, 255));

	float lineLength = 160;
	float xEnd, yEnd;
	float angle = 0;
	float rotateSpeed = PI / 360;

	setlinestyle(PS_SOLID, 3);								 // Line width 3
	while (1)
	{
		cleardevice();
		angle += rotateSpeed;
		if (angle > 2 * PI)                                  // Prevent angle data from increasing indefinitely
		{
			angle -= 2 * PI;
		}
		xEnd = lineLength * cos(-angle) + width / 2;         // Calculate the end coordinates of a needle
		yEnd = lineLength * sin(-angle) + height / 2;
		setlinecolor(RGB(0, 0, 0));
		line(width / 2, height / 2, xEnd, yEnd);             // Draw a needle
		setlinecolor(HSVtoRGB(0, 0.9, 0.8));                 // Set the disc line color to red
		circle(width / 2, height / 2, 60);
		Sleep(10);
	}
	closegraph();
	return 0;
}

Batch Draw Multiple Needles

Use arrays to record the angle values of each needle. In addition, when more elements are drawn, an apparent picture flicker occurs, and the batch drawing function can be used. BeginBatchDraw() is used to start a batch drawing, and any drawing operation will be temporarily off-screen until FlushBatchDraw() or EndBatchDraw() outputs the previous drawing.

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

int main()
{
	float PI = 3.1415926;
	int width = 800;
	int height = 600;
	initgraph(width, height);
	setbkcolor(RGB(255, 255, 255));
	setlinestyle(PS_SOLID, 3);								     // Line width 3

	float lineLength = 160;
	float xEnd, yEnd;
	float rotateSpeed = PI / 360;
	int lineNum = 20;
	float Angles[20];
	int i;
	for (i = 0; i < lineNum; i++)
	{
		Angles[i] = i * 2 * PI / lineNum;
	}

	BeginBatchDraw();                                           
	while (1)
	{
		cleardevice();
		setlinecolor(RGB(0, 0, 0));
		for (i = 0; i < lineNum; i++)
		{
			Angles[i] += rotateSpeed;
			if (Angles[i] > 2 * PI)                              // Prevent angle data from increasing indefinitely
			{
				Angles[i] -= 2 * PI;
			}
			xEnd = lineLength * cos(-Angles[i]) + width / 2;     // Calculate the end coordinates of a needle
			yEnd = lineLength * sin(-Angles[i]) + height / 2;
			line(width / 2, height / 2, xEnd, yEnd);             // Draw a needle
			
		}

		setlinecolor(HSVtoRGB(0, 0.9, 0.8));                     // Set the disc line color to red
		circle(width / 2, height / 2, 60);
		FlushBatchDraw();
		Sleep(10);
	}
	closegraph();
	return 0;
}

Needle Launch and Addition

First draw a pin on the left side of the screen to indicate the location to be emitted; when the user presses the space bar, the number of pins is increased by 1, and the initial angle of the newly added pin is PI. The user continuously presses the space bar to generate new pins

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

int main()
{
	float PI = 3.1415926;
	int width = 800;
	int height = 600;
	initgraph(width, height);
	setbkcolor(RGB(255, 255, 255));
	setlinestyle(PS_SOLID, 3);								     // Line width 3

	float lineLength = 160;
	float xEnd, yEnd;
	float rotateSpeed = PI / 360;
	int lineNum = 0;
	float Angles[1000];
	int i;

	BeginBatchDraw();                                           
	while (1)
	{
		cleardevice();
		setlinecolor(RGB(0, 0, 0));
		line(0, height / 2, lineLength, height / 2);             // A pin in the left firing area

		for (i = 0; i < lineNum; i++)
		{
			Angles[i] += rotateSpeed;
			if (Angles[i] > 2 * PI)                              // Prevent angle data from increasing indefinitely
			{
				Angles[i] -= 2 * PI;
			}
			xEnd = lineLength * cos(-Angles[i]) + width / 2;     // Calculate the end coordinates of a needle
			yEnd = lineLength * sin(-Angles[i]) + height / 2;
			line(width / 2, height / 2, xEnd, yEnd);             // Draw a needle
		}

		if (_kbhit())
		{
			char input = _getch();
			if (input == ' ')                                    // If Spacebar
			{
				lineNum++;
				Angles[lineNum - 1] = PI;
				xEnd = lineLength * cos(-Angles[lineNum - 1]) + width / 2;
				yEnd = lineLength * sin(-Angles[lineNum - 1]) + height / 2;
				line(width / 2, height / 2, xEnd, yEnd);
			}
		}
		setlinecolor(HSVtoRGB(0, 0.9, 0.8));                     // Set the disc line color to red
		circle(width / 2, height / 2, 60);
		FlushBatchDraw();
		Sleep(10);
	}
	closegraph();
	return 0;
}

Game Failure Judgment

When the absolute difference of rotation angle between the two pins is less than PI/60, collision is judged

for (i = 0; i < lineNum - 1; i++)                // Compare new needles with all previous ones
{
	if (fabs(Angles[lineNum - 1] - Angles[i]) < PI / 60)
	{
		rotateSpeed = 0;                         // Stop rotating if colliding
		break;
	}
}

Score and display improvement

When the user presses the space bar and the game does not fail, the score increases by 1:

score += 1;

Finally, convert the score to string output:

TCHAR s[20]; // Define String Array
_stprintf(s, _T("%d"), score);
settextstyle(50, 0, _T("Times"));
settextcolor(RGB(50, 50, 50));
outtextxy(65, 200, s);

Fill the drawing disc, and as the number of pins increases, the disc filling color becomes more vibrant:

setfillcolor(HSVtoRGB(0, lineNum / 60.0, 0.8));
setlinecolor(HSVtoRGB(0, 0.9, 0.8));
fillcircle(width / 2, height / 2);

Set the color of the spinning needle to blue and the newly launched needle to red:

setlinecolor(RGB(0, 0, 255));
if (i == lineNum - 1)
{
	setlinecolor(RGB(255, 0, 0));
}

Complete Code

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

int main()
{
	float PI = 3.1415926;
	int width = 800;
	int height = 600;
	initgraph(width, height);
	setbkcolor(RGB(255, 255, 255));
	setlinestyle(PS_SOLID, 3);								     // Line width 3

	float lineLength = 160;
	float xEnd, yEnd;
	float rotateSpeed = PI / 360;
	int lineNum = 0;
	float Angles[1000];
	int score = 0;
	int i;

	BeginBatchDraw();                                           
	while (1)
	{
		cleardevice();
		setlinecolor(RGB(0, 0, 0));
		line(0, height / 2, lineLength, height / 2);             // A pin in the left firing area

		for (i = 0; i < lineNum; i++)
		{
			Angles[i] += rotateSpeed;
			if (Angles[i] > 2 * PI)                              // Prevent angle data from increasing indefinitely
			{
				Angles[i] -= 2 * PI;
			}
			xEnd = lineLength * cos(-Angles[i]) + width / 2;     // Calculate the end coordinates of a needle
			yEnd = lineLength * sin(-Angles[i]) + height / 2;
			setlinecolor(RGB(0, 0, 255));                        // Set the color of the pin to blue
			if (i == lineNum - 1)
			{
				setlinecolor(RGB(255, 0, 0));                    // The new pin is red
			}
			line(width / 2, height / 2, xEnd, yEnd);             // Draw a needle
		}

		if (_kbhit() && rotateSpeed != 0)
		{
			char input = _getch();
			if (input == ' ')                                    // If Spacebar
			{
				lineNum++;
				Angles[lineNum - 1] = PI;
				xEnd = lineLength * cos(-Angles[lineNum - 1]) + width / 2;
				yEnd = lineLength * sin(-Angles[lineNum - 1]) + height / 2;
				line(width / 2, height / 2, xEnd, yEnd);
				for (i = 0; i < lineNum - 1; i++)                // Compare new needles with all previous ones
				{
					if (fabs(Angles[lineNum - 1] - Angles[i]) < PI / 60)
					{
						rotateSpeed = 0;                         // Stop rotating if colliding
						break;
					}
				}
				score += 1;
			}
		}
		setfillcolor(HSVtoRGB(0, lineNum / 60.0, 0.8));          // The more needles, the brighter the disc color
		setlinecolor(HSVtoRGB(0, 0.9, 0.8));                     // Disc lines are red
		fillcircle(width / 2, height / 2, 60);                   // Draw the middle disc
		TCHAR s[20];                                             // Define String Array
		swprintf_s(s, _T("%d"), score);
		settextstyle(50, 0, _T("Times"));                        // Set text size, font
		settextcolor(RGB(50, 50, 50));
		outtextxy(65, 200, s);

		FlushBatchDraw();
		Sleep(10);
	}
	closegraph();
	return 0;
}

Keywords: C++

Added by nite4000 on Thu, 30 Sep 2021 19:05:36 +0300