// *********************************************************************************** // Programs written by R.Swan - rs108@mdx.ac.uk - www.netyaroze-europe.com/~middex2 // Taken from the tutorial by P.Passmore - p.passmore@mdx.ac.uk // Tutorial file can be found at the above web site // Step ten - add a road to drive around on // *********************************************************************************** // *********************************************************************************** // Preprocessor functions // *********************************************************************************** #define FADER 0 #define FADEG 0 #define FADEB 0 #include "header.h" //#include "function.c" // **** create global variables, structures, headers and arrays (mostly system stuff) u_long CirclePressed = 0; u_long LapsCounter = 0; u_long TimeCurrent, TimeFastest, TimeSlowest; u_long PlayerStartedRacing=0; long PlayerTilt; u_long DrawSection = 0; u_long DrawSectionFlag = 0; GsSPRITE DialSprite; GsSPRITE PointerSprite; void RotateTrack(u_long tAngle, u_long tTrackNumber); void UpdateWorld(); void MoveToNextTrackSection(); u_long CheckCollide(u_long tSection); // *********************************************************************************** // Main function // *********************************************************************************** void main() { TimeCurrent=0; TimeSlowest=0; TimeFastest=9999999; GhostArrayInUse = 0; GhostInUse = 0; GhostMaxPosition = 0; TRANSPARENCY = 0; LoadTIMData(TIM_DIAL); LoadTIMData(TIM_POINTER); LoadTIMData(TIM_BARR); LoadTIMData(TIM_GRASS); LoadTIMData(TIM_LBARR); LoadTIMData(TIM_LOGO); LoadTIMData(TIM_LROAD); LoadTIMData(TIM_ROAD); LoadTIMData(TIM_TREE); SetSpriteInfo(&DialSprite, TIM_DIAL, -150, 52); DialSprite.attribute += (1<<30) + (1<<28);// + (1<<29); SetSpriteInfo(&PointerSprite, TIM_POINTER, -150, 110); PointerSprite.attribute += (1<<30); PointerSprite.mx = 12; PointerSprite.my = 12; PointerSprite.scalex = PointerSprite.scaley = ONE*0.52; FntLoad(960, 256); // load font into area of frame // specified by 960, 256 FntOpen(-160, -70, 320, 100, 0, 512); // specify where on screen text goes // (0, 0) is center of screen PadInit(); // initialise joypad reading InitialiseGraphics(); // initialise graphics InitialiseCounter(); InitView(&Camera, 250, 0, 0,-900,-1500, 0,-200,1000 ,&CarModel.Object_Coord); // InitView(&Camera, 250, 0, 0,-600,-200, 0,-200,1000 ,&CarModel.Object_Coord); // InitView(&Camera, 250, 0, 0,-7000,-2000, 0,0,3000 ,&CarModel.Object_Coord); // initialise all cameras InitAllLights(); // call function that creates two lights InitTrack(); InitModel(&CarModel, 30500, -100, 40000, (u_long *)CAR_MEM_ADDR); InitModel(&GhostModel, 30500, -100, 40000, (u_long *)CAR_MEM_ADDR); // prepare objects for use // car's position set to (0, -200, 0); GhostModel.Object_Handler.attribute += TRANSPARENCY; Fogging.dqa = -15000; // this is a measure of the distance // at which objects start to fade to // the specified colours. IT IS NOT // directly related to world units. // The more negative the value, the // farther in front of you an object // has to be before it starts to fade Fogging.dqb = 5120*5120*1.0; // this is a measure of how far either // side of the distance above that // objects fade in or out. A value of // 5120*5120*2 = very abrupt fading // 5120*5120*0.7 = very gradual fade Fogging.rfc = FADER; // set colour for objects to fade to Fogging.gfc = FADEG; Fogging.bfc = FADEB; GsSetLightMode(1); // set fogging to be used in light GsSetFogParam(&Fogging); // define which fogging to be used while(Running) // do loop while program is running { // FntPrint("Speed (%d)\n", VerticalSync); // FntPrint("GhostInUse (%d)\n", GhostInUse); // FntPrint("GhostArrayInUse (%d)\n", GhostArrayInUse); // FntPrint("GhostArrayPosition (%d)", GhostArrayPosition); // display speed of screen drawing // FntPrint("X %d\n", CarModel.Object_Coord.coord.t[0]); // FntPrint("Z %d\n", CarModel.Object_Coord.coord.t[2]); ProcessUserInput(); // call function to process joypad UpdateWorld(); MoveToNextTrackSection(); RenderWorld(); // render the playstation screen } ResetGraph(3); // clear up before quitting }; // *********************************************************************************** // User defined drawing functions // *********************************************************************************** // **** update all objects + track void UpdateWorld() { u_long tTemp1, tTemp2; if (LapsCounter>0) { for (tTemp1=1; tTemp1<10; tTemp1++) { for (tTemp2=0; tTemp2<7; tTemp2++) { if (tTemp1==1) Numbers[1][tTemp2].x ++; Numbers[tTemp1][tTemp2].y++; if ((LapsCounter == 6) && (tTemp1!=1)) Numbers[tTemp1][tTemp2].x ++; } } LapsCounter--; }; PointerSprite.rotate = -(abs(CarModel.speed)) * 921; CarModel.Object_Coord.coord.t[1] = -100-(abs(CarModel.speed)); if (CarModel.Object_Coord.coord.t[1] < -300) CarModel.Object_Coord.coord.t[1] = -300; if (PlayerStartedRacing==1) { CounterDigits[0][4] += 2; TimeCurrent++; } for (tTemp1 = 4; tTemp1 != 0; tTemp1--) { if (CounterDigits[0][tTemp1] > 9) { CounterDigits[0][tTemp1] = CounterDigits[0][tTemp1] % 10; CounterDigits[0][tTemp1-1]++; } if (CounterDigits[0][1] > 5) { CounterDigits[0][1] = CounterDigits[0][1] % 6; CounterDigits[0][0]++; } } if (CounterDigits[0][0] == 10) CounterDigits[0][0] = 0; for (tTemp1 = 0; tTemp1 < 5; tTemp1++) { Numbers[0][tTemp1].u = CounterDigits[0][tTemp1]*16; } tTemp2 = CheckCollide(DrawSection); CarModel.speed *= 0.985; switch(tTemp2) { case TRACK: break; case GRASS: if (abs(CarModel.speed)>175) CarModel.speed *= 0.97; break; case SMASH: { CarModel.speed *= -1.5; break;}; case TREES: if (abs(CarModel.speed)>100) CarModel.speed *= 0.9; break; }; MoveModelForward(&CarModel, CarModel.speed); // move man every frame if (tTemp2 == SMASH) CarModel.speed *= 0.2; GsSetRefView2(&Camera); // activates the view PlayerTilt *= 0.95; RotateModel(&CarModel, 0, PlayerTilt, PlayerTilt*8); Camera.rz = -PlayerTilt * 5 * 360; if (GhostInUse > 0) { if (GhostArrayPosition<2000) { Ghost[GhostArrayInUse][GhostArrayPosition].x = CarModel.Object_Coord.coord.t[0]; Ghost[GhostArrayInUse][GhostArrayPosition].y = CarModel.Object_Coord.coord.t[1]; Ghost[GhostArrayInUse][GhostArrayPosition].z = CarModel.Object_Coord.coord.t[2]; Ghost[GhostArrayInUse][GhostArrayPosition].rotation = CarModel.rotation.vy; Ghost[GhostArrayInUse][GhostArrayPosition].direction = CarModel.rotation.vz; if ((GhostInUse == 2) && (GhostArrayPosition-100) CarModel.speed-=8;}; if (PAD& PADleft) {PlayerTilt -= 3;}; // rotate car anti-clockwise if (PAD& PADright) {PlayerTilt += 3;}; // rotate car clockwise if (PAD& PADL1) {PlayerTilt -= 2; // rotate car anti-clockwise if (CarModel.speed>0) CarModel.speed *= 0.97;}; if (PAD& PADR1) { PlayerTilt += 2; // rotate car clockwise if (CarModel.speed>0) CarModel.speed *= 0.97;}; if ((PAD& PADcircle) && (CirclePressed == 0)) { CirclePressed = 1; TRANSPARENCY = (1<<30) - TRANSPARENCY; GhostModel.Object_Handler.attribute = TRANSPARENCY; }; if (!(PAD& PADcircle)) CirclePressed = 0; }; // **** Rotate an object about it's own center void RotateTrack(u_long tAngle, u_long tTrackNumber) { SVECTOR tRotate; MATRIX tMatrix; // temporary rotation matrix tRotate.vx = 0; // set up rotation about the axes tRotate.vy = 4096-(tAngle*1024); tRotate.vz = 0; RotMatrix(&tRotate, &tMatrix); // turn vector into rotation matrix MulMatrix0( &TrackData.Object_Coord[tTrackNumber].coord, &tMatrix, &TrackData.Object_Coord[tTrackNumber].coord); // multiply object and rotation matrices TrackData.Object_Coord[tTrackNumber].flg = 0; // signify object has changed }; void MoveToNextTrackSection() { u_long tTemp1, tTemp2; u_long tTempX1, tTempZ1; u_long tTempX2, tTempZ2; u_long tTempX3, tTempZ3; u_long tSection = (DrawSection+1) % GROUND_OBJECTS; u_long tSection2 = (DrawSection-1+GROUND_OBJECTS) % GROUND_OBJECTS; tTempX1 = labs(CarModel.Object_Coord.coord.t[0] - GroundCheck1[DrawSection][0]); tTempZ1 = labs(CarModel.Object_Coord.coord.t[2] - GroundCheck1[DrawSection][1]); tTempX2 = labs(CarModel.Object_Coord.coord.t[0] - GroundCheck1[tSection][0]); tTempZ2 = labs(CarModel.Object_Coord.coord.t[2] - GroundCheck1[tSection][1]); tTempX3 = labs(CarModel.Object_Coord.coord.t[0] - GroundCheck1[tSection2][0]); tTempZ3 = labs(CarModel.Object_Coord.coord.t[2] - GroundCheck1[tSection2][1]); if ((tTempX1+tTempZ1) > (tTempX2+tTempZ2)) { DrawSection = (DrawSection+1) % GROUND_OBJECTS; if (DrawSection == 0) { if (GhostInUse == 0) GhostInUse = 1; if (PlayerStartedRacing == 1) { u_long tColR = 64, tColG = 64, tColB = 64; LapsCounter = 12; for (tTemp1=9; tTemp1>1; tTemp1--) { for (tTemp2=0; tTemp2<7; tTemp2++) { Numbers[tTemp1][tTemp2].u = Numbers[tTemp1-1][tTemp2].u; Numbers[tTemp1][tTemp2].attribute = Numbers[tTemp1-1][tTemp2].attribute; Numbers[tTemp1][tTemp2].r = Numbers[tTemp1-1][tTemp2].r; Numbers[tTemp1][tTemp2].g = Numbers[tTemp1-1][tTemp2].g; Numbers[tTemp1][tTemp2].b = Numbers[tTemp1-1][tTemp2].b; Numbers[tTemp1][tTemp2].y -= 12; Numbers[tTemp1][tTemp2].x = Numbers[tTemp1-1][tTemp2].x+1; } } for (tTemp2=0; tTemp2<7; tTemp2++) { Numbers[1][tTemp2].u = Numbers[tTemp1-1][tTemp2].u; Numbers[1][tTemp2].attribute = Numbers[tTemp1-1][tTemp2].attribute; Numbers[1][tTemp2].r = Numbers[tTemp1-1][tTemp2].r; Numbers[1][tTemp2].g = Numbers[tTemp1-1][tTemp2].g; Numbers[1][tTemp2].b = Numbers[tTemp1-1][tTemp2].b; Numbers[1][tTemp2].x -= 12; Numbers[1][tTemp2].y -= 12; }; if ((TimeCurrent+25)>TimeSlowest) { tColR = 128; tColG = 128; tColB = 64; } if (TimeCurrent>TimeSlowest) { if (!(TimeCurrent0) && (GhostArrayPosition<2000)) { GhostArrayInUse = 1-GhostArrayInUse; GhostInUse = 2; GhostMaxPosition = GhostArrayPosition; }; } for (tTemp1=0; tTemp1<7; tTemp1++) { Numbers[1][tTemp1].u = Numbers[0][tTemp1].u; CounterDigits[1][tTemp1] = CounterDigits[0][tTemp1]; CounterDigits[0][tTemp1] = 0; if (tTemp1<5) Numbers[0][tTemp1].u = 0; Numbers[1][tTemp1].attribute = (1<<30)+(1<<28); Numbers[1][tTemp1].r = tColR; Numbers[1][tTemp1].g = tColG; Numbers[1][tTemp1].b = tColB; } TimeCurrent=0; } else { PlayerStartedRacing=1; for (tTemp1=0; tTemp1<7; tTemp1++) Numbers[0][tTemp1].attribute = (1<<30)+(1<<28); TimeCurrent=0; } GhostArrayPosition = 0; } } else { if ((tTempX3+tTempZ3) < (tTempX1+tTempZ1)) { DrawSection = (DrawSection-1+GROUND_OBJECTS) % GROUND_OBJECTS; } } }; u_long CheckCollide(u_long tSection) { u_long tReturn; u_long tTrack = RawGroundArray[tSection]; u_long tDir = GroundCheck1[tSection][5]; long tTempX,tTempZ; switch(tDir) { case 0: { tTempX = (CarModel.Object_Coord.coord.t[0] - GroundCheck1[tSection][0]); tTempZ = (CarModel.Object_Coord.coord.t[2] - GroundCheck1[tSection][1]); break; }; case 1: { tTempX = (CarModel.Object_Coord.coord.t[2] - GroundCheck1[tSection][1]); tTempZ = (CarModel.Object_Coord.coord.t[0] - GroundCheck1[tSection][0]); break; }; case 2: { tTempX = (-CarModel.Object_Coord.coord.t[0] + GroundCheck1[tSection][0]); tTempZ = (-CarModel.Object_Coord.coord.t[2] + GroundCheck1[tSection][1]); break; }; case 3: { tTempX = (-CarModel.Object_Coord.coord.t[2] + GroundCheck1[tSection][1]); tTempZ = (-CarModel.Object_Coord.coord.t[0] + GroundCheck1[tSection][0]); break; }; }; tReturn = TRACK; switch(tTrack) { case FORWARD: { if ((tTempX>(GROUND_SIZE*0.5)) || (tTempX<-(GROUND_SIZE*0.5))) tReturn = GRASS; break; }; case TUNNEL: { if ((tTempX>(GROUND_SIZE*0.7)) || (tTempX<-(GROUND_SIZE*0.7))) tReturn = SMASH; break; }; case TREE_L: { if (tTempX>(GROUND_SIZE*0.5)) tReturn=GRASS; if (tTempX<-(GROUND_SIZE*0.5)) tReturn = TREES; break; }; case TREE_R: { if (tTempX>(GROUND_SIZE*0.5)) tReturn=TREES; if (tTempX<-(GROUND_SIZE*0.5)) tReturn = GRASS; break; }; case LEFT: { if ((tTempX>(GROUND_SIZE*0.5)) || (tTempX<-(GROUND_SIZE*0.5))) tReturn = GRASS; break; }; case RIGHT: { if ((tTempX>(GROUND_SIZE*0.5)) || (tTempX<-(GROUND_SIZE*0.5))) tReturn = GRASS; break; }; }; if ((tTempX>(GROUND_SIZE*2)) || (tTempX<-(GROUND_SIZE*2)) || (tTempZ<-(GROUND_SIZE*2)) || (tTempZ>(GROUND_SIZE*3.5))) tReturn = SMASH; return tReturn; }