collision.cpp

Go to the documentation of this file.
00001 
00002 //
00003 // Das Tank - Copyright (C) 2006, 2007 Windsor Schmidt <windsor@windsorworld.net>
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License as published by the Free
00007 // Software Foundation; either version 2 of the License, or (at your option)
00008 // any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful, but WITHOUT
00011 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
00013 // more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along with
00016 // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00017 // Place, Suite 330, Boston, MA 02111-1307 USA
00018 //
00020 
00021 
00022 #ifndef STDAFX
00023 #include "stdafx.h"
00024 #endif
00025 
00026 // use to hold all the interaction logic responses for various collisions / interactions
00027 int collisionInteract[INTERACTION_MATRIX_SIZE * INTERACTION_MATRIX_SIZE];
00028 int damageInteract[INTERACTION_MATRIX_SIZE * INTERACTION_MATRIX_SIZE];
00029 int effectInteract[INTERACTION_MATRIX_SIZE * INTERACTION_MATRIX_SIZE];
00030 
00031 
00043 void DoCollisions(CWorld * ThisWorld)
00044 {
00045        CObject * Current = ThisWorld->Objects;
00046        CObject * Other = ThisWorld->Objects;
00047 
00048        // A little speed optimization, this flag changes state each time through the colllision routine.
00049        // The outer collision loop flags each object with the current 'checked' state as it's checked for
00050        // collision, and so later iterations will skip a 'reverse check' of the same two objects. When the
00051        // outer loop is complete and all the objects have been tested for colision, the check flag changes
00052        // polarity on the next collision routine run, and all the nodes are now considered 'unchecked' again.
00053        static bool bCheckState = true;
00054        if (bCheckState == true) bCheckState = false; // these two lines toggle the flag each pass
00055        else bCheckState = true;
00056 
00057        while(Current != NULL)
00058        {
00059               Other = ThisWorld->Objects; // reset the 'other' object each time
00060 
00061               // check against every other object
00062               while(Other != NULL)
00063               {
00064                      if(Current == Other) goto no_collision; // checking collision with ourself, duh
00065 
00066                      if(Other->bCheckedForCollision == bCheckState) goto no_collision; // already tested this pair; skip
00067 
00068                      // check bounding boxes and bail out with goto if we find a 'can't be touching' situation
00069                      if(Current->Position.y + Current->fBBBottom > Other->Position.y + Other->fBBTop) goto no_collision;
00070                      if(Current->Position.y + Current->fBBTop < Other->Position.y + Other->fBBBottom) goto no_collision;
00071                      if(Current->Position.x + Current->fBBRight < Other->Position.x + Other->fBBLeft) goto no_collision;
00072                      if(Current->Position.x + Current->fBBLeft > Other->Position.x + Other->fBBRight) goto no_collision;
00073 
00074                      // bounding boxes occured, so process a hit.
00075                      Collide(ThisWorld, Current, Other);
00076 
00077                      ThisWorld->iNumCollisions ++; // update total # of collisions for debug info
00078 
00079 no_collision: // handy goto jump-point
00080 
00081                      // done checking this object, so flag it
00082                      Current->bCheckedForCollision = bCheckState;
00083 
00084                      Other = Other->Next; // check next 'other' object next time around loop, if there is one
00085               }
00086               Current = Current->Next; // check next object for collisions, if there is one
00087        }
00088 }
00089 
00090 
00102 void Collide(CWorld * ThisWorld, CObject * ObjA, CObject * ObjB)
00103 {
00104        int response = 0;
00105 
00106        // find out which collision reponse is appropriate for this collision
00107        response = getInteraction(MATRIXID_COLLISION, ObjA->iType, ObjB->iType);
00108 
00109        switch(response)
00110        {
00111        case RESPONSE_NULL:
00112               break;
00113 
00114        case RESPONSE_COL_REFLECT_A:
00115               PlaySound(SOUNDID_BOUNCE); // play a sound effect
00116               PhysicsReflect(ThisWorld, ObjA, ObjB);
00117               break;
00118 
00119        case RESPONSE_COL_REFLECT_B:
00120               PlaySound(SOUNDID_BOUNCE); // play a sound effect
00121               PhysicsReflect(ThisWorld, ObjB, ObjA);
00122               break;
00123 
00124        case RESPONSE_COL_REFLECT_BOTH:
00125               PlaySound(SOUNDID_BOUNCE); // play a sound effect
00126               PhysicsReflect(ThisWorld, ObjA, ObjB);
00127               PhysicsReflect(ThisWorld, ObjB, ObjA);
00128               break;
00129 
00130        case RESPONSE_COL_STOP_A:
00131               PhysicsStop(ObjA, ObjB);
00132               break;
00133 
00134        case RESPONSE_COL_STOP_B:
00135               PhysicsStop(ObjB, ObjA);
00136               break;
00137 
00138        case RESPONSE_COL_STOP_BOTH:
00139               PhysicsStop(ObjA, ObjB);
00140               PhysicsStop(ObjB, ObjA);
00141               break;
00142 
00143        case RESPONSE_COL_ELASTIC:
00144               PhysicsElasticCollision(ObjA, ObjB);
00145               break;
00146 
00147        case RESPONSE_COL_DAMPED:
00148               PhysicsDampedCollision(ObjA, ObjB);
00149               break;
00150        }
00151 
00152        // find out which damage reponse is appropriate for this collision
00153        response = getInteraction(MATRIXID_DAMAGE, ObjA->iType, ObjB->iType);
00154 
00155        switch(response)
00156        {
00157        case RESPONSE_NULL:
00158               break;
00159 
00160        case RESPONSE_DMG_A:
00161               GameLogicDamage(ObjA, ObjB);
00162               break;
00163 
00164        case RESPONSE_DMG_B:
00165               GameLogicDamage(ObjB, ObjA);
00166               break;
00167 
00168        case RESPONSE_DMG_BOTH:
00169               GameLogicDamage(ObjA, ObjB);
00170               GameLogicDamage(ObjB, ObjA);
00171               break;
00172 
00173        case RESPONSE_DMG_KILL_A:
00174               ObjA->iHealth = 0;
00175               break;
00176 
00177        case RESPONSE_DMG_KILL_B:
00178               ObjB->iHealth = 0;
00179               break;
00180 
00181        case RESPONSE_DMG_KILL_BOTH:
00182               ObjA->iHealth = 0;
00183               ObjB->iHealth = 0;
00184               break;
00185 
00186        }
00187 
00188        // find out which effect reponse is appropriate for this collision
00189        response = getInteraction(MATRIXID_EFFECT, ObjA->iType, ObjB->iType);
00190               
00191        switch(response)
00192        {
00193        case RESPONSE_NULL:
00194               break;
00195        case RESPONSE_EFF_EQUIP_A:
00196               GameLogicEquip(ObjA, ObjB);
00197               break;
00198        case RESPONSE_EFF_EQUIP_B:
00199               GameLogicEquip(ObjB, ObjA);
00200               break;
00201        }
00202 }
00203 
00204 
00212 int InitCollision(void)
00213 {
00214        // load interaction data from disk
00215        if(DAS_ERROR == loadInteractionMatrix(collisionInteract, "dat\\collision_interact")) { return DAS_ERROR; }
00216        if(DAS_ERROR == loadInteractionMatrix(damageInteract, "dat\\damage_interact")) { return DAS_ERROR; }
00217        if(DAS_ERROR == loadInteractionMatrix(effectInteract, "dat\\effect_interact")) { return DAS_ERROR; }
00218 
00219        return 0; // looks good
00220 }
00221 
00222 
00230 int loadInteractionMatrix(int * matrix, const char * filename)
00231 {
00232        FILE * file;
00233        char string[256];
00234        char currentChar = 0;
00235        int iX, iY, iZ;
00236        iX = iY = iZ = 0;
00237 
00238        fopen_s(&file, filename, "r");
00239        if(NULL == file) { return DAS_ERROR; }
00240 
00241        // read in matrix
00242        for(iY = 0; iY < INTERACTION_MATRIX_SIZE; iY++) // for each row
00243        {
00244               for(iX = 0; iX < INTERACTION_MATRIX_SIZE; iX++) // for each cell on that row
00245               {
00246                      for(iZ=0; iZ<256; iZ++) // read in this cell's data
00247                      {
00248                             fread(&currentChar, 1, 1, file);
00249 
00250                             if(currentChar == 9 || currentChar == 10) // tab or newline
00251                             {
00252                                    string[iZ] = 0;
00253                                    break;
00254                             }
00255                             else // another character
00256                             {
00257                                    string[iZ] = currentChar;
00258                             }
00259 
00260                             matrix[iY * INTERACTION_MATRIX_SIZE + iX] = atoi(string);
00261                      }
00262               }
00263        }
00264 
00265        fclose(file);
00266 
00267        return 0;
00268 }
00269 
00270 
00276 int getInteraction(int matrixID, int typeID_A, int typeID_B)
00277 {
00278        switch(matrixID)
00279        {
00280        case MATRIXID_COLLISION:
00281               return(collisionInteract[typeID_A * INTERACTION_MATRIX_SIZE + typeID_B]);
00282               break;
00283 
00284        case MATRIXID_DAMAGE:
00285               return(damageInteract[typeID_A * INTERACTION_MATRIX_SIZE + typeID_B]);
00286               break;
00287 
00288        case MATRIXID_EFFECT:
00289               return(effectInteract[typeID_A * INTERACTION_MATRIX_SIZE + typeID_B]);
00290               break;
00291        }
00292 
00293        return(DAS_ERROR); // error, probably was passed an invalid matrixID
00294 }
00295 
00296 
00303 void ProcessTileCollisions(CWorld * ThisWorld)
00304 {
00305        int iX, iY, iZ;
00306        bool doPeriodicEffect = false;
00307        bool doPeriodicSound = false;
00308        static Uint32 tileEffectTimer = SDL_GetTicks();
00309        static Uint32 tileSoundTimer = SDL_GetTicks();
00310        CObject * Current;
00311        CEffect * NewEffect = NULL;
00312 
00313        if(SDL_GetTicks() - tileEffectTimer > TILE_EFFECT_TIMER)
00314        {
00315               doPeriodicEffect = true;
00316               tileEffectTimer = SDL_GetTicks();
00317        }
00318 
00319        if(SDL_GetTicks() - tileSoundTimer > TILE_SOUND_TIMER)
00320        {
00321               doPeriodicSound = true;
00322               tileSoundTimer = SDL_GetTicks();
00323        }
00324 
00325        for(iZ = 0; iZ < NUM_PLAYERS; iZ++)
00326        {
00327               Current = ThisWorld->Player[iZ];
00328 
00329               for(iY = 0; iY < MAP_SIZE; iY++)
00330               {
00331                      for(iX = 0; iX < MAP_SIZE; iX++)
00332                      {
00333                             if(Current->Position.y + Current->fBBBottom > iY * CELL_SIZE + CELL_SIZE) continue;
00334                             if(Current->Position.y + Current->fBBTop < iY * CELL_SIZE) continue;
00335                             if(Current->Position.x + Current->fBBRight < iX * CELL_SIZE) continue;
00336                             if(Current->Position.x + Current->fBBLeft > iX * CELL_SIZE + CELL_SIZE) continue;
00337 
00338                             // player is on the current tile, so do something about it
00339                             switch(ThisWorld->tiles[(iY * MAP_SIZE) + iX].iTileEffect)
00340                             {
00341                             case TILE_EFFECT_DAMAGE:
00342                                    if(doPeriodicEffect)
00343                                    {
00344                                           Current->iHealth -= ThisWorld->tiles[(iY * MAP_SIZE) + iX].iDamage;
00345 
00346                                           NewEffect = new CEffect(EFFECTID_PSYSTEM);
00347                                           NewEffect->PSys = new PSystem(Current->Position, Vector(0.0015,0,0), 2*PI, 1.00, 2, 10);
00348                                           NewEffect->PSys->SetColor(1.0, 0.6, 0.2);
00349                                           ThisWorld->AddEffect(NewEffect);
00350 
00351                                    }
00352 
00353                                    if(doPeriodicSound)
00354                                    {
00355                                           PlaySound(SOUNDID_BURNING);
00356                                    }
00357                                    break;
00358 
00359                             default:
00360                                    break;
00361                             }
00362                      }
00363               }
00364        }
00365 
00366        doPeriodicEffect = false;
00367        doPeriodicSound = false;
00368 }

 

Copyright Windsor Schmidt 2006 - All rights reserved.