/* * (C) COPYRIGHT Vincent S. Cojot and others 1996-1997 * All Rights Reserved * Licensed Materials - Property of Vincent S. Cojot and others. * Use, duplication or disclosure restricted by Vincent S. Cojot. */ #include #include #include #include #include #ifdef USING_MESA #include #else #include #endif #include "defines.h" #include "collisions.h" /***************************************************************/ /* Fonction principale de la gestion des collisions. C'est a elle */ /* que revient la tache de determiner si il y a collision et, dans */ /* ce cas, quelle fonction de gestion des collisions il faut appeller. */ /***************************************************************/ GLvoid VerifierCollision(GLvoid) { /* Reduit la taille du monde connu a un carre de 40x40 pour faire des */ /* hypotheses sur les collisions */ ReduceWorldSize(); /* Calcule la distance du mobile au centre du carre local. */ RCdistance = hypot (RscenePosx, RscenePosz); if ( VerifyClose(13) ) { #ifdef DEBUG printf("Not close..........\n"); #endif WasInside = 0; } else { /* Calcule la distance du mobile au centre du monde virtuel. */ Cdistance = hypot (scenePosx, scenePosz); if ( Cdistance < 13 ) { #ifdef DEBUG printf("Cylindre...\n"); #endif if (WasInside == 0) BangOnCylinder(); } else { if ( !VerifyVeryClose(8) ) { if ( VerifyOutOfThisWorld() ) { if ( VerifyEvenOrOdd() ) { #ifdef DEBUG printf("PRISME..\n"); #endif if (WasInside == 0) BangOnPrism(); } else { #ifdef DEBUG printf("CUBE..\n"); #endif if (WasInside == 0) BangOnCube(); } } else { WasInside = 0; #ifdef DEBUG printf ("Out of this world.\n"); #endif } } else { WasInside = 0; } } } #ifdef DEBUG printf("Xpos: %.2f ,", scenePosx); printf("Zpos: %.2f ,", scenePosz); printf("RXpos: %.2f ,", RscenePosx); printf("RZpos: %.2f\n", RscenePosz); #endif } /***************************************************************/ /* Fonction de determination de la position de depart. */ /* C'est une troisieme version de l'algorithme de collision qui */ /* renvoie la valeur VRAI si on est dans un object, FALSE autrement. */ /***************************************************************/ GLint FindStartupPosition(GLvoid) { /* utilise le nombre de micro-secondes de l'heure actuelle pour */ /* servir de nombre aleatoire. */ gettimeofday( &temps2, NULL); /* Utilise le nombre aleatoire obtenu pour generer une source de */ /* nombres pseudo-aleatoires. */ srand(temps2.tv_usec); /* Utilise un premier nombre aleatoire. */ RandomscenePosx = fmod(cos(rand())*rand()/150, 150); /* Utilise un deuxieme nombre aleatoire. */ RandomscenePosz = fmod(sin(rand())*rand()/150, 150); /* Utilise un troisieme nombre aleatoire. */ RandomsceneAngle = fmod(tan(rand())*rand()/180, 180) + 180.0; #ifdef DEBUG printf("Angle: %.2f\n", RandomsceneAngle); #endif /* Reduit la taille du monde connu a un carre de 40x40 pour faire des */ /* hypotheses sur les collisions. Cf ReduceWorldSize(); */ RscenePosx = RandomscenePosx - ceil( (RandomscenePosx - 20.0) /40.0 )*40.0 ; RscenePosz = RandomscenePosz - ceil( (RandomscenePosz - 20.0) /40.0 )*40.0 ; /* Calcule la distance du mobile au centre du carre local. */ RCdistance = hypot (RscenePosx, RscenePosz); if ( VerifyClose(13) ) { /* Position non dans un objet. */ } else { /* Calcule la distance du mobile au centre du monde virtuel. */ Cdistance = hypot (RandomscenePosx, RandomscenePosz); if ( Cdistance < 13 ) { return 1; } else { if ( !VerifyVeryClose(8) ) { if ( VerifyOutOfThisWorldGeneric() ) { if ( VerifyEvenOrOdd() ) { return 1; } else { return 1; } } else { /* Position non dans un objet. */ } } else { /* Position non dans un objet. */ } } } /* Il faut maintenant verifier les collisions avec les autres Tanks */ /* et les epaves de nos victimes.. */ /* Pour tous les tanks possibles..*/ for (j=0; j= DESTRUCTION_DELAY) { DestroyedTanks[j].Destroyed = 0; } else { DestroyedTanks[j].Destroyed++; } } else { glTranslated( 0.0, -0.3, 0.0); /* Le tank est detruit donc il est un peu remue.. :) */ glRotated(-3, 0.0, 0.0, 1.0); glRotated(-5, 1.0, 0.0, 0.0); glCallList(WIRE_DESTROYED_TANK); } } else { /* Si le tank vient d'etre detruit.. */ /* affiche le tank enemi non encore detruit. */ if (DestroyedTanks[j].Destroyed) { glCallList(ALL_MY_RED_SOLID_TANK); if (DestroyedTanks[j].Destroyed >= DESTRUCTION_DELAY) { DestroyedTanks[j].Destroyed = 0; } else { DestroyedTanks[j].Destroyed++; } } else { glTranslated( 0.0, -0.3, 0.0); /* Le tank est detruit donc il est un peu remue.. :) */ glRotated(-3, 0.0, 0.0, 1.0); glRotated(-5, 1.0, 0.0, 0.0); glCallList(SOLID_DESTROYED_TANK); } } glPopMatrix(); /* Verifie les collisions avec notre tank car on ne doit */ /* pas pouvoir rentrer dans les autres tanks.. */ if ( hypot (scenePosx - DestroyedTanks[j].Posx , scenePosz - DestroyedTanks[j].Posz) < 6.0 ) { if (!WasInside) LongSpeed = -LongSpeed; WasInside = 1; } } } /* for j */ } /***************************************************************/ /* La fonction CallAnExplosion( Explosx, Explosy, Explosz) fait */ /* apparaitre une explosion au point ( Explosx, Explosy, Explosz). */ /***************************************************************/ GLvoid CallAllExplosions() { for (j=0; j distance ) { return 1; } else { return 0; } } /***************************************************************/ /* Fonction pour verifier si on des chances de rentrer dans le cylindre */ /* central de la scene. Retourne Vrai si trop loin, faux si trop pres.*/ /***************************************************************/ GLint VerifyClose(GLint distance) { if ( RCdistance > distance ) { return 1; } else { return 0; } } /***************************************************************/ /* Fonction pour verifier si on est dans une zone paire ou impaire. */ /* Fonction pour verifier si on a affaire a un cube ou a un prisme. */ /***************************************************************/ GLint VerifyEvenOrOdd(GLvoid) { res_temp = floor( (scenePosz - 20.0) /40.0 ) + floor( (scenePosx - 20.0) /40.0 ); if ( (2*floor(res_temp/2)) < res_temp ) { return 1; } else { return 0; } } /***************************************************************/ /* Fonction pour verifier si on est en dehors des obstacles. (tank). */ /***************************************************************/ GLint VerifyOutOfThisWorld(GLvoid) { if ( ( fabs(scenePosx) > 140) || ( fabs(scenePosz) > 140 ) ) { return 0; } else { return 1; } } /***************************************************************/ /* Fonction pour verifier si on est en dehors des obstacles. (tank). */ /***************************************************************/ GLint VerifyOutOfThisWorldGeneric(GLvoid) { if ( ( fabs(RandomscenePosx) > 140) || ( fabs(RandomscenePosz) > 140 ) ) { return 0; } else { return 1; } } /***************************************************************/ /* Fonction pour verifier si on est en dehors des obstacles. (Missile). */ /***************************************************************/ GLint VerifyOutOfThisWorldMissile(GLint Which) { if ( ( fabs(Missiles[Which].Posx) > 140) || ( fabs(Missiles[Which].Posz) > 140 ) ) { return 0; } else { return 1; } } /***************************************************************/ /* Fonction determinant la facon dont on rebondit sur le cylindre */ /***************************************************************/ GLvoid BangOnCylinder(GLvoid) { LongSpeed = -(LongSpeed/2+sgn(LongSpeed)); WasInside = 1; } /***************************************************************/ /* Fonction determinant la facon dont on rebondit sur un cube */ /***************************************************************/ GLvoid BangOnCube(GLvoid) { LongSpeed = -(LongSpeed/2+sgn(LongSpeed)); WasInside = 1; } /***************************************************************/ /* Fonction determinant la facon dont on rebondit sur un prisme */ /***************************************************************/ GLvoid BangOnPrism(GLvoid) { LongSpeed = -(LongSpeed/2+sgn(LongSpeed)); WasInside = 1; } /***************************************************************/ /* Fonction de destruction d'un missile dont on a determine */ /* la collision avec un obstacle. */ /***************************************************************/ GLvoid ExplodeMissile(GLint Which, GLint Who) { /* Enleve le flag VRAI du missile qui a explose. */ Missiles[Which].Valid = 0; /* Decremente le nombre de missiles en vol.*/ FlyingMissile--; /* Decremente le nombre de nos missiles en vol si c'etait le notre.*/ if (Which == 0) { MyFlyingMissile = 0; } OneExplosion.x = -Missiles[Which].Posx; OneExplosion.y = 0.0; OneExplosion.z = -Missiles[Which].Posz; OneExplosion.Angle = Missiles[Which].Angle; sprintf( OneExplosion.Name, OurName); if (Who) { sprintf( OneExplosion.Destroyed, Tanks[Who-1].Name); } else { sprintf( OneExplosion.Destroyed, " "); } InsertExplosion(OneExplosion); SendMyExplosionPacket(); } /***************************************************************/ /* Fonction de destruction d'un tank dont on a determine */ /* la collision avec notre missile. Il faut aussi appeler ExplodeMissile*/ /* conjointement avec cette fonction pour faire exploser le missile. */ /***************************************************************/ GLvoid ExplodeTank(GLint Which) { /* Enleve le flag VRAI du tank qui a explose. */ Tanks[Which].Valid = 0; /* Decremente le nombre de tanks dans le jeu.*/ tanks--; /* Si on n'est pas en mode Network, insere une epave de tanks */ /* apres l'explosion de celui que nous avons touche..*/ if (!Network) { OneDestroyedTank.Posx = Tanks[Which].Posx; OneDestroyedTank.Posz = Tanks[Which].Posz; OneDestroyedTank.Angle = Tanks[Which].Angle; /* Insere une epave de tank...*/ InsertDestroyedTank(OneDestroyedTank); } /* Affiche un message de victoire... */ ResetInfoMessage(); sprintf(InfoMessage.texta, " You really nailed that tank!!!"); sprintf(InfoMessage.textc, " May %s rest in peace..",Tanks[Which].Name); InfoMessage.Valid = 1; InfoMessage.Age = -1.0; } /***************************************************************/ /* Fonction d'orientation du missile par rapport au tank grace a l'angle */ /* entre deux vecteurs. */ /***************************************************************/ GLfloat OrienteMissile(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { if ( ( x1 != 0 ) || ( y1 != 0 ) ) { /* Normalise le vecteur */ Vlength = hypot(x1,y1) ; x1 = x1 / Vlength ; y1 = y1 / Vlength ; } if ( ( x2 != 0 ) || ( y2 != 0 ) ) { /* Normalise le vecteur */ Vlength = hypot(x2,y2) ; x2 = x2 / Vlength ; y2 = y2 / Vlength ; } /* Calcul de l'angle */ Theta = acos ( (x1*x2 + y1*y2) / 1.001 ) * ( sgn( asin ( x1*y2 - x2*y1) ) ); #ifdef DEBUG printf(" Angle: %f \n", Theta*180/PI) ; #endif return Theta*180/PI; } /**************************************************************************/ /* Fonction chargee d'inserer un tank dans la matrice des tanks a la */ /* premiere place disponible. */ /**************************************************************************/ GLvoid InsertTank(TANK OneTank) { GLint i = 0; /* Recherche de la prochaine case libre. */ while ( Tanks[i].Valid ) { i++; } if (i >= MAX_TANKS) { ResetInfoMessage(); sprintf(InfoMessage.textb, " Too Many Tanks, can't insert!!!"); InfoMessage.Valid = 1; InfoMessage.Age = 1.0; } else { Tanks[i].Posx = OneTank.Posx; Tanks[i].Posz = OneTank.Posz; Tanks[i].Angle = OneTank.Angle; Tanks[i].Valid = 1; Tanks[i].Destroyed = 0; if (Network) { sprintf(Tanks[i].Name, OneTank.Name); } else { sprintf(Tanks[i].Name, "Evil Guy %i", (int)(i+1)); } /* Augmente d'un le nombre de tanks. */ tanks++; } } /**************************************************************************/ /* Fonction chargee d'inserer un missile dans la matrice des missiles a la */ /* premiere place disponible. */ /**************************************************************************/ GLvoid InsertMissile(MISSILE OneMissile) { /* On commence a la deuxieme case car la premiere est reservee au */ /* missile de notre propre tank si ce dernier en lance un. */ GLint i = 1; /* Recherche de la prochaine case libre. */ while ( Missiles[i].Valid ) { i++; } if (i >= MAX_MISSILES) { ResetInfoMessage(); sprintf(InfoMessage.textb, " Too Many Missiles, can't insert!!!"); InfoMessage.Valid = 1; InfoMessage.Age = 1.0; } else { Missiles[i].Posx = OneMissile.Posx; Missiles[i].Posz = OneMissile.Posz; Missiles[i].Incx = OneMissile.Incx; Missiles[i].Incz = OneMissile.Incz; Missiles[i].Angle = OneMissile.Angle; Missiles[i].Age = 0; Missiles[i].Valid = 1; /* Augmente d'un le nombre de missiles. */ FlyingMissile++; } } /**************************************************************************/ /* Fonction chargee d'inserer une explosion dans la matrice des explosions */ /* a la premiere place disponible. */ /**************************************************************************/ GLvoid InsertExplosion(EXPLOSION OneExplosion) { GLint i = 0; /* Recherche de la prochaine case libre. */ while ( Explosions[i].Valid ) { i++; } if (i >= MAX_EXPLOSIONS) { ResetInfoMessage(); sprintf(InfoMessage.textb, " Too Many Explosions, can't insert!!!"); InfoMessage.Valid = 1; InfoMessage.Age = 1.0; } else { Explosions[i].x = OneExplosion.x; Explosions[i].y = OneExplosion.y; Explosions[i].z = OneExplosion.z; Explosions[i].Angle = OneExplosion.Angle; Explosions[i].Age = 0; Explosions[i].Valid = 1; sprintf(Explosions[i].Name, OneExplosion.Name); sprintf(Explosions[i].Destroyed, OneExplosion.Destroyed); /* Augmente d'une le nombre d'explosions. */ explosion++; } } /**************************************************************************/ /* Fonction chargee d'inserer un tank dans la matrice des tanks a la */ /* premiere place disponible. */ /**************************************************************************/ GLvoid InsertDestroyedTank(TANK OneDestroyedTank) { GLint i = 0; /* Recherche de la prochaine case libre. */ while ( DestroyedTanks[i].Valid ) { i++; } if (i >= MAX_DESTROYED_TANKS) { ResetInfoMessage(); sprintf(InfoMessage.textb, " Too Many Tank Wrecks, can't insert!!!"); InfoMessage.Valid = 1; InfoMessage.Age = 1.0; } else { DestroyedTanks[i].Posx = OneDestroyedTank.Posx; DestroyedTanks[i].Posz = OneDestroyedTank.Posz; DestroyedTanks[i].Angle = OneDestroyedTank.Angle; DestroyedTanks[i].Valid = 1; DestroyedTanks[i].Destroyed = 1; /* Augmente d'un le nombre de tanks. */ destroyed++; } }