//========================================================================================================================================
// 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
//========================================================================================================================================