Until now, the Praedium’s engine supported only keyboard input and that is absolutely enough for a typical text-based game.
But some of them actually go as far as to implement some mouse input handling as an alternative or part of the actual game controls.
As I’ve stated already in the first creative highlight, some mouse events, such as hovering, would be very useful to easily show the player some hints about different objects.
Also, nowadays I was wondering about player controls to also support mouse input or even restrict them to mouse input. This seems like a better approach to me, due to keyboard controls feeling a little bit too awkward in this kind of game.
Another point for this change is that I have an idea of changing the initial vision of typical Harvest Moon styled game. Typically, you control a single character and I have an idea to introduce multiple character managing - for example a whole family on a farm.
This changes the gameplay a lot and introduces a somewhat more fresh idea.
All in all, the mouse input handling seemed like a good issue to tackle, so let’s get into it!
Integrating mouse events
Just as before, I’d like to keep away from specific frameworks so the engine becomes more flexible. That is why we need to define an enumeration type that will represent different mouse buttons.
For now we will stick with left, middle and right mouse buttons.
Having defined that, we follow the pattern and define a
MouseInfo structure containing all important information received from given mouse event, be it a button press, release or simply mouse move.
As you can see the structure has information about mouse position, which mouse button (if such is present) the event is about and whether that button is down or not. There is also an enumeration type introduced that specifies which type of event we are dealing with.
In case of keyboard events we only had to check if the Down flag was true or false and we knew everything. But in this case we do not know if given
MouseInfo instance came from a mouse move event or a simple button event.
This structure is used in the custom
MouseInfoEventArgs that will be passed inside the engine on any of the events listed above.
Game class needs to define these events and event handlers to which game objects could also react.
The game calls the
UI instance and tells it to apply the received mouse information. In case of mouse move events, we only apply the mouse position just to be safe.
The UI contains a
<MouseButton, bool> dictionary to keep track of which button is pressed at current moment and which is not. It also keeps track of current mouse position.
Having all this set up and properly implemented within the game’s form we may move along and show some example on how to use this.
The example in question will be an implementation of simple rectangular mouse selection commonly used within strategy games to select multiple units.
Whenever the player presses the left mouse button and then moves the mouse while holding the button down, a rectangle is drawn to show the selection he is creating. When the mouse button is released, the selection is created, and units selected (if any were within the selection rectangle).
Firstly, let’s define a new game object, one that will handle these mouse controls.
This object will be keeping track the selection’s position - the starting and ending point, and based on that configure the renderer on the fly to render a simple rectangle.
BoxRenderer has not been yet introduced by me in the details, to put it simply - it does what you expect it to. Based on given parameters it renders a box in the terminal using some special characters representing lines.
Interacting with the
MouseController is made by calling
These methods will be called from a new
MouseSelectionHandler component that will be taking use of the new event handlers.
The code is pretty much straightforward. In the
OnStart setup callback, we connect the proper methods to event handlers.
Whenever the game registers a mouse movement, we check if we are currently processing a selection and the mouse position parsed to terminal units changed. If that is true, we call the controller and tell it to change the selection.
On left mouse button release, we end the selection and this would be the moment when we actually would look for some units and mark them as selected.
On left mouse button press, we check if controller isn’t already processing a selection and if not, we tell it to start processing, starting from the event’s mouse position.
Clean and straight to the point! And now behold the results:
Mouse selection example.
Today I have walked you through the implementation of mouse input handling within the Praedium’s engine and it’s usage in practice within the Praedium’s game code.
I hope you find the code to be straightforward and clean as that is also very important.
Again, the engine is being kept framework-agnostic for flexibility.
Having implemented the creation of the selection rectangle and rendering of it, I can continue to implement some actual controls.
Of course the point and click controls will need some path finding which I’m going to implement next up.
That’s it for today’s post! See you next time!