Skip to content

Instantly share code, notes, and snippets.

@andrelevi
Last active March 15, 2016 05:15
Show Gist options
  • Save andrelevi/51e827126f93fb51dc4e to your computer and use it in GitHub Desktop.
Save andrelevi/51e827126f93fb51dc4e to your computer and use it in GitHub Desktop.
Simple particle system written in Elm. Must edit Graphics.Collage source to expose sprite function.
import List exposing (map, head, concatMap, concat, append)
import Color exposing (..)
import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import Mouse
import Window
import Random exposing (generate, list, float)
import Debug
import AnimationFrame
-- HELPERS
zip4 : List a -> List b -> List c -> List d -> List (a,b,c,d)
zip4 ws xs ys zs =
case (ws, xs, ys, zs) of
( w :: ws', x :: xs', y :: ys', z :: zs' ) ->
(w,x,y,z) :: zip4 ws' xs' ys' zs'
(_, _, _, _) ->
[]
-- CONSTANTS
particleCount = 15
xBounds = 200
yBounds = 200
spritesheet = "imgs/sprites/particle_o_2x.png"
frameCount = 11
maxFrame = frameCount - 1
-- MODEL
type alias Particle =
{ x: Float
, y: Float
, speed: Float -- responsbile for velocity and frame change frequency
, frame: Float
}
xs = generate (list particleCount (float -xBounds xBounds)) <| Random.initialSeed 0
ys = generate (list particleCount (float -yBounds yBounds)) <| (snd xs)
speeds = generate (list particleCount (float 0 2)) <| (snd ys)
framePointers = generate (list particleCount (float 0 maxFrame)) <| (snd speeds)
zippedProperties = zip4 (fst xs) (fst ys) (fst speeds) (fst framePointers)
particles : List Particle
particles = map (\(x, y, speed, frame) -> { x = x, y = y, speed = speed, frame = frame}) zippedProperties
-- UPDATE
update : (Int, Int) -> List Particle -> List Particle
update mousePosition particles =
map (\p -> step p mousePosition) particles
step : Particle -> (Int, Int) -> Particle
step p (mouseX, mouseY) =
let
velocityX = p.speed + ((toFloat mouseX) / 300)
velocityY = p.speed + ((toFloat mouseY) / 300)
newX = p.x + velocityX
newY = p.y + velocityY
newFrame = if p.frame + p.speed > maxFrame then 0 else p.frame + (p.speed / 40)
in
{ p |
x <- if newX > xBounds then -xBounds else newX,
y <- if newY > yBounds then -yBounds else newY,
frame <-newFrame
}
-- VIEW
showParticle : Particle -> Form
showParticle p =
sprite 40 40 ((floor p.frame) * 40, 0) spritesheet
|> move (p.x, p.y)
view : (Int, Int) -> List Particle -> Element
view (w, h) particles =
collage w h <| map showParticle particles
-- SIGNALS
main : Signal Element
main =
Signal.map2 view Window.dimensions (Signal.foldp update particles input)
input : Signal (Int, Int)
input =
Signal.sampleOn AnimationFrame.frame Mouse.position
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment