大球吃小球
2021-2-4
(0)
一、简介
大球吃小球,模拟自小游戏,左键按下状态拖动小球进行移动,躲避大球的同时尽量多吃小球。
玩法简单,程序也简单。开始界面按下左键开始游戏,按下右键退出程序。
新生球保护期:在 500ms 后可以被玩家吃到,在 800ms 后可以击杀玩家。
相同大小的小球碰撞时判断玩家失败。
二、游戏截图
三、游戏源码
/*
程序名称:
大球吃小球
简介:
模拟小游戏,左键按下状态拖动小球进行移动,躲避大球的同时尽量多吃小球
环境:
VS2019 + EasyX_20210115(beta)
时间:
2021.2.4
作者:
Teternity(QQ:1926594835)
版权:
作者原创,无抄袭,不涉及版权问题,仅用作学习
*/
/* ---------------头文件--------------- */
#include <iostream>
#include <vector>
#include <mutex>
#include <future>
#include <atomic>
#include <easyx.h>
#include <conio.h>
/* ---------------全局量--------------- */
const int win_width = 640; // 窗口宽
const int win_height = 468; // 窗口高
const int ir = 5; // 玩家控制的小球初始半径
int r = ir; // 玩家控制的小球半径
int score = 0; // 得分:所吃小球的半径之和
const int nBall = 38; // 小球数
int px = 320, py = 240; // 玩家控制的小球位置
const COLORREF color = WHITE; // 玩家控制的小球颜色
std::atomic_bool finished = false; // 是否结束
std::mutex drawMut; // 绘制锁
/* ---------------小球数据结构--------------- */
struct Ball
{
int r; // 半径
int px, py; // 位置
int dx, dy; // 方向
COLORREF color; // 颜色
clock_t speed, tcur, tborn; // 速度、当前刷新时间、创建时间
};
/* ---------------新建小球--------------- */
void NewBall(Ball& ball)
{
ball.r = rand() % 20 + 3;
ball.px = rand() % 640;
ball.py = rand() % 480;
ball.dx = (rand() % 3 + 1) * ((rand() % 100) > 50 ? 1 : -1);
ball.dy = (rand() % 3 + 1) * ((rand() % 100) > 50 ? 1 : -1);
ball.color = HSVtoRGB(rand() % 360, (rand() % 50 + 50) / 100.0f, (rand() % 50 + 50) / 100.0f);
ball.speed = rand() % 20 + 30;
ball.tcur = clock();
ball.tborn = clock();
}
/* ---------------根据小球颜色绘制小球--------------- */
void DrawBall(int x, int y, int r, COLORREF c, bool self = false)
{
drawMut.lock();
setfillcolor(c);
solidcircle(x, y, r);
if (self) circle(x, y, r + 4);
drawMut.unlock();
}
/* ---------------运行--------------- */
void RunThread()
{
srand((unsigned)time(nullptr));
// 创建小球并显示
std::vector<Ball> vb;
vb.resize(nBall);
for (int i = 0; i < nBall; ++i)
{
Ball ball{};
NewBall(ball);
vb[i] = ball;
}
for (auto& val : vb) DrawBall(val.px, val.py, val.r, val.color);
FlushBatchDraw();
auto it = vb.begin();
while (true)
{
if (it == vb.end()) it = vb.begin();
// 可以刷新位置
if (clock() - it->tcur >= it->speed)
{
DrawBall(it->px, it->py, it->r, it->color);
it->px += it->dx;
it->py += it->dy;
DrawBall(it->px, it->py, it->r, it->color);
FlushBatchDraw();
it->tcur = clock();
}
// 小球相撞
if (sqrt((px - it->px) * (px - it->px) + (py - it->py) * (py - it->py)) <= 1.0 * r + it->r)
{
// 结束
if (it->r >= r && clock() - it->tborn > 800)
{
finished = true;
return;
}
// 玩家吃到
else if (it->r < r && clock() - it->tborn > 500)
{
score += it->r;
DrawBall(it->px, it->py, it->r, it->color);
NewBall(*it);
DrawBall(it->px, it->py, it->r, it->color);
FlushBatchDraw();
}
}
// 小球出边界
else if (it->px < -it->r / 2 || it->px > 639 + it->r / 2 || it->py < -it->r / 2 || it->py > 479 + it->r / 2)
{
DrawBall(it->px, it->py, it->r, it->color);
NewBall(*it);
DrawBall(it->px, it->py, it->r, it->color);
FlushBatchDraw();
}
++it;
}
}
/* ---------------开始界面--------------- */
bool Start()
{
settextcolor(RGB(220, 140, 0));
settextstyle(48, 0, _T("楷体"));
const TCHAR* text = _T("大球吃小球");
outtextxy((win_width - textwidth(text)) / 2, (win_height - textheight(text)) / 8, text);
settextstyle(24, 0, _T("楷体"));
text = _T("左键按下开始游戏,右键按下退出");
outtextxy((win_width - textwidth(text)) / 2, (win_height - textheight(text)) / 2, text);
settextstyle(20, 0, _T("楷体"));
text = _T("左键按下拖动小球,躲避大球的同时尽量多的吃小球");
outtextxy((win_width - textwidth(text)) / 2, (win_height - textheight(text)) / 8 * 7, text);
MOUSEMSG msg{};
bool quit = true;
while (true)
{
if (MouseHit())
{
while (MouseHit()) msg = GetMouseMsg();
if (msg.uMsg == WM_LBUTTONDOWN)
{
quit = false;
break;
}
else if (msg.uMsg == WM_RBUTTONDOWN) break;
}
Sleep(1);
}
return !quit;
}
/* ---------------主程序--------------- */
int main()
{
initgraph(win_width, win_height, EW_NOMINIMIZE);
setrop2(R2_XORPEN);
if (Start()) cleardevice();
else
{
closegraph();
return 0;
}
while (true)
{
// 重置数据
r = ir;
score = 0;
px = 320;
py = 240;
finished = false;
// 绘制小球并运行线程
cleardevice();
setlinecolor(LIGHTGRAY);
DrawBall(px, py, r, color, true);
BeginBatchDraw();
std::thread(RunThread).detach();
// 游戏循环
bool ldown = false;
MOUSEMSG msg{};
int mx = -1, my = -1;
while (!finished)
{
if (MouseHit())
{
while (MouseHit()) msg = GetMouseMsg();
// 左键按下
if (msg.uMsg == WM_LBUTTONDOWN)
{
ldown = true;
mx = msg.x;
my = msg.y;
}
// 左键按下状态拖动鼠标
else if (ldown && msg.mkLButton && msg.uMsg == WM_MOUSEMOVE)
{
if (finished) break;
DrawBall(px, py, r, color, true);
px += msg.x - mx;
py += msg.y - my;
int temp = ir + score / 20;
if (temp < 20) r = temp;
DrawBall(px, py, r, color, true);
FlushBatchDraw();
mx = msg.x;
my = msg.y;
}
// 左键抬起
else if (msg.uMsg == WM_LBUTTONUP)
{
mx = -1;
my = -1;
}
}
Sleep(1);
}
EndBatchDraw();
// 结束弹窗
TCHAR text[128]{};
_stprintf_s(text, _T("恭喜你得分 %d,是否继续游戏?"), score);
if (IDNO == MessageBox(GetHWnd(), text, _T("游戏结束"), MB_YESNO)) break;
}
closegraph();
return 0;
}
添加评论
取消回复