rot_collisions.js.coffee | |
---|---|
rot_collisisons.js main() for the rotation collisions page demos | |
= require ./plugins = require mylibs/vec = require mylibs/Math = require mylibs/Array = require mylibs/Line = require mylibs/Circle = require mylibs/Rectangle = require mylibs/Canvas = require mylibs/collisions | $(document).ready ->
canvas = new Canvas($("#maincanvas").get(0))
canvas.setOrigin('bottomleft')
elapsed = lastTime = 0
line = line2 = null
ball = null
rec = null
objects = []
otherObject = 0
paused = true
ballMoving = false
rotationOffset = false
lineLength = 0
angle = 0
startingAngle = 0
angVel = ballDistance = ballAngle = perpDist = collisionIn = 0
drawInfo = (text) ->
$('#info').append(text + '<br/>')
clearInfo = ->
$('#info').html('')
drawText = (text, x, y) ->
canvas.inContext((ctxt) -> |
when origin is cartesian, we must restore to world view to draw text | if !canvas.inWorldView()
ctxt.scale(1, -1);
ctxt.translate(0, -canvas.height);
ctxt.fillStyle = 'black'
ctxt.font = '12px Arial sans-serif'
ctxt.textBaseline = 'top'
ctxt.fillText(text, x, y)
)
drawScene = () ->
canvas.clear()
drawText "Collision in #{collisionIn}", canvas.width/2, 20
drawText "angle: #{line.rotation}", canvas.width/2, 40
for obj in objects
switch obj.name
when 'Line'
canvas.drawCircleAt(obj.x(), obj.y(), 1, {color: 'black'})
canvas.drawLine(obj)
when 'Circle'
canvas.inContext ->
canvas.drawCircle obj
when 'Rectangle'
canvas.inContext((ctxt) -> |
Draw center of rectangle | canvas.drawCircleAt(obj.x(), obj.y(), 2, {color: 'black'})
if obj.rotation != 0
canvas.translate obj.x(), obj.y()
canvas.rotate(Math.degreesToRadians(obj.rotation))
canvas.translate(-obj.x(), -obj.y())
canvas.drawRect obj
)
setupScene = ->
angle = lastAngle = startingAngle = $("input[name=sAngle]").val() || 0
angularVel = $("input[name=angVel]").val() || 0
otherObject = parseInt($("input[name=object]:checked").val())
rotationOffset = $("input[name=rotationOffset]:checked").val() == "1"
$('#sangle').html(startingAngle)
$('#angvel').html(angularVel)
objects = []
ball = null
line2 = null
lineLength = 150
|
draw rotating line | line = new Line(canvas.width/2, canvas.height/2, 0, 0, {
color: 'black',
rotation: startingAngle,
length: lineLength
})
objects.push line
|
Create other object based on selection | switch otherObject
when 1, 2 |
other object is ball | ball = new Circle(canvas.width/2+lineLength/1.2, canvas.height/2, 0, {
radius: lineLength/8,
color: 'blue'
}) |
give ball a velocity if moving option checked | if otherObject == 2
ballMoving = true
ball.velocity = $V([-5, 10, 0]) |
these two variable can be computed dynamically if the ball is moving | ballDistance = ball.pos.subtract(line.pos).mag()
ballAngle = Math.degreesToRadians 90
objects.push ball
when 3, 4 |
other object is line. need vector for direction, not rotation | line2Angle = $("input[name=s2Angle]").val() || 350
line2Length = 250
line2 = new Line(line.x()+145, line.y()-50, 0, 0, {
rotation: line2Angle,
length: line2Length
})
if otherObject == 4
line2.setAngularVelocity(-angularVel)
objects.push line2
rec = new Rectangle(canvas.width/2, canvas.height/2, 0, 40, 40, {
rotation: startingAngle
})
|
make line fixed to rectangle side if rotation offset checked | if rotationOffset
line.moveTo(if canvas.inWorldView() then rec.origin() else rec.cartesianOrigin()) |
point of rotation's perp. distance from line | perpDist = rec.height / 2
line.setAngularVelocity(angularVel)
angVel = line.angularVelocity('r')
lineToCenterDist = line.pos.subtract(rec.pos).mag()
clearInfo()
drawInfo("Angle: #{line.rotation}")
drawInfo("Line length: #{lineLength}")
drawInfo("rotation axis: #{line.pos.inspect()}")
drawInfo("ang vel: #{angVel}")
drawInfo("k: #{perpDist}")
drawInfo("d to center: #{lineToCenterDist}")
updateObjects = (t) -> |
update the line's rotation and others | line.moveByTime(t)
rec.rotation = line.rotation
ball.moveByTime(t) if ball
line2.moveByTime(t) if line2
|
if rotating around a point | if rotationOffset |
get new origin of rotated rectangle and move line to it | o = rec.cartesianOrigin() |
Use negative rotation to force clockwise rotation direction | o2 = o.to2D().rotate(Math.degreesToRadians(-rec.rotation), rec.pos.to2D())
line.moveTo $V([o2.e(1), o2.e(2), 0])
checkCollisions = (t) -> |
Pick earliest time to collision from list | firstCollision = (times...) ->
(t for t in times when collisions.isImpendingCollision(t)).min()
|
Use different detection methods depending on ball movement | if ballMoving
res = collisions.angularCollisionLineCircle2(line, ball, t)
collisionIn = res.t
paused = collisionIn == 0
else if ball
collisionIn = collisions.angularCollisionLineCircle(
Math.degreesToRadians(line.rotation),
angVel, line.length,
ball.radius, ballDistance, ballAngle,
perpDist)
else # another line
if line2.isRotating() |
check using triangle test | res = collisions.angularCollisionLineLine(line, line2, t)
collisionIn = res.t
paused = collisionIn == 0
else # colliding with stationary line |
check for collision on flat | c1 = collisions.angularCollisionLineStationaryLine(
Math.degreesToRadians(line.rotation),
angVel,
line, line2, false) |
check for collision with endpoints | c2 = collisions.angularCollisionLineStationaryLine(
Math.degreesToRadians(line.rotation),
angVel,
line, line2, true)
collisionIn = firstCollision(c1, c2) || collisions.NONE
paused ||= collisions.isImpendingCollision(collisionIn) && (Math.abs(collisionIn) < 0.04)
|
animate all objects | update = -> |
Pass latest timestep to the collision detection function | timeNow = new Date().getTime()
if lastTime != 0
elapsed = (timeNow - lastTime) / 1000
elapsed = 0.1 if elapsed > 0.1
updateObjects(elapsed)
checkCollisions(elapsed)
lastTime = timeNow |
tick funtion | tick = ->
requestAnimFrame(tick)
unless paused
update()
drawScene(objects, elapsed)
|
event handlers | $('canvas').click ->
paused = !paused
$('input').change -> setupScene()
setupScene()
tick()
|