// main.c // BUGGY DEMO //----------- //Platform: Playstation //By: Jason Spreadborough //Date: 27-1-99 // INCLUDES //---------- #include #include #include "pad.h" #include "addrs.h" #include "lib2d.h" #include "height.h" // also includes 3dgraph.h #include "sound.h" // DEFINES //--------- #define TileLength (10) #define TileWidth (10) #define LENGTH (20) #define WIDTH (20) #define NumberOfVertices (400) // Length * width #define NumberOfLines (800) // Vertices * 2 #define TITLE (0) #define GAME (1) #define QUIT (9) // MACROS //-------- #define LINE_setVERTEX(v,_x,_y,_z) \ (v)->vec.vx = (_x), \ (v)->vec.vy = (_y), \ (v)->vec.vz = (_z) #define LINE_setENDS(l,_s,_e) \ (l)->start = (_s), \ (l)->end = (_e) // STRUCTS / UNION //----------------- typedef struct { u_long start, end; } LINE_INFO; typedef struct { VECTOR vec; short x,y,z; } VECTOR_INFO; // PROTOTYPES //------------ void InitTransProj(); void TransProj(VECTOR *pos, short *x, short *y, short *z); void CreateGrid(long heights[41][41]); long BeaconTest(ObjectStruct testObject); void UpdateWorldTitle(); void RenderWorldTitle(); u_long ProcessUserInputTitle(); void UpdateWorldGame(); void RenderWorldGame(); u_long ProcessUserInputGame(); void UpdateObject(ObjectStruct *theObject,u_long ViewFollow); // GLOBALS //--------- long v_count=0; MapObject myOBJ; ObjectStruct buggy; // the buggy object ObjectStruct LFWheel, RFWheel, LBWheel, RBWheel;// seperate wheels used for animation. GsBOXF scanner; GsBOXF buggyLocation; GsBOXF checkPoint; GsRVIEW2 ViewPoint; //viewing system GsFOGPARAM Fogging; GsSPRITE TitleP1; // Title screen 2D graphics GsSPRITE TitleP2; GsSPRITE Time; GsSPRITE Lap; GsSPRITE Timer[6]; GsSPRITE LapCount; GsBOXF Highlight; u_long PADstatus=0; // pad varible status u_long VerticalSync=0; // used for v sync speed test thingy ! // wireframe globals VECTOR_INFO Vertices[NumberOfVertices]; LINE_INFO Lines[NumberOfLines]; GsLINE LINE_IN_3D; // the actual line seen on the screen static GsCOORDINATE2 trans; short ProjectionDistance = 500; // sounds voice_data beep; voice_data ting; voice_data car; ////////////////////////////////////////////////////////////////////// // FUNCTIONS //----------- // ** TITLE SCREEN FUNCTIONS ** //------------------------------ // Draw title screen stuff void RenderWorldTitle() { u_long temp,index; RenderPrepare(); for (index=0; index>5); } DrawObject(&buggy,5); DrawObject(&LBWheel,5); DrawObject(&RBWheel,5); DrawObject(&LFWheel,5); DrawObject(&RFWheel,5); DrawSprite(&TitleP1,200); DrawSprite(&TitleP2,200); DrawBox(&Highlight,0); RenderFinish(); } // Update title selections to match those on screen. // And update vertices for wireframe model. void UpdateWorldTitle() { u_long tTemp1; for (tTemp1=0; tTemp1vx; trans.coord.t[1] = pos->vy; trans.coord.t[2] = pos->vz; trans.flg=0; // Translate to Screen Coordinate GsGetLs(&trans,&mat); ApplyMatrixLV(&mat, pos, &v); // Perspective projection 3d to 2d if(mat.t[2]) // avoid divide by zero { *x = ProjectionDistance * v.vx / mat.t[2]; *y = ProjectionDistance * v.vy / mat.t[2]; *z = mat.t[2]; } else { *x = 0; *y = 0; *z = 0; } } // Create a Flat Grid void CreateGrid(long heights[41][41]) { long index,index2,x=0,y=0,counter; // Create Vertices for(index=0; index < NumberOfVertices; index++) { LINE_setVERTEX(&Vertices[index], TileLength*x, 0, TileWidth*y); // printf("Veritce %d = %d , 0 , %d\n",(int)index,(int)(TileLength*x),(int)(TileWidth*y)); if(++x == LENGTH) {x=0, y++;} } // Translate The whole grid so that its centre is at the worlds centre // I know this looks silly but Im too tired to think of anything clever! //for(index=0; index < NumberOfVertices; index++) //{ // LINE_setVERTEX(&Vertices[index],Vertices[index].vec.vx-500, 0, Vertices[index].vec.vz-500); //} counter = 0; x=0; //Create X Lines for(index=0; index < WIDTH;index++) { for(index2=0; index2 < LENGTH-1; index2++) { LINE_setENDS(&Lines[counter],x+1 ,x ); // printf("Line %d = %d to %d\n",(int)counter,(int)x+1,(int)(x)); counter++; x++; } x++; } y=0; //Create Z lines for(index2=0;index < NumberOfVertices;index++) { LINE_setENDS(&Lines[counter], y, y+WIDTH); counter++; y++; } x=y=2; // Set heights to that of array. for(index=0; index < NumberOfVertices; index++) { LINE_setVERTEX(&Vertices[index],Vertices[index].vec.vx, heights[x][y]/10, Vertices[index].vec.vz); x+=2; if(x > 40){x=2; y+=2;} } } /////////////////////////////////////////////////////////////////////// // ** GAME FUNCTIONS ** // This function deals with double buffering and drawing of 3D objects, // also takes care of onscreen displays such as scores etc. void RenderWorldGame() { RenderPrepare(); // InitialiseMapLights(); // Draw terrain and map objects DrawMap(buggy.Object_Coord); DrawMapObjects(buggy.Object_Coord); // InitialiseLights(); // Draw 3d models DrawObject(&buggy,5); DrawObject(&LBWheel,5); DrawObject(&RBWheel,5); DrawObject(&LFWheel,5); DrawObject(&RFWheel,5); // Draw 2d sprites DrawSprite(&Time,0); DrawSprite(&Lap,0); DrawSprite(&Timer[0],0); DrawSprite(&Timer[1],0); DrawSprite(&Timer[2],0); DrawSprite(&Timer[3],0); DrawSprite(&Timer[4],0); DrawSprite(&Timer[5],0); DrawSprite(&LapCount,0); DrawBox(&scanner,1); DrawBox(&buggyLocation,0); DrawBox(&checkPoint,0); // VerticalSync = VSync(0); //print message // FntPrint("\n\n\n\n\nGame\n"); // FntPrint(" \n%d/320\n ",VerticalSync); // FntPrint("current Beacon =%d\n", buggy.CurrentBeacon); // FntPrint("beacon 1 X =%d\n", buggy.BeaconLocation[0].vx); // FntPrint("beacon 1 Z =%d\n", buggy.BeaconLocation[0].vz); // FntPrint("\nbeacon actual =%d\n",Level1.Beacons[buggy.CurrentBeacon][0].vx); // FntPrint("beacon actual =%d\n",Level1.Beacons[buggy.CurrentBeacon][0].vz); // FntPrint("\nbeacon actual =%d\n",Level1.Beacons[buggy.CurrentBeacon][1].vx); // FntPrint("beacon actual =%d\n",Level1.Beacons[buggy.CurrentBeacon][1].vz); // FntPrint("buggy x=%d\n",buggy.Object_Coord.coord.t[0]); // FntPrint("buggy z=%d\n",buggy.Object_Coord.coord.t[2]); // force text output to the PSX screen // FntFlush(-1); RenderFinish(); } // Simply updates everything within the game. void UpdateWorldGame() { long index; long sum; // Update models UpdateObject(&buggy,1); GetBeacon(buggy.CurrentBeacon,&buggy.BeaconLocation[0],&buggy.BeaconLocation[1]); //Move to next beacon/check point ?? if(BeaconTest(buggy)) { PlaySFX(&beep); if(++buggy.CurrentBeacon == 11) { buggy.CurrentBeacon = 0; buggy.Lap++; } } //Update timer and lap counter for(index=0; index<6; index++) { switch(index) { case 0: sum = (((v_count/3000)%60)/10); break; case 1: sum = (((v_count/3000)%60)%10); break; case 2: sum = (((v_count/50)%60)/10); break; case 3: sum = (((v_count/50)%60)%10); break; case 4: sum = (((v_count*25)%60)/10); break; case 5: sum = (((v_count*25)%60)%10); break; } switch(sum) { case 0: SetSpriteInfo(&Timer[index],N0_TIM,(index*11)-99,-101); break; case 1: SetSpriteInfo(&Timer[index],N1_TIM,(index*11)-99,-101); break; case 2: SetSpriteInfo(&Timer[index],N2_TIM,(index*11)-99,-101); break; case 3: SetSpriteInfo(&Timer[index],N3_TIM,(index*11)-99,-101); break; case 4: SetSpriteInfo(&Timer[index],N4_TIM,(index*11)-99,-101); break; case 5: SetSpriteInfo(&Timer[index],N5_TIM,(index*11)-99,-101); break; case 6: SetSpriteInfo(&Timer[index],N6_TIM,(index*11)-99,-101); break; case 7: SetSpriteInfo(&Timer[index],N7_TIM,(index*11)-99,-101); break; case 8: SetSpriteInfo(&Timer[index],N8_TIM,(index*11)-99,-101); break; case 9: SetSpriteInfo(&Timer[index],N9_TIM,(index*11)-99,-101); break; } } switch(buggy.Lap) { case 0: SetSpriteInfo(&LapCount,N0_TIM,120,-101); break; case 1: SetSpriteInfo(&LapCount,N1_TIM,120,-101); break; case 2: SetSpriteInfo(&LapCount,N2_TIM,120,-101); break; case 3: SetSpriteInfo(&LapCount,N3_TIM,120,-101); break; } SetBoxPos(&buggyLocation,(buggy.Object_Coord.coord.t[0]/3000)+110,(buggy.Object_Coord.coord.t[2]/3000)+70,3,3); SetBoxPos(&checkPoint,(buggy.BeaconLocation[0].vx/3000)+110,(buggy.BeaconLocation[0].vz/3000)+70,3,3); v_count++; }; // Processes all inputs during the game. Simply adjusts player object varibles. // All important player stuff is taken care of else where. u_long ProcessUserInputGame() { // create PAD variable to hold states of both joypads u_long PAD = PadRead(); // standard check. Quit if pad1 has start pressed buggy.PedalDown = FALSE; if (PAD& PADR1) return(TITLE); if (PAD& PADLleft) buggy.yAngle -= buggy.TurnSpeed; if (PAD& PADLright)buggy.yAngle += buggy.TurnSpeed; if (PAD& PADcross) { buggy.Acceleration += buggy.AccelerateSpeed; buggy.PedalDown = TRUE; } if (PAD& PADsquare) { buggy.Acceleration -= buggy.AccelerateSpeed; buggy.PedalDown = TRUE; } // if (PAD& PADtriangle) // if(PAD& PADcircle) if(PAD& PADselect) { buggy.CurrentBeacon = 0; buggy.Object_Coord.coord = GsIDMATRIX; buggy.Object_Coord.flg = 0; } return(GAME); } ///////////////////////////////////////////////////////////////////////////////// // ** OBJECT FUNCTIONS ** // This function updates the given object according to its position. It'll set // up the object with the correct height and rotation and also move the object // accordinly, also applys physics to the model. // [Only use this function for moving objects.] // This function is pretty long and hard to follow so there are a lot of comments // within. void UpdateObject(ObjectStruct *theObject,u_long ViewFollow) { static long changed=0; MATRIX matTemp; SVECTOR Rotation1,Rotation2,Rotation3, forward; VECTOR tempDirection; long HeightToLeft, HeightToRight; long HeightToFront, HeightToBack; // ORIENTATION BIT matTemp = GsIDMATRIX; // set Direction forward.vx = 0; forward.vz = -1000; // needs to be the same size as in Tan calulation (FindOrientation())?????? forward.vy = 0; // clip Y rotation (just to be on the safe side !) if(theObject->yAngle > 4095) theObject->yAngle = theObject->yAngle - 4096; if(theObject->yAngle < 0 ) theObject->yAngle = 4096 + theObject->yAngle; // setup rotation vector Rotation1.vx = 0; Rotation1.vy = theObject->yAngle; Rotation1.vz = 0; // rotate forward vector. So I have a vector that goes directly in front. RotMatrix(&Rotation1,&matTemp); ApplyMatrix(&matTemp,&forward,&theObject->Direction); if(theObject->InAir == FALSE) { // Set objects height theObject->Object_Coord.coord.t[1] = FindHeight(theObject->Object_Coord.coord.t[0], theObject->Object_Coord.coord.t[2]); // Find offset heights for the front and back of object HeightToFront = FindHeight(theObject->Object_Coord.coord.t[0]+(theObject->Direction.vx), theObject->Object_Coord.coord.t[2]+(theObject->Direction.vz)); HeightToBack = FindHeight(theObject->Object_Coord.coord.t[0]-(theObject->Direction.vx), theObject->Object_Coord.coord.t[2]-(theObject->Direction.vz)); // setup rotation vector again this time at an extra 90 degrees. So // I have a vector that goes out to the side of the object. matTemp = GsIDMATRIX; Rotation1.vx = Rotation1.vz = 0; Rotation1.vy = theObject->yAngle + 1024; // rotate forward vector RotMatrix(&Rotation1,&matTemp); ApplyMatrix(&matTemp,&forward,&tempDirection); // Find offset heights for the left and right of the object HeightToRight = FindHeight(theObject->Object_Coord.coord.t[0]+(tempDirection.vx), theObject->Object_Coord.coord.t[2]+(tempDirection.vz)); HeightToLeft = FindHeight(theObject->Object_Coord.coord.t[0]-(tempDirection.vx), theObject->Object_Coord.coord.t[2]-(tempDirection.vz)); //Set Objects X Rotation Vector Rotation2.vx = FindRotation(HeightToFront,HeightToBack,2000); Rotation2.vy = Rotation2.vz = 0; // FntPrint(" vx = %d ",Rotation2.vx); //Set Objects Z Rotation Vector. Rotation3.vz = FindRotation(HeightToLeft,HeightToRight,2000); Rotation3.vy = Rotation3.vx = 0; // FntPrint(" vz = %d ",Rotation3.vz); // Set Objects Y Rotation Vector. Rotation1.vy = theObject->yAngle; Rotation1.vx = Rotation1.vz = 0; // FntPrint(" vy = %d ",Rotation1.vy); // Reset Matrix without losing translations. // [this also stops rotation deformations accuring]. theObject->Object_Coord.coord.m[0][0]= theObject->Object_Coord.coord.m[1][1]= theObject->Object_Coord.coord.m[2][2]=ONE; theObject->Object_Coord.coord.m[0][1]= theObject->Object_Coord.coord.m[0][2]= theObject->Object_Coord.coord.m[1][0]= theObject->Object_Coord.coord.m[1][2]= theObject->Object_Coord.coord.m[2][0]= theObject->Object_Coord.coord.m[2][1]=0; //Rotate Object. Explicit ordering of rotations Y,X,Z. (must be better way?) matTemp = GsIDMATRIX; RotMatrix(&Rotation1, &matTemp); MulMatrix0(&theObject->Object_Coord.coord, &matTemp, &theObject->Object_Coord.coord); matTemp = GsIDMATRIX; RotMatrix(&Rotation2, &matTemp); MulMatrix0(&theObject->Object_Coord.coord, &matTemp, &theObject->Object_Coord.coord); matTemp = GsIDMATRIX; RotMatrix(&Rotation3, &matTemp); MulMatrix0(&theObject->Object_Coord.coord, &matTemp, &theObject->Object_Coord.coord); // PHYSICS STUFF // Apply Speed Constraints if(theObject->Acceleration > theObject->MaxSpeed) theObject->Acceleration = theObject->MaxSpeed; else if(theObject->Acceleration < -theObject->MaxSpeed>>1) theObject->Acceleration = -theObject->MaxSpeed>>1; //Apply Friction if(theObject->PedalDown==FALSE) { if(theObject->Acceleration > 0) if(theObject->Acceleration > getFriction()) theObject->Acceleration -= getFriction(); else theObject->Acceleration =0; else if(theObject->Acceleration < 0) if(theObject->Acceleration < -getFriction()) theObject->Acceleration += getFriction(); else theObject->Acceleration =0; } // Apply Gravity - (Gravity is applied to acceleration because it contributes // to friction when on a slope, which is what I want to model). // The slope is the difference between the front height and back. // Applied after speed constraints so it can contribute to speed // making down hill runs faster then say a flat run. theObject->Acceleration += ((HeightToBack - HeightToFront)>>9); // FntPrint("difference = %d",(int)(HeightToBack - HeightToFront)>>9); // FntPrint("\nAcc = %d \n",(int)theObject->Acceleration); // // velocity calculation if(theObject->Acceleration != 0) { theObject->Velocity.vx = -((theObject->Direction.vx>>4) * theObject->Acceleration); theObject->Velocity.vy = -((theObject->Direction.vy>>4) * theObject->Acceleration); theObject->Velocity.vz = -((theObject->Direction.vz>>4) * theObject->Acceleration); } else { theObject->Velocity.vx = theObject->Velocity.vy = theObject->Velocity.vz = 0; } //Send object into the air?? // if(theObject >= ) // { // theObject->InAir = TRUE; // // // // } } else // Object is in the air { //Trajectory Stuff theObject->Acceleration += getWind(); theObject->Velocity.vy += getGravity(); if(theObject->Acceleration != 0) { theObject->Velocity.vx = -((theObject->Direction.vx>>4) * theObject->Acceleration); theObject->Velocity.vz = -((theObject->Direction.vz>>4) * theObject->Acceleration); } // Has object reached the floor ? if(theObject->Object_Coord.coord.t[1] >= FindHeight(theObject->Object_Coord.coord.t[0], theObject->Object_Coord.coord.t[2])) theObject->InAir = FALSE; } // Apply velocity to object !!!! ApplyVelocity(theObject); // make sure object is redrawn. theObject->Object_Coord.flg = 0; // Rotate the wheels RotateModelMatrix(&LBWheel,-theObject->Acceleration<<4,0,0); RotateModelMatrix(&RBWheel,-theObject->Acceleration<<4,0,0); if(changed ==0) { if(theObject->lastYAngle > theObject->yAngle) { RotateModelMatrix(&LFWheel,0/*-theObject->Acceleration<<4*/,-400,0); RotateModelMatrix(&RFWheel,0/*-theObject->Acceleration<<4*/,-400,0); changed =1; } else if(theObject->lastYAngle < theObject->yAngle) { RotateModelMatrix(&LFWheel,0/*-theObject->Acceleration<<4*/,400,0); RotateModelMatrix(&RFWheel,0/*-theObject->Acceleration<<4*/,400,0); changed =2; } else{} } else { if(theObject->lastYAngle == theObject->yAngle) switch(changed) { case 0: break; case 1: RotateModelMatrix(&LFWheel,0/*-theObject->Acceleration<<4*/,400,0); RotateModelMatrix(&RFWheel,0/*-theObject->Acceleration<<4*/,400,0); changed = 0; break; case 2: RotateModelMatrix(&LFWheel,0/*-theObject->Acceleration<<4*/,-400,0); RotateModelMatrix(&RFWheel,0/*-theObject->Acceleration<<4*/,-400,0); changed = 0; break; } } //RotateModelMatrix(&LFWheel,-theObject->Acceleration<<4,0,0); //RotateModelMatrix(&RFWheel,-theObject->Acceleration<<4,0,0); //If flag set, make camera follow this object. if(ViewFollow) { // Set view from point to an angle behind the object ViewPoint.vpx = theObject->Object_Coord.coord.t[0] + (theObject->Direction.vx<<2); ViewPoint.vpy = theObject->Object_Coord.coord.t[1] - 3000; ViewPoint.vpz = theObject->Object_Coord.coord.t[2] + (theObject->Direction.vz<<2); // Look at this. ViewPoint.vrx = theObject->Object_Coord.coord.t[0] - (theObject->Direction.vx<<2); ViewPoint.vry = theObject->Object_Coord.coord.t[1]; ViewPoint.vrz = theObject->Object_Coord.coord.t[2] - (theObject->Direction.vz<<2); GsSetRefView2(&ViewPoint); } theObject->lastYAngle = theObject->yAngle; } // Test to see if object has past a check point! // Uses simple 2d bounding box collision test. long BeaconTest(ObjectStruct testObject) { long highX,lowX; long highZ,lowZ; if(testObject.BeaconLocation[0].vx > testObject.BeaconLocation[1].vx) { highX = testObject.BeaconLocation[0].vx; lowX = testObject.BeaconLocation[1].vx; } else { highX = testObject.BeaconLocation[1].vx; lowX = testObject.BeaconLocation[0].vx; } if(testObject.BeaconLocation[0].vz > testObject.BeaconLocation[1].vz) { highZ = testObject.BeaconLocation[0].vz; lowZ = testObject.BeaconLocation[1].vz; } else { highZ = testObject.BeaconLocation[1].vz; lowZ = testObject.BeaconLocation[0].vz; } //printf("highX=%d,lowX=%d,highZ=%d,lowZ=%d\n",highX,lowX,highZ,lowZ); if((testObject.Object_Coord.coord.t[0] >= lowX) && (testObject.Object_Coord.coord.t[0] <= highX) && (testObject.Object_Coord.coord.t[2] >= lowZ) && (testObject.Object_Coord.coord.t[2] <= highZ) ) { return(1); } return(0); } //////////////////////////////////////////////////////////////////////// // **** M A I N **** //------------------ int main() { u_long GameRunning = TRUE; // FLAG Has game been exited u_long GameState = TITLE;// FLAG Which part of game are we in. (e.g title) // set up print-to-screen font, the parameters are where the font is FntLoad(960, 256); FntOpen(-150, -110, 300, 220, 0, 512); // initialise the joypad PadInit(); // initialise graphics Initialise3DGraphics(); LoadTextures(); InitialiseLights(); // Fogging fades to black. Fogging.dqa = -15000; Fogging.dqb = 5120*5120*1.0; Fogging.rfc = Fogging.gfc = Fogging.bfc = 0; GsSetLightMode(1); GsSetFogParam(&Fogging); // initialise 3d models InitialiseModel(&buggy,0,-500,0,500,(u_long *)BODY_TMD); InitialiseModel(&LFWheel,550,0,500,0,(u_long *)WHEEL_TMD); LFWheel.Object_Coord.super = &buggy.Object_Coord; InitialiseModel(&LBWheel,550,0,-500,0,(u_long *)WHEEL_TMD); LBWheel.Object_Coord.super = &buggy.Object_Coord; InitialiseModel(&RFWheel,-550,0,500,0,(u_long *)WHEEL_TMD); RFWheel.Object_Coord.super = &buggy.Object_Coord; InitialiseModel(&RBWheel,-550,0,-500,0,(u_long *)WHEEL_TMD); RBWheel.Object_Coord.super = &buggy.Object_Coord; //initialise wireframe model. InitTransProj(); CreateGrid(Level1.heightFields); InitialiseLights(); //Initialise 2d sprites SetSpriteInfo(&TitleP1,TITLE1_TIM,-80,0); SetSpriteInfo(&TitleP2,TITLE2_TIM,80,0); SetBoxPos(&Highlight,-160,65,50,20); SetLineRGB(&Highlight,200,0,0); BitSet(&Highlight.attribute,1<<30); SetBoxPos(&scanner,100,60,60,60); SetLineRGB(&scanner,0,0,200); BitSet(&scanner.attribute,1<<30); SetBoxPos(&buggyLocation,110,80,2,2); SetLineRGB(&buggyLocation,200,0,0); SetBoxPos(&checkPoint,110,90,2,2); SetLineRGB(&checkPoint,0,0,0); SetSpriteInfo(&Time,TIME_TIM,-90,-100); SetSpriteInfo(&Lap,LAP_TIM,100,-100); SetSpriteInfo(&Timer[0],N0_TIM,-50,-100); SetSpriteInfo(&Timer[1],N0_TIM,-40,-100); SetSpriteInfo(&Timer[2],N0_TIM,-30,-100); SetSpriteInfo(&Timer[3],N0_TIM,-20,-100); SetSpriteInfo(&Timer[4],N0_TIM,-10,-100); SetSpriteInfo(&Timer[5],N0_TIM,0,-100); SetSpriteInfo(&LapCount,N0_TIM,120,-100); SetLevelMap(); SetCurrentMap(&Level1); InitialiseMap1Objects(); SetupMap(); // Create TMDS InitSound(); InitSFX(&beep,vab_id,2,0,50,0,127,127); InitSFX(&ting,vab_id,0,0,68,0,127,127); InitSFX(&car,vab_id,1,0,68,0,127,127); // Main game loop while(GameRunning == TRUE) { PlaySFX(&car); InitialiseView(&ViewPoint,500, 0, -100, -400, -300, 0, -200, 400); // Main title screen loop SetModel(&buggy.Object_Coord,-1020,4300,15150); while(GameState == TITLE) { GameState = ProcessUserInputTitle(); UpdateWorldTitle(); RenderWorldTitle(); } InitialiseView(&ViewPoint,250, 0, 0, -2000, -3000, 0, 0, 0); SetModel(&buggy.Object_Coord,9000,0,23000); // Actual game loop while(GameState == GAME) { GameState = ProcessUserInputGame(); UpdateWorldGame(); RenderWorldGame(); if(buggy.Lap == 4) { GameState = TITLE; buggy.Lap = 0; buggy.CurrentBeacon = 0; buggy.yAngle = 0; } } // set Quit state. if(GameState == QUIT) { GameRunning = FALSE; } } StopSound(); ResetGraph(3); return 0; }