Getting Started: Input
In this tutorial we're continuing from where we left off in the first GettingStarted: Graphics tutorial. In this tutorial we'll implement a new dynamic to our game, keyboard and mouse controls.
Overview:
- Adding keyboard controls
- Using input controllers
- Using movement controllers
- Adding mouse controls
- Synopsis
This tutorial requires that you've completed the first GettingStarted: Graphics tutorial. You can always get the full source for the Getting Started: Graphics tutorial .
Adding keyboard controls
When we last left our Getting Started project we had a red circle that would move across the screen at a constant 200 pixels per second. Lets now add controls to control the movement of the circle.
Open up the MyGame.ts, lets now add boolean flags to dictate which way we're trying to move:
Next we need to modify our directional boolean values based on keyboard input, lets use the KeyboardHandler. Lets add some code to the MyGame constructor:
Lets look at what we just added. For each movement we have code that essentially does: All game input handlers can be accessed via the games Input field.
Next lets make our circle move based on our movement flags! We currently have
which we can modify to move our circle in right direction when the specified movement flag is true. Lets first make a class level field that will represent the circles move speed; add the following to the end of the other field declarations at the top of the MyGame class:
now modify the Update function to look like:
We're essentially checking each of our flags and then moving the circle in the corresponding direction as long as the flag is true.
If we now run the game (ctrl+f5) you should be able to move the circle around the screen by pressing the arrow keys.
Using input controllers
We just got our circle to move around the screen but I'm sure as you were writing the code for the movements you noticed that adding helper functions could drastically reduce the code length. So lets go back through our code and re-write it to use EndGate InputControllers.
Lets start by using the DirectionalInputController; lets add an input controller to the list of private variables in our MyGame class:
Now here comes the magic! Remove all of the Keyboard binding lines of codes in the MyGame constructor and replace them with:
The constructor should now look like:
The function that we pass into the DirectionalInputController constructor is triggered whenever a move command is attempted via the keys "w, a, s, d, Up, Left, Down, Right" (by default). You can always override these key combinations through the expanded constructor. Therefore we can update our movement flags entirely based off of the output from the passed in callback function.
If you were to run the application you'd see that the application behaves the same but you can now ALSO move your circle with "w, a, s, d". Not to mention we've reduced the code count significantly.
Using movement controllers
As a next step in refactoring our code lets go back through and re-write it to use EndGate MovementControllers.
Lets start by using the LinearMovementController; lets add a movement controller to the list of private variables in our MyGame class:
Next, remove all the movement flags from the field declaration list. The top of the MyGame class should look like this:
Next remove EVERYTHING from the body of the Update function, yes I said everything; and then add 1 line of code to the update function, it should look like:
Now for the final two pieces to tie everything together. Lets instantiate our movement controller, add the following to the constructor:
We initialize a linear movement controller and pass in an array of moveable objects that will be moved by the movement controller, in this case we just need to pass in our circle, and then we pass in the rate at which they should move.
Note: There are more overrides to the LinearMovementController object to allow more flexible ways to control how it moves.
Lets replace the body of the input controller's callback function to utilize the movement controller. The three lines that involve declaring the input controller should look like:
You can now run the project (ctrl + f5) and it will behave as it did but with far fewer lines! The MyGame.ts should look something like this:
class MyGame extends eg.Game { private _circle: eg.Graphics.Circle; private _circleSpeed: number = 200; private _inputController: eg.InputControllers.DirectionalInputController; private _movementController: eg.MovementControllers.LinearMovementController; constructor() { super(); this._circle = new eg.Graphics.Circle(100, 150, 40, "red"); this._movementController = new eg.MovementControllers.LinearMovementController([this._circle], this._circleSpeed); this._inputController = new eg.InputControllers.DirectionalInputController(this.Input.Keyboard, (direction: string, startMoving: boolean) => { this._movementController.Move(direction, startMoving); }); this.Scene.Add(this._circle); } public Update(gameTime: eg.GameTime): void { this._movementController.Update(gameTime); } }Adding mouse controls
We've implemented the ability to move the circle via the keyboard but what about the mouse? We can utilize the MouseHandler to accomplish this. Add the following code to the MyGame constructor The reason why the movement controller is the object that we alter is because it is monitoring the circle object. Whatever the movement controller's position is will directly affect the position of the circle.
If you run the application you will now be able to alter the circles position by clicking. The next important thing to discuss is how we attach functions to our OnClick handler. The OnClick handler is an EventHandler1 object which can be bound or unbound to. When the event is triggered any bound functions are then executed. You'll see event handlers scattered throughout the EndGate code base.
Synopsis
Through this tutorial you've learned how to move the red circle via keyboard commands and mouse clicks. By now you should have a brief understanding of InputControllers and MovementControllers so if the time arises you can create your own.
Lastly here's how the MyGame.ts file should look after the tutorial has been completed:
- MyGame.ts:
class MyGame extends eg.Game { private _circle: eg.Graphics.Circle; private _circleSpeed: number = 200; private _inputController: eg.InputControllers.DirectionalInputController; private _movementController: eg.MovementControllers.LinearMovementController; constructor() { super(); this._circle = new eg.Graphics.Circle(100, 150, 40, "red"); this._movementController = new eg.MovementControllers.LinearMovementController([this._circle], this._circleSpeed); this._inputController = new eg.InputControllers.DirectionalInputController(this.Input.Keyboard, (direction: string, startMoving: boolean) => { this._movementController.Move(direction, startMoving); }); this.Input.Mouse.OnClick.Bind((event: eg.Input.IMouseClickEvent) => { this._movementController.Position = event.Position; }); this.Scene.Add(this._circle); } public Update(gameTime: eg.GameTime): void { this._movementController.Update(gameTime); } }
And if you'd like to get the project source in its entirety you can always download it here:
To continue onto the next tutorial click Here.