Squeaking
24 October 2019
That took a bit of refactoring, but now I have a menu that shows up and works.
Then I lost a bunch of time trying to get an animation of it for the blog! I found a neat tool ScreenToGif that worked to capture the action. But, putting this in the page caused an endlessly looping gif, which is no fun to have when reading the surrounding text. After a bit of fiddling, I’ve added some JavaScript to the blog that makes it possible to click on a stopped gif to replay it. Then, changing the last frame to include a replay hint, it is something I can live with for now.
)
(the first simple menu in action)
Things are coming together a bit, although having to repeatedly press the WASD keys to move a blob about slowly isn’t much fun! The monotony of this has made my next step abundantly clear - it’s time to hook up the Mouse.
Traps
Mouse control in the Windows environment is insanely good at what it does, namely allowing the user to control windows and direct input. But, for my game, I don’t want to build a point and click interface. I want to treat the Mouse as a continuous stream of input that is converted into a thrust value as a function of distance moved. And Windows doesn’t work that way - as soon as the Mouse hits the edge of the Desktop, it stops. That simply won’t do.
The annoying thing about this is I’m pretty sure deep under the hood the Mouse is just sending a stream of mickeys without regard to the window, Desktop, or anything else. It’s a classic case of all the layers of abstraction getting in the way. It is the price we pay for all the other things that the OS has simplified for us.
I’ve given this quite some thought, and the only way I can see to make this function the way I want is to take control of the cursor completely. First Capture the Mouse and move it to the centre of the window, then, every time Mouse movement is detected, move it back to the centre of the window, and accumulate the Move in the input buffer. In this case, the Move will be defined as the distance between the window centre and the current mouse location. Then when the input is collected that will be the total movement since the last collection.
Unfortunately, there are some downsides to this approach. The most obvious being that I’ve captured and controlled the Mouse. When the window loses focus (e.g. alt+tab), I need to be careful to restore the Mouse to a usable state for standard windows. Then there is the buffering issue. At any given time there can, in theory, be multiple mouse movement updates in the input queue. If I process one of them, then reset the mouse location to the centre of the screen (and hence my relative position). I then receive another update from the queue that was actually relative to the last mouse location, that’s not going to give the correct answer. So clearly I need to make sure to flush the underlying windows message queue when handling a mouse update, prior to recentring. Wpf is another level of abstraction again over the top of the message queue. So, how to flush the queue in Wpf?
Absolutist Mice
What I actually want is the absolute location of the mouse relative to the window at any given moment. I don’t want to process the message queue at all. In Win32 land, I’d do this with GetCursorPos but exactly how this maps into Wpf is a bit opaque. It seems that Mouse.GetPosition(gameArea) should give me exactly what I wanted, but I haven’t yet found any definitive documentation, nor does it seem straightforward to test.
Looking at the next step, namely setting the mouse location, I find that Wpf doesn’t even seem to have a method for this.
So. Being a bit pragmatic, if I have to use Win32 interop to set the mouse location, I might as well use Win32 interop to get the position too. Since I already have a high-frequency UI tick, it seems that that would be the ideal place to hook in a check of the mouse position and recentering of it. Basically, ignore the Wpf handling of the mouse altogether.
Bzzzt
Buuuut. There is another fly in the ointment. How to detect mouse clicks? I know I’ll eventually want to handle left-click and right-click events in the game, so best to consider this before coding anything. I could simply check for a mouse down condition at the time of the position check, but humans can react pretty darn quick at times and having a mouse click missed would be a horrible user experience. So really I’m going to have to listen to the event queue for mouse clicks. Now, a mouse click event in Wpf also includes the location of the mouse, but that is a relative location and not an absolute. What to do? I could get the absolute position myself at the time of the click. But I don’t think I’m going to. Instead, I’m going to just aggregate all the clicks in a single UI Tick and pretend they all happened at the same time. Since the game itself is using mouse movement for thrust and not specific pointing I’m hoping this won’t be noticeable.
Mouse Plan
In conclusion, my plan is:
Time to write some code and see if this approach works.