参考
- 《C和C++游戏趣味编程》 童晶
见缝插针
“见缝插针”游戏:按下空格键后发射一根针到圆盘上,所有针逆时针方向转动;如果新发射的针碰到已有的针,游戏结束
绘制圆盘与针
绘制一个圆表示圆盘、一条线段表示一根针,圆心坐标及线段起点坐标均为(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); // 线宽为3
setlinecolor(RGB(0, 0, 0));
line(width / 2, height / 2, width / 2 + 160, height / 2); // 绘制一根针
setlinecolor(HSVtoRGB(0, 0.9, 0.8)); // 设置圆盘线条颜色为红色
circle(width / 2, height / 2, 60);
_getch();
closegraph();
return 0;
}
针的旋转
针的起点坐标为画面中心(width/2, height/2),假设针的长度为lineLength,针的旋转角度为angle,则由三角函数可以求出针的末端坐标(xEnd, yEnd)。然后,让针的角度逐渐增加,就实现了针的旋转效果
#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); // 线宽为3
while (1)
{
cleardevice();
angle += rotateSpeed;
if (angle > 2 * PI) // 防止角度数据无限增加
{
angle -= 2 * PI;
}
xEnd = lineLength * cos(-angle) + width / 2; // 计算针的末端坐标
yEnd = lineLength * sin(-angle) + height / 2;
setlinecolor(RGB(0, 0, 0));
line(width / 2, height / 2, xEnd, yEnd); // 绘制一根针
setlinecolor(HSVtoRGB(0, 0.9, 0.8)); // 设置圆盘线条颜色为红色
circle(width / 2, height / 2, 60);
Sleep(10);
}
closegraph();
return 0;
}
批量绘制多根针
用数组记录每根针的角度值。另外,当绘制的元素较多时,会出现明显的画面闪烁,这时可以使用批量绘图函数。BeginBatchDraw()用于开始批量绘图,执行后任何绘图操作都将暂时不输出到屏幕上,直到FlushBatchDraw()或EndBatchDraw()才将之前的绘图输出
#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); // 线宽为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) // 防止角度数据无限增加
{
Angles[i] -= 2 * PI;
}
xEnd = lineLength * cos(-Angles[i]) + width / 2; // 计算针的末端坐标
yEnd = lineLength * sin(-Angles[i]) + height / 2;
line(width / 2, height / 2, xEnd, yEnd); // 绘制一根针
}
setlinecolor(HSVtoRGB(0, 0.9, 0.8)); // 设置圆盘线条颜色为红色
circle(width / 2, height / 2, 60);
FlushBatchDraw();
Sleep(10);
}
closegraph();
return 0;
}
针的发射与新增
首先在画面左边绘制一根针,表示待发射的位置;当用户按下空格键,针的个数加1,并且新增加的针初始角度为PI。用户不断按下空格键,即可持续生成新的针
#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); // 线宽为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); // 左边发射区域的一根针
for (i = 0; i < lineNum; i++)
{
Angles[i] += rotateSpeed;
if (Angles[i] > 2 * PI) // 防止角度数据无限增加
{
Angles[i] -= 2 * PI;
}
xEnd = lineLength * cos(-Angles[i]) + width / 2; // 计算针的末端坐标
yEnd = lineLength * sin(-Angles[i]) + height / 2;
line(width / 2, height / 2, xEnd, yEnd); // 绘制一根针
}
if (_kbhit())
{
char input = _getch();
if (input == ' ') // 如果为空格键
{
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)); // 设置圆盘线条颜色为红色
circle(width / 2, height / 2, 60);
FlushBatchDraw();
Sleep(10);
}
closegraph();
return 0;
}
游戏失败判断
当两根针的旋转角度差的绝对值小于PI/60时,判断发生了碰撞
for (i = 0; i < lineNum - 1; i++) // 拿新的针和之前所有针比较
{
if (fabs(Angles[lineNum - 1] - Angles[i]) < PI / 60)
{
rotateSpeed = 0; // 如果碰撞,停止旋转
break;
}
}
得分与显示效果改进
当用户按空格键并且游戏没有失败,则得分增加1:
score += 1;
最后将score转换为字符串输出:
TCHAR s[20]; // 定义字符串数组
_stprintf(s, _T("%d"), score);
settextstyle(50, 0, _T("Times"));
settextcolor(RGB(50, 50, 50));
outtextxy(65, 200, s);
填充绘制圆盘,随着针数的增加,圆盘填充颜色越来鲜艳:
setfillcolor(HSVtoRGB(0, lineNum / 60.0, 0.8));
setlinecolor(HSVtoRGB(0, 0.9, 0.8));
fillcircle(width / 2, height / 2);
将正在旋转的针的颜色设为蓝色,最新发射的针的颜色设为红色:
setlinecolor(RGB(0, 0, 255));
if (i == lineNum - 1)
{
setlinecolor(RGB(255, 0, 0));
}
完整代码
#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); // 线宽为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); // 左边发射区域的一根针
for (i = 0; i < lineNum; i++)
{
Angles[i] += rotateSpeed;
if (Angles[i] > 2 * PI) // 防止角度数据无限增加
{
Angles[i] -= 2 * PI;
}
xEnd = lineLength * cos(-Angles[i]) + width / 2; // 计算针的末端坐标
yEnd = lineLength * sin(-Angles[i]) + height / 2;
setlinecolor(RGB(0, 0, 255)); // 设定旋转针的颜色为蓝色
if (i == lineNum - 1)
{
setlinecolor(RGB(255, 0, 0)); // 新增的针为红色
}
line(width / 2, height / 2, xEnd, yEnd); // 绘制一根针
}
if (_kbhit() && rotateSpeed != 0)
{
char input = _getch();
if (input == ' ') // 如果为空格键
{
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++) // 拿新的针和之前所有针比较
{
if (fabs(Angles[lineNum - 1] - Angles[i]) < PI / 60)
{
rotateSpeed = 0; // 如果碰撞,停止旋转
break;
}
}
score += 1;
}
}
setfillcolor(HSVtoRGB(0, lineNum / 60.0, 0.8)); // 针越多,圆盘颜色越鲜艳
setlinecolor(HSVtoRGB(0, 0.9, 0.8)); // 圆盘线条颜色为红色
fillcircle(width / 2, height / 2, 60); // 绘制中间的圆盘
TCHAR s[20]; // 定义字符串数组
swprintf_s(s, _T("%d"), score);
settextstyle(50, 0, _T("Times")); // 设置文字大小、字体
settextcolor(RGB(50, 50, 50));
outtextxy(65, 200, s);
FlushBatchDraw();
Sleep(10);
}
closegraph();
return 0;
}