Skip to content

Instantly share code, notes, and snippets.

@fredguth
Created January 24, 2016 00:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fredguth/cf37d01a9d7b4f0f1f9d to your computer and use it in GitHub Desktop.
Save fredguth/cf37d01a9d7b4f0f1f9d to your computer and use it in GitHub Desktop.
Part4: Following Elm Tutorial
import Graphics.Element exposing (..)
import Graphics.Collage exposing (..)
import Color exposing (..)
import Mouse
import Window
import Random
import Time exposing (..)
import Signal exposing (foldp)
--Model
(width, height) = (400, 400)
(hWidth, hHeight) =
(width/2, height/2)
type alias Vec =
(Float, Float)
type alias Pill =
{ pos : Vec
, vel : Vec
, rad : Float
, col : Color
}
type alias Game =
{ player : Pill
, pills : List Pill }
defaultGame =
{ player = defaultPlayer
, pills = []}
newPill : Float -> Pill
newPill x =
{ defaultPill | pos = (x, hHeight)}
type Event = Tick (Time, (Int, Int)) | Add Pill
vecAdd : Vec -> Vec -> Vec
vecAdd (ax, ay) (bx, by) =
(ax + bx, ay + by)
vecSub : Vec -> Vec -> Vec
vecSub (ax, ay) (bx, by) =
(ax - bx, ay - by)
vecLen : Vec -> Float
vecLen (x, y) =
sqrt (x * x + y * y )
vecMulS : Vec -> Time -> Vec
vecMulS (x, y) t =
(x*t, y*t)
defaultPill =
{ pos = (0,hHeight)
, vel = (0,-30)
, rad = 15
, col = lightRed
}
defaultPlayer =
{defaultPill | pos = (0,0)
, col = black}
gen = Random.float -hWidth hWidth
seed0 = Random.initialSeed 12
-- Update
stepGame : Event -> Game -> Game
stepGame event ({player, pills} as g) =
case event of
Tick (t, mp) ->
let
hit pill= (vecLen (vecSub player.pos pill.pos)) < (player.rad + pill.rad)
unculled = List.filter (\{pos} -> snd pos > -hHeight) pills
untouched = List.filter (not << hit) unculled
in
{g|pills = List.map (stepPill t) untouched
,player = stepPlayer mp player}
Add p ->
{g|pills = p :: g.pills}
stepPill : Time -> Pill -> Pill
stepPill t p =
{p|pos = vecAdd p.pos (vecMulS p.vel t)}
-- in the future, maybe it is a good idea to have a type Player.
-- For now, we are using Pill as player type.
stepPlayer : (Int, Int) -> Pill -> Pill
stepPlayer (x, y) p =
{p|pos = (toFloat x, toFloat y)}
-- View
render : (Int, Int) -> Game -> Element
render (w,h) game =
let formPill {rad, col, pos} = circle rad
|> filled col
|> move pos
forms = formPill game.player ::List.map formPill game.pills
in
color lightGray <| container w h middle
<| color white
<| collage width height forms
-- Input
relativeMouse : (Int, Int) -> (Int, Int) -> (Int, Int)
relativeMouse (origin_x, origin_y) (x, y) =
(x-origin_x, origin_y - y)
center : (Int, Int) -> (Int, Int)
center (w,h) =
(w//2, h//2)
mouseSignal =
Signal.map2 relativeMouse (Signal.map center Window.dimensions) Mouse.position
input : Signal (Time, (Int, Int))
input =
let time = Signal.map inSeconds (fps 30)
mouse = Signal.sampleOn time (Signal.map2 relativeMouse (Signal.map center Window.dimensions) Mouse.position)
in Signal.map2 (,) time mouse
-- Random Signal
type alias State =
{value: Float
,seed: Random.Seed}
state0 = State 0 (Random.initialSeed 42)
rstep : a -> State -> State
rstep _ state =
let (value', seed') = Random.generate gen state.seed
in State value' seed'
state : Signal Pill
state =
let
statesig = Signal.foldp rstep state0 (fps 1)
floatsig = Signal.map .value statesig
in
Signal.map newPill floatsig
event =
let t = Signal.map inSeconds (fps 30)
in
Signal.merge
(Signal.map Tick input)
(Signal.map Add state)
main =
Signal.map2 render
Window.dimensions
(foldp stepGame defaultGame event)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment