Skip to content

Instantly share code, notes, and snippets.

@darkoverlordofdata
Created March 19, 2015 03:46
Show Gist options
  • Save darkoverlordofdata/084530da8b8b7896e26e to your computer and use it in GitHub Desktop.
Save darkoverlordofdata/084530da8b8b7896e26e to your computer and use it in GitHub Desktop.
Box2D MouseJoint
###
* Set up the environment
###
do ->
###
* Polyfil the requestAnimationFrame method
###
unless window.requestAnimationFrame
window.requestAnimationFrame = do ->
window.webkitRequestAnimationFrame or window.mozRequestAnimationFrame or window.oRequestAnimationFrame or window.msRequestAnimationFrame or (callback) ->
window.setTimeout callback, 1000 / 60
return
window.addEventListener 'load', ->
###
* If desktop, use stats
###
unless navigator.isCocoonJS
container = document.createElement('div')
document.body.appendChild container
stats = new Stats()
container.appendChild stats.domElement
stats.domElement.style.position = 'absolute'
###
* configure the canvas element
###
canvas = document.createElement((if navigator.isCocoonJS then 'screencanvas' else 'canvas'))
canvas.width = window.innerWidth * window.devicePixelRatio
canvas.height = window.innerHeight * window.devicePixelRatio
canvas.style.width = '100%'
canvas.style.height = '100%'
document.body.appendChild canvas
new MouseJoint(canvas, stats)
return
, true
MathUtil = ->
MathUtil.RADIANS = Math.PI / 180
MathUtil.DEGREES = 180 / Math.PI
MathUtil.rndRange = (min, max) ->
min + (Math.random() * (max - min))
MathUtil.rndIntRange = (min, max) ->
Math.round MathUtil.rndRange(min, max)
MathUtil.toRadians = (degrees) ->
degrees * MathUtil.RADIANS
MathUtil.toDegrees = (radians) ->
radians * MathUtil.DEGREES
MathUtil.hitTest = (x1, y1, w1, h1, x2, y2, w2, h2) ->
return true if y1 < y2 + h2 if y1 + h1 > y2 if x1 < x2 + w2 if x1 + w1 > x2
false
class MouseJoint
METER = 100
width: 0
height: 0
bodies: null
actors: null
stage: null
renderer: null
world: null
mouseJoint: null
touchX: null
touchY: null
isBegin: false
stats: null
listener: null
assets: [
"assets/ball.png"
"assets/box.jpg"
]
###
* Initialize the game
###
constructor: (canvas, @stats) ->
@bodies = []
@actors = []
@width = canvas.width
@height = canvas.height
@stage = new PIXI.Stage(0xDDDDDD, true)
@renderer = PIXI.autoDetectRenderer(@width, @height, canvas, false)
loader = new PIXI.AssetLoader(@assets)
loader.onComplete = @start
loader.load()
### Events ###
if typeof window.ontouchstart is 'undefined'
events = ['mousedown', 'mouseup']
@listener = document
else
events = ['touchstart', 'touchend']
@listener = if navigator.isCocoonJS then document else canvas
for event in events
@listener.addEventListener event, @[event], true
return
###
* Start up the level
###
start: =>
###
* Elements
###
@world = new Box2D.Dynamics.b2World(new Box2D.Common.Math.b2Vec2(0, 10), true)
polyFixture = new Box2D.Dynamics.b2FixtureDef()
polyFixture.shape = new Box2D.Collision.Shapes.b2PolygonShape()
polyFixture.density = 1
circleFixture = new Box2D.Dynamics.b2FixtureDef()
circleFixture.shape = new Box2D.Collision.Shapes.b2CircleShape()
circleFixture.density = 1
circleFixture.restitution = 0.7
bodyDef = new Box2D.Dynamics.b2BodyDef()
bodyDef.type = Box2D.Dynamics.b2Body.b2_staticBody
#down
polyFixture.shape.SetAsBox 10, 1
bodyDef.position.Set 9, @height / METER + 1
@world.CreateBody(bodyDef).CreateFixture polyFixture
#left
polyFixture.shape.SetAsBox 1, 100
bodyDef.position.Set -1, 0
@world.CreateBody(bodyDef).CreateFixture polyFixture
#right
bodyDef.position.Set @width / METER + 1, 0
@world.CreateBody(bodyDef).CreateFixture polyFixture
bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody
i = 0
while i < 10
bodyDef.position.Set MathUtil.rndRange(0, @width) / METER, -MathUtil.rndRange(50, 5000) / METER
body = @world.CreateBody(bodyDef)
s = undefined
if Math.random() > 0.5
s = MathUtil.rndRange(70, 100)
circleFixture.shape.SetRadius s / 2 / METER
body.CreateFixture circleFixture
@bodies.push body
ball = new PIXI.Sprite(PIXI.Texture.fromFrame("assets/ball.png"))
@stage.addChild ball
ball.i = i
ball.anchor.x = ball.anchor.y = 0.5
ball.scale.x = ball.scale.y = s / 100
@actors.push ball
#
else
s = MathUtil.rndRange(50, 100)
polyFixture.shape.SetAsBox s / 2 / METER, s / 2 / METER
body.CreateFixture polyFixture
@bodies.push body
box = new PIXI.Sprite(PIXI.Texture.fromFrame("assets/box.jpg"))
@stage.addChild box
box.i = i
box.anchor.x = box.anchor.y = 0.5
box.scale.x = s / 100
box.scale.y = s / 100
@actors.push box
i++
@update()
return
###
* The Game Loop
###
update: =>
requestAnimationFrame @update
if @isBegin and not @mouseJoint
dragBody = @getBodyAtMouse()
if dragBody
jointDef = new Box2D.Dynamics.Joints.b2MouseJointDef()
jointDef.bodyA = @world.GetGroundBody()
jointDef.bodyB = dragBody
jointDef.target.Set @touchX, @touchY
jointDef.collideConnected = true
jointDef.maxForce = 300.0 * dragBody.GetMass()
@mouseJoint = @world.CreateJoint(jointDef)
dragBody.SetAwake true
if @mouseJoint
if @isBegin
@mouseJoint.SetTarget new Box2D.Common.Math.b2Vec2(@touchX, @touchY)
else
@world.DestroyJoint @mouseJoint
@mouseJoint = null
@world.Step 1 / 60, 3, 3
@world.ClearForces()
n = @actors.length
i = 0
while i < n
body = @bodies[i]
actor = @actors[i]
position = body.GetPosition()
actor.position.x = position.x * 100
actor.position.y = position.y * 100
actor.rotation = body.GetAngle()
i++
@renderer.render @stage
@stats?.update()
return
getBodyAtMouse: =>
mousePos = new Box2D.Common.Math.b2Vec2(@touchX, @touchY)
aabb = new Box2D.Collision.b2AABB()
aabb.lowerBound.Set @touchX - 0.001, @touchY - 0.001
aabb.upperBound.Set @touchX + 0.001, @touchY + 0.001
body = undefined
@world.QueryAABB ((fixture) ->
unless fixture.GetBody().GetType() is Box2D.Dynamics.b2BodyDef.b2_staticBody
if fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), mousePos)
body = fixture.GetBody()
return false
true
), aabb
body
###
* Events
###
mousedown: (event) =>
@isBegin = true
@mousemove event
@listener.addEventListener 'mousemove', @mousemove, true
return
mouseup: (event) =>
@listener.removeEventListener 'mousemove', @mousemove, true
@isBegin = false
@touchX = undefined
@touchY = undefined
return
mousemove: (event) =>
@touchX = event.clientX / METER
@touchY = event.clientY / METER
return
touchstart: (event) =>
@isBegin = true
@touchmove event
@listener.addEventListener 'touchmove', @touchmove, true
return
touchend: (event) =>
@listener.removeEventListener 'touchmove', @touchmove, true
@isBegin = false
@touchX = undefined
@touchY = undefined
return
touchmove: (event) =>
touche = event.changedTouches[0]
@touchX = (touche.pageX*window.devicePixelRatio) / METER
@touchY = (touche.pageY*window.devicePixelRatio) / METER
return
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment