Jump to content
  • Advertisement
Sign in to follow this  
simpler

Weird bugs on different machines

This topic is 2773 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've just started testing my 2D game on different computers we got at home and I'm really confused with the issues I get.

I'm using DirectInput to keep track of the mouse position, I just add the delta of the mouse movent for each frame. However the position of the mouse cursor gets wrong as I move it around, it seems like it gets more wrong the faster I move (but i'm not 100% sure). Code:



// the directinput way

void Mouse::updateMouseDX(void)
{
mPos.x += gDInput->mouseDX();
mPos.y += gDInput->mouseDY();
}





float DirectInput::mouseDX()
{
return (float)mMouseState.lX;
}



This works great on my own computer but when I try on other ones I get the bug I described above, which feels really weird.

I tried to not use DirectInput as well, ended up with this:



void Mouse::updateMouseWIN(void)
{
static POINT tmpPos;
static int screenWidth = GetSystemMetrics(SM_CXFULLSCREEN);
static int screenHeight = GetSystemMetrics(SM_CYFULLSCREEN);
RECT windowRect;

GetCursorPos(&tmpPos);
GetWindowRect(mMainWnd, &windowRect);

// we don't want any coordinates outside the window
if(tmpPos.x <= windowRect.left)
mPos.x = windowRect.left;
else if(tmpPos.y <= windowRect.top)
mPos.y = windowRect.top;
else if(tmpPos.y >= windowRect.bottom)
mPos.y = windowRect.bottom;
else {
// correctment, the border etc
mPos.x = tmpPos.x - windowRect.left;
mPos.y = tmpPos.y - windowRect.top;

mPos.x-=8;
mPos.y-=30;
}

mDX = mPos.x - mLastPos.x;
mDY = mPos.y - mLastPos.y;

mLastPos = mPos;
}



Now the mouse coordinates don't messes up when I move it but the y coordinates are about 10 pixels displaced, so I have to click outside object to actually press them.


I don't know what could be causing this but I'm thinking about the resolution or something. The game is windowed with a size of 1400x900. The size of the window is correct on other machines as well, but on my laptop for example the screen resolution is greather then the one it works on, but the screen is smaller.


[font="'Arial Unicode MS"]I [/font]appreciate all help :)



Share this post


Link to post
Share on other sites
Advertisement
Why don't you get the mouse position from the window procedure? That's what most people do. You get perfect client-space coordinates that way.

Share this post


Link to post
Share on other sites
Will look into that for sure! Can I get the mouse movement as well, or do I have to calculate that myself?

Share this post


Link to post
Share on other sites
What do you mean by mouse movement? Are you talking about the relative difference between the last frame and the current one instead of the absolute mouse position on the window? If so, you'll need to calculate that yourself because the window procedure returns the absolute coordinates of the cursor. Still, that is easy to calculate if you really need it. All you do is take the current screen space position and subtract it from the previous one the last time the window procedure was called and it will give you the difference.

Edit: It works something like this:

int curX; // current x/y
int curY;
int relX; // current relative x/y coordinates from the last time the mouse moved
int relY;

LRESULT APIENTRY WndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_MOUSEMOVE:
int newX = GET_X_LPARAM(lParam);
int newY = GET_Y_LPARAM(lParam);
relX = newX - curX;
relY = newY - curY;
curX = newX;
curY = newY;
break;

default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
}

I've not done much in C++ in a while, but that should be correct.

Share this post


Link to post
Share on other sites
Yes I ment the difference. Thanks for the snippet, I'm not that experienced with using the window procedure so it was kind of you. Will try this out to see if it removes my problems!

Share this post


Link to post
Share on other sites
Doing it like you suggested works like a charm on my own computer, but on others I still get the same problem I had before. The Y coordinate is about 10 pixels wrong. The weird thing is that when I have it in the top left corner it's coordinates are correct, that is (0, 0). And when I move it to the bottom they are still what they should be. However when I'm clicking menu items then it's way off.

I have no idea why this is but I'm still thinking about the resolution :/

Here's a link if you want to test it: http://dl.dropbox.co...2D/Simply2D.rar

EDIT: It's only the custom level "noneB" that works

Share this post


Link to post
Share on other sites
Here is a class I wrote using direct input, which works perfectly on the pc's I have tested it on.

To use it just put this before your main loop;

Input *input=new Input(hWnd);

Then poll the mouse in your main loop;

input->pollMouse();
input->cursorUpdate();

And update your cursor / sprite position with the values returned by;

input->cursorGetX();
input->cursorGetY();

I'd love to know how you go :cool:

#pragma once
#define DIRECTINPUT_VERSION 0x0800

#include<Windows.h>
#include<dinput.h>

#pragma comment(lib,"dinput8.lib")
#pragma comment(lib,"dxguid.lib")

class Input
{
public:
DIMOUSESTATE2 mMouseState;

Input(HWND hWnd)
{
if(init==0)
{
mDInput=NULL;
mKeyboard=NULL;
mMouse=NULL;

DirectInput8Create(GetModuleHandle(NULL),DIRECTINPUT_VERSION,IID_IDirectInput8,(void**)&mDInput,NULL);

mDInput->CreateDevice(GUID_SysKeyboard,&mKeyboard,NULL);
mKeyboard->SetDataFormat(&c_dfDIKeyboard);
mKeyboard->SetCooperativeLevel(hWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
mKeyboard->Acquire();

mDInput->CreateDevice(GUID_SysMouse,&mMouse,NULL);
mMouse->SetDataFormat(&c_dfDIMouse2);
mMouse->SetCooperativeLevel(hWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE); // Mouse set to exclusive mode else NONEXCLUSIVE
mMouse->Acquire();
}
++(this->init);
}
~Input()
{
--(this->init);
if(init==0)
{
mMouse->Unacquire();
mMouse->Release();
mKeyboard->Unacquire();
mKeyboard->Release();
mDInput->Release();
}
}

public:
bool getKeyboard(int keycode)
{
mKeyboard->Acquire();
mKeyboard->GetDeviceState(sizeof(mKeyboardState),(void**)&mKeyboardState);
if((mKeyboardState[keycode]&0x80)!=0)
{
return true;
}
return false;
}

void pollMouse()
{
mMouse->Acquire();
mMouse->GetDeviceState(sizeof(DIMOUSESTATE2),(void**)&mMouseState);
return;
}

void cursorUpdate()
{
if(mMouseState.lX>0)
fMousePosX=fMousePosX+mMouseState.lX*(1+mMouseState.lX*0.025f);
if(mMouseState.lX<0)
fMousePosX=fMousePosX+mMouseState.lX*(1-mMouseState.lX*0.025f);
if(mMouseState.lY>0)
fMousePosY=fMousePosY+mMouseState.lY*(1+mMouseState.lY*0.025f);
if(mMouseState.lY<0)
fMousePosY=fMousePosY+mMouseState.lY*(1-mMouseState.lY*0.025f);
}

float cursorGetX()
{
if(fMousePosX<=-1)
fMousePosX=0;
if(fMousePosX>=(GetSystemMetrics(SM_CXSCREEN)))
fMousePosX=(float)(GetSystemMetrics(SM_CXSCREEN))-1;
return fMousePosX;
}

float cursorGetY()
{
if(fMousePosY<=-1)
fMousePosY=0;
if(fMousePosY>=(GetSystemMetrics(SM_CYSCREEN)))
fMousePosY=(float)(GetSystemMetrics(SM_CYSCREEN))-1;
return fMousePosY;
}

private:
static int init;
IDirectInput8 *mDInput;
IDirectInputDevice8 *mKeyboard;
IDirectInputDevice8 *mMouse;
char mKeyboardState[256];
float fMousePosX;
float fMousePosY;
};

int Input::init=0;




[edit]
By the way, steer clear of the keyboard component in the class (or even remove it). There are many issues with keyboard input with Direct Input. But, you can't go wrong on the mouse side of things :)

Share this post


Link to post
Share on other sites
Thanks a lot for all that code lonewolff, really appreciate it!

However the coordinates of the cursor got screwed when I tried to use it. The coordinates increases way to fast. I'm curious about what this line exactly does:

fMousePosX=fMousePosX+mMouseState.lX*(1+mMouseState.lX*0.025f);

Why don't you just do fMousePosX += mMouseState.lX? What's the magic behind your way and how did you find those values?

EDIT:

It doesn't seem like the resolution is causing the mouse coordinates to update wrong. I switched screen between my computer and my brothers, and it still works on mine. Now I'm clueless, the only thing I can think of is that I do something wrong in the setup of the window so here's the code for the initalization:



void D3DApp::initMainWindow()
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = mhAppInst;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "D3DWndClassName";

if( !RegisterClass(&wc) )
{
MessageBox(0, "RegisterClass FAILED", 0, 0);
PostQuitMessage(0);
}

// Default to a window with a client area rectangle of 800x600.

RECT R = {0, 0, 1400, 900};
AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
mhMainWnd = CreateWindow("D3DWndClassName", mMainWndCaption.c_str(),
WS_OVERLAPPEDWINDOW, GetSystemMetrics(SM_CXSCREEN)/2-(R.right/2),
GetSystemMetrics(SM_CYSCREEN)/2-(R.bottom/2), R.right, R.bottom,
0, 0, mhAppInst, 0);

if( !mhMainWnd )
{
MessageBox(0, "CreateWindow FAILED", 0, 0);
PostQuitMessage(0);
}

ShowWindow(mhMainWnd, SW_SHOW);
UpdateWindow(mhMainWnd);
}

void D3DApp::initDirect3D()
{
// Step 1: Create the IDirect3D9 object.

md3dObject = Direct3DCreate9(D3D_SDK_VERSION);
if( !md3dObject )
{
MessageBox(0, "Direct3DCreate9 FAILED", 0, 0);
PostQuitMessage(0);
}


// Step 2: Verify hardware support for specified formats in windowed and full screen modes.

D3DDISPLAYMODE mode;
md3dObject->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);
HR(md3dObject->CheckDeviceType(D3DADAPTER_DEFAULT, mDevType, mode.Format, mode.Format, true));
HR(md3dObject->CheckDeviceType(D3DADAPTER_DEFAULT, mDevType, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, false));

// Step 3: Check for requested vertex processing and pure device.

D3DCAPS9 caps;
HR(md3dObject->GetDeviceCaps(D3DADAPTER_DEFAULT, mDevType, &caps));

DWORD devBehaviorFlags = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
devBehaviorFlags |= mRequestedVP;
else
devBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

// If pure device and HW T&L supported
if( caps.DevCaps & D3DDEVCAPS_PUREDEVICE &&
devBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
devBehaviorFlags |= D3DCREATE_PUREDEVICE;

// Step 4: Fill out the D3DPRESENT_PARAMETERS structure.

md3dPP.BackBufferWidth = 0;
md3dPP.BackBufferHeight = 0;
md3dPP.BackBufferFormat = D3DFMT_UNKNOWN;
md3dPP.BackBufferCount = 1;
md3dPP.MultiSampleType = D3DMULTISAMPLE_NONE;
md3dPP.MultiSampleQuality = 0;
md3dPP.SwapEffect = D3DSWAPEFFECT_DISCARD;
md3dPP.hDeviceWindow = mhMainWnd;
md3dPP.Windowed = true;
md3dPP.EnableAutoDepthStencil = true;
md3dPP.AutoDepthStencilFormat = D3DFMT_D24S8;
md3dPP.Flags = 0;
md3dPP.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
md3dPP.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;


// Step 5: Create the device.

HR(md3dObject->CreateDevice(
D3DADAPTER_DEFAULT, // primary adapter
mDevType, // device type
mhMainWnd, // window associated with device
devBehaviorFlags, // vertex processing
&md3dPP, // present parameters
&gd3dDevice)); // return created device
}

Share this post


Link to post
Share on other sites
After doing some researches I've learnt that DirectInput don't return the relative mouse coordinates in pixels, but rather in some weird device units called "mickeyes" ( or similar ). My solution to this problem was to hide the cursor with

ShowCursor(false);

and then manually track the coordinates I get with the DirectInput mouse relative values. I draw my own cursor from a bitmap image and it's basicly a textured-quad. I also set the position of the invisible mouse to be the same as the one you see, so it wont be confusing when you leave the client area of the window. The only issue with doing it in this way is that the cursor is invisble when I for example press the "X" button to the top right, but I believe I should be able to make it visible just by adding some if statements.

I'm still wondering why it did work on my computer but not on others before. I would love if someone could explain this.

Please tell me what you think about doing it the way I did. I know it's prefered to use WM_MOUSEMOVE or WM_INPUT, but WM_MOUSEMOVE didn't have the accuracy I needed and WM_INPUT felt more complexed than DirectInput.

Cheers,
simpler

Share this post


Link to post
Share on other sites
Hi there!

The 'magic number' is a variable to include mouse acceleration, otherwise movement feels a bit wierd.

With the closing of the window. I guess you could ShowCursor(true) when the program cursor hits the boundary of you window. When, I wrote the class I was intending it for use in a full screen game I was working on. But, I am aware of what you are experiencing.

As for why it didn't work before for you on different PC's, not sure :huh:

Out of interest. Did the DirectInput method work consistently for you between PC's?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!