API Documentation
1 /* 2 GLGE WebGL Graphics Engine 3 Copyright (c) 2010, Paul Brunt 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of GLGE nor the 14 names of its contributors may be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY 21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @fileOverview 31 * @name glge_physicscar.js 32 * @author me@paulbrunt.co.uk 33 */ 34 (function(GLGE){ 35 36 /** 37 * @class Physics Car class 38 * @augments GLGE.PhysicsBox 39 * @see GLGE.PhysicsWheel 40 */ 41 GLGE.PhysicsCar=function(uid){ 42 GLGE.PhysicsBox.call(this,uid); 43 this.wheels=[]; 44 this.setRotationalVelocityDamping([0.1,0.6,0.1]); 45 this.setLinearVelocityDamping([0.996,0.92,0.996]); 46 return this; 47 } 48 GLGE.augment(GLGE.PhysicsBox,GLGE.PhysicsCar); 49 GLGE.PhysicsCar.prototype.className="PhysicsCar"; 50 GLGE.Group.prototype.addPhysicsCar=GLGE.Group.prototype.addChild; 51 GLGE.Scene.prototype.addPhysicsCar=GLGE.Group.prototype.addChild; 52 /** 53 * Applies a driving force to the car 54 * @param {number} force the item driving force to apply to each powered wheel 55 */ 56 GLGE.PhysicsCar.prototype.drive=function(force){ 57 for(var i=0;i<this.wheels.length;i++){ 58 var wheel=this.wheels[i]; 59 if(wheel.powered) wheel.drive(force); 60 } 61 return this; 62 } 63 /** 64 * Applies a brake to the car 65 * @param {number} brake the level of braking 66 */ 67 GLGE.PhysicsCar.prototype.brake=function(brake){ 68 for(var i=0;i<this.wheels.length;i++){ 69 if(this.wheels[i].powered) this.wheels[i].brake(brake); 70 } 71 return this; 72 } 73 /** 74 * Adds a wheel to the car 75 * @param {GLGE.PhysicsWheel} wheel a wheel to add to the car 76 */ 77 GLGE.PhysicsCar.prototype.addPhysicsWheel=function(wheel){ 78 this.wheels.push(wheel); 79 return GLGE.PhysicsBox.prototype.addChild.call(this,wheel); 80 } 81 /** 82 * Removes a wheel from the car 83 * @param {GLGE.PhysicsWheel} wheel a wheel to remove 84 */ 85 GLGE.PhysicsCar.prototype.removeWheel=function(wheel){ 86 var idx=this.wheels.indexOf(wheel); 87 if(idx>-1) this.wheels.splice(idx,1); 88 return GLGE.PhsyicsBox.prototype.addChild.call(this,wheel); 89 } 90 /** 91 * does the physics stuff 92 * @private 93 */ 94 GLGE.PhysicsCar.prototype.getScene=function(){ 95 var child=this; 96 while(child.parent) child=child.parent; 97 return child; 98 } 99 /** 100 * does the physics stuff 101 * @private 102 */ 103 GLGE.PhysicsCar.prototype.preProcess=function(dt){ 104 var scene=this.getScene(); 105 var velocity=this.getVelocity(); 106 var carMass=this.getMass(); 107 var wheels=this.wheels 108 for(var i=0;i<wheels.length;i++){ 109 var wheel=wheels[i]; 110 var mat=wheel.getModelMatrix(); 111 var tangent=GLGE.toUnitVec3([mat[2],mat[6],mat[10]]); 112 var up=GLGE.toUnitVec3([mat[1],mat[5],mat[9]]); 113 var forward=GLGE.toUnitVec3([mat[0],mat[4],mat[8]]); 114 var position=[mat[3],mat[7],mat[11]]; 115 116 var wheelRadius=wheel.radius; 117 var travel=wheel.travel; 118 var spring=wheel.spring; 119 var sideFriction=wheel.sideFriction; 120 var frontFriction=wheel.frontFriction; 121 122 var springForce=0; 123 var result=scene.segmentTest(position,GLGE.scaleVec3(up,-travel-wheelRadius),this); 124 if(result){ 125 var distanceToFloor=result.distance-wheelRadius; 126 if(distanceToFloor<travel){ 127 springForce=(travel-distanceToFloor)/travel*spring; 128 this.addWorldForce(GLGE.scaleVec3(up,springForce),position); 129 wheel.innerGroup.setLocY(wheelRadius-result.distance); 130 } 131 //turning force 132 //var sideForce=springForce*sideFriction; //although correct having a varible side force makes things very difficult to control 133 var sideForce=sideFriction; 134 var dot=GLGE.scaleVec3(tangent,-GLGE.dotVec3(tangent,velocity)*sideForce); 135 this.addWorldForce(dot,position); 136 }else{ 137 wheel.innerGroup.setLocY(-travel); 138 } 139 140 var maxForwardForce=springForce*frontFriction; //frictional force 141 var maxdw=(maxForwardForce*dt*dt)/wheelRadius; 142 var dw=0; 143 144 //do the wheel turn 145 if(wheel.oldPos){ 146 var delta=GLGE.dotVec3(GLGE.subVec3(position,wheel.oldPos),forward)/wheelRadius; 147 var dw=delta/dt-wheel.angVel; 148 if(dw<-maxdw) dw=-maxdw; 149 if(dw>maxdw) dw=maxdw; 150 } 151 if(wheel.driveForce){ 152 var drive=wheel.driveForce*(1-wheel.braking); 153 if(drive<-maxForwardForce) drive=maxForwardForce; 154 if(drive>maxForwardForce) drive=maxForwardForce; 155 this.addWorldForce(GLGE.scaleVec3(forward,drive),position); 156 dw+=(wheel.driveForce/carMass*dt)/wheelRadius; 157 } 158 if(wheel.braking){ 159 var frontVel=GLGE.dotVec3(velocity,forward); 160 var braking=-wheel.braking*frontVel/dt 161 if(braking<-maxForwardForce) braking=-maxForwardForce; 162 if(braking>maxForwardForce) braking=maxForwardForce; 163 this.addWorldForce(GLGE.scaleVec3(forward,braking),position); 164 } 165 166 wheel.angVel+=dw; 167 if(wheel.brake) wheel.angVel*=(1-wheel.braking); 168 wheel.innerGroup.setRotZ(wheel.innerGroup.getRotZ()-wheel.angVel*dt); 169 wheel.angVel*=0.995; 170 wheel.oldPos=position; 171 172 } 173 174 GLGE.PhysicsBox.prototype.preProcess.call(this,dt); 175 176 } 177 178 179 /** 180 * @class physics wheel class used with PhysicsCar class 181 * @augments GLGE.Group 182 * @see GLGE.PhysicsBox 183 */ 184 GLGE.PhysicsWheel=function(uid){ 185 GLGE.Group.call(this,uid); 186 this.innerGroup=new GLGE.Group; 187 GLGE.Group.prototype.addChild.call(this,this.innerGroup); 188 return this; 189 } 190 GLGE.augment(GLGE.Group,GLGE.PhysicsWheel); 191 GLGE.PhysicsWheel.prototype.radius=1; 192 GLGE.PhysicsWheel.prototype.travel=0.75; 193 GLGE.PhysicsWheel.prototype.angVel=0; 194 GLGE.PhysicsWheel.prototype.spring=90; 195 GLGE.PhysicsWheel.prototype.braking=0; 196 GLGE.PhysicsWheel.prototype.driveForce=0; 197 GLGE.PhysicsWheel.prototype.powered=false; 198 GLGE.PhysicsWheel.prototype.sideFriction=3; //sideways friction co-efficient 199 GLGE.PhysicsWheel.prototype.frontFriction=3; //front friction force 200 GLGE.PhysicsWheel.prototype.className="PhysicsWheel"; 201 202 /** 203 * Adds a child to the wheel container 204 * @param {object} child a GLGE object to represent the wheel 205 */ 206 GLGE.PhysicsWheel.prototype.addChild=function(child){ 207 return this.innerGroup.addChild(child); 208 } 209 /** 210 * Removes a child to the wheel container 211 * @param {object} child a GLGE object to represent the wheel 212 */ 213 GLGE.PhysicsWheel.prototype.removeChild=function(child){ 214 return this.innerGroup.removeChild(child); 215 } 216 GLGE.PhysicsWheel.prototype.addGroup=GLGE.PhysicsWheel.prototype.addChild; 217 GLGE.PhysicsWheel.prototype.addCollada=GLGE.PhysicsWheel.prototype.addChild; 218 GLGE.PhysicsWheel.prototype.addObject=GLGE.PhysicsWheel.prototype.addChild; 219 GLGE.PhysicsWheel.prototype.addMD2=GLGE.PhysicsWheel.prototype.addChild; 220 GLGE.PhysicsWheel.prototype.addMD3=GLGE.PhysicsWheel.prototype.addChild; 221 GLGE.PhysicsWheel.prototype.addWavefront=GLGE.PhysicsWheel.prototype.addChild; 222 223 224 /** 225 * Sets the wheel to be a powered wheel 226 * @param {boolean} powered flag indicateding if wheel is powered 227 */ 228 GLGE.PhysicsWheel.prototype.setPowered=function(powered){ 229 this.powered=powered; 230 return this; 231 } 232 233 /** 234 * Sets the wheel Radius 235 * @param {number} radius the wheel radius 236 */ 237 GLGE.PhysicsWheel.prototype.setRadius=function(radius){ 238 this.radius=radius; 239 return this; 240 } 241 /** 242 * Sets the suspension spring distance 243 * @param {number} radius the wheel radius 244 */ 245 GLGE.PhysicsWheel.prototype.setSpring=function(spring){ 246 this.spring=spring; 247 return this; 248 } 249 /** 250 * Sets the suspension travel distance 251 * @param {number} travel the suspension travel 252 */ 253 GLGE.PhysicsWheel.prototype.setTravel=function(travel){ 254 this.travel=travel; 255 return this; 256 } 257 /** 258 * Sets the front friction coefficient 259 * @param {number} friction the front fricition coefficient 260 */ 261 GLGE.PhysicsWheel.prototype.setFrontFriction=function(friction){ 262 this.frontFriction=friction; 263 return this; 264 } 265 /** 266 * Sets the side friction coefficient 267 * @param {number} friction the side fricition coefficient 268 */ 269 GLGE.PhysicsWheel.prototype.setSideFriction=function(friction){ 270 this.sideFriction=friction; 271 return this; 272 } 273 /** 274 * Sets the wheel Rotation 275 * @param {number} rotation the rotation of the wheel 276 */ 277 GLGE.PhysicsWheel.prototype.setWheelRotation=function(rotation){ 278 this.setRotY(rotation); 279 return this; 280 } 281 /** 282 * Gets the wheel Rotation 283 * @returns the wheel roation in radians 284 */ 285 GLGE.PhysicsWheel.prototype.getWheelRotation=function(rotation){ 286 return this.getRotY(); 287 } 288 /** 289 * Gets the wheel Radius 290 * @returns the wheel radius 291 */ 292 GLGE.PhysicsWheel.prototype.getRadius=function(){ 293 return this.radius; 294 } 295 /** 296 * Gets the suspension spring 297 * @returns the wheel radius 298 */ 299 GLGE.PhysicsWheel.prototype.getSpring=function(){ 300 return this.spring; 301 } 302 /** 303 * Gets the suspension travel distance 304 * @returns the suspension travel 305 */ 306 GLGE.PhysicsWheel.prototype.getTravel=function(){ 307 return this.travel; 308 } 309 /** 310 * Gets the front friction coefficient 311 * @returns the front fricition coefficient 312 */ 313 GLGE.PhysicsWheel.prototype.getFrontFriction=function(){ 314 return this.frontFriction; 315 } 316 /** 317 * Gets the side friction coefficient 318 * @returns the side fricition coefficient 319 */ 320 GLGE.PhysicsWheel.prototype.getSideFriction=function(){ 321 return this.sideFriction; 322 } 323 324 /** 325 * Sets a driving force for the wheel 326 * @param {number} force the driving force in N 327 */ 328 GLGE.PhysicsWheel.prototype.drive=function(force){ 329 this.driveForce=force; 330 return this; 331 } 332 /** 333 * Sets the braking level 334 * @param {number} brake 0-1 value indicating the level of braking 335 */ 336 GLGE.PhysicsWheel.prototype.brake=function(brake){ 337 this.braking=brake; 338 return this; 339 } 340 341 })(GLGE);