模拟物理碰撞要解决的几个问题:
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,并没有加入多线程等技术,所以程序里的坐标等数据的同步并不精准,上,下,左,右键最好是短暂地点一下即松开,连着按的话会出现速度的突兀变化):
/** * 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://download.csdn.net/detail/mzlogin/4059869