Planning
Yesterday, I left off with the gamepad controls working, but only in a way that basically broke all of the challenge of the game. The change allowed the player to move outside the defined player boundaries, which meant they could shoot from below the canvas with impunity. Hurray! Today, I’m going to fix that.
Adding a Layer of Abstraction
First, directional control functions were moved from gamePiece
to controls
. Another layer of abstraction was added to handle getActiveDirection
checking. Previously, it called movementKeys[targetDirection]
to get the state of all directions (true
/false
). Now it calls checkDirection
, which in turn calls movementKeys[direction]
to handle the keys, and OR
s that with checkDirectionOfLeftStick
, which does some Math.ceil/floor
logic to get the current direction.
Before:
|
|
After:
|
|
The movementKeys
object was renamed to boundaries
, and this.checkDirection(direction)
is called instead of returning directly from the keysPressed
map.
The checkDirection
function will check both the controller and keyboard states. See the gamepad values conversion in action.
|
|
And checkDirectionOfLeftStick
compares the x
,y
values of the controls.activeLeftStick
object, which contains the values detected by the detectControllerMovement
function, with the predefined movementCoordinates
object, which just maps a direction to coordinate values.
|
|
Commits:
Sticky Boundaries, Yuck
Once the direction logic was straightened out (though perhaps still in need of some refactor treatment), I could control the player with both WASD
and the gamepad’s left stick, but the gamePiece
sticks on the boundaries of the play area. This is because the direction boolean check is still triggering, say, upLeft
when the piece cannot move in the left direction, when left should be ignored. So it’s being moved, then moved back, making it appear to stick.
At first, I couldn’t figure out why this was happening, since the booleans in the directionResults
object should be ignoring an upLeft
if boundaries.insideLeft
is false
. Then I realized that the speed update to the gamePiece
was completely ignoring these checks and using the original values of the activeLeftStick
object, regardless of the direction filter. This meant that at least one of upLeft
/downLeft
/upRight
/downRight
was almost always active, since this value was being retained even when the boundary was checked.
I think another layer of control is needed on the activeLeftStick
object.
The below solution partially solves the problem, but the piece still gets stuck in the corners. This makes sense, since it disallows movement in the target direction of those conditions are met, but doesn’t account for those conditions being met when attempting to move in the opposite direction.
Before:
|
|
After:
|
|
To properly handle the corner cases, the leftStickValues
will need to be modified after the direction is determined. This can be done in a new checkDirectionOfLeftStick
function, after the compareResult
is obtained:
|
|
controls.alignLeftStickValuesToBoundaries
:
|
|
This is not the easiest to follow. Fortunately, there is some commonality between the edge cases, so it can be cleaned up a bit:
controls.alignLeftStickValuesToBoundaries
refactor:
|
|
No more sticky mess!
Commit: 980c34b
Weighting the Movement
Finally, the values of the controls.activeLeftStick
object need to be applied to controls.getPositionModifiers
function to get the appropriate weighted movement.
The activeLeftStick
values are checked for non-zero, and if the check passes, the left stick’s weighted value is multiplied by the default gamePieceSpeed
. Math.abs
is used to accommodate the existing logic for the keyboard controls, where the direction is applied through logic rather than the input (as the controller does). Since we already know the direction, we no longer need the sign of the stick coordinate.
Before:
|
|
After:
|
|
Commit: 899d5e0
Post Session
Finally! Gamepad controls are done (for a single player).
I think at this point, some additional unit tests are needed, and the falling bug needs the add-a-mushroom feature. I’m targeting the end of the week to be feature complete.
Also, as I was working on this, I felt the urge to add a second player, so I’ve added a new issue for that. That should be fun, and will probably trigger a host of refactors to what I did today with the gamepad controls.