HGE (Haaf's Game Engine) 是一款輕量級 2D 遊戲引擎,適合學習遊戲核心循環與物理模擬。本文通過一個「快樂小球」Demo,展示如何在 Win32 SDK 原生環境下實現帶摩擦力的碰撞反彈,並討論聲音參數設計思路。
friction (0, 1),每幀 dx *= friction; dy *= friction; 模擬自然減速。x+dx, y+dy 是否超出邊界,若超出則位置修正(鏡像回彈)並速度取反(dx = -dx)。
/** collision.cpp - 小球封閉區域碰撞模擬 **/
#include <windows.h>
float x = 100.0f, y = 100.0f; // 球中心坐標
float speed = 10.0f; // 初始速度響應值
float friction = 0.99f; // 摩擦係數
float dx = 0.0f, dy = 0.0f; // 速度分量
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, PSTR, int nShow) {
WNDCLASS wc = {0};
wc.lpszClassName = "GenericAppClass";
wc.lpfnWndProc = MainWndProc;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = "GenericAppMenu";
RegisterClass(&wc);
HWND hWnd = CreateWindow("GenericAppClass", "Happy Ball",
WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,
100, 100, 800, 600, NULL, NULL, hInst, NULL);
ShowWindow(hWnd, nShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
static PAINTSTRUCT ps;
static HDC hDC;
static HBRUSH hBrush;
static RECT rect;
const int R = 16;
switch (msg) {
case WM_CREATE:
SetTimer(hwnd, 1, 5, NULL); // 5ms 定時器 ~200FPS 物理步進
hBrush = CreateSolidBrush(RGB(0,0,0));
return 0;
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
SelectObject(hDC, hBrush);
Ellipse(hDC, x-R, y-R, x+R, y+R); // 繪製小球
EndPaint(hwnd, &ps);
break;
case WM_KEYDOWN:
switch (wp) {
case VK_UP: dy -= speed; break;
case VK_DOWN: dy += speed; break;
case VK_LEFT: dx -= speed; break;
case VK_RIGHT: dx += speed; break;
}
break;
case WM_TIMER: { // 物理步進
dx *= friction; dy *= friction;
x += dx; y += dy;
GetClientRect(hwnd, &rect);
// X 軸邊界
if (x > rect.right - R) { x = (rect.right - R) - (x - (rect.right - R)); dx = -dx; }
if (x < R) { x = R + R - x; dx = -dx; }
// Y 軸邊界
if (y > rect.bottom - R) { y = rect.bottom - R - (y - (rect.bottom - R)); dy = -dy; }
if (y < R) { y = R + R - y; dy = -dy; }
InvalidateRect(hwnd, &rect, TRUE); // 觸發重繪
break;
}
case WM_DESTROY:
KillTimer(hwnd, 1);
DeleteObject(hBrush);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wp, lp);
}
SetTimer(hwnd, 1, 5, NULL) 每 5ms 觸發 WM_TIMER,在其中更新位置速度,而非在繪製消息中計算,實現渲染與邏輯解耦。
右邊界超出 delta = x - (right - R),修正位置 x = (right - R) - delta,等價於鏡像反射,保證球體不穿牆且能量守恆(忽略摩擦)。
WM_KEYDOWN 直接修改速度分量,而非位置,配合摩擦力產生「滑行感」。注意:長按按鍵會疊加速度,Demo 中建議輕點鬆開。
HGE 封裝了精靈、聲音、粒子系統,上述邏輯對應 hge->System_SetState(HGE_FRAMEFUNC, FrameFunc) 回調中執行,繪製用 hgeSprite->Render(x, y),聲音用 hge->Effect_PlayEx() 可直接設置音量、聲道、播放速率,無需手動計算聲道混合。
完整源碼與可執行文件:https://up.2cto.com/2012/0213/20120213111636377.rar
這個 Demo 雖簡單,卻包含了遊戲主循環、定時器驅動物理、邊界碰撞響應、鍵盤輸入處理、GDI 繪製等核心要素。理解這些基礎,是進階學習 HGE、Box2D、Unity 等引擎物理系統的紮實墊腳石。