Skip to content

Instantly share code, notes, and snippets.

@yonax
Created December 15, 2015 10:37
Show Gist options
  • Save yonax/0beb5dc96e990dc87ffa to your computer and use it in GitHub Desktop.
Save yonax/0beb5dc96e990dc87ffa to your computer and use it in GitHub Desktop.
import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import Random
import Color exposing (Color)
import Time exposing (fps)
type alias Vector = (Float, Float)
type alias Circle =
{ center : Vector
, r : Float
, v : Vector
, color : Color
}
width = 800
height = 800
type alias Model = List Circle
randomVector : Float -> Float -> Random.Generator Vector
randomVector a b = Random.pair (Random.float a b) (Random.float a b)
randomColor : Random.Generator Color
randomColor = Random.map3 Color.rgb (Random.int 0 255) (Random.int 0 255) (Random.int 0 255)
randomCircle : Random.Generator Circle
randomCircle = Random.map4 Circle (randomVector (-width/2) (width/2)) (Random.float 30 150) (randomVector -3 3) randomColor
(.+) : Vector -> Vector -> Vector
(.+) (x, y) (x', y') = (x + x', y + y')
dist : Vector -> Vector -> Float
dist (x, y) (x', y') = sqrt ((x - x')*(x - x') + (y - y')*(y - y'))
mid : Vector -> Vector -> Vector
mid (x, y) (x', y') = ((x + x') / 2, (y + y') / 2)
neg : Vector -> Vector
neg (x, y) = (-x, -y)
type alias Overlap =
{ center : Vector,
r : Float,
color : Color
}
overlap : Circle -> Circle -> Maybe Overlap
overlap c c' =
let
amount = (dist (c.center) (c'.center)) - c.r - c'.r
interp c1 c2 = Color.rgb ((c1.red + c2.blue) // 2) ((c1.green + c2.red) // 2) ((c1.green + c2.green) // 2)
in
if amount >= 0 then
Nothing
else
Just { center=mid c.center c'.center
, r=amount
, color=interp (Color.toRgb c.color) (Color.toRgb c'.color)
}
initModel : Int -> Model
initModel n = Random.list n randomCircle |> flip Random.generate (Random.initialSeed 200) |> fst
fit : Vector -> Bool
fit (x, y) = x >= (-width/2) && x < (width/2) && y >= (-width / 2) && y < (width/2)
updateCircle c =
let
newCenter = c.center .+ c.v
in
{ c | center = newCenter
, v = if fit newCenter then c.v else neg c.v
}
update : Model -> Model
update = List.map updateCircle
model : Signal Model
model = Signal.foldp (\_ s -> update s) (initModel 30) (fps 30)
scene circles =
let
overlaps = List.concatMap (\c -> List.filterMap (overlap c) circles) circles
drawCircle {center, r, color} = circle (-r) |> outlined {defaultLine | color=color} |> move center
in
collage 800 800 <| (List.map drawCircle overlaps)
main = Signal.map scene model
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment