Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# game development: Modifying state variables

Tags:

c#

.net

f#

open SFML.Graphics
open SFML.Window

let window = new RenderWindow(new VideoMode(200u, 200u), "SFML works!")
let shape = new CircleShape(10.0f, FillColor=Color.Green)
let mutable pressedKey = Keyboard.Key.Unknown

let moveKeys = [ Keyboard.Key.Up; Keyboard.Key.Left;
                 Keyboard.Key.Down; Keyboard.Key.Right ]

let keyPress (e : KeyEventArgs) =
    match e.Code with
    | moveKeys -> pressedKey <- e.Code
    | _ -> pressedKey <- Keyboard.Key.Unknown

let keyRelease (e : KeyEventArgs) =
    let pressedKeys = List.filter (fun key -> Keyboard.IsKeyPressed(key)) moveKeys
    if pressedKeys.IsEmpty then pressedKey <- Keyboard.Key.Unknown
    else pressedKey <- pressedKeys.Head

window.Closed.Add(fun evArgs -> window.Close())
window.KeyPressed.Add(keyPress)
window.KeyReleased.Add(keyRelease)

while window.IsOpen() do
    match pressedKey with
    | Keyboard.Key.Up    -> shape.Position <- new Vector2f(shape.Position.X, shape.Position.Y - 0.1f)
    | Keyboard.Key.Left  -> shape.Position <- new Vector2f(shape.Position.X - 0.1f, shape.Position.Y)
    | Keyboard.Key.Down  -> shape.Position <- new Vector2f(shape.Position.X, shape.Position.Y + 0.1f)
    | Keyboard.Key.Right -> shape.Position <- new Vector2f(shape.Position.X + 0.1f, shape.Position.Y)
    | _ -> ()

    window.DispatchEvents()
    window.Clear()
    window.Draw(shape)
    window.Display()

In the above code sample I create a circle and let it move around by pressing arrow keys. The state variable in question is the position of the circle, represented by a Vector2f object (part of the SFML library)

My question relates to the end of the code segment, where I find the pressed key and then move the circle. From a C# background this part of my code seems bad.

In C# I would simply do the following:

switch (pressedKey) {
    case Keyboard.Key.Up:
         shape.Position.Y -= 0.1f;
    // etc, etc
}
  1. Does creating these new Vector2f objects cause unnecessary overhead compared to the way I would modify the state variable in C#?

  2. Is there a better way of doing this?

like image 250
xcvd Avatar asked Feb 27 '14 15:02

xcvd


People also ask

What does ⟨F⟩ mean?

This sound is usually considered to be an allophone of /h/, which is pronounced in different ways depending upon its context; Japanese /h/ is pronounced as [ɸ] before /u/. In Welsh orthography, ⟨f⟩ represents /v/ while ⟨ff⟩ represents /f/. In Slavic languages, ⟨f⟩ is used primarily in words of foreign (Greek, Latin, or Germanic) origin.

What does the letter F mean in math?

In countries such as the United States, the letter "F" is defined as a failure in terms of academic evaluation. Other countries that use this system include Saudi Arabia, Venezuela, and the Netherlands. In the hexadecimal number system, the letter "F" or "f" is used to represent the hexadecimal digit fifteen (equivalent to 15 10 ).

What does F stand for in the Etruscan alphabet?

In the Etruscan alphabet, 'F' probably represented /w/, as in Greek, and the Etruscans formed the digraph 'FH' to represent /f/.

Is the letter F doubled at the end of words?

It is often doubled at the end of words. Exceptionally, it represents the voiced labiodental fricative / v / in the common word "of". F is the twelfth least frequently used letter in the English language (after C, G, Y, P, B, V, K, J, X, Q, and Z ), with a frequency of about 2.23% in words.


2 Answers

1) This is a performance question which is always case specific. The answer in this case is No. If you are doing this to 10,000 objects in a loop then yes, use mutable data. In general making things immutable allows you to make easier assumptions about their behavior which is hugely important.

2) Here is a possible direction you can go with this code.

open SFML.Graphics
open SFML.Window
open System

type HandleKeyboard(window : RenderWindow) =
    let mutable keyState = Set.empty

    let keyPressedHandle = 
        window.KeyPressed.Subscribe(fun key -> 
            keyState <- keyState.Add key.Code)

    let keyReleasedHandle = 
        window.KeyReleased.Subscribe(fun key -> 
            keyState <- keyState.Remove key.Code)

    let validMovementKey (keyPress : Keyboard.Key) =
        match keyPress with
        | Keyboard.Key.Up
        | Keyboard.Key.Left
        | Keyboard.Key.Down
        | Keyboard.Key.Right -> true
        | _ -> false

    let keyToMovement (keyPress : Keyboard.Key) =
        match keyPress with
        | Keyboard.Key.Up    -> Vector2f( 0.0f, -0.1f)
        | Keyboard.Key.Left  -> Vector2f(-0.1f,  0.0f)
        | Keyboard.Key.Down  -> Vector2f( 0.0f,  0.1f)
        | Keyboard.Key.Right -> Vector2f( 0.1f,  0.0f)
        | _ -> Vector2f(0.0f, 0.0f)

    member this.IsKeyPressed (key : Keyboard.Key) = 
        keyState |> Set.contains key

    member this.GetMovement () =
        keyState
        |> Set.filter validMovementKey
        |> Seq.map keyToMovement
        |> Seq.fold (+) (Vector2f(0.0f, 0.0f))

    interface IDisposable with
        member this.Dispose() =
            keyPressedHandle.Dispose()
            keyReleasedHandle.Dispose()

type SomeState = { 
    position : Vector2f;
    }

let startGame() =
    use window = new RenderWindow(VideoMode(200u, 200u), "SFML works!")
    use shape = new CircleShape(10.0f, FillColor = Color.Green)
    use keyboard = new HandleKeyboard(window)

    window.Closed.Add(fun evArgs -> window.Close())

    let rec mainLoop state =
        window.DispatchEvents()

        if keyboard.IsKeyPressed Keyboard.Key.Escape then
            window.Close()

        let newPosition = state.position + keyboard.GetMovement()
        shape.Position <- newPosition

        if window.IsOpen() then
            window.Clear()
            window.Draw(shape)
            window.Display()

            mainLoop {position = newPosition}

    mainLoop {position = Vector2f(0.0f, 0.0f)}

startGame()
like image 125
gradbot Avatar answered Nov 02 '22 23:11

gradbot


I think if you are worried about the overhead of creating a small object corresponding to a keypress, you are worrying about the wrong thing. The number of keypresses is relatively small.

By changing your vector2 type, you can make it possible to write code similar to the C# code ( essentially, you make the backing store variables mutable).

like image 22
John Palmer Avatar answered Nov 02 '22 23:11

John Palmer