CMakeLists + Win32 绘制金刚石图案
参考视频
#ifndef UNICODE
#define UNICODE
#endif
#include <math.h>
#include <Windows.h>
#include <stdio.h>
#include <wchar.h>
#define PI 3.1415926 // PI
#define ROUND(d) int(d+0.5) // 四舍五入
// 点
class CP2
{
public:
CP2() :_x(0), _y(0)
{
}
CP2(double x, double y)
{
_x = x;
_y = y;
}
virtual ~CP2() {};
public:
double _x;
double _y;
};
// 金刚石
class CDiamond
{
public:
CDiamond()
{
_n = 0;
_r = 0;
_p = NULL;
}
virtual ~CDiamond()
{
delete[] _p;
_p = NULL;
}
// 设置参数
void SetParmeter(int n, double r, CP2 pt)
{
_n = n;
_r = r;
_pt = pt;
_p = new CP2[n];
}
// 读入等分点
void ReadVertex()
{
double Theta = 2 * PI / _n; // 定义金刚石图案的等分角
for (size_t i = 0; i < _n; i++) // 计算等分点坐标
{
_p[i]._x = _r * cos(i * Theta);
_p[i]._y = _r * sin(i * Theta);
}
}
// 绘图
void Draw(HDC hDC)
{
for (size_t i = 0; i < _n - 1; i++) //直线链接等分点
{
for (size_t j = i + 1; j < _n; j++)
{
MoveToEx(hDC, ROUND(_pt._x + _p[i]._x), ROUND(_pt._y + _p[i]._y), NULL);
LineTo(hDC, ROUND(_pt._x + _p[j]._x), ROUND(_pt._y + _p[j]._y));
}
}
}
private:
int _n; // 等分点数
double _r; // 圆半径
CP2 _pt; // 中心点
CP2* _p; // 等分点一维数组
};
CDiamond* m_Diamond; // 图案对象指针
CP2 m_Pt; // 图案中心
int m_R, m_N; // 半径及等分点
int m_DirectionX, m_DirectionY; // 运动状态
int m_HalfClientWidth, m_HalfClientHeight; // 客户区半宽高
bool m_Paly; // 动画开关
HWND m_hwnd;
// 绘制物体
void DrawObject(HDC hdc)
{
// 初始化 金刚石图案
m_Diamond = new CDiamond();
m_Diamond->SetParmeter(m_N, m_R, m_Pt);
m_Diamond->ReadVertex();
m_Diamond->Draw(hdc);
delete m_Diamond;
}
// 边界测试
void CollisionDetection()
{
if (m_Pt._x + m_R >= m_HalfClientWidth) // 右侧碰撞
m_DirectionX = -1;
if (m_Pt._x - m_R <= -m_HalfClientWidth) // 左侧碰撞
m_DirectionX = 1;
if (m_Pt._y + m_R >= m_HalfClientHeight) // 上侧碰撞
m_DirectionY = -1;
if (m_Pt._y - m_R <= -m_HalfClientHeight) // 下侧碰撞
m_DirectionY = 1;
}
// 双缓冲
void DoubleBuffer(HDC hdc)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
// 内存DC
HDC memDC = CreateCompatibleDC(hdc); // 创建兼容DC 画板
HBITMAP newBitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); // 创建画布
HGDIOBJ oldBitmap = SelectObject(memDC,newBitmap); // 将画布选入画板
FillRect(memDC, &rc, (HBRUSH)(COLOR_WINDOW + 1));
DrawText(memDC, L"空格开始动画", wcslen(L"空格开始动画"), &rc, NULL);
SetMapMode(memDC, MM_ANISOTROPIC);
SetWindowExtEx(memDC, rc.right, rc.bottom, NULL);
SetViewportExtEx(memDC, rc.right, rc.bottom, NULL);
SetViewportOrgEx(memDC, ROUND(rc.right / 2), ROUND(rc.bottom / 2), NULL);
DrawObject(memDC);
CollisionDetection();
BitBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, memDC, ROUND(-rc.right / 2) , ROUND(-rc.bottom / 2), SRCCOPY);
SelectObject(memDC, oldBitmap);
DeleteObject(newBitmap);
DeleteDC(memDC);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (uMsg)
{
case WM_TIMER:
m_Pt._x += m_DirectionX;
m_Pt._y += m_DirectionY;
InvalidateRect(hwnd,NULL,FALSE);
return 0;
case WM_KEYDOWN:
// 按下空格
if (GetKeyState(VK_SPACE) & 0x8000)
{
m_Paly = !m_Paly;
}
if (m_Paly)
{
// 产生 WM_TIMER 消息
SetTimer(hwnd, 0,10, NULL);
}
else
{
// 销毁 WM_TIMER 消息
KillTimer(hwnd, 0);
}
return 0;
case WM_PAINT:
{
RECT rect;
GetClientRect(hwnd,&rect);
m_HalfClientWidth = rect.right/2;
m_HalfClientHeight = rect.bottom / 2;
hdc = BeginPaint(hwnd, &ps);
DoubleBuffer(hdc);
EndPaint(hwnd, &ps);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"02-双缓冲动画算法";
WNDCLASS wc = { };
wc.style = CS_HREDRAW | CS_VREDRAW; // 重新绘制整个工作区
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"02-双缓冲动画算法", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
m_hwnd = hwnd;
m_Pt = CP2(0, 0);
m_N = 20;
m_R = 200;
m_DirectionX = 1;
m_DirectionY = 1;
m_Paly = false;
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}