Fork me on GitHub

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);