Keys: Z = left, X = right, Space = fire
Play along to the Prodigy:
Techie bit
The game was developed in F# using the freely available Visual Studio 2010 Shell and targets Silverlight 4. F# is a multi-paradigm .Net programming language, that encompasses functional programming as well as imperative and object-oriented programming styles.
Graphics
The graphics were drawn in binary as 0s and 1s:
let invader1 =
[|
12,
[|
0b000001100000
0b000011110000
0b000111111000
0b001101101100
0b001111111100
0b000010010000
0b000101101000
0b001010010100
|]
|]
and transformed to a WriteableBitmap
let toBitmap (width,xs:int []) =
let bitmap = WriteableBitmap(width,xs.Length)
let pixels = bitmap.Pixels
xs |> Array.iteri (fun y xs ->
for x = 0 to width-1 do
let bit = 1 <<< (width - 1 - x)
pixels.[x+y*width] <-
xs &&& bit = bit
|> (function true -> 0xffffffff | false -> 0x00000000)
)
bitmap
Yield!
Sprite animation is implemented as state machines using F# Sequences:
let wait n = seq { for x = 1 to n do yield () }
let animation = seq {
let i = ref i
while true do
yield! wait 6
images.[!i].Visibility <- Visibility.Collapsed
i := (!i+1) % images.Length
images.[!i].Visibility <- Visibility.Visible
}
the sequence cycles through the provided images.
Keys
Games need to know if a key is down. F# has a lightweight equivalent of Reactive Extensions (Rx) baked in the Observable Module which provides higher order functions over Events:
type Action = Left | Right | Fire
let toAction = function
| Key.Z -> Some Left
| Key.X -> Some Right
| Key.Space -> Some Fire
| _ -> None
let mutable actions = set []
let startObservingKeys () =
control.KeyDown
|> Observable.choose (fun ke -> toAction ke.Key)
|> Observable.subscribe(fun action ->
actions <- Set.add action actions)
|> remember
control.KeyUp
|> Observable.choose (fun ke -> toAction ke.Key)
|> Observable.subscribe (fun action ->
actions <- Set.remove action actions)
|> remember
Selective memory
Well-behaved classes should remember the resources they have acquired and forget them once they are finished with them:
let mutable disposables = []
let remember disposable = disposables <- disposable :: disposables
let dispose (d:IDisposable) = d.Dispose()
let forget () = disposables |> List.iter dispose; disposables <- []
Je regrette rien:
interface System.IDisposable with
member this.Dispose() = forget()
References