//collision.cpp //detect and handle collisions between objects and other objects or objects and ground #include #include "entities.h" #include "carphysics.h" #include "gameframe.h" #include "roads.h" #include "particles.h" #include "text.h" #include "parser.h" #include "gamesound.h" #include "controls.h" #include "environment.h" #include "random.h" #include "collision.h" #ifndef __TARGET_TOOLAPP #endif #include "gamemem.h" #define kSeperationFactor 0.001 #define kMaxSeperation 10 #define kFindNormalFactor 0.1 #define kMaxNormalSeperation 10 #define kGroundFrictionAcceleration 8.0 #define kMinVelo 0.2 #define kMinRotVelo 0.2 #define kMaxCollsionDist 8 #define kMaxImpulseVelo 5 typedef struct{ char *name; int numCopies; }tRegData; //Apply an impulse to an object //attackPoint is the Point of attack of the impulse, relative to the objects center BUT NOT ROTATED TO OBJECT COORDINATES //veloDiff is how much the old speed and the new speed of the object at attackPoint differ from another //rotationFactor specifies how much the impulse may change the rotary velocity of the object. //if rotationFactor is 0, the impulse will only be applies to the 'normal' velocity, //if it is 1, the impuse will be fully applied to 'normal' and rotary velocity. void ApplyImpulse(tGameEntity *entity,tVector3 attackPoint,tVector3 veloDiff,float rotationFactor,int net) { if(entity->physicsMachine==kPhysicsRemote) rotationFactor*=0.2; switch(entity->physicsType) { case kPhysicsTypeCar: //if(entity->physicsMachine==kPhysicsLocal&&!gReplay) { // if(entity==gViewedEntity) // printf("hitme! %f\n",~veloDiff); tCarPhysics *phys=(tCarPhysics*)entity->physics; tCarDefinition *car=&(phys->car); //how mcuh force is required to accelerate the object? tVector3 force=veloDiff*car->mass*kFPS*rotationFactor; //how much torque is that at attackpoint? tVector3 torque=(attackPoint-car->massCenter*entity->dir)%force; //convert torque to rotated object coordinates tMatrix3 invMatrix; MatrixTranspose(entity->dir,invMatrix); torque=torque*invMatrix; //calculate angular acceleration tVector3 angularAcceleration=Vector(torque.x/car->inertia.x,torque.y/car->inertia.y,torque.z/car->inertia.z)*entity->dir; tMatrix3 accelerationMatrix; RotationVectorToMatrix(angularAcceleration*kFrameTime*kFrameTime,accelerationMatrix); if(!net) { phys->arcadeSteerVelo+=angularAcceleration.y*kFrameTime*kFrameTime; if(fabs(phys->arcadeSteerVelo)>0.5)phys->arcadeSteerVelo=sign(phys->arcadeSteerVelo)*0.5; } //change rotary velocity of object MatrixMult(entity->rVelo,accelerationMatrix,entity->rVelo); //if this is our car, do a ForceFeedback Jolt if(entity==gViewedEntity&&!gReplay) { float impact=~veloDiff; impact*=0.2; if(impact>1)impact=1; FFBJolt(impact,impact,0.3); } //change velocity of object if(!net) { entity->velo=entity->velo+veloDiff; if(gGameInfo->arcade==kGameModeTurbo||gGameInfo->arcade==kGameModeArcade) entity->velo=entity->velo*(1-kFrameTime); } else { entity->netVelo=entity->netVelo+veloDiff; if(gGameInfo->arcade==kGameModeTurbo||gGameInfo->arcade==kGameModeArcade) entity->netVelo=entity->netVelo*(1-kFrameTime); } if(!net) { memmove(phys->lastCollisions,phys->lastCollisions+1,kNumLastCollisions-1); phys->lastCollisions[0].frameCount=gFrameCount; phys->lastCollisions[0].attackPoint=attackPoint; phys->lastCollisions[0].veloDiff=veloDiff; phys->lastCollisions[0].rotationFactor=rotationFactor; } for(int i=0;ilastVelos[i]=entity->velo; entity->lastAccel[i]=Vector(0,0,0); MatrixIdentity(entity->lastRVelos[i]); } if(gGameInfo->demolition) { tVector3 attackDir=!(attackPoint*invMatrix); float damage=(~veloDiff)*(2+attackDir.z+(attackDir.y>0.5?attackDir.y*20:0)); if(damage>10) phys->damage+=damage; } } break; case kPhysicsTypeSolid: { tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics)); tVector3 force=veloDiff*ent->mass*kFPS*rotationFactor; tVector3 torque=(attackPoint-ent->massCenter*entity->dir)%force; tMatrix3 invMatrix; MatrixTranspose(entity->dir,invMatrix); torque=torque*invMatrix; tVector3 angularAcceleration=torque*1/ent->inertia*entity->dir; //if(~angularAcceleration>1+~entity->velo)angularAcceleration=!angularAcceleration*(1+~entity->velo); tMatrix3 accelerationMatrix; RotationVectorToMatrix(angularAcceleration*kFrameTime*kFrameTime,accelerationMatrix); MatrixMult(entity->rVelo,accelerationMatrix,entity->rVelo); entity->velo=entity->velo+veloDiff; } break; } } //returns true if an object is moving, false if it isn't int CheckForMotion(tGameEntity *entity) { if(~entity->velo>kMinVelo) return true; float rotMotion=~((Vector(1,0,0)*entity->rVelo)-Vector(1,0,0))*kFPS; if(rotMotion1) CarPlayCrashNoise(carEntity,FileGetIndexedReference(FileGetReference("scratch.wav"),RandomInt(0,4)),2.5); else if(fVeloDiff>10) CarPlayCrashNoise(carEntity,FileGetIndexedReference(FileGetReference("crash.wav"),RandomInt(0,6)),2.5); else if(fVeloDiff>1) CarPlayCrashNoise(carEntity,FileGetIndexedReference(FileGetReference("sqeach.wav"),RandomInt(0,3)),2.5); } //tests if entity collides with the ground and taks appropiate actions void CheckGroundCollision(tGameEntity *entity) { int numCollBoxes; tCollBox *boxes; tCarPhysics *phys; tCarDefinition *car; //gets collsion boxes for object switch(entity->physicsType) { case kPhysicsTypeCar: phys=(tCarPhysics*)entity->physics; car=&(phys->car); numCollBoxes=car->numCollBoxes; boxes=car->coll; break; case kPhysicsTypeSolid: tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics)); numCollBoxes=ent->numCollBoxes; boxes=ent->coll; break; } //for cars we take a few extra points to improve precision int numEdges=(entity->physicsType==kPhysicsTypeCar?12:8); for(int box=0;boxdir; tVector3 globalPoint=rotPoint+entity->pos; int surfaceType=-1; //...check if it reaches into the ground. if(GetGroundOffset(globalPoint,&entity->lastRoadIndex,&normal,&surfaceType)<0) { if(entity->physicsType==kPhysicsTypeCar) phys->collision=gFrameCount; tVector3 pointVelo=((rotPoint*entity->rVelo)-rotPoint)*kFPS+entity->velo; tVector3 testPoint=globalPoint-pointVelo*kFindNormalFactor*kFrameTime; tVector3 testNormal; //try moving the point backwards along its velocity vector until //it doen't touch the ground anymore, to get the exact point of impact int count; for(count=0;countlastRoadIndex,&testNormal,0)<0;count++) { testPoint=testPoint-pointVelo*kFindNormalFactor*kFrameTime; normal=testNormal; } //Calculate the speed of impact with the ground float veloDiff=(-normal*pointVelo); //Apply the ground's Counter-Impulse if(veloDiff>0) { tVector3 pointGroundBrake=kGroundFrictionAcceleration*kFrameTime*(entity->physicsType==kPhysicsTypeCar?kCarCollisionRate:kSolidCollisionRate)*!((normal%pointVelo)%normal); float groundFactor=normal*Vector(0,1,0)*0.25; float strictHit=1; tVector3 impulseVelo=normal*veloDiff*(0.4-groundFactor*0.3)-pointGroundBrake; if(~impulseVelo>kMaxImpulseVelo) impulseVelo=!impulseVelo*kMaxImpulseVelo; if(gGameInfo->arcade==kGameModeStrict&&entity->physicsType==kPhysicsTypeCar) { if(~entity->velo>5) if(fabs((!impulseVelo).y)<0.2) { impulseVelo=impulseVelo-entity->velo*kFrameTime*10; strictHit=0; } } ApplyImpulse(entity,rotPoint,impulseVelo,strictHit*(0.5-0.5*groundFactor),false); // ApplyImpulse(entity,rotPoint,impulseVelo,0.1); } //move the object away from the ground until it doesn't touch ground any longer //if(entity->physicsMachine==kPhysicsLocal) for(int count=0;countlastRoadIndex,&testNormal,0)<0;count++) { entity->pos=entity->pos+normal*kSeperationFactor*count; globalPoint=globalPoint+normal*kSeperationFactor*count; if(surfaceType!=-1) if(gSurfaceTypes->types[surfaceType].sparksEnable) { float sparks=(~entity->velo-kMinSparkVelo)/(kMaxSparkVelo-kMinSparkVelo); if(sparks>1)sparks=1; sparks*=kMaxSpark; if(entity->physicsType==kPhysicsTypeSolid) { tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics)); if(!ent->sparks) sparks=0; } if(sparks>0.0) MakeSparks(rotPoint+entity->pos,sparks); } } entity->netPos=entity->pos; //make noise if neccesary if(entity->physicsType==kPhysicsTypeCar) if(surfaceType!=-1) if(gSurfaceTypes->types[surfaceType].squeachEnable) MakeSqueaks(entity,veloDiff,-normal*!pointVelo); } } } #define kMinSparkCollVelo 0.0 #define kMaxSparkCollVelo 40.0 #define kMaxSparkColl 200.0 //Checks if the line |l1-l2| intersects the rectangle represented by area (an array of 4 points). //returns the point of intersection (if any) in hit. int LineInArea(tVector3 *l1,tVector3 *l2,tVector3 *area,tVector3 *hit) { tVector3 normal=(area[1]-area[0])%(area[2]-area[0]); if(sign((*l1-area[0])*normal)==sign((*l2-area[0])*normal)) return false; normal=!normal; float dist=(*l1-area[0])*normal; tVector3 dir=!(*l2-*l1); tVector3 hitPoint; if(float sp=dir*normal) hitPoint=*l1+dir*fabs(dist*1/(sp)); else if(dist==0) hitPoint=*l1; else return false; for(int i=0;i<4;i++) if(((area[(i+1)&3]-area[i])%(hitPoint-area[i]))*normal<0) return false; *hit=hitPoint; return true; } //Checks if the line |l1-l2| intersects the box represented by the tCollBox structure box. //returns the point of intersection (if any) in hit. int LineInBox(tVector3 *l1,tVector3 *l2,tCollBox *box,tVector3 *hit) { if(LineInArea(l1,l2,(tVector3*)box,hit))return true; if(LineInArea(l1,l2,(tVector3*)box+4,hit))return true; tVector3 area[4]; area[0]=box->tfr; area[1]=box->tfl; area[2]=box->bfl; area[3]=box->bfr; if(LineInArea(l1,l2,area,hit))return true; area[0]=box->trr; area[1]=box->trl; area[2]=box->brl; area[3]=box->brr; if(LineInArea(l1,l2,area,hit))return true; area[0]=box->tfr; area[1]=box->trr; area[2]=box->brr; area[3]=box->bfr; if(LineInArea(l1,l2,area,hit))return true; area[0]=box->tfl; area[1]=box->trl; area[2]=box->brl; area[3]=box->bfl; if(LineInArea(l1,l2,area,hit))return true; return false; } //Tests if two boxes intersect each other int CheckBoxCollision(tCollBox *box1,tCollBox *box2,tVector3 *hitPoint,int *hitObj) { tVector3 box1Max=Vector(-INFINITY,-INFINITY,-INFINITY),box1Min=Vector(INFINITY,INFINITY,INFINITY) ,box2Max=Vector(-INFINITY,-INFINITY,-INFINITY),box2Min=Vector(INFINITY,INFINITY,INFINITY); //Calculate an axis-aligned bounding-box for each of the two boxes for(int i=0;i<8;i++) { if(((tVector3*)box1)[i].xbox1Max.x)box1Max.x=((tVector3*)box1)[i].x; if(((tVector3*)box1)[i].y>box1Max.y)box1Max.y=((tVector3*)box1)[i].y; if(((tVector3*)box1)[i].z>box1Max.z)box1Max.z=((tVector3*)box1)[i].z; if(((tVector3*)box2)[i].xbox2Max.x)box2Max.x=((tVector3*)box2)[i].x; if(((tVector3*)box2)[i].y>box2Max.y)box2Max.y=((tVector3*)box2)[i].y; if(((tVector3*)box2)[i].z>box2Max.z)box2Max.z=((tVector3*)box2)[i].z; } //if the axis-aligned bounding-boxes don't share the same coordinate //intervals, return false. if(box1Max.xextends.x) extends.x=fabs(((tVector3*)(boxes+i))[j].x); if(fabs(((tVector3*)(boxes+i))[j].y)>extends.y) extends.y=fabs(((tVector3*)(boxes+i))[j].y); if(fabs(((tVector3*)(boxes+i))[j].z)>extends.z) extends.z=fabs(((tVector3*)(boxes+i))[j].z); } return ~extends; } //implements the physical laws of collision. //given two velocities and two masses, returns two new velocities //collType defines what type of collision this is: //if collType=0, this is a completely plastic collision, ie. both objects will be moving at the same speed afterwards. //if collType=1, this is a completely elastic collision, ie. both objects will be moving away from each other. void CalcCollisionImpulses(tVector3 v1,tVector3 v2,float m1,float m2,tVector3 *v1n,tVector3 *v2n,float collType) { tVector3 vUnelastic=(m1*v1+m2*v2)/(m1+m2); tVector3 v1Elastic=(m1*v1+m2*(2*v2-v1))/(m1+m2); tVector3 v2Elastic=(m2*v2+m1*(2*v1-v2))/(m1+m2); *v1n=collType*v1Elastic+(1-collType)*vUnelastic; *v2n=collType*v2Elastic+(1-collType)*vUnelastic; } //Tests for a collision between a car and a solid entity (any obstacles, etc.. in the game), and takes appropoiate action void HandleCarSolidCollision(tGameEntity *carEntity,tGameEntity *entity) { tCarPhysics *phys=(tCarPhysics*)carEntity->physics; tCarDefinition *car=&(phys->car); tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics)); //get bounding sphere radii of objects if(!car->maxCollRadius)car->maxCollRadius=CalcMaxCollRadius(car->coll,car->numCollBoxes); if(!ent->maxCollRadius)ent->maxCollRadius=CalcMaxCollRadius(ent->coll,ent->numCollBoxes); //tests if the object's bounding spheres intersect tVector3 dist=carEntity->pos-entity->pos; if(sqr(dist)>sqr(car->maxCollRadius+ent->maxCollRadius)) return; tVector3 hitPoint; int coll=false; int movable=ent->movable; if(!ent->liquid) if(movable) { if(CheckBoxListCollision(car->coll,ent->coll,car->numCollBoxes,ent->numCollBoxes,carEntity->dir,entity->dir,carEntity->pos,entity->pos,&hitPoint)) { if((entity->pos-carEntity->pos)*carEntity->velo>0) { entity->pos=entity->pos+carEntity->velo*kFrameTime; coll=true; } } } else if(CheckBoxListCollision(car->coll,ent->coll,car->numCollBoxes,ent->numCollBoxes,carEntity->dir,entity->dir,carEntity->pos,entity->pos,&hitPoint)) { carEntity->pos=carEntity->oldPos; MatrixCopy(carEntity->oldDir,carEntity->dir); coll=true; phys->collision=gFrameCount; } else coll=CheckBoxListCollision(car->coll,ent->coll,car->numCollBoxes,ent->numCollBoxes,carEntity->dir,entity->dir,carEntity->pos,entity->pos,&hitPoint); //was there a collision? if(coll) { //is the object movable (like a barrel, etc..) if(movable) { //calculate new velocities of car and object tVector3 carHitPoint=hitPoint-carEntity->pos; tVector3 carPointVelo=((carHitPoint*carEntity->rVelo)-carHitPoint)*kFPS+carEntity->velo; tVector3 entHitPoint=hitPoint-entity->pos; tVector3 entPointVelo=((entHitPoint*entity->rVelo)-entHitPoint)*kFPS+entity->velo; tVector3 newCarPointVelo; tVector3 newEntPointVelo; CalcCollisionImpulses(carPointVelo,entPointVelo,car->mass,ent->mass,&newCarPointVelo,&newEntPointVelo,0.5); float carImpulseScale=(~carEntity->velo)/10; if(carImpulseScale>1)carImpulseScale=1; ApplyImpulse(carEntity,carHitPoint,(newCarPointVelo-carPointVelo)*0.6*carImpulseScale,0.15,false); tVector3 oldVelo=entity->velo; tMatrix3 oldrVelo; MatrixCopy(entity->rVelo,oldrVelo); ApplyImpulse(entity,entHitPoint,(newEntPointVelo-entPointVelo)*0.25,0.5,false); if(ent->mass>=kSolidEntityNetworkMass&&carEntity->physicsMachine==kPhysicsLocal) entity->lastFrame=gFrameCount; if(ent->numSounds) { float vol=~(newEntPointVelo-entPointVelo)*0.1; if(vol>0.5) CarPlayCrashNoise(carEntity,FileGetIndexedReference(ent->sound,RandomInt(0,ent->numSounds)),vol); } } else//object not movable (eg. trees, etc..) { tVector3 entHitPoint=hitPoint-entity->pos; hitPoint=hitPoint-carEntity->pos; tVector3 rotVelo=((hitPoint*carEntity->rVelo)-hitPoint)*kFPS; if(~rotVelo>5)rotVelo=!rotVelo*5; tVector3 pointVelo=rotVelo+carEntity->velo; float sparks=(~carEntity->velo-kMinSparkVelo)/(kMaxSparkVelo-kMinSparkVelo); if(sparks>1)sparks=1; sparks*=kMaxSpark*kFrameTime; MakeSparks(hitPoint+carEntity->pos,sparks); MakeSqueaks(carEntity,~pointVelo,1); ApplyImpulse(carEntity,hitPoint,-pointVelo*0.25,0.8,false); if(~carEntity->velo>10&&ent->inertia&&!ent->movable) { tVector3 torque=(entHitPoint)%(carEntity->velo*car->mass*kFPS); tMatrix3 invMatrix; MatrixTranspose(entity->dir,invMatrix); torque=torque*invMatrix; tVector3 angularAcceleration=torque*1/ent->inertia*entity->dir; tMatrix3 accelerationMatrix; RotationVectorToMatrix(angularAcceleration*kFrameTime*kFrameTime,accelerationMatrix); MatrixMult(entity->dir,accelerationMatrix,entity->dir); carEntity->pos=carEntity->pos-carEntity->velo*kFrameTime*6; } float v=~carEntity->velo; if(v>5) carEntity->velo=carEntity->velo*((v-5)/v); else carEntity->velo=Vector(0,0,0); } if(entity->untouchable) gDisqualified=true; } } //Checks if two cars collide and take appropiate action void HandleCarCarCollision(tGameEntity *carEntity1,tGameEntity *carEntity2) { tCarPhysics *phys1=(tCarPhysics*)carEntity1->physics; tCarDefinition *car1=&(phys1->car); tCarPhysics *phys2=(tCarPhysics*)carEntity2->physics; tCarDefinition *car2=&(phys2->car); //get bounding sphere radii of objects if(!car1->maxCollRadius)car1->maxCollRadius=CalcMaxCollRadius(car1->coll,car1->numCollBoxes); if(!car2->maxCollRadius)car2->maxCollRadius=CalcMaxCollRadius(car2->coll,car2->numCollBoxes); //tests if the object's bounding spheres intersect tVector3 dist=carEntity1->pos-carEntity2->pos; if(sqr(dist)>sqr(car1->maxCollRadius+car2->maxCollRadius)) return; tVector3 hitPoint; int coll=false; //tests if objects box lists intersect while(CheckBoxListCollision(car1->coll,car2->coll,car1->numCollBoxes,car2->numCollBoxes,carEntity1->dir,carEntity2->dir,carEntity1->pos,carEntity2->pos,&hitPoint)&&!(gReplay&&coll)) { //move cars away from ech other until they no longer intersect if(!gReplay) { tVector3 diff=carEntity1->pos-carEntity2->pos; carEntity2->pos=carEntity1->pos-diff*1.01; carEntity1->pos=carEntity2->pos+diff*(1.01*1.01); } coll=true; } //was there a collision? if(coll) { //calculate new velocities of cars tVector3 car1HitPoint=hitPoint-carEntity1->pos; tVector3 car1PointVelo=((car1HitPoint*carEntity1->rVelo)-car1HitPoint)*kFPS; if(carEntity1->physicsMachine==kPhysicsLocal) car1PointVelo=car1PointVelo+carEntity1->velo; else car1PointVelo=car1PointVelo+carEntity1->collVelo; tVector3 car2HitPoint=hitPoint-carEntity2->pos; tVector3 car2PointVelo=((car2HitPoint*carEntity2->rVelo)-car2HitPoint)*kFPS; if(carEntity2->physicsMachine==kPhysicsLocal) car2PointVelo=car2PointVelo+carEntity2->velo; else car2PointVelo=car2PointVelo+carEntity2->collVelo; tVector3 newCar1PointVelo; tVector3 newCar2PointVelo; if(!gReplay) { CalcCollisionImpulses(car1PointVelo,car2PointVelo,car1->mass,car2->mass,&newCar1PointVelo,&newCar2PointVelo,1); ApplyImpulse(carEntity1,car1HitPoint,(newCar1PointVelo-car1PointVelo)*0.25,0.1,false); ApplyImpulse(carEntity2,car2HitPoint,(newCar2PointVelo-car2PointVelo)*0.25,0.1,false); carEntity1->netVelo=carEntity1->velo; MatrixCopy(carEntity1->rVelo,carEntity1->netRVelo); carEntity1->netPos=carEntity1->pos; MatrixCopy(carEntity1->dir,carEntity1->netDir); carEntity2->netVelo=carEntity2->velo; MatrixCopy(carEntity2->rVelo,carEntity2->netRVelo); carEntity2->netPos=carEntity2->pos; MatrixCopy(carEntity2->dir,carEntity2->netDir); carEntity1->accel=Vector(0,0,0); carEntity2->accel=Vector(0,0,0); } float impulse=~(newCar1PointVelo-car1PointVelo)+~(newCar2PointVelo-car2PointVelo); float sparks=(impulse-kMinSparkVelo)/(kMaxSparkVelo-kMinSparkVelo); if(sparks>1)sparks=1; sparks*=kMaxSpark*kFrameTime*5; MakeSparks(hitPoint,sparks); MakeSqueaks(carEntity1,impulse,1); } } //for a car, test if it collides with anything else (ground, other cars or objects). void CarCheckCollision(tGameEntity *carEntity) { tGameEntity *entity=(tGameEntity*)gFirstEntity->next; //if(carEntity->physicsMachine==kPhysicsLocal) { // if(!gReplay) if(!(gFrameCount%kCarCollisionRate)) { if(carEntity->physicsMachine!=kPhysicsLocal) gQuickRoadCollision=true; gRoadRestrictedBorders=true; CheckGroundCollision(carEntity); gRoadRestrictedBorders=false; gQuickRoadCollision=false; } } //for each other object, test for collision. if(!(gFrameCount%kCarCollisionRate)) while(entity!=gFirstEntity) { entity->regData=carEntity->regData; if(sqr(entity->pos-carEntity->pos)<500) if(entity!=carEntity) switch(entity->physicsType) { case kPhysicsTypeSolid: HandleCarSolidCollision(carEntity,entity); break; case kPhysicsTypeCar: //if(carEntity->physicsMachine==kPhysicsLocal) HandleCarCarCollision(carEntity,entity); break; } entity=(tGameEntity*)entity->next; } } //for a solid entity, check if it intersects with the ground void SolidCheckCollision(tGameEntity *entity) { tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics)); if(!ent->movable) return; CheckGroundCollision(entity); tVector3 xDiff=*MatrixGetXVector(entity->rVelo)-Vector(1,0,0); tVector3 yDiff=*MatrixGetYVector(entity->rVelo)-Vector(0,1,0); tVector3 zDiff=*MatrixGetZVector(entity->rVelo)-Vector(0,0,1); *MatrixGetXVector(entity->rVelo)=*MatrixGetXVector(entity->rVelo)-xDiff*1.5*kFrameTime; *MatrixGetYVector(entity->rVelo)=*MatrixGetYVector(entity->rVelo)-yDiff*1.5*kFrameTime; *MatrixGetZVector(entity->rVelo)=*MatrixGetZVector(entity->rVelo)-zDiff*1.5*kFrameTime; } tRegData rd; //check for any object collisions void CollisionFrame() { tGameEntity *entity=(tGameEntity*)gFirstEntity->next; while(entity!=gFirstEntity) { entity->regData=&rd; //has the object moved in the last second? //if we have a solid entity like a barrel which has been kicked over by a car, //we don't need to process collisions with the ground anymore once the barrel //has come to rest. if(entity->lastActivity+kFPS>gFrameCount&&entity->id>=0) //if(entity->physicsMachine!=kPhysicsRemote||entity->lastCollFrame==0||entity->lastCollFrame>gFrameCount-kFPS) switch(entity->physicsType) { case kPhysicsTypeCar: CarCheckCollision(entity); break; case kPhysicsTypeSolid: if(!(gFrameCount%kSolidCollisionRate)) SolidCheckCollision(entity); break; } entity=(tGameEntity*)entity->next; } }