Untitled

 avatar
unknown
plain_text
5 months ago
2.5 kB
4
Indexable
#r "nuget:DIKU.Canvas"
open Canvas
open Color
open System
open Asteroids.Vectors
open Asteroids.RandomGenerator
open Asteroids.Asteroids


let width = 400
let height = 400
let center = (200.0, 200.0)
let speed = 5.0

type Vec = float * float

type Moth(pos: Vec, hdng: float) =
    member val pos = pos with get, set
    member val heading = hdng with get, set
    member this.draw =
        let x, y = this.pos
        filledEllipse yellow 5.0 5.0 |> translate x y

let randomHeadingChange () = 
    (Random().NextDouble() * 20.0 - 10.0) * Math.PI / 180.0

let wrap (x: float) (y: float) =
    let x' = if x < 0.0 then float width + x elif x > float width then x - float width else x
    let y' = if y < 0.0 then float height + y elif y > float height then y - float height else y
    (x', y')

let move (pos: Vec) (heading: float) : Vec =
    let dx = Math.Cos(heading) * speed
    let dy = Math.Sin(heading) * speed
    let x, y = pos
    wrap (x + dx) (y + dy)

let adjustHeadingToLight (pos: Vec) (target: Vec) : float =
    let x, y = pos
    let tx, ty = target
    Math.Atan2(ty - y, tx - x)

type State = { lamp: bool; moths: Moth list }

let initialMoths = 
    [ Moth((5.0, 7.0), randomHeadingChange())
      Moth((100.0, 100.0), randomHeadingChange())
      Moth((50.0, 50.0), randomHeadingChange())
      Moth((100.0, 50.0), randomHeadingChange())
      Moth((50.0, 100.0), randomHeadingChange()) ]

let draw (state: State) =
    let lamplight = 
        if state.lamp then
            filledEllipse white 10.0 10.0 |> translate 200.0 200.0
        else 
            filledEllipse blue 10.0 10.0 |> translate 200.0 200.0
    let mothDrawings = state.moths |> List.map (fun m -> m.draw)
    make (List.fold onto lamplight mothDrawings)

let react (state: State) (ev: Event) : State option =
    match ev with
    | Key ' ' -> { state with lamp = not state.lamp }
    | TimerTick ->
        let target = (200.0, 200.0)
        let updatedMoths =
            state.moths
            |> List.map (fun m -> 
                if state.lamp then 
                    m.heading <- adjustHeadingToLight m.pos target
                else 
                    m.heading <- m.heading + randomHeadingChange()
                m.pos <- move m.pos m.heading
                m)
        { state with moths = updatedMoths }
    | _ -> state
    |> Some

let interval = Some 100
let initialstate = { lamp = false; moths = initialMoths }

interact "moth sim" width height interval draw react initialstate
Editor is loading...
Leave a Comment