Skip to content

Commit

Permalink
Working on angular forces and collisions
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmire committed Feb 23, 2013
1 parent c33c9dd commit b804302
Show file tree
Hide file tree
Showing 13 changed files with 701 additions and 238 deletions.
24 changes: 24 additions & 0 deletions README.md
@@ -0,0 +1,24 @@

## Vector math

### Dot product and perp dot product

Dot product: v1.mag * v2.mag * cos(theta)
v1.x*v2.x + v1.y*v2.y
Perp dot product: v1.mag * v2.mag * sin(theta)
-v1.y*v2.x + v1.x*v2.y

## Resources consulted for this project (in order of viewing)

* http://gafferongames.com/game-physics/fix-your-timestep
* http://gafferongames.com/game-physics/integration-basics
* http://gafferongames.com/game-physics/spring-physics/
* http://chrishecker.com/Rigid_Body_Dynamics
* http://www.youtube.com/watch?v=LbKKzMag5Rc
* http://gamedev.stackexchange.com/questions/25838/when-to-detect-collisions-in-game-loop
* http://www.wildbunny.co.uk/blog/2011/04/06/physics-engines-for-dummies/
* http://www.wildbunny.co.uk/blog/2011/04/20/collision-detection-for-dummies/
* http://www.wildbunny.co.uk/blog/vector-maths-a-primer-for-games-programmers/
* http://www.codezealot.org/archives/88
* http://www.codezealot.org/archives/153
* http://research.ncl.ac.uk/game/mastersdegree/gametechnologies/
85 changes: 85 additions & 0 deletions js/demos/angular.js
@@ -0,0 +1,85 @@

'use strict';

(function() {
var Projectile, canvas, canvasObjects

Projectile = P(CanvasObject, function (proto, uber, klass) {
klass.maxSpeed = 5
return {
setOptions: function (opts) {
uber.setOptions.apply(this, arguments)
this.vel = Vec2(3,0)
this.pos = Vec2(200,200)
},

calculateForces: function (nextState, t) {
var values = {},
linearForce,
angularForce,
forceAmount = 0.3,
forceDampening = 0.1,
torqueAmount = 0.3,
torqueDampening = 0.1

linearForce = Vec2()
if (keyboard.keyIsPressed('UP')) {
linearForce += forceAmount
}
// apply viscous damper force (from F = kx - cv)
// XXX: don't we want to damp velocity and not force?
linearForce -= Vec2.mul(nextState.velocity, forceDampening)
if (linearForce < 0.001) {
linearForce = 0
}

angularForce = 0
if (keyboard.keyIsPressed('LEFT')) {
angularForce += torqueAmount
} else if (keyboard.keyIsPressed('RIGHT')) {
angularForce -= torqueAmount
}
// apply viscous damper force (from F = kx - cv)
// XXX: don't we want to damp velocity and not force?
angularForce -= Vec2.mul(nextState.angularVelocity, torqueDampening)
if (angularForce < 0.001) {
angularForce = 0
}

values.torque = angularForce
values.force = Vec2.rotate(Vec2(linearForce, 0), angularForce)

return values
},

draw: function () {
var pos, ori, color
pos = this.interpState.position
ori = this.interpState.orientation
color = (this.index == 0) ? "red" : "black"
this.canvas.triangle(pos[0], pos[1], this.width, this.height, {
rotate: ori,
fill: color
})
}
}
})

//---

canvas = Canvas("#wrapper", {
width: 1000,
height: 400
})
canvasObjects = canvas.buildObjectCollection(CanvasObjectCollection)
canvasObjects.addObject(Projectile, {
width: 8,
height: 6,
position: Vec2(canvas.height - 6),
orientation: (Math.PI / 2),
gravity: false
})

window.canvas = canvas
})()

54 changes: 34 additions & 20 deletions js/demos/boids.js
Expand Up @@ -12,10 +12,12 @@
this.index = options.index
},

setVel: function() {
uber.setVel.call(this)
this.parent.applyRulesTo(this)
collision.applyTo(this.canvas, this)
update: function (t, dt) {
this.boidAcc = this.parent.calculateBoidAcc(boid)
},

accelerationAt: function(newState, t) {
this.parent.applyRulesTo(this, newState, t)
},

render: function() {
Expand All @@ -28,6 +30,7 @@
}
}
})

BoidCollection = P(DrawableCollection, function () {
return {
sepDistLimit: 50,
Expand All @@ -50,9 +53,10 @@
},

applyRulesTo: function (boid) {
this._applyCohesionRule(boid)
this._applySeparationRule(boid)
this._applyAlignmentRule(boid)
var deltaAcc = Vec2(0,0)
this._applyCohesionRule(boid, deltaAcc)
this._applySeparationRule(boid, deltaAcc)
this._applyAlignmentRule(boid, deltaAcc)
},

// Cohesion: Boids try to fly towards the center of mass of neighboring
Expand All @@ -62,23 +66,33 @@
// because when a boid is trying to figure out where the center is,
// though, it's not going to include itself (since it can't see itself).
//
_applyCohesionRule: function (boid) {
var v, i, len, j
v = Vec2(0,0)
// TODO: Only consider nearest objects
for (i = 0, j = 0, len = this.objects.length; i < len; i++) {
if (this.objects[i] === boid) continue
Vec2.add(v, this.objects[i].pos)
j++
_applyCohesionRule: function (boid, deltaAcc) {
var i, len, numNearBoids, v, w, dist
// Calculate the center of nearby boids
i = 0
j = 0
len = this.objects.length
numNearBoids = 0
w = Vec2(0,0)
while (i < len) {
v = Vec2(0,0)
if (this.objects[i] !== boid) {
Vec2.sub(boid.pos, this.objects[i].pos, v)
dist = Vec2.mag(v)
if (v <= 40) {
Vec2.add(w, this.objects[i].pos)
numNearBoids++
}
}
i++
}
// The avg is the centroid
Vec2.div(v, j)
Vec2.div(w, numNearBoids)
// The diff is the line pointing from me to the centroid
Vec2.sub(v, boid.pos)
Vec2.sub(w, boid.pos)
// So, my displacement vector is a small movement toward the centroid
Vec2.div(v, 100)
Vec2.div(w, 100)
// Apply the rule
Vec2.add(boid.vel, v)
Vec2.add(deltaAcc, w)
},

// Separation: Boids try to keep a small distance away from other objects
Expand Down
38 changes: 19 additions & 19 deletions js/demos/repulsion.js
Expand Up @@ -7,20 +7,20 @@
repulsion = {
// TODO
applyTo: function (canvas, obj) {
var bb, ob, f, newvel, k, dxa, dxb, dya, dyb, velslope, extra, xr, newpos
var bb, ob, f, newvel, q, dxa, dxb, dya, dyb, velslope, extra, xr, newpos

// Smooth repulsion:
// * at |x - p| = k, factor = 0
// * at |x - p| = 0, factor = 1
// So, factor for x direction is ((k - |x - p|) / k)
// * at |a - b| = q, factor = 0
// * at |a - b| = 0, factor = 1
// So, factor for x direction is ((q - |a - b|) / q)

// Calculate new displacement

bb = canvas.getBounds() // Box bounds
ob = obj.getBounds() // Object bounds
f = 0.5
newvel = obj.vel.slice(0)
k = 30
q = 30

// The distance the object is past the bound
dxa = Math.abs(ob[0][0] - bb[0][0])
Expand All @@ -31,31 +31,31 @@

// Modify the velocity by the amount the object is near the bound.
// The closer the object is to the bound (and, technically, the further it is past the
// "safe area" which is designated by k), the further it's pushed away.
// "safe area" which is designated by q), the further it's pushed away.
// As long as the object is near the bound, it's continually pushed away, and the
// effect is that it eventually changes direction.
//
// FIXME: The problem with this is that when the object exits the force field it doesn't
// quite return to its original velocity... also the force field may push with a bigger
// force than the object itself
if (dxa < k) {
extra = ((k - dxa) / k)
if (dxa < q) {
extra = ((q - dxa) / q)
xr = f * extra
newvel[0] += xr
}
if (dxb < k) {
extra = ((k - dxb) / k)
if (dxb < q) {
extra = ((q - dxb) / q)
xr = f * extra
debug("extra: ((" + k + " - " + dxb + ") / " + k + ") = " + extra)
debug("extra: ((" + q + " - " + dxb + ") / " + q + ") = " + extra)
newvel[0] -= xr
}
if (dya < k) {
extra = ((k - dya) / k)
if (dya < q) {
extra = ((q - dya) / q)
yr = f * extra
newvel[1] += yr
}
if (dyb < k) {
extra = ((k - dyb) / k)
if (dyb < q) {
extra = ((q - dyb) / q)
yr = f * extra
newvel[1] -= yr
}
Expand All @@ -74,15 +74,15 @@
},

accelerationAt: function(obj, t) {
var k, b, acc, spring, diff
k = 32
var q, b, acc, spring, diff
q = 32
b = 1
acc = Vec2(0,0)
spring = Vec2(200,170)
diff = Vec2(0,0)
Vec2.sub(spring, obj.pos, diff)
acc[0] = k * (diff[0] / this.mass) - b * obj.vel[0]
acc[1] = k * (diff[1] / this.mass) - b * obj.vel[1]
acc[0] = q * (diff[0] / this.mass) - b * obj.vel[0]
acc[1] = q * (diff[1] / this.mass) - b * obj.vel[1]
//console.log(JSON.stringify({acc: acc}))
return acc
},
Expand Down

0 comments on commit b804302

Please sign in to comment.