Building a roguelike in F# from scratch - Multi Key Commands

Words
282
Reading
2 min
Listen
Play
9y

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 :

Finally the GitHub Repo

Feel free to ask questions and happy coding :)

Woz

Building a roguelike in F# from scratch - Multi Key Commands | Ecency