This makes sure the mouse won’t get to the edge of the window and prevent the player from rotating the camera before moving the mouse away from the edge and pressing+dragging again. But there is a problem now that every time the player clicks on a DirectGUI button, the mouse jumps to the middle of the screen. What can be done to avoid this?
When the user clicks on a DirectGui button, it will not send the “mouse1” event, but it will still send “mouse1-up” when he releases the button. So you can deal with this particular problem by listening for these two events, and only activating the mouse-resetting mode after you have heard “mouse1” and until you have heard “mouse1-up”.
But I think you have a bigger problem with your design. First, note that base.win.movePointer() isn’t portable unless you first put the mouse in “relative” mode. (It doesn’t work as well on Linux, and it doesn’t work at all on Mac OSX, without this mode switch.)
Mac OSX enforces this rule because it’s generally considered good interface design not to yank the mouse pointer away from the user’s direct control unless it is a special mode in which the user is likely to expect this behavior.
In general, I’d tend to agree. It’s probably a better design to have this camera mode be something the user activates explicitly, say by holding down the shift key or something, rather than on all the time. Certainly you don’t want this kind of mouse behavior active at the same time DirectGui buttons are also active, because they’re two so very different ways of using the mouse, and it’s likely to cause confusion or frustration if they’re both active at once. So you should consider having a modal switch that the user can activate to (a) turn on relative mouse mode and activate your camera interface, and (b) hide all of the onscreen DirectGui buttons.
I’m not sure what part of the design you don’t like. If you mean assigning a mouse button to camera controls and having clickable GUI on the same screen, then it’s like that in the original game we are porting. I’ve seen it in many games, including some Panda3d ones.
If you mean repositioning the mouse cursor and having clickable GUI on the same screen, then I agree, it might be a bad idea. Actually in the original game, the mouse cursor isn’t repositioned, however you can go out of the game window having the mouse button held down and the camera controls will still work.
If I could achieve this with Panda, I’d be more than glad as it would be identical to the original game and that’s what I’m aiming for.
However, I don’t know how.
Right now calculating the camera heading and pitch are easy:
While the mouse button remains held down, the pointer will still belong to the window, and you will still get a value for getX() and getY(). It will just exceed the range -1 … 1. When the mouse button is released and the pointer is outside the window, then it will no longer return a value.
Oh I see. I didn’t check if it works while a mouse button is held down and was getting this
Assertion failed: _has_mouse at line 65 of c:\buildslave\dev_sdk_win32\build\pan
da3d\panda\src\tform\mouseWatcher.I
Traceback (most recent call last):
File "test.py", line 6, in mouseTask
print base.mouseWatcherNode.getMouseX()
AssertionError: _has_mouse at line 65 of c:\buildslave\dev_sdk_win32\build\panda
3d\panda\src\tform\mouseWatcher.I
:task(error): Exception occurred in PythonTask mouseTask
Traceback (most recent call last):
File "test.py", line 12, in <module>
run()
File "C:\Panda3D-1.8.0\direct\showbase\ShowBase.py", line 2630, in run
self.taskMgr.run()
File "C:\Panda3D-1.8.0\direct\task\Task.py", line 502, in run
self.step()
File "C:\Panda3D-1.8.0\direct\task\Task.py", line 460, in step
self.mgr.poll()
File "test.py", line 6, in mouseTask
print base.mouseWatcherNode.getMouseX()
AssertionError: _has_mouse at line 65 of c:\buildslave\dev_sdk_win32\build\panda
3d\panda\src\tform\mouseWatcher.I
Any ideas how to calculate the heading and pitch values now though? I could try to post a small snippet on how it works right now.
Sure, just retain the previous pointer value each frame, and subtract the previous value from the current value (instead of subtracting the center value from the current value).
You should check base.mouseWatcherNode.hasMouse(), and ensure it returns true, before you call base.mouseWatcherNode.getMouseX(), to avoid the exception.