39 lines
1.4 KiB
FSharp
39 lines
1.4 KiB
FSharp
/// m06 view: the picture is plain data (a list of shapes); drawing it is somebody else's job (m07).
|
|
module Snake.View
|
|
|
|
open Snake.Model
|
|
|
|
/// A thing to draw.
|
|
type Shape =
|
|
| Rect of x: int * y: int * w: int * h: int * color: string
|
|
| Text of x: int * y: int * text: string * color: string * size: int * align: string
|
|
|
|
/// A picture: shapes drawn in order.
|
|
type Scene = Shape list
|
|
|
|
let CELL = 20
|
|
|
|
let private text x y str size align = Text(x, y, str, "#ffffff", size, align)
|
|
|
|
// One cell, inset by 1px so neighbouring segments show a gap.
|
|
let private cell (p: Point) color =
|
|
Rect(p.X * CELL + 1, p.Y * CELL + 1, CELL - 2, CELL - 2, color)
|
|
|
|
let private overlay (state: GameState) : Scene =
|
|
let cx = state.Width * CELL / 2
|
|
let cy = state.Height * CELL / 2
|
|
let banner title hint = [ text cx cy title 32 "center"; text cx (cy + 30) hint 16 "center" ]
|
|
|
|
match state.Status with
|
|
| Paused -> banner "Paused" "Press Space to resume"
|
|
| GameOver -> banner "Game Over" "Press R to restart"
|
|
| Won -> banner "You Win!" "Press R to restart"
|
|
| Playing -> []
|
|
|
|
let view (state: GameState) : Scene =
|
|
[ Rect(0, 0, state.Width * CELL, state.Height * CELL, "#111111") ]
|
|
@ (state.Apple |> Option.map (fun a -> cell a "#e53935") |> Option.toList)
|
|
@ (state.Snake |> List.mapi (fun i p -> cell p (if i = 0 then "#7cb342" else "#43a047")))
|
|
@ [ text 6 18 $"Score: {state.Score}" 16 "left" ]
|
|
@ overlay state
|