Skip to content

Instantly share code, notes, and snippets.

@Fishrock123
Forked from maccman/canvas.physics.coffee
Created April 11, 2013 03:29
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 Fishrock123/5360519 to your computer and use it in GitHub Desktop.
Save Fishrock123/5360519 to your computer and use it in GitHub Desktop.
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
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment