模擬物理碰撞要解決的幾個問題:
1.怎樣模擬速度的變化?
設置一個摩擦系數friction(0<friction<1.0)和響應用戶按鍵之後的一個X坐標單時間片增量dx,一個Y坐標單時間片增量dy,每隔一個時間片dx *= friction; dy *= friction;只要參數設置得當,看起來就會覺得速度自然地減慢.因為我們所用的浮點數的數據類型的精度限制,物體在經過一定數量時間片後就會停下來.
2.怎樣模擬碰撞?
每個時間片處理過程中,判斷物體的邊緣坐標加上dx與dy後有沒有超過屏幕邊緣,如果超過,則采取一定的策略重新設置物體坐標讓其在正常范圍內,如X軸超過,則對dx取反;如Y軸超過,則對dy取反.計算好坐標之後再進行繪圖.
3.碰撞過程中的聲音處理
這裡涉及到音量,左右聲道,播放速度.對音量和播放速度可以按照場景來設置,可以考慮根據X,Y坐標作為其中一個參數.左右聲道比較合理的處理方案是根據窗口寬度和物體X坐標來決定左右聲道的混合比例.
WINDOWS SDK窗口對此過程的模擬(僅摹仿了速度和碰撞等,對聲音的相關處理貌似比較復雜,還沒搞清楚怎麼寫.由於是做個簡單DEMO,並沒有加入多線程等技術,所以程序裡的坐標等數據的同步並不精准,上,下,左,右鍵最好是短暫地點一下即松開,連著按的話會出現速度的突兀變化):
[cpp]
/**
* FILE : collision.cpp
* 功能 : 模擬一個小球在一個封閉區域內的碰撞等活動
* 作者 : mzlogin ( http://blog.csdn.net/mzlogin )
* 聲明 : 版權沒有 盜版不究
*/
#include <windows.h>
float x = 100.0f; // 球的中心點X坐標
float y = 100.0f; // 球的中心點Y坐標
float speed = 10.0f; // 球響應按鈕後的初始速度
float friction = 0.99f; // 球與地面的摩擦系數
float dx = 0.0f; // X軸增量
float dy = 0.0f; // Y軸增量
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
WNDCLASS wc;
MSG msg;
HWND hWnd;
if( !hPrevInstance )
{
wc.lpszClassName = "GenericAppClass";
wc.lpfnWndProc = MainWndProc;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
wc.lpszMenuName = "GenericAppMenu";
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClass( &wc );
}
hWnd = CreateWindow( "GenericAppClass",
"Happy Ball",
WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX) & (~WS_THICKFRAME),
100,
100,
800,
600,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow( hWnd, nCmdShow );
while( GetMessage( &msg, NULL, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
static HDC hDC;
static HBRUSH hBrush;
static RECT rect;
GetClientRect(hwnd, &rect);
const int nRadius = 16;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, 1, 5, NULL);
hBrush = CreateSolidBrush(RGB(0,0,0));
return 0;
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
SelectObject(hDC, hBrush);
Ellipse(hDC, x - nRadius, y - nRadius, x + nRadius, y + nRadius);
EndPaint(hwnd, &ps);
break;
case WM_KEYDOWN:
switch (wParam)
{
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;
if (x > rect.right - nRadius) { x = (rect.right - nRadius) - (x - (rect.right - nRadius)); dx = -dx; }
if (x < nRadius) { x = nRadius + nRadius - x; dx = -dx; }
if (y > rect.bottom - nRadius) { y = rect.bottom - nRadius - (y - (rect.bottom - nRadius)); dy = -dy; }
if (y < nRadius) {y = nRadius + nRadius - y; dy = -dy; }
InvalidateRect(hwnd, &rect, TRUE);
break;
case WM_DESTROY:
KillTimer(hwnd, 1);
DeleteObject(hBrush);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
HGE示例源碼及Win32SDK源碼及可運行程序下載地址:http://up.2cto.com/2012/0213/20120213111636377.rar
摘自 活該你挨踢