patterncsharpMinor
Turn multiple key presses into single GameAction
Viewed 0 times
turnintosinglemultiplepressesgameactionkey
Problem
The
Only one
Now, I need to detect this as a single
I'm sure you can see how this can get quickly out of hand. How can I make it better?
InputHandler class for my game detects key presses, turns each one into a GameAction, and raises an event:public class InputHandler
{
public delegate void ActionListener(GameActions gameAction);
public event ActionListener ActionRequested;
private void ProcessKeyboard(KeyboardState keyboardState)
{
var pressedKeys = keyboardState.PressedKeys();
foreach (var inputAction in pressedKeys.Select(GetInputAction))
{
ActionRequested(inputAction.Down);
}
var releasedKeys = keyboardState.ReleasedKeys(prevPressedKeys);
foreach (var inputAction in releasedKeys.Select(GetInputAction))
{
ActionRequested(inputAction.Up);
}
prevPressedKeys = pressedKeys;
}
}Only one
GameAction can be requested at a time. This means that if you press the key bound to GameActions.MoveUp and the key bound to GameActions.MoveLeft at the same time, two separate events are raised and it looks like your character is moving diagonally.Now, I need to detect this as a single
GameAction, e.g. GameActions.MoveUpLeft. There has to be a better way to do it than what I've come up with.private void ProcessKeyboard(KeyboardState keyboardState)
{
var pressedKeys = keyboardState.PressedKeys();
var inputActions = pressedKeys.Select(GetInputAction).ToList();
var downActions = inputActions.Select(ia => ia.Down);
if (downActions.Contains(GameActions.MoveUp) && downActions.Contains(GameActions.MoveLeft))
{
ActionRequested(GameActions.MoveUpLeft);
}
else if (downActions.Contains(GameActions.MoveUp) && downActions.Contains(GameActions.MoveRight))
{
ActionRequested(GameActions.MoveUpRight);
}
else if ...
}I'm sure you can see how this can get quickly out of hand. How can I make it better?
Solution
var pressedKeys = keyboardState.PressedKeys();
var inputActions = pressedKeys.Select(GetInputAction).ToList();
var downActions = inputActions.Select(ia => ia.Down);This is what's painted you into the corner you're in. You're not showing your
GameActions enum (a better name would be GameAction, or even better, MoveDirection..actually, Direction suffices, since all there is to it is a bunch of values that each represent a direction - the point is, enum type names should not be plural), but I presume it looks something like this:public enum GameActions
{
MoveLeft,
MoveUpLeft,
MoveUp,
MoveUpRight,
MoveRight,
MoveDownRight,
MoveDown,
MoveDownLeft
}The problem is that
MoveUpLeft is a combination of MoveUp and MoveLeft, and since the enum type itself doesn't account for it, your code has to.I'd suggest using a
[Flags] attribute:[Flags]
public enum Direction
{
Left = 1,
Top = 2,
Right = 4,
Down = 8
}Then, instead of
downActions being an IEnumerable and using LINQ IEnumearble.Contains extension, you can add the values of all "down actions", and pass ActionRequested an enum value that represents the sum of all pressed directions, be it Left+Top, Down+Right or whatever. The [Flags] attribute merely serves as a visual cue to remind you that these values can be combined and, using bitwise AND operations or simply, the .HasFlag() method, the handler can determine whether the received value 3 contains Direction.Left:void ActionRequested(Direction direction)
{
if (direction.HasFlag(Direction.Left))
{
// direction contains Direction.Left
}
if (direction.HasFlag(Direction.Right))
{
// direction contains Direction.Right
}
if (direction.HasFlag(Direction.Top))
{
// direction contains Direction.Top
}
if (direction.HasFlag(Direction.Bottom))
{
// direction contains Direction.Bottom
}
}It's not clear from your post exactly what
GetInputAction does and what downActions means, so it's hard to recommend a change that will fit into your code, but here's some inspiration:class Program
{
[Flags]
public enum Direction
{
Left = 1,
Top = 2,
Right = 4,
Bottom = 8
}
static void Main(string[] args)
{
var direction = (Direction)3;
Console.WriteLine("Direction: {0}", direction);
Console.WriteLine("Left: {0}", direction.HasFlag(Direction.Left);
Console.WriteLine("Top: {0}", direction.HasFlag(Direction.Top);
Console.WriteLine("Right: {0}", direction.HasFlag(Direction.Right);
Console.WriteLine("Bottom: {0}", direction.HasFlag(Direction.Bottom);
Console.ReadLine();
}
}Output:
Code Snippets
var pressedKeys = keyboardState.PressedKeys();
var inputActions = pressedKeys.Select(GetInputAction).ToList();
var downActions = inputActions.Select(ia => ia.Down);public enum GameActions
{
MoveLeft,
MoveUpLeft,
MoveUp,
MoveUpRight,
MoveRight,
MoveDownRight,
MoveDown,
MoveDownLeft
}[Flags]
public enum Direction
{
Left = 1,
Top = 2,
Right = 4,
Down = 8
}void ActionRequested(Direction direction)
{
if (direction.HasFlag(Direction.Left))
{
// direction contains Direction.Left
}
if (direction.HasFlag(Direction.Right))
{
// direction contains Direction.Right
}
if (direction.HasFlag(Direction.Top))
{
// direction contains Direction.Top
}
if (direction.HasFlag(Direction.Bottom))
{
// direction contains Direction.Bottom
}
}class Program
{
[Flags]
public enum Direction
{
Left = 1,
Top = 2,
Right = 4,
Bottom = 8
}
static void Main(string[] args)
{
var direction = (Direction)3;
Console.WriteLine("Direction: {0}", direction);
Console.WriteLine("Left: {0}", direction.HasFlag(Direction.Left);
Console.WriteLine("Top: {0}", direction.HasFlag(Direction.Top);
Console.WriteLine("Right: {0}", direction.HasFlag(Direction.Right);
Console.WriteLine("Bottom: {0}", direction.HasFlag(Direction.Bottom);
Console.ReadLine();
}
}Context
StackExchange Code Review Q#46404, answer score: 6
Revisions (0)
No revisions yet.