//-------------------------------------------------------------------------------------------------- // F4 Racing //-------------------------------------------------------------------------------------------------- // This is an advancement in my game making skills, building off the back of my work on the "Collect the Balls" game. //-------------------------------------------------------------------------------------------------- // created by Rune //-------------------------------------------------------------------------------------------------- #define OLC_PGE_APPLICATION #include "pixelGameEngine.h" // used for drawing the game //-------------------------------------------------------------------------------------------------- // class //-------------------------------------------------------------------------------------------------- class Racer : public olc::PixelGameEngine { public: Racer() { sAppName = "F4 Racing"; } private: float car_pos = 0.0f; float distance = 0.0f; float speed = 0.0f; float curvature = 0.0f; float track_curve = 0.0f; float car_curve = 0.0f; float track_dist = 0.0f; float cur_lap_time = 0.0f; std::vector> vecTrack; std::list list_times; public: // Menu Setup //---------------------------------------- struct MenuItem { std::string label; // label olc::vi2d pos; // label's position }; struct Object { olc::vf2d pos; //The x position represents how far to the left/right it is from the center. -1 ~ 1: Road's range. The y position is how far along the track it is. olc::vf2d size; bool rendered=false; olc::vf2d drawPos; olc::vf2d drawSize; }; std::vector mainMenu; std::vector playGame; std::vector pickTrack; std::vector grandPrix; std::vector selectCar; std::vector controls; std::vector gameOver; std::vector gameObjects; enum class state { MAIN_MENU, TRACK_SELECT, CUP_SELECT, CAR_SELECT, CONTROLS, RUN_GAME }; state gameState = state::MAIN_MENU; // Variables //---------------------------------------- // lap times // player int score; // score at end of track; based on final place int lap; // current lap player is on int place; // current place player is in olc::Decal* car; // initialize car image olc::Decal* hill; // initialize hill image olc::Decal* grass; // initialize grass image olc::Decal* road; // initialize road image //-------------------------------------------------------------------------------------------------- // Create Game Objects //-------------------------------------------------------------------------------------------------- bool OnUserCreate() override { // show menu options mainMenu = { { "START GAME", { ScreenWidth() / 2, ScreenHeight() / 2 } }, { "CONTROLS", { ScreenWidth() / 2, ScreenHeight() / 2 + 16} }, { "QUIT", {ScreenWidth() / 2, ScreenHeight() / 2 + 32 } } }; playGame = { { "TRACK SELECTION", { ScreenWidth() / 2, ScreenHeight() / 2 } }, { "GRAND PRIX", { ScreenWidth() / 2, ScreenHeight() / 2 + 32 } } }; // show track options pickTrack = { { "LOOP", { ScreenWidth() / 3, ScreenHeight() / 3 } }, { "INFINITY", { ScreenWidth() / 2, ScreenHeight() / 3 } }, { "ARROWHEAD", { ScreenWidth() / 3 * 2, ScreenHeight() / 3 } }//, // track 4 //{ "OVERPASS", { ScreenWidth() / 3 * 2, ScreenHeight() / 3 * 2 } }, // track 6 // track 7 // track 8 // track 9 }; grandPrix = { // { "INDIE CUP", { ScreenWidth() / 2, ScreenHeight() / 2 } } // { "STREET CUP", { ScreenWidth() / 2, ScreenHeight() / 2 } } // { "PRO CUP", { ScreenWidth() / 2, ScreenHeight() / 2 } } { "GRAND PRIX", { ScreenWidth() / 2, ScreenHeight() / 2 } } }; selectCar = { { "RED", { ScreenWidth() / 5, ScreenHeight() / 3 } }, { "BLUE", { ScreenWidth() / 5 * 2, ScreenHeight() / 3 } }, { "GREEN", { ScreenWidth() / 5 * 3, ScreenHeight() / 3 } }, { "GOLD", { ScreenWidth() / 5 * 4, ScreenHeight() / 3 } }, { "PURPLE", { ScreenWidth() / 5, ScreenHeight() / 3 * 2 } }, { "WHITE", { ScreenWidth() / 5 * 2, ScreenHeight() / 3 * 2 } }, { "ORANGE", { ScreenWidth() / 5 * 3, ScreenHeight() / 3 * 2 } }, { "BLACK", { ScreenWidth() / 5 * 4, ScreenHeight() / 3 * 2 } } }; gameOver = { "Return to Main Menu" }; //---------------------------------------- car = new olc::Decal(new olc::Sprite("car.png")); // load car image hill = new olc::Decal(new olc::Sprite("mountain.png"), false, false); // load hill image grass = new olc::Decal(new olc::Sprite("grass.png"), false, false); // load grass image road = new olc::Decal(new olc::Sprite("road.png"), false, false); // load grass image // track layout vecTrack.push_back(std::make_pair(0.0f, 10.0f)); // start/finish line vecTrack.push_back(std::make_pair(0.0f, 200.0f)); // straight vecTrack.push_back(std::make_pair(1.0f, 200.0f)); // sharp right vecTrack.push_back(std::make_pair(0.0f, 400.0f)); // long straight vecTrack.push_back(std::make_pair(-1.0f, 100.0f)); // soft left vecTrack.push_back(std::make_pair(0.0f, 200.0f)); // straight vecTrack.push_back(std::make_pair(-1.0f, 200.0f)); // sharp left vecTrack.push_back(std::make_pair(1.0f, 200.0f)); // sharp right vecTrack.push_back(std::make_pair(0.0, 200.0f)); // straight vecTrack.push_back(std::make_pair(0.2f, 500.0f)); // gradual right vecTrack.push_back(std::make_pair(0.0f, 200.0f)); // straight for (auto t : vecTrack) { track_dist += t.second; } list_times = { 0,0,0,0,0 }; Object dot1 = {{0,600},{16,16}}; Object dot2 = {{0,900},{16,16}}; gameObjects.push_back(dot1); gameObjects.push_back(dot2); return true; } //-------------------------------------------------------------------------------------------------- // Main Game Function //-------------------------------------------------------------------------------------------------- bool OnUserUpdate(float fElapsedTime) override { Clear(olc::BLACK); // get point on track float offset = 0; int TrackSection = 0; cur_lap_time += fElapsedTime; // record lap time if (distance >= track_dist) { distance -= track_dist; list_times.push_front(cur_lap_time); // push time to front list_times.pop_back(); // pop time to back cur_lap_time = 0.0f; } // find position on track (could optimize) << should probably optimize given the complexity of this game while (TrackSection < vecTrack.size() && offset <= distance) { offset += vecTrack[TrackSection].second; TrackSection++; } float TargetCurvature = vecTrack[TrackSection - 1].first; // drawing curves to screen float TrackCurveDiff = (TargetCurvature - curvature) * fElapsedTime * speed; // correcting the drawing of curves to the screen curvature += TrackCurveDiff; // update track curve difference track_curve += (curvature) * fElapsedTime * speed; // dry skybox GradientFillRectDecal({ 0.0f, 0.0f }, { ScreenWidth() + 0.0f, ScreenHeight() / 2 + 0.0f }, olc::DARK_BLUE, olc::BLUE, olc::BLUE, olc::DARK_BLUE); // the hills have eyes; y'know, like in Super Mario Bros. What reference did you think was going to be here? DrawPartialDecal({ 0.0f, ScreenHeight() / 2 - 100.0f }, hill, { 0.0f + track_curve * 200, 0.0f }, { ScreenWidth() + 0.0f, (float)hill->sprite->height }, { 1.5f, 1.0f }); //DrawPartialDecal({ 180.0f, ScreenHeight() / 2 - 100.0f }, hill, { 0.0f + track_curve * 200, 0.0f }, { ScreenWidth() + 0.0f, (float)hill->sprite->height }); // draw grass DrawPartialWarpedDecal(grass, { { 0.0f, ScreenHeight() / 2 + 0.0f }, { -ScreenWidth() * 2 + 0.0f, ScreenHeight() + 0.0f}, { ScreenWidth() * 2 + ScreenWidth() + 0.0f, ScreenHeight() + 0.0f }, { ScreenWidth() + 0.0f, ScreenHeight() / 2 + 0.0f } }, { 0.0f, -distance/12.0f }, { 1 * 32, 5 * 2 } ); std::vector pos; std::vector uv; for (Object&obj:gameObjects) { obj.rendered=false; } // draw track canvas for (int y = 0; y < ScreenHeight() / 2; y++) { // track canvas variables float perspective = (float)y / (ScreenHeight() / 2.0f); float mid_point = 0.5f + curvature * powf((1.0f - perspective), 3); float road_width = 0.1f + perspective * 0.8f; float curb_width = road_width * 0.15f; road_width *= 0.5f; int lf_curb = (mid_point - road_width) * ScreenWidth(); int rt_curb = (mid_point + road_width) * ScreenWidth(); int row = ScreenHeight() / 2 + y; // drawing grass and curb olc::Pixel curb_col = sinf(80.0f * powf(1.0f - perspective, 3) + distance) > 0.0f ? olc::RED : olc::WHITE; pos.push_back({lf_curb,row}); pos.push_back({rt_curb,row}); float horizonDistance = powf(1.0f - perspective, 2)*80; if (distance+horizonDistance>track_dist-20&&distance+horizonDistanceobj.pos.y&&(distance+horizonDistance)=ScreenHeight()/2+ScreenHeight()/2*perspectiveRange) { std::cout<<":"<= 0.8f) { speed -= 5.0f * fElapsedTime; } // clamp speed if (speed < 0.0f) speed = 0.0f; if (speed > 1.0f) speed = 1.0f; // move car along track according to car speed distance += (70.0f * speed) * fElapsedTime; // draw car car_pos = car_curve - track_curve; DrawDecal({ ScreenWidth() / 2 - 128 + car_pos * ScreenWidth() / 2, ScreenHeight() / 4 * 3.0f - 128 }, car); SetPixelMode(olc::Pixel::ALPHA); // spedometer std::string mph = std::to_string(speed); DrawStringDecal({4, 4},std::to_string(distance)); // show time auto disp_time = [](float t) { int min = t / 60.0f; int sec = t - (min * 60.0f); int milli = (t - (float)sec) * 1000.0f; // need to change this out to a 'DrawString()' function instead return std::to_string(min) + "." + std::to_string(sec) + ":" + std::to_string(milli); }; // correct for the first '0' in the seconds timer //if () //{ // // draw min + '0' + sec + milli // DrawString(4, 16, disp_time(cur_lap_time)); //} //else //{ DrawString(4, 16, disp_time(cur_lap_time)); //} // display last 5 lap times int j = 30; for (auto l : list_times) { DrawString(10, j, disp_time(l)); j += 10; } // debug code //std::string numb1 = std::to_string(car_pos); //DrawString(4, 26, numb1); //std::string numb2 = std::to_string(track_dist); //DrawString(4, 38, numb2); return true; } }; //-------------------------------------------------------------------------------------------------- int main() { std::cout<<(-265%50)<<"\n"; std::cout<<(-26%50)<<"\n"; Racer game; if (game.Construct(1280, 720, 1, 1)) game.Start(); return 0; } //-------------------------------------------------------------------------------------------------- // END OF FILE //--------------------------------------------------------------------------------------------------