Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace skarpt_blask
- open System
- open Foundation
- open AppKit
- open CoreGraphics
- module Animation =
- type Flake = {
- x: float
- y: float
- dx: float
- dy: float
- size: float
- }
- type State = {flakes: Flake list; repeller: (float*float) option}
- type Message =
- | State of AsyncReplyChannel<State>
- | Update of (State -> State)
- | Repeller of float*float
- let create () =
- MailboxProcessor<Message>.Start(fun mailbox ->
- let spawn =
- let rnd = new System.Random ()
- fun () ->
- { x = rnd.NextDouble() * Config.width
- y = Config.height * rnd.NextDouble()
- dx = (rnd.NextDouble() / 4.0) - 0.25
- dy = -0.3 - (rnd.NextDouble() / 2.0)
- size = rnd.NextDouble() * 8.0 + 5.0}
- let respawn () = {spawn () with y = Config.height + 10.0}
- let rec animate () = async {
- do! Async.Sleep 10
- Update (fun state ->
- let move flake =
- { flake with
- x = flake.x + flake.dx * Config.speed
- y = flake.y + flake.dy * Config.speed
- }
- let repell repeller flake =
- flake
- let check (flake: Flake) =
- if flake.y < -flake.size ||
- flake.x < -flake.size ||
- flake.x > Config.width then respawn ()
- else flake
- {state with flakes = state.flakes |> List.map (move >> (repell state.repeller) check) }
- ) |> mailbox.Post
- do! animate ()
- }
- let rec engine state =
- async {
- let! incoming = mailbox.Receive ()
- match incoming with
- | State reply ->
- reply.Reply state
- do! state |> engine
- | Update fn ->
- do! state |> fn |> engine
- | Repeller (x,y) ->
- do! {state with repeller = Some (x,y)} |> engine
- }
- animate () |> Async.Start
- { flakes = List.init Config.flakes (fun _ -> spawn())
- repeller = Some (Config.width/2.0,Config.height/2.0)}
- |> engine
- )
- type SnowyView () as this =
- inherit NSView ()
- do
- this.Frame <- new CGRect(0.0,0.0,Config.width, Config.height)
- let animation = Animation.create ()
- let drawFlake (context: NSGraphicsContext) (flake: Animation.Flake) =
- Config.snowColor.SetFill ()
- let rect = new CGRect(flake.x,flake.y,flake.size,flake.size)
- context.GraphicsPort.FillEllipseInRect rect
- let drawBackground (context: NSGraphicsContext) =
- Config.backgroundColor.SetFill ()
- context.GraphicsPort.FillRect this.Frame
- override this.DrawRect dirty =
- base.DrawRect dirty
- let context = NSGraphicsContext.CurrentContext
- drawBackground context
- let state = animation.PostAndReply Animation.State
- state.flakes |> List.iter (drawFlake context);
- async {
- do! Async.Sleep 20 // ~ 50 FPS
- this.InvokeOnMainThread (fun () -> this.SetNeedsDisplayInRect this.Frame)
- } |> Async.Start
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement