/** * Flade - Flash Dynamics Engine * Release 0.4 alpha * Surface class * Copyright 2004, 2005 Alec Cove * * This file is part of Flade. The Flash Dynamics Engine. * * Flade is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Flade is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Flade; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Flash is a registered trademark of Macromedia */ Surface = function(p1, p2) { this.p1 = p1; this.p2 = p2; this.isOrientH = true; this.normal = new Vector(0,0); this.calcNormal(); // some precalculations this.rise = this.p2.y - this.p1.y; this.run = this.p2.x - this.p1.x; this.invRun = 1 / this.run; this.slope = this.rise / this.run; this.invB = 1 / (this.run * this.run + this.rise * this.rise); var drawClipName = "surfdrawclip_" + this.depth; this.dmc = createEmptyMovieClip (drawClipName, this.depth); this.dmc.lineStyle(0, 0x222288, 100); Surface.prototype.depth++; } Surface.prototype.depth = 2000; Surface.prototype.setIsOrientH = function(isOrientH) { this.isOrientH = isOrientH; } Surface.prototype.calcNormal = function() { // find normal var dx = this.p2.x - this.p1.x; var dy = this.p2.y - this.p1.y; this.normal.x = dy this.normal.y = -dx; // normalize var mag = Math.sqrt ( (this.normal.x * this.normal.x) + (this.normal.y * this.normal.y)); this.normal.x /= mag; this.normal.y /= mag; } Surface.prototype.paint = function() { Graphics.prototype.paintLine(this.dmc, this.p1.x, this.p1.y, this.p2.x, this.p2.y); } Surface.prototype.resolveWheelCollision = function(w, sysObj) { if (this.bounds(w.wp.curr, w.contactRadius)) { // get the closest point on the surface this.getClosestPoint(w.wp.curr, w.closestPoint); // get the normal of the circle relative to the location of the closest point var circleNormal = w.closestPoint.minusNew(w.wp.curr); circleNormal.normalize(); /* * if the center of the wheel has broken the ground plane * keep the normal from 'flipping' to the opposite direction. * for small wheels, this prevents break-throughs */ if (this.inequality(w.wp.curr)) { var absCX = Math.abs(circleNormal.x); circleNormal.x = (this.normal.x < 0) ? absCX : -absCX circleNormal.y = Math.abs(circleNormal.y); } // get contact point on edge of circle var contactPoint = w.wp.curr.plusNew(circleNormal.mult(w.wr)); if (this.segmentInequality(contactPoint)) { // project back var dx = contactPoint.x - w.closestPoint.x; var dy = contactPoint.y - w.closestPoint.y; w.wp.curr.x -= dx; w.wp.curr.y -= dy; w.resolve(this.normal); } } } Surface.prototype.resolveParticleCollision = function(p, sysObj) { if (this.boundedSegmentInequality(p.curr)) { var vel = p.curr.minusNew(p.prev); var sDotV = this.normal.dot(vel); if (sDotV < 0) { // compute momentum of particle perpendicular to normal var velProjection = vel.minusNew(this.normal.multNew(sDotV)); var perpMomentum = velProjection.multNew(sysObj.coeffFric); // compute momentum of particle in direction of normal var normMomentum = this.normal.multNew(sDotV * sysObj.coeffRest); var totalMomentum = normMomentum.plusNew(perpMomentum); // set new velocity w/ total momentum var newVel = vel.minusNew(totalMomentum); // project out of collision var mirrorPos = this.normal.dot(p.curr.minusNew(this.p1)) * sysObj.coeffRest; p.curr.minus(this.normal.multNew(mirrorPos)); // apply new velocity p.prev = p.curr.minusNew(newVel); } } } Surface.prototype.segmentInequality = function(toPoint) { var u = this.findU(toPoint); var isUnder = this.inequality(toPoint); return (u >= 0 && u <= 1 && isUnder); } Surface.prototype.boundedSegmentInequality = function(toPoint) { var isBound; if (this.isOrientH) { isBound = ((toPoint.x >= this.p1.x) && (toPoint.x <= this.p2.x)); } else if (this.p1.y < this.p2.y) { isBound = ((toPoint.y >= this.p1.y) && (toPoint.y <= this.p2.y)); } else { isBound = ((toPoint.y <= this.p1.y) && (toPoint.y >= this.p2.y)); } if (isBound) { return isUnder = this.inequality(toPoint); } return false; } Surface.prototype.inequality = function(toPoint) { // equation of a line var line = this.slope * (toPoint.x - this.p1.x) + (this.p1.y - toPoint.y); return (line <= 0); } Surface.prototype.bounds = function(toPoint, r) { return ((toPoint.x >= this.p1.x - r) && (toPoint.x <= this.p2.x + r)); } Surface.prototype.getClosestPoint = function(toPoint, returnVect) { var u = this.findU(toPoint); if (u <= 0) return this.p1; if (u >= 1) return this.p2; var x = this.p1.x + u * (this.p2.x - this.p1.x); var y = this.p1.y + u * (this.p2.y - this.p1.y); returnVect.x = x; returnVect.y = y; } Surface.prototype.findU = function (p) { var a = (p.x - this.p1.x) * this.run + (p.y - this.p1.y) * this.rise; return a * this.invB; }