博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
获取鼠标的原始移动值
阅读量:6307 次
发布时间:2019-06-22

本文共 7724 字,大约阅读时间需要 25 分钟。

获取鼠标的原始移动值,应用于类似cs中鼠标移动,控制相机的转向问题!

最近在模仿cs的部分功能,做一个小射击游戏。用w-a-s-d控制相机在平面上移动,用鼠标控制转向时,遇到一个问题。获取鼠标位置时,使用的是GetCursorPos方法,这个方面返回鼠标的当前屏幕坐标,这样就存在一个问题:假设鼠标当前坐标p0(x,y) =(300, 300)移动鼠标向右,此时p1(500, 400),这样有个

delta(500-300, 400 - 300) = (200, 100),此时,鼠标向右移动,对应相机在3D坐标中的方向,应该是以y轴为中心,顺时针旋转,但此时能转动的最大角度就是 ScreenWidth - p0.x,如果想一直不停地转圈圈,则不能实现。

解决方法有两个:

1、当检测到鼠标位置超出范围时,将其重新设置成屏幕中心(类似一个相对小的值),这样当下次鼠标继续向一个方面时,能够重新利用delta值转动相机

/*if (curPos.x || curPos.x >= VAL_WINDOW_WIDTH)

   {
   curPos.x = VAL_WINDOW_WIDTH/2;
   }
   if (curPos.y || curPos.y >= VAL_WINDOW_HEIGHT)
   {
   curPos.y = VAL_WINDOW_HEIGHT/2;
   }*/

SetCursorPos(curPos.x, curPos.y);

2、利用下面的方法,获取鼠标的移动的相对位置,比如说鼠标当前在位置p0(x0,y0),当我们移动鼠标时,鼠标值会有个相对前一个点位置的变化值

pDelta(xdelta, ydelta),这样就可以直接获取这个值来转动相机,而不需要利用方法1来计算相对位置。获取方法如下,转自msdn

Introduction

A standard computer mouse returns data at 400 dots per inch (DPI), whereas a high-definition mouse generates data at 800 DPI or greater. This makes input from a high-definition mouse much more precise than that from a standard mouse. However, high-definition data cannot be obtained through the standard WM_MOUSEMOVE messages. In general, games will benefit from high-definition mouse devices but games that obtain mouse data using just WM_MOUSEMOVE won't be able to access the full, un-filtered resolution of the mouse.

A number of companies are manufacturing high-definition mouse devices, such as Microsoft and Logitech. With the increasing popularity of high-resolution mouse devices, it is important that developers understand how to use the information generated by these devices optimally. This article focuses on the best way to optimize the performance of such mouse input in a game like a first-person shooter.

More general information about high-definition input devices can be found on product Web sites, like .

Retrieving Mouse Movement Data

There are three primary methods to retrieve mouse data:

There are advantages and disadvantages to each method, depending on how the data will be used.

WM_MOUSEMOVE

The simplest method of reading mouse movement data is through WM_MOUSEMOVE messages. The following is example of how to read mouse movement data from the WM_MOUSEMOVE message:

case WM_MOUSEMOVE:    {        int xPosAbsolute = GET_X_PARAM(lParam);         int yPosAbsolute = GET_Y_PARAM(lParam);        // ...        break;    }

The primary disadvantage to data from WM_MOUSEMOVE is that it is limited to the screen resolution. This means that if you move the mouse slightly — but not enough to cause the pointer to move to the next pixel — then no WM_MOUSEMOVE message is generated. So, using this method to read mouse movement negates the benefits of high-definition input.

The advantage to WM_MOUSEMOVE, however, is that Windows applies pointer acceleration (also known as ballistics) to the raw mouse data, which makes the mouse pointer behave as customers expect. This makes WM_MOUSEMOVE the preferred option for pointer control (over WM_INPUT or DirectInput), since it results in more natural behavior for users. While WM_MOUSEMOVE is ideal for moving mouse pointers, it is not so good for moving a first-person camera, since the high-definition precision will be lost.

More information about WM_MOUSEMOVE can be found at

WM_INPUT

The second method of obtaining mouse data is to read WM_INPUT messages. Processing WM_INPUT messages is more complicated than processing WM_MOUSEMOVE messages, but WM_INPUT messages are read directly from the Human Interface Device (HID) stack and reflect high-definition results.

To read mouse movement data from the WM_INPUT message, the device must first be registered; the following code provides an example of this:

#ifndef HID_USAGE_PAGE_GENERIC    #define HID_USAGE_PAGE_GENERIC         ((USHORT) 0x01)    #endif    #ifndef HID_USAGE_GENERIC_MOUSE    #define HID_USAGE_GENERIC_MOUSE        ((USHORT) 0x02)    #endif    RAWINPUTDEVICE Rid[1];    Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;     Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;     Rid[0].dwFlags = RIDEV_INPUTSINK;       Rid[0].hwndTarget = hWnd;    RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]);

The following code handles WM_INPUT messages in the application's WinProc handler:

case WM_INPUT:     {        UINT dwSize = 40;        static BYTE lpb[40];            GetRawInputData((HRAWINPUT)lParam, RID_INPUT,                         lpb, &dwSize, sizeof(RAWINPUTHEADER));            RAWINPUT* raw = (RAWINPUT*)lpb;            if (raw->header.dwType == RIM_TYPEMOUSE)         {            int xPosRelative = raw->data.mouse.lLastX;            int yPosRelative = raw->data.mouse.lLastY;        }         break;    }

The advantage to using WM_INPUT is that your game receives raw data from the mouse at the lowest level possible.

The disadvantage is that WM_INPUT has no ballistics applied to its data, so if you want to drive a cursor with this data, extra effort will be required to make the cursor behave like it does in Windows. For more information about applying pointer ballistics, see

More information about WM_INPUT can be found at

DirectInput

DirectInput is a set of API calls that abstracts input devices on the system. Internally, DirectInput creates a second thread to read WM_INPUT data, and using the DirectInput APIs will add more overhead than simply reading WM_INPUT directly. DirectInput is only useful for reading data from DirectInput joysticks; however, if you only need to support the Xbox 360 controller for Windows, then use XInput instead. Overall, using DirectInput offers no advantages when reading data from mouse or keyboard devices, and the use of DirectInput in these scenarios is discouraged.

Compare the complexity of using DirectInput, shown in the following code, to the methods previously described. The following set of calls are needed to create a DirectInput mouse:

LPDIRECTINPUT8 pDI;    LPDIRECTINPUTDEVICE8 pMouse;        hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,                              IID_IDirectInput8, (VOID**)&pDI, NULL );    if( FAILED(hr) )        return hr;        hr = pDI->CreateDevice( GUID_SysMouse, &pMouse, NULL );    if( FAILED(hr) )        return hr;        hr = pMouse->SetDataFormat( &c_dfDIMouse2 );    if( FAILED(hr) )        return hr;        hr = pMouse->SetCooperativeLevel( hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND );    if( FAILED(hr) )        return hr;        if( !bImmediate )    {        DIPROPDWORD dipdw;        dipdw.diph.dwSize       = sizeof(DIPROPDWORD);        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);        dipdw.diph.dwObj        = 0;        dipdw.diph.dwHow        = DIPH_DEVICE;        dipdw.dwData            = 16; // Arbitrary buffer size            if( FAILED( hr = pMouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) )            return hr;    }        pMouse->Acquire();

And then the DirectInput mouse device can be read each frame:

DIMOUSESTATE2 dims2;     ZeroMemory( &dims2, sizeof(dims2) );        hr = pMouse->GetDeviceState( sizeof(DIMOUSESTATE2),                                  &dims2 );    if( FAILED(hr) )     {        hr = pMouse->Acquire();        while( hr == DIERR_INPUTLOST )             hr = pMouse->Acquire();            return S_OK;     }        int xPosRelative = dims2.lX;    int yPosRelative = dims2.lY;

Summary

Overall, the best method to receive high-definition mouse movement data is WM_INPUT. If your users are just moving a mouse pointer, then consider using WM_MOUSEMOVE to avoid needing to perform pointer ballistics. Both of these window messages will work well even if the mouse isn't a high-definition mouse. By supporting high definition, Windows games can offer more precise control to users.

转载于:https://www.cnblogs.com/blong880123/archive/2012/07/08/2581197.html

你可能感兴趣的文章
宏定义函数的易错点
查看>>
洛谷【P2458】[SDOI2006]保安站岗 题解 树上DP
查看>>
Shredding Company 碎纸机,dfs()枚举每一种情况,再加剪枝。
查看>>
命名空间和模块化编程 - C++快速入门39
查看>>
结构化程序设计03 - 零基础入门学习Delphi12
查看>>
今天才知道怎么插入代码!!!!!!!!!
查看>>
D2007在64位Win7出现 delphi 2007 assertion failure thread32.cpp 的解决办法
查看>>
STM32的TAMPER-RTC管脚作为Tamper的使用[转]
查看>>
[记]一个逐步“优化”的范例程序
查看>>
2012-01-09_2
查看>>
Visual Studio 2015 开发MVC4出现错误
查看>>
MongoDB 学习笔记之 批处理
查看>>
orcale 之 存储过程
查看>>
A程序是B程序的输入
查看>>
java基础数组(带基础排序法)
查看>>
[20180316]理解db file parallel read等待事件.txt
查看>>
文件系统02 - 零基础入门学习Delphi35
查看>>
8.转型
查看>>
php类中调用array_walk()函数
查看>>
在线一键生成安卓证书keystore文件
查看>>