generated from sigonasr2/CPlusPlusProjectTemplate
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1331 lines
42 KiB
1331 lines
42 KiB
//========================================================================================================================================
|
|
// 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
|
|
// black box code by Sigonasr2 from the OLC (one lone coder) Discord server
|
|
//========================================================================================================================================
|
|
#include "pixelGameEngine.h" // used for drawing the game
|
|
|
|
//========================================================================================================================================
|
|
// protected variables
|
|
//========================================================================================================================================
|
|
class Racer : public olc::PixelGameEngine
|
|
{
|
|
public:
|
|
Racer()
|
|
{
|
|
sAppName = "F4 Racing";
|
|
}
|
|
|
|
private:
|
|
float curvature = 0.f; // probably the player's horizontal position in relation to the track's curve
|
|
float track_curve = 0.f;
|
|
float car_curve = 0.f; // wtf....
|
|
float track_dist = 0.f; // total distance of the circuit
|
|
|
|
float cur_lap_time = 0.f;
|
|
|
|
std::vector<std::pair<float, float>> vecTrack;
|
|
std::list<float> list_times;
|
|
|
|
bool bothKeysPressed = false; // checking for dual key press; could probably work with more than 2 keys
|
|
|
|
// custom controls template
|
|
olc::Key Move_Up = olc::UP;
|
|
olc::Key Move_Down = olc::DOWN;
|
|
olc::Key Move_Left = olc::LEFT;
|
|
olc::Key Move_Right = olc::RIGHT;
|
|
|
|
std::array<std::string, 4> keyslist = { "UP", "DOWN", "LEFT", "RIGHT" };
|
|
int configKeyIndex = -1;
|
|
char pressedKey;
|
|
|
|
// selection screen variables
|
|
int cup = -1;
|
|
int track = -1;
|
|
int player = 0;
|
|
|
|
//========================================================================================================================================
|
|
// Menu Setup
|
|
//========================================================================================================================================
|
|
public:
|
|
bool activeOption = true; // highlighting current option
|
|
int highlighted;
|
|
|
|
struct MenuItem
|
|
{
|
|
std::string label; // label
|
|
olc::vi2d pos; // label's position
|
|
std::string label2; // another label to right of label
|
|
};
|
|
|
|
struct Object
|
|
{
|
|
olc::vf2d pos{ 0, 0 }; // 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{ 1, 1 };
|
|
olc::Decal* decal = nullptr;
|
|
olc::vf2d offset{ 0, 0 }; // how far off the image will be
|
|
bool rendered = false;
|
|
olc::vf2d drawPos;
|
|
olc::vf2d drawSize;
|
|
olc::vf2d drawOffsetPos;
|
|
};
|
|
|
|
std::vector<MenuItem> mainMenu;
|
|
std::vector<MenuItem> playGame;
|
|
std::vector<MenuItem> pickTrack;
|
|
std::vector<MenuItem> grandPrix;
|
|
std::vector<MenuItem> selectCar;
|
|
std::vector<MenuItem> controls;
|
|
std::vector<MenuItem> pause;
|
|
std::vector<MenuItem> gameOver;
|
|
|
|
std::vector<Object> gameObjects;
|
|
|
|
enum class state
|
|
{
|
|
MAIN_MENU, PLAY_GAME, RUN_GAME, CONTROLS, PAUSED, RESUME, END_GAME, // main
|
|
TRACK_SELECT, CUP_SELECT, CAR_SELECT, // game
|
|
INDIE, STREET, PRO, GRAND_PRIX // cups
|
|
};
|
|
|
|
state gameState = state::MAIN_MENU;
|
|
|
|
//========================================================================================================================================
|
|
// Variables
|
|
//========================================================================================================================================
|
|
|
|
// lap times
|
|
|
|
// player
|
|
int cur_place; // current place player is in
|
|
int total_place = 8; // total number of places in race
|
|
int tracks_left;
|
|
|
|
struct Racecar
|
|
{
|
|
float car_pos = 0.f; // track the horizontal location of player, as the track begins to curve away
|
|
float distance = 0.f; // track the "vertical" location of player; basically, they're somewhere on the track between the start and finish line
|
|
float speed = 0.f;
|
|
int color = 0; // track the player color; unselected colors become AI racers
|
|
int score = 0; // score at end of track; based on final place
|
|
int cur_lap = 0; // current lap player is on
|
|
bool is_Player;
|
|
};
|
|
|
|
std::vector<Racecar> cars;
|
|
|
|
// initialize sprites
|
|
olc::Decal* car;
|
|
olc::Decal* hill;
|
|
olc::Decal* grass;
|
|
olc::Decal* road;
|
|
olc::Decal* banner;
|
|
olc::Decal* title;
|
|
olc::Decal* cups;
|
|
olc::Decal* tracks;
|
|
olc::Decal* select;
|
|
|
|
std::string KeyToString(olc::Key key)
|
|
{
|
|
const std::array<std::string, 98> keyStrings =
|
|
{
|
|
"NONE","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9",
|
|
"F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","UP","DOWN","LEFT","RIGHT","SPACE","TAB","SHIFT","CTRL","INS","DEL","HOME","END","PGUP","PGDN","BACK","ESCAPE","ENTER","ENTER",
|
|
"PAUSE","SCROLL LK","Kp-0","Kp-1","Kp-2","Kp-3","Kp-4","Kp-5","Kp-6","Kp-7","Kp-8","Kp-9","Kp-*","Kp-/","Kp-+","Kp--","Kp-.",".","=",",","-","OEM_1",
|
|
"OEM_2","OEM_3","OEM_4","OEM_5","OEM_6","OEM_7","OEM_8","CAPS LOCK","END"
|
|
};
|
|
return keyStrings[key];
|
|
}
|
|
|
|
struct Track
|
|
{
|
|
std::vector <std::pair <float, float>> curves; // curves
|
|
std::string name; // names
|
|
int laps; // laps
|
|
};
|
|
|
|
// special track ;)
|
|
Track javidx9 =
|
|
{
|
|
// they'll likely be wonky for the game as it's not really modified to fit my units of
|
|
// these happen to be measured in meters, as per Javid's original construction measure
|
|
{{0.f, 10.f}, {0.f, 200.f}, {1.f, 200.f}, {0.f, 400.f}, {-1.f, 100.f},
|
|
{0.f, 200.f}, {-1.f, 200.f}, {1.f, 200.f}, {0.f, 200.f}, {0.2f, 500.f}, {0.f, 200.f}}, "JAVIDX9", 3
|
|
};
|
|
|
|
// all 9 tracks below are running on yards for their distance units
|
|
// this means the end results are in miles; rather than kilometers
|
|
// enjoy the US measures of Burgers per Freedom Eagle
|
|
//==================================================================================================
|
|
Track circuit =
|
|
{
|
|
// Classic Oval; 1 mile loop, 1,760 yards
|
|
{ {0.f, 10.f}, {0.f, 270.f}, {-1.f, 330.f}, {0.f, 550.f}, {-1.f, 330.f}, {0.f, 270.f} }, "CIRCUIT", 3
|
|
};
|
|
|
|
Track infinity =
|
|
{
|
|
// figure eight
|
|
{{0.f, 10.f}, // flag (straight); this is positioned somewhere after the intersection
|
|
{0.f, 190.f }, {-1.f, 200.f},
|
|
{0.f, 500.f }, // straight; this crosses the first straight, to provide for chances of crashing
|
|
{1.f, 200.f }, {0.f, 300.f }}, "INFINITY", 3
|
|
};
|
|
|
|
Track arrow_head =
|
|
{
|
|
// fancy triangle
|
|
{{0.f, 10.f}, {0.f, 490.f}, {1.f, 130.f}, {0.f, 1000.f}, {1.f, 130.f},
|
|
{0.f, 500.f}, {-1.f, 130.f}, {0.f, 500.f}, {1.f, 130.f}, {0.f, 500.f}}, "ARROW HEAD", 3
|
|
};
|
|
|
|
Track track_4 = // ???
|
|
{
|
|
//{{0.f, 10.f},},
|
|
|
|
// ripped from circuit
|
|
{ {0.f, 10.f}, {0.f, 270.f}, {-1.f, 330.f}, {0.f, 550.f}, {-1.f, 330.f}, {0.f, 270.f} },
|
|
"Track 4", 3
|
|
};
|
|
|
|
Track overpass =
|
|
{
|
|
// kind of a folded figure eight
|
|
//{{0.f, 10.f}, {0.f, 0.f}, {1.f, 0.f}, {0.f, 0.f}, {1.f, 0.f}, {1.f, 0.f}, {0.f, 0.f}, {1.f, 0.f}, {0.f, 0.f}},
|
|
|
|
// ripped from infinity
|
|
{{0.f, 10.f}, {0.f, 190.f }, {-1.f, 200.f}, {0.f, 500.f }, {1.f, 200.f }, {0.f, 300.f }},
|
|
"OVERPASS", 3
|
|
};
|
|
|
|
Track peanut=
|
|
{
|
|
// No more rhymes now. I mean it!
|
|
// Anybody want a peanut?
|
|
// GAH!!!
|
|
//{{0.f, 10.f},},
|
|
|
|
// ripped from arrow head
|
|
{{0.f, 10.f}, {0.f, 490.f}, {1.f, 130.f}, {0.f, 1000.f}, {1.f, 130.f},
|
|
{0.f, 500.f}, {-1.f, 130.f}, {0.f, 500.f}, {1.f, 130.f}, {0.f, 500.f}},
|
|
"PEANUT", 4
|
|
};
|
|
|
|
Track track_7 = // ???
|
|
{
|
|
//{{0.f, 10.f},},
|
|
|
|
// ripped from circuit
|
|
{ {0.f, 10.f}, {0.f, 270.f}, {-1.f, 330.f}, {0.f, 550.f}, {-1.f, 330.f}, {0.f, 270.f} },
|
|
"Track 7", 3
|
|
};
|
|
|
|
Track trident =
|
|
{
|
|
// is your preferred Neptune or Poseidon?
|
|
//{{0.f, 10.f},},
|
|
|
|
// ripped from infinity
|
|
{{0.f, 10.f}, {0.f, 190.f }, {-1.f, 200.f}, {0.f, 500.f }, {1.f, 200.f }, {0.f, 300.f }},
|
|
"TRIDENT", 3
|
|
};
|
|
|
|
Track star =
|
|
{
|
|
// spangled banner; oh say can you see....
|
|
// look, I suck at singing, and not gonna look up the lyrics, just, enjoy American awesomeness
|
|
//{{0.f, 10.f},},
|
|
|
|
// ripped from arrow head
|
|
{{0.f, 10.f}, {0.f, 490.f}, {1.f, 130.f}, {0.f, 1000.f}, {1.f, 130.f},
|
|
{0.f, 500.f}, {-1.f, 130.f}, {0.f, 500.f}, {1.f, 130.f}, {0.f, 500.f}},
|
|
"STAR", 3
|
|
};
|
|
|
|
std::vector <Track> trackList =
|
|
{
|
|
circuit, infinity, arrow_head,
|
|
track_4, overpass, peanut,
|
|
track_7, trident, star,
|
|
javidx9,
|
|
};
|
|
|
|
|
|
//========================================================================================================================================
|
|
// Create Game Objects
|
|
//========================================================================================================================================
|
|
bool OnUserCreate() override
|
|
{
|
|
mainMenu = // show menu options
|
|
{
|
|
{ "START GAME", { ScreenWidth() / 2, ScreenHeight() / 5 * 3} },
|
|
{ "CONTROLS", { ScreenWidth() / 2, ScreenHeight() / 5 * 3 + 64} },
|
|
{ "QUIT", {ScreenWidth() / 2, ScreenHeight() / 5 * 3 + 128 } }
|
|
};
|
|
|
|
playGame =
|
|
{
|
|
{ "TRACK SELECTION", { ScreenWidth() / 2, ScreenHeight() / 4 } },
|
|
{ "GRAND PRIX", { ScreenWidth() / 2, ScreenHeight() / 2 } },
|
|
{ "BACK", { ScreenWidth() / 2, ScreenHeight() / 6 * 5} }
|
|
};
|
|
|
|
pickTrack = // show track options
|
|
{
|
|
{ "CIRCUIT", { ScreenWidth() / 4, ScreenHeight() / 4 } }, { "INFINITY", { ScreenWidth() / 2, ScreenHeight() / 4 } },
|
|
{ "ARROWHEAD", { ScreenWidth() / 4 * 3, ScreenHeight() / 4 } }, { "Track 4", { ScreenWidth() / 4, ScreenHeight() / 2 }},
|
|
{ "OVERPASS", { ScreenWidth() / 2, ScreenHeight() / 2 } }, { "PEANUT", { ScreenWidth() / 4 * 3, ScreenHeight() / 2 } } ,
|
|
{ "Track 7", { ScreenWidth() / 4, ScreenHeight() / 4 * 3 } }, { "TRIDENT", { ScreenWidth() / 2, ScreenHeight() / 4 * 3 } },
|
|
{ "STAR", { ScreenWidth() / 4 * 3, ScreenHeight() / 4 * 3 } }, { "BACK", { ScreenWidth() / 2, ScreenHeight() / 6 * 5} }
|
|
};
|
|
|
|
grandPrix = // show race cups
|
|
{
|
|
{ "INDIE CUP", { ScreenWidth() / 3, ScreenHeight() / 3 } }, { "STREET CUP", { ScreenWidth() / 3 * 2, ScreenHeight() / 3 } },
|
|
{ "PRO CUP", { ScreenWidth() / 3, ScreenHeight() / 3 * 2 } }, { "GRAND PRIX", { ScreenWidth() / 3 * 2, ScreenHeight() / 3 * 2 } },
|
|
{ "BACK", { ScreenWidth() / 2, ScreenHeight() / 6 * 5 } }
|
|
};
|
|
|
|
selectCar = // pick a color
|
|
{
|
|
{ "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 } },
|
|
{ "BACK", { ScreenWidth() / 2, ScreenHeight() / 6 * 5} }
|
|
};
|
|
|
|
controls = // customize controls
|
|
{
|
|
{ "FORWARD", { ScreenWidth() / 3, ScreenHeight() / 9 * 2 }, KeyToString(Move_Up) }, { "BACK", { ScreenWidth() / 3, ScreenHeight() / 9 * 3 }, KeyToString(Move_Down) },
|
|
{ "LEFT", { ScreenWidth() / 3, ScreenHeight() / 9 * 4 }, KeyToString(Move_Left) }, { "RIGHT", { ScreenWidth() / 3, ScreenHeight() / 9 * 5 }, KeyToString(Move_Right) },
|
|
{ "DEFAULT", { ScreenWidth() / 2, ScreenHeight() / 9 * 6} }, { "BACK", { ScreenWidth() / 2, ScreenHeight() / 6 * 5} }
|
|
};
|
|
|
|
pause =
|
|
{
|
|
{ "RESUME", { ScreenWidth() / 2, ScreenHeight() / 9 * 3} }, { "RESTART", { ScreenWidth() / 2, ScreenHeight() / 9 * 4} },
|
|
{ "MENU", { ScreenWidth() / 2, ScreenHeight() / 9 * 5} }, { "QUIT", { ScreenWidth() / 2, ScreenHeight() / 9 * 6} }
|
|
};
|
|
|
|
gameOver =
|
|
{
|
|
{ "MENU", { ScreenWidth() / 2, ScreenHeight() / 9 * 5} }, { "QUIT", { ScreenWidth() / 2, ScreenHeight() / 9 * 6} }
|
|
};
|
|
|
|
//========================================================================================================================================
|
|
// load sprites
|
|
car = new olc::Decal(new olc::Sprite("art/car.png")); // will contain 8 car, with 3 angles per car
|
|
hill = new olc::Decal(new olc::Sprite("art/hills.png"), false, false);
|
|
grass = new olc::Decal(new olc::Sprite("art/grass.png"), false, false);
|
|
road = new olc::Decal(new olc::Sprite("art/road.png"), false, false); // holds both road and flag line
|
|
banner = new olc::Decal(new olc::Sprite("art/start.png"), false, false);
|
|
title = new olc::Decal(new olc::Sprite("art/title.png"));
|
|
cups = new olc::Decal(new olc::Sprite("art/cups.png")); // 64 px tiles; 128 px image
|
|
tracks = new olc::Decal(new olc::Sprite("art/tracks.png")); // 64 px tiles; 192 px image
|
|
select = new olc::Decal(new olc::Sprite("art/f4 racer.png"));
|
|
|
|
// track stuff
|
|
list_times = {}; // this needs modification, as most tracks will likely have 4 laps, some with 3, and some with 5
|
|
gameObjects.push_back({ {-1.5,500}, {10,6}, banner, {0,240} });
|
|
cars.push_back({}); cars.push_back({}); cars.push_back({}); cars.push_back({});
|
|
cars.push_back({}); cars.push_back({}); cars.push_back({}); cars.push_back({});
|
|
|
|
return true;
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// reset game
|
|
//========================================================================================================================================
|
|
|
|
void Reset()
|
|
{
|
|
// car_pos = 0.0f;
|
|
// distance = 0.0f;
|
|
// speed = 0.0f;
|
|
//
|
|
// curvature = 0.0f;
|
|
// track_curve = 0.0f;
|
|
// car_curve = 0.0f;
|
|
// track_dist = 0.0f;
|
|
//
|
|
// cur_lap_time = 0.0f;
|
|
// cur_lap = 0;
|
|
//
|
|
// // Note: the following all need to be reset during the process, when they've been implemented
|
|
// // -all lap times
|
|
// // -score
|
|
// //
|
|
// // if called from other parts of the program, other than the 'F1' key, it should be resetting to the menu
|
|
// // the 'F1' key is meant to reset the player on the current track they're on
|
|
// //
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// curves
|
|
//========================================================================================================================================
|
|
void FindCurves()
|
|
{
|
|
vecTrack.clear();
|
|
for (int i = 0; i < trackList[track].curves.size(); i++)
|
|
{
|
|
vecTrack.push_back(trackList[track].curves[i]);
|
|
track_dist += vecTrack[i].second;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// main menu
|
|
//========================================================================================================================================
|
|
void DisplayMenu(std::vector<MenuItem> list)
|
|
{
|
|
// drawing and coloring menu selections
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
olc::vi2d textSize = GetTextSize(list[i].label) / 2 * 4;
|
|
olc::Pixel textCol = olc::GREY; // greys out unselected options
|
|
if (highlighted == i)
|
|
{
|
|
textCol = olc::Pixel(255, 201, 14); // gold
|
|
}
|
|
|
|
DrawStringDecal(list[i].pos - textSize, list[i].label, textCol, { 4.0f, 4.0f });
|
|
if (list[i].label2.size() > 0)
|
|
{
|
|
olc::vi2d offset = { ScreenWidth() / 3, - textSize.y / 2 };
|
|
DrawStringDecal(list[i].pos + offset, list[i].label2, textCol, { 4.0f, 4.0f });
|
|
}
|
|
}
|
|
|
|
// selecting options
|
|
highlighted = std::clamp(highlighted, 0, (int)list.size() - 1); // loop if out of range
|
|
|
|
int shortest = 9999999;
|
|
int largest = -9999999;
|
|
int targetItem = highlighted;
|
|
|
|
//========================================================================================================================================
|
|
if (GetKey(olc::Key::DOWN).bPressed)
|
|
{
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.x == list[i].pos.x)
|
|
{
|
|
if (list[highlighted].pos.y < list[i].pos.y)
|
|
{
|
|
// it's below us
|
|
int dist = abs(list[highlighted].pos.y - list[i].pos.y);
|
|
|
|
if (dist < shortest)
|
|
{
|
|
targetItem = i;
|
|
shortest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.y < list[i].pos.y)
|
|
{
|
|
// it's above us
|
|
int dist = abs(list[highlighted].pos.y - list[i].pos.y);
|
|
|
|
if (dist < shortest)
|
|
{
|
|
targetItem = i;
|
|
shortest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// it failed, try another method
|
|
if (highlighted == targetItem)
|
|
{
|
|
targetItem = 0;
|
|
}
|
|
highlighted = targetItem;
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
if (GetKey(olc::Key::UP).bPressed)
|
|
{
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.x == list[i].pos.x)
|
|
{
|
|
if (list[highlighted].pos.y > list[i].pos.y)
|
|
{
|
|
// it's above us
|
|
int dist = abs(list[highlighted].pos.y - list[i].pos.y);
|
|
|
|
if (dist < shortest)
|
|
{
|
|
targetItem = i;
|
|
shortest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.y > list[i].pos.y)
|
|
{
|
|
// it's below us
|
|
int dist = abs(list[highlighted].pos.y - list[i].pos.y);
|
|
|
|
if (dist < shortest)
|
|
{
|
|
targetItem = i;
|
|
shortest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// it failed, try another method
|
|
if (highlighted == targetItem)
|
|
{
|
|
targetItem = list.size() - 1;
|
|
}
|
|
highlighted = targetItem;
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
if (GetKey(olc::Key::RIGHT).bPressed)
|
|
{
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.y == list[i].pos.y)
|
|
{
|
|
if (list[highlighted].pos.x < list[i].pos.x)
|
|
{
|
|
// it's to the right
|
|
int dist = abs(list[highlighted].pos.x - list[i].pos.x);
|
|
|
|
if (dist < shortest)
|
|
{
|
|
targetItem = i;
|
|
shortest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (highlighted == targetItem)
|
|
{
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.y == list[i].pos.y)
|
|
{
|
|
if (list[highlighted].pos.x > list[i].pos.x)
|
|
{
|
|
// it's to the left
|
|
int dist = abs(list[highlighted].pos.x - list[i].pos.x);
|
|
|
|
if (dist > largest)
|
|
{
|
|
targetItem = i;
|
|
largest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
highlighted = targetItem;
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
if (GetKey(olc::Key::LEFT).bPressed)
|
|
{
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.y == list[i].pos.y)
|
|
{
|
|
if (list[highlighted].pos.x > list[i].pos.x)
|
|
{
|
|
// it's to the right
|
|
int dist = abs(list[highlighted].pos.x - list[i].pos.x);
|
|
|
|
if (dist < shortest)
|
|
{
|
|
targetItem = i;
|
|
shortest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (highlighted == targetItem)
|
|
{
|
|
for (int i = 0; i < list.size(); i++)
|
|
{
|
|
if (highlighted != i)
|
|
{
|
|
if (list[highlighted].pos.y == list[i].pos.y)
|
|
{
|
|
if (list[highlighted].pos.x < list[i].pos.x)
|
|
{
|
|
// it's to the left
|
|
int dist = abs(list[highlighted].pos.x - list[i].pos.x);
|
|
|
|
if (dist > largest)
|
|
{
|
|
targetItem = i;
|
|
largest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
highlighted = targetItem;
|
|
}
|
|
|
|
//========================================
|
|
if (highlighted >= (int)list.size())
|
|
{
|
|
highlighted = 0; // wrap around when above max
|
|
}
|
|
if (highlighted < 0)
|
|
{
|
|
highlighted = list.size() - 1; // wrap around when below zero
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// controls
|
|
//========================================================================================================================================
|
|
void GetAnyKeyPress(olc::Key keypress) override
|
|
{
|
|
if (configKeyIndex != -1)
|
|
{
|
|
switch (configKeyIndex)
|
|
{
|
|
case 0:
|
|
Move_Up = keypress;
|
|
break;
|
|
case 1:
|
|
Move_Right = keypress;
|
|
break;
|
|
case 2:
|
|
Move_Left = keypress;
|
|
break;
|
|
case 3:
|
|
Move_Down = keypress;
|
|
break;
|
|
}
|
|
controls[configKeyIndex].label2 = KeyToString(keypress);
|
|
configKeyIndex = -1;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// Main Game Function
|
|
//========================================================================================================================================
|
|
bool OnUserUpdate(float fElapsedTime) override
|
|
{
|
|
if (GetKey(olc::Key::CTRL).bHeld && GetKey(olc::Key::F12).bHeld && !bothKeysPressed)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// draw 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 });
|
|
DrawPartialWarpedDecal // draw grass
|
|
(
|
|
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, -cars[0].distance}, {1 * 32, 4 * 64}
|
|
);
|
|
|
|
//========================================================================================================================================
|
|
if (gameState == state::MAIN_MENU)
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 16));
|
|
// display title
|
|
DrawDecal({ 95.5f, 95.5f }, title/*, {0.4f, 0.4f}*/);
|
|
DisplayMenu(mainMenu);
|
|
//DrawStringDecal({ ScreenWidth() / 2 + 0.0f, ScreenHeight() / 2 + 0.0f }, "START GAME", olc::WHITE, { 4.0f, 4.0f });
|
|
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
// vertical menu
|
|
if (highlighted == 0)
|
|
{
|
|
gameState = state::PLAY_GAME;
|
|
highlighted = 0;
|
|
}
|
|
else if (highlighted == 1)
|
|
{
|
|
gameState = state::CONTROLS;
|
|
highlighted = 0;
|
|
}
|
|
else
|
|
{
|
|
return false; // quit game
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed)
|
|
{
|
|
return false; // exit via Escape key
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::PLAY_GAME)
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 16));
|
|
|
|
//for (int i = 0; i < 2; i++)
|
|
//{
|
|
// int image_x = i % 1;
|
|
// int image_y = i / 2;
|
|
// DrawPartialDecal
|
|
// (
|
|
// { ScreenWidth() / 2 * (image_x + 1) - 168.f, ScreenHeight() / 5 * (image_y + 1) - 76.f },
|
|
// select, { image_x * 168.f, image_y * 38.f }, { 168, 76 }, { 2.0f, 2.0f },
|
|
// (highlighted == i) ? olc::WHITE : olc::DARK_GREY
|
|
// );
|
|
//}
|
|
|
|
DisplayMenu(playGame);
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
// vertical menu
|
|
if (highlighted == 0)
|
|
{
|
|
gameState = state::TRACK_SELECT;
|
|
highlighted = 0;
|
|
}
|
|
else if (highlighted == 1)
|
|
{
|
|
gameState = state::CUP_SELECT;
|
|
highlighted = 0;
|
|
}
|
|
else
|
|
{
|
|
gameState = state::MAIN_MENU; // return to menu
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::BACK).bPressed)
|
|
{
|
|
gameState = state::MAIN_MENU;
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::TRACK_SELECT)
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 16));
|
|
|
|
for (int i = 0; i < 9; i++)
|
|
{
|
|
int image_x = i % 3;
|
|
int image_y = i / 3;
|
|
DrawPartialDecal
|
|
(
|
|
{ ScreenWidth() / 4 * (image_x + 1) - 64.f, ScreenHeight() / 4 * (image_y + 1) - 150.f },
|
|
tracks, { image_x * 64.f, image_y * 64.f }, { 64,64 }, { 2.0f, 2.0f },
|
|
(highlighted == i) ? olc::WHITE : olc::DARK_GREY
|
|
);
|
|
}
|
|
|
|
DisplayMenu(pickTrack);
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
if (highlighted >= 0 && highlighted <= 8)
|
|
{
|
|
track = highlighted;
|
|
gameState = state::CAR_SELECT;
|
|
highlighted = 0;
|
|
}
|
|
else
|
|
{
|
|
gameState = state::PLAY_GAME;
|
|
highlighted = 0;
|
|
track = -1;
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::CTRL).bHeld && GetKey(olc::Key::F9).bHeld)
|
|
{
|
|
// cheat code for Javidx9's original track
|
|
track = 0;
|
|
gameState = state::CAR_SELECT;
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::BACK).bPressed)
|
|
{
|
|
gameState = state::PLAY_GAME;
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::CUP_SELECT)
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 16));
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
int image_x = i % 2;
|
|
int image_y = i / 2;
|
|
DrawPartialDecal
|
|
(
|
|
{ ScreenWidth() / 3 * (image_x + 1) - 96.f, ScreenHeight() / 3 * (image_y + 1) - 192.f },
|
|
cups, { image_x * 64.f, image_y * 64.f }, { 64, 64 }, { 3.0f, 3.0f },
|
|
(highlighted == i) ? olc::WHITE : olc::DARK_GREY
|
|
);
|
|
}
|
|
|
|
DisplayMenu(grandPrix);
|
|
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
// 2 x 2 menu
|
|
std::array<state, 4> gameStates = { state::INDIE, state::STREET, state::PRO, state::GRAND_PRIX };
|
|
if (highlighted >= 0 && highlighted <= 3)
|
|
{
|
|
gameState = gameStates[highlighted];
|
|
cup = highlighted;
|
|
gameState = state::CAR_SELECT;
|
|
tracks_left = 2;
|
|
track = highlighted * 3;
|
|
if (highlighted == 3)
|
|
{
|
|
track = 0;
|
|
tracks_left = 8;
|
|
}
|
|
highlighted = 0;
|
|
}
|
|
else
|
|
{
|
|
gameState = state::PLAY_GAME; // return to menu
|
|
cup = -1;
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::CTRL).bHeld && GetKey(olc::Key::F9).bHeld)
|
|
{
|
|
// cheat code for Javidx9 Grand Prix Cup
|
|
// add's Javid's track to the end of the standard Grand Prix
|
|
cup = 0;
|
|
track = 0;
|
|
gameState = state::CAR_SELECT;
|
|
tracks_left = 9;
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::BACK).bPressed)
|
|
{
|
|
gameState = state::PLAY_GAME;
|
|
cup = -1;
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::CAR_SELECT)
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 16));
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
int image_x = i % 4;
|
|
int image_y = i / 4;
|
|
DrawPartialDecal
|
|
(
|
|
{ ScreenWidth() / 5 * (image_x + 1) - 96.f, ScreenHeight() / 3 * (image_y + 1) - 192.f },
|
|
car, { image_x * 256.f, image_y * 192.f }, {256, 192}, {.75f, .75f},
|
|
(highlighted == i) ? olc::WHITE : olc::DARK_GREY
|
|
);
|
|
}
|
|
|
|
DisplayMenu(selectCar);
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
if (highlighted >= 0 && highlighted <= 7)
|
|
{
|
|
player = highlighted;
|
|
int carIndex = 1; // start at 1, as the player's car is index 0
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (i != highlighted)
|
|
{
|
|
cars[carIndex].color = i; // when color is not player selected color, assign it to next AI car
|
|
carIndex++;
|
|
}
|
|
else
|
|
{
|
|
cars[0].color = i; // player chosen color; assigned to player
|
|
}
|
|
}
|
|
gameState = state::RUN_GAME;
|
|
FindCurves();
|
|
}
|
|
else
|
|
{
|
|
if (cup != -1)
|
|
{
|
|
// return to cup select
|
|
gameState = state::CUP_SELECT;
|
|
}
|
|
else
|
|
{
|
|
// return to track select
|
|
gameState = state::TRACK_SELECT;
|
|
}
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::BACK).bPressed)
|
|
{
|
|
if (cup != -1)
|
|
{
|
|
// return to cup select
|
|
gameState = state::CUP_SELECT;
|
|
}
|
|
else
|
|
{
|
|
// return to track select
|
|
gameState = state::TRACK_SELECT;
|
|
}
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::CONTROLS)
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 16));
|
|
DisplayMenu(controls);
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
if (highlighted >= 0 && highlighted <= 3)
|
|
{
|
|
configKeyIndex = highlighted;
|
|
}
|
|
else if (highlighted == 4)
|
|
{
|
|
// reset default controls
|
|
DisplayMenu(controls);
|
|
Move_Up = olc::W;
|
|
Move_Down = olc::S;
|
|
Move_Left = olc::A;
|
|
Move_Right = olc::D;
|
|
|
|
}
|
|
else
|
|
{
|
|
gameState = state::MAIN_MENU;
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::BACK).bPressed)
|
|
{
|
|
gameState = state::MAIN_MENU;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::PAUSED) // pause menu
|
|
{
|
|
FillRectDecal({ 0, 0 }, { ScreenWidth() + 0.f, ScreenHeight() + 0.f }, olc::Pixel(0, 0, 0, 64));
|
|
DisplayMenu(pause);
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
if (highlighted == 0)
|
|
{
|
|
gameState = state::RUN_GAME;
|
|
highlighted = 0;
|
|
}
|
|
if (highlighted == 1)
|
|
{
|
|
// restart the track
|
|
// this will ONLY work on tracks after the track selection screen
|
|
// or on the first track in each cup (1, 4, 7, 1)
|
|
Reset();
|
|
gameState = state::RUN_GAME;
|
|
highlighted = 0;
|
|
}
|
|
if (highlighted == 2)
|
|
{
|
|
// main menu
|
|
Reset();
|
|
gameState = state::MAIN_MENU;
|
|
highlighted = 0;
|
|
}
|
|
if (highlighted == 3)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::PAUSE).bPressed)
|
|
{
|
|
gameState = state::RUN_GAME;
|
|
highlighted = 0;
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
else if (gameState == state::END_GAME)
|
|
{
|
|
// alter this code so as to implement an END TRACK and END CUP state
|
|
// according to Sigonasr, booleans should be used and set/unset appropriately to pull it off
|
|
DrawStringDecal({ ScreenWidth() / 3 + 0.f, ScreenHeight() / 3 + 0.f }, "RACE COMPLETE!", olc::WHITE, { 4.f, 4.f });
|
|
DisplayMenu(gameOver);
|
|
if (GetKey(olc::Key::ENTER).bPressed || GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
if (highlighted == 0)
|
|
{
|
|
// main menu
|
|
Reset();
|
|
gameState = state::MAIN_MENU;
|
|
highlighted = 0;
|
|
}
|
|
if (highlighted == 1)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// at the end of a single track, a list of all times should be shown, along with positions
|
|
// the player's should be highlighted, to stick out from the AI times; this will likely be White, with AI being Grey
|
|
// based on position at the end of the race, one of 3 trophies should be thrown onto the screen (if in 1, 2, or 3); and nothing if 4+
|
|
// however, these should *only* show up under the single track races
|
|
|
|
// under the cup races, as players complete each track, it should *NOT* show the trophies upon completing each track, regardless of place
|
|
// at the end of the cup, it should throw up the cup appropriate to the race; indie = bronze, street = silver, pro = gold, grand prix = platinum
|
|
// this should happen for first place winners
|
|
// will need to work out something for 2nd and 3rd for the Indie and Street cups
|
|
// points will be counted up, based on position per track; this determines final cup winner
|
|
// if perfect on grand prix, players will get platinum cup, otherwise, they'll get a gold cup
|
|
// these cup options, may very well change where 1st is gold, 2nd is silver, 3rd is bronze, and perfect is platinum, regardless of the cup
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
//========================================================================================================================================
|
|
else if (gameState == state::RUN_GAME) // run main game loop
|
|
{
|
|
Clear(olc::BLACK); // this still needed? we've since replaced it with the gradient sky box
|
|
int sec = (int)cur_lap_time % 60;
|
|
|
|
olc::vf2d center = { (float)ScreenWidth() / 2, 32 };
|
|
olc::vf2d textSize = GetTextSize(trackList[track].name) * 4;
|
|
if (sec < 3 && cars[0].cur_lap < 1)
|
|
{
|
|
DrawStringDecal(center - textSize / 2, trackList[track].name, olc::WHITE, { 4.f, 4.f });
|
|
}
|
|
else
|
|
{
|
|
DrawStringDecal(center - textSize / 2, trackList[track].name, olc::Pixel(0, 0, 0, 96), { 4.f, 4.f });
|
|
}
|
|
|
|
DrawStringDecal({0,32},std::to_string(cars[0].distance));
|
|
|
|
if (GetKey(olc::Key::ESCAPE).bPressed || GetKey(olc::Key::PAUSE).bPressed)
|
|
{
|
|
gameState = state::PAUSED;
|
|
highlighted = 0;
|
|
}
|
|
|
|
// debug quick-reset
|
|
if (GetKey(olc::Key::F4).bPressed)
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
// jump to end of lap
|
|
if (GetKey(olc::Key::F12).bPressed)
|
|
{
|
|
cars[0].distance = track_dist - 50.f;
|
|
}
|
|
|
|
for (Object& obj : gameObjects)
|
|
{
|
|
obj.rendered=false;
|
|
}
|
|
//========================================================================================================================================
|
|
// | | player location on track
|
|
//========================================================================================================================================
|
|
// get a point on the track
|
|
float offset = 0;
|
|
int TrackSection = 0;
|
|
|
|
cur_lap_time += fElapsedTime;
|
|
|
|
// find position on track (could optimize) << should probably optimize given the complexity of this game
|
|
while (TrackSection < vecTrack.size() && offset <= cars[0].distance)
|
|
{
|
|
offset += vecTrack[TrackSection].second;
|
|
TrackSection++;
|
|
}
|
|
|
|
float TargetCurvature = vecTrack[TrackSection - 1].first; // drawing curves to screen
|
|
|
|
float TrackCurveDiff = (TargetCurvature - curvature) * fElapsedTime * cars[0].speed; // correcting the drawing of curves to the screen
|
|
curvature += TrackCurveDiff; // update track curve difference
|
|
|
|
track_curve += (curvature)*fElapsedTime * cars[0].speed;
|
|
|
|
//========================================================================================================================================
|
|
// | | draw racetrack canvas
|
|
//========================================================================================================================================
|
|
|
|
std::vector<olc::vf2d> pos;
|
|
std::vector<olc::vf2d> uvs;
|
|
for (int y = 0; y < ScreenHeight() / 2; y++)
|
|
{
|
|
// racetrack 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;
|
|
|
|
float horizon = powf(1.0f - perspective, 2) * 80;
|
|
|
|
// check for finish line
|
|
if (cars[0].distance + horizon > track_dist - 20 && cars[0].distance + horizon < track_dist)
|
|
{
|
|
// draw checkerboard pattern
|
|
uvs.push_back({ 0, (float)fmod(((cars[0].distance + horizon) - (track_dist - 20)) / 20.0f, 0.5f) + 0.5f });
|
|
uvs.push_back({ 1, (float)fmod(((cars[0].distance + horizon) - (track_dist - 20)) / 20.0f, 0.5f) + 0.5f });
|
|
}
|
|
else
|
|
{
|
|
// draw standard track piece
|
|
uvs.push_back({ 0, sinf(80.0f * powf(1.0f - perspective, 2) + cars[0].distance) / 4 + 0.25f });
|
|
uvs.push_back({ 1, sinf(80.0f * powf(1.0f - perspective, 2) + cars[0].distance) / 4 + 0.25f });
|
|
}
|
|
|
|
// drawing grass and curb
|
|
pos.push_back({ lf_curb + 0.0f, row + 0.0f });
|
|
pos.push_back({ rt_curb + 0.0f, row + 0.0f });
|
|
|
|
// black box rendering shenanigans; if I ever understand programming enough at a later date, I can figure out wtf is going on here
|
|
// render distant objects via perspective
|
|
int i = 0;
|
|
for (Object& obj : gameObjects)
|
|
{
|
|
float horizonRange = powf(1.0f - perspective, 2) * ((cars[0].distance + horizon) - obj.pos.y) / horizon;
|
|
if (!obj.rendered && (cars[0].distance + horizon) > obj.pos.y && (cars[0].distance + horizon) < obj.pos.y + 80 && row >= ScreenHeight() / 2 + ScreenHeight() / 2 * horizonRange)
|
|
{
|
|
obj.drawPos = { (mid_point + road_width * obj.pos.x) * ScreenWidth(), horizonRange * (ScreenHeight() / 2) + ScreenHeight() / 2 };
|
|
obj.drawOffsetPos = { obj.offset.x, obj.size.y * road_width * -obj.offset.y };
|
|
obj.drawSize = { obj.size.x * road_width, obj.size.y * road_width };
|
|
obj.rendered = true;
|
|
// yeah.... so, even after copying it manually, i still have no clue what this thing is doing, lol
|
|
}
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// on the road again; drawing the track
|
|
SetDecalStructure(olc::DecalStructure::STRIP);
|
|
DrawPolygonDecal(road, pos, uvs);
|
|
SetDecalStructure(olc::DecalStructure::FAN);
|
|
|
|
// draw trackside props
|
|
for (Object& obj : gameObjects)
|
|
{
|
|
if (obj.rendered)
|
|
{
|
|
if (obj.decal != nullptr)
|
|
{
|
|
DrawDecal(obj.drawPos + obj.drawOffsetPos, obj.decal, obj.drawSize);
|
|
}
|
|
else
|
|
{
|
|
FillRectDecal(obj.drawPos, obj.drawSize, olc::BLUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// | | car movement
|
|
//========================================================================================================================================
|
|
int car_dir = 0; // default car facing
|
|
|
|
if (GetKey(Move_Up).bHeld)
|
|
{
|
|
cars[0].speed += 2.0f * fElapsedTime;
|
|
}
|
|
else // might remove this in a later stage of development
|
|
{
|
|
cars[0].speed -= 1.0f * fElapsedTime;
|
|
}
|
|
if (GetKey(Move_Down).bHeld)
|
|
{
|
|
// move back ?
|
|
cars[0].distance -= 20.0f * fElapsedTime;
|
|
}
|
|
if (GetKey(Move_Left).bHeld)
|
|
{
|
|
car_curve -= 0.7f * fElapsedTime;
|
|
car_dir = -1;
|
|
}
|
|
if (GetKey(Move_Right).bHeld)
|
|
{
|
|
car_curve += 0.7f * fElapsedTime;
|
|
car_dir = +1;
|
|
}
|
|
|
|
// slow car if on grass
|
|
if (fabs(car_curve - track_curve) >= 0.8f)
|
|
{
|
|
cars[0].speed -= 5.0f * fElapsedTime;
|
|
}
|
|
|
|
// clamp speed
|
|
if (cars[0].speed < 0.0f) cars[0].speed = 0.0f;
|
|
if (cars[0].speed > 1.0f) cars[0].speed = 1.0f;
|
|
|
|
// move car along track according to car speed
|
|
cars[0].distance += (70.0f * cars[0].speed) * fElapsedTime;
|
|
|
|
//// super cheap AI movement; just pushes cars along the track currently
|
|
//for (int i = 1; i < 8; i++)
|
|
//{
|
|
// cars[i].distance += cars[i].speed;
|
|
//}
|
|
//
|
|
//// sort car distance and laps
|
|
//std::sort(cars.begin(), cars.end(), [&](auto& car1, auto& car2)
|
|
// {
|
|
// return car1.distance > car2.distance;
|
|
// });
|
|
|
|
cars[0].car_pos = car_curve - track_curve;
|
|
|
|
// draw car
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
int image_x = cars[i].color % 4;
|
|
int image_y = cars[i].color / 4;
|
|
DrawPartialDecal({ ScreenWidth() / 2 - 128.f + cars[i].car_pos * ScreenWidth() / 2, ScreenHeight() / 4 * 3.0f - 128.f }, car, { image_x * 256.f, image_y * 192.f }, { 256, 192 }, { 1, 1 }, olc::WHITE);
|
|
SetPixelMode(olc::Pixel::ALPHA);
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// | | track lap times
|
|
//========================================================================================================================================
|
|
|
|
// crossing the finish line
|
|
if (cars[0].distance >= track_dist)
|
|
{
|
|
// record lap time
|
|
cars[0].distance -= track_dist;
|
|
list_times.push_back(cur_lap_time); // pop time to back
|
|
cur_lap_time = 0.f;
|
|
cars[0].cur_lap++;
|
|
|
|
if (tracks_left == 0 && cars[0].cur_lap >= trackList[track].laps)
|
|
{
|
|
gameState = state::END_GAME;
|
|
}
|
|
else if (cup >= 0 && cars[0].cur_lap >= trackList[track].laps)
|
|
{
|
|
Reset();
|
|
FindCurves();
|
|
track++;
|
|
tracks_left--;
|
|
}
|
|
}
|
|
|
|
// draw lap counter
|
|
DrawStringDecal({ 10.f, 16 }, std::to_string(cars[0].cur_lap + 1) + "/" + std::to_string(trackList[track].laps), olc::WHITE, {3.f, 3.f});
|
|
|
|
// draw place counter
|
|
DrawStringDecal({ ScreenWidth() - 90.f, 16 }, std::to_string(cur_place) + "/" + std::to_string(total_place), olc::WHITE, {3.f, 3.f});
|
|
|
|
// show time
|
|
std::string disp_time;
|
|
int min = (int)cur_lap_time / 60;
|
|
// int sec; is found at beginning of 'RUN_GAME' state
|
|
int milli = (int)( (cur_lap_time - (int)cur_lap_time) * 1000 );
|
|
|
|
if (min < 10)
|
|
{
|
|
disp_time += "0";
|
|
}
|
|
disp_time += std::to_string(min);
|
|
disp_time += ":";
|
|
if (sec < 10)
|
|
{
|
|
disp_time += "0";
|
|
}
|
|
disp_time += std::to_string(sec);
|
|
disp_time += ".";
|
|
if (milli < 10)
|
|
{
|
|
disp_time += "0";
|
|
}
|
|
if (milli < 100)
|
|
{
|
|
disp_time += "0";
|
|
}
|
|
disp_time += std::to_string(milli);
|
|
|
|
DrawStringDecal({ 100, 16 }, disp_time, olc::WHITE, { 1.5f, 1.5f });
|
|
|
|
// display lap times
|
|
float j = 30;
|
|
for (auto l : list_times)
|
|
{
|
|
//DrawStringDecal({ 10, j }, disp_time(l));
|
|
j += 10;
|
|
}
|
|
//------------------------------
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//========================================================================================================================================
|
|
int main()
|
|
{
|
|
Racer game;
|
|
if (game.Construct(1280, 720, 1, 1))
|
|
game.Start();
|
|
|
|
return 0;
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// END OF FILE
|
|
//========================================================================================================================================
|