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(¤tChar, 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.