我使用DirectX11编写简单的游戏引擎,并且我使用Win32 API创建窗口并处理用户输入。我正在实施一个光线投射例程来拾取和放置地形上的实体,并且一切正常,除了当我尝试在地面上放置一些东西时,它在顶部和左边有一个奇怪的偏移:
经过相当多的调试后我发现我的代码运行正常,问题在于我发送给光线投射类/函数的窗口坐标:
LRESULT Game::GameWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_LBUTTONDOWN:
/*MessageBox(mWindow, L"left mouse button clicked", L"CLICK", MB_OK);*/
Timer::GetInstance()->Stop();
-------> Input::GetInstance()->Place(lParam & 0xFFFF, lParam >> 16 & 0xFFFF, mCamera, mEntity, mTerrain, mRenderer);
return 0;
// ....
// .... other cases
}
}
鼠标光标的坐标不在0和窗口宽度/高度之间(在我的情况下为1024 X 768),但最大宽度为1004,最大高度为718(当我点击底部时,或多或少)窗口的右上角),这是我在调试应用程序时读到的内容。
最后证明,如果我在代码中使用这些宽度和高度,对象就会被放置在应有的位置。 所以我的问题是,坐标怎么不覆盖整个窗口大小?我错过了什么/做错了吗?我怎样才能得到正确的坐标?
修改
我的功能需要客户区域坐标,当然是窗口内的鼠标光标的坐标。
编辑编辑
这是我用来创建窗口的代码
void Game::InitializeWindow(HINSTANCE hInstance)
{
WNDCLASS windowClass = {};
windowClass.hInstance = hInstance;
windowClass.lpfnWndProc = &WndProc;
windowClass.lpszClassName = L"wndClass";
windowClass.lpszMenuName = NULL;
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
RegisterClass(&windowClass);
mWindow = CreateWindow(L"wndClass", L"DirectX 11 Engine", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, DisplayManager::GetInstance()->GetDisplayWidth(), DisplayManager::GetInstance()->GetDisplayHeight(), 0, 0, hInstance, 0);
if (!mWindow)
ErrorBox(L"window creation failed");
ShowWindow(mWindow, SW_SHOW);
UpdateWindow(mWindow);
}
答案 0 :(得分:3)
您从WM_LBUTTONDOWN
收到的坐标是客户坐标,并且是正确的。这里的真正问题源于窗口区域和客户区域之间的区别。
窗口区域包含整个窗口,包括标题栏和边框。您从RECT
获得的GetWindowRect
大小足以覆盖窗口的每个像素,以便在屏幕上叠加该大小的黑盒会导致整个窗口,标题栏和边框包含在内,消失。
然而,客户区是Windows为您创建的边框内的区域。您从RECT
获得的GetClientRect
足够大,再次,在屏幕上叠加一个大小的黑盒子将覆盖整个3D场景,但保留标题栏和边框可见。
这里的理论和定义都很好,但现在我们需要解决这个问题。事实证明,除了Remy Lebeau指出的API合规性问题(使用GET_X_LPARAM()
/ GET_Y_LPARAM()
而非转移)之外,您在窗口过程中使用的代码完全正常,无需修改。引入错误的实际位置是在窗口创建代码期间。
nWidth
的{{1}}和nHeight
参数指定了窗口的宽度和高度,而不是客户区。因此,您的客户区域将更小。但是,您希望客户区具有这些宽度。
事实证明,这是一个常见的事件,Windows 2000添加了一个函数来为给定的客户区域生成适当的窗口宽度和高度:CreateWindow
。要使用它,请将AdjustWindowRect
来电更改为以下内容:
CreateWindow
这将抵消您的坐标,以确保客户区域的大小与DisplayManager认为的大小完全相同。
修改强>
如果您有扩展窗口样式,RECT windowRect;
windowRect.top = 0;
windowRect.left = 0;
windowRect.right = DisplayManager::GetInstance()->GetDisplayWidth();
windowRect.bottom = DisplayManager::GetInstance()->GetDisplayHeight();
AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);
mWindow = CreateWindow(L"wndClass",
L"DirectX 11 Engine",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
windowRect.right,
windowRect.bottom,
0,
0,
hInstance,
0);
允许您将这些扩展窗口样式指定为该函数的附加第四个参数。