Building a roguelike in F# from scratch - Multi Key Commands
Introduction
Recursion really is a thing of beauty :)
I have updated the player command generator so it will handle commands that take multiple key presses. The working commands are now:
- W - Up
- A - Left
- S - Down
- D - Right
- Space - Idle
- O + [WASD] - Open the door in that direction
- C + [WASD] - Close the door in that direction
Reading the keyboard
The change to implement this was so simple in the end. There is a new function called handleKeyPress, this handles all the building. It is called initially with a None command builder.
- If W,A,S,D or Space are pressed it calls selectActorCommand, which you saw last time.
- If O or C are pressed it calls back into itself with the related builder. Next time if W,A,S or D are pressed it will build the Open or Close command in that direction.
let selectCommand validator operation direction actorId level =
level
|> validator direction actorId
|> bind (fun l -> operation direction actorId l)
let private selectActorCommand direction actorId level =
resultOrElse {
return! selectCommand isValidMove buildMoveActorCommand direction actorId level
return! selectCommand canOpenDoor buildOpenDoorCommand direction actorId level
return! (invalidCommand level)
}
let rec handleKeyPress activeBuilder actorId =
let workingBuilder =
match activeBuilder with
| Some builder -> builder
| None -> selectActorCommand
match Console.ReadKey().Key with
| ConsoleKey.O -> handleKeyPress (Some buildOpenDoorCommand) actorId
| ConsoleKey.C -> handleKeyPress (Some buildCloseDoorCommand) actorId
| ConsoleKey.W -> workingBuilder north actorId
| ConsoleKey.A -> workingBuilder west actorId
| ConsoleKey.S -> workingBuilder south actorId
| ConsoleKey.D -> workingBuilder east actorId
| ConsoleKey.Spacebar -> idleCommand
| _ -> invalidCommand
let getPlayerCommand actorId = handleKeyPress None actorId
The only issue at the moment is termination if the player holders down O or C, that should not be an issue as this should be tail call recursive. If this proves to be incorrect I will need to revisit it. Good enough for now.
Summary
Short one today, but nice simple change that gives a lot of power for very little work. Most of it already existed just needed moving around a bit :)
And for those who have only just found the series, here is the story so far for Building a roguelike in F# from scratch :
- Introduction
- Repo and Initial Types
- First Problems
- Level Queries
- CRUD Operations
- Validation
- Game Loop Time
- It's ALIVE
- Working Doors
Finally the GitHub Repo
Feel free to ask questions and happy coding :)
Woz