Skip to content

Instantly share code, notes, and snippets.

@jamster
Forked from maccman/canvas.physics.coffee
Created May 29, 2013 13:46
Show Gist options
  • Select an option

  • Save jamster/5670355 to your computer and use it in GitHub Desktop.

Select an option

Save jamster/5670355 to your computer and use it in GitHub Desktop.

Revisions

  1. @maccman maccman created this gist Apr 11, 2013.
    161 changes: 161 additions & 0 deletions canvas.physics.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,161 @@
    class Point
    constructor: (@x = 0, @y = 0) ->
    if isNaN(@x) or isNaN(@y)
    throw new Error('Invalid coords')

    add: (point) ->
    @x += point.x
    @y += point.y

    subtract: (point) ->
    @x -= point.x
    @y -= point.y

    scale: (multiplier) ->
    @x *= multiplier
    @y *= multiplier

    min: (x, y) ->
    @x = x if @x < x
    @y = y if @y < y

    max: (x, y) ->
    @x = x if @x > x
    @y = y if @y > y

    replace: (point) ->
    @x = point.x
    @y = point.y

    dup: ->
    new @constructor(@x, @y)

    class Force extends Point

    class Particle
    constructor: (x = 0, y = 0) ->
    @current = new Point(x, y)
    @previous = new Point(x, y)
    @force = new Point

    step: (timeStep) ->
    @verlet(timeStep)
    @constrain()

    render: ->

    setForce: (@force) ->

    getCoords: ->
    [@current.x, @current.y]

    moveTo: (x, y) ->
    @current.x = x if x?
    @current.y = y if y?

    # Private

    verlet: (timeStep = 0.6) ->
    calcPoint = new Point(0, 0)
    tempPoint = @current.dup()

    forcePoint = @force.dup()
    forcePoint.scale(timeStep * timeStep)

    calcPoint.add(@current)
    calcPoint.subtract(@previous)
    calcPoint.add(forcePoint)

    @current.add(calcPoint)
    @previous.replace(tempPoint)

    constrain: ->

    class Element
    constructor: (@x = 0,
    @y = 0,
    @width = 50,
    @height = 50) ->
    @particle = new Particle(x, y)

    setForce: (force) ->
    @particle.setForce(force)

    step: (timeStep) ->
    @particle.step(timeStep)
    @constrain()

    moveTo: (x, y) ->
    @particle.moveTo(x, y)

    render: (ctx) ->
    [@x, @y] = @particle.getCoords()
    ctx.moveTo(@x, @y)
    @paint(ctx)

    # Override these

    constrain: ->

    paint: (ctx) -> throw 'Must implement paint()'

    class Rectangle extends Element
    paint: (ctx) ->
    ctx.fillStyle = "rgb(200,0,0)"
    ctx.fillRect(@x, @y, @width, @height)

    class Stage
    constructor: ->
    @el = document.createElement('canvas')
    @el.width = 300
    @el.height = 300

    @ctx = @el.getContext('2d')
    @particles = []
    @forces = []

    run: =>
    @tick()
    window.requestAnimationFrame(@run)

    addElement: (element) =>
    @particles.push(element)

    addParticle: (push) =>
    @particles.push(particle)

    addForce: (force) =>
    @forces.push(force)

    # Private

    tick: =>
    @step()
    @render()

    step: =>
    force = new Point
    force.add(f) for f in @forces

    for particle in @particles
    particle.setForce(force)
    particle.step()

    render: =>
    @reset()

    for particle in @particles
    @ctx.save()
    particle.render(@ctx)
    @ctx.restore()

    reset: =>
    @ctx.clearRect(0, 0, @el.width, @el.height)

    @CanvasPhysics =
    Stage: Stage
    Point: Point
    Force: Force
    Particle: Particle
    Element: Element
    Rectangle: Rectangle
    18 changes: 18 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    <!DOCTYPE html>
    <html>
    <head>
    <script src="lib/canvas.physics.js"></script>
    </head>
    <body>
    <div id="app"></div>

    <script>
    var stage = new CanvasPhysics.Stage;
    stage.addForce(new CanvasPhysics.Force(0, 0.9)); // Gravity
    stage.addElement(new CanvasPhysics.Rectangle);

    app.appendChild(stage.el);
    stage.run();
    </script>
    </body>
    </html>