@ -1,183 +1,26 @@
//--------------------------------------------------------------------------------------------------
// 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
# include "pixelGameEngine.h"
//--------------------------------------------------------------------------------------------------
// class
//--------------------------------------------------------------------------------------------------
class Racer : public olc : : PixelGameEngine
class PressDetect : public olc : : PixelGameEngine
{
public :
Racer ( )
PressDetect ( )
{
sAppName = " F4 Racing " ;
sAppName = " Double Press Down Detect " ;
}
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 < std : : pair < float , float > > vecTrack ;
std : : list < float > list_times ;
bool bothKeysPressed = false ;
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 < MenuItem > mainMenu ;
std : : vector < MenuItem > playGame ;
std : : vector < MenuItem > pickTrack ;
std : : vector < MenuItem > grandPrix ;
std : : vector < MenuItem > selectCar ;
std : : vector < MenuItem > controls ;
std : : vector < std : : string > gameOver ;
std : : vector < Object > 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 ;
}
@ -186,218 +29,31 @@ public:
//--------------------------------------------------------------------------------------------------
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 < olc : : vf2d > pos ;
std : : vector < olc : : vf2d > 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 + horizonDistance < track_dist ) {
uv . push_back ( { 0 , fmod ( ( ( distance + horizonDistance ) - ( track_dist - 20 ) ) / 20.0F , 0.5 ) + 0.5 } ) ;
uv . push_back ( { 1 , fmod ( ( ( distance + horizonDistance ) - ( track_dist - 20 ) ) / 20.0F , 0.5 ) + 0.5 } ) ;
} else {
uv . push_back ( { 0 , sinf ( 80.0f * powf ( 1.0f - perspective , 2 ) + distance ) / 4 + 0.25 } ) ;
uv . push_back ( { 1 , sinf ( 80.0f * powf ( 1.0f - perspective , 2 ) + distance ) / 4 + 0.25 } ) ;
}
int i = 0 ;
for ( Object & obj : gameObjects ) {
float perspectiveRange = powf ( 1.0f - perspective , 2 ) * ( ( distance + 80 ) - obj . pos . y ) / 80 ;
if ( ! obj . rendered & & ( distance + horizonDistance ) > obj . pos . y & & ( distance + horizonDistance ) < obj . pos . y + 80 & & row > = ScreenHeight ( ) / 2 + ScreenHeight ( ) / 2 * perspectiveRange ) {
std : : cout < < " : " < < powf ( 1.0f - perspective , 2 ) < < " , " < < ( distance + 80 ) < < " , " < < obj . pos . y < < " , " < < row < < " , " < < ScreenHeight ( ) / 2 + ScreenHeight ( ) / 2 * perspectiveRange < < " \n " ;
float horizonRange = powf ( 1.0f - perspective , 2 ) * ( ( distance + horizonDistance ) - obj . pos . y ) / horizonDistance ;
obj . drawPos = { mid_point * ScreenWidth ( ) , horizonRange * ( ScreenHeight ( ) / 2 ) + ScreenHeight ( ) / 2 } ;
std : : cout < < obj . pos . y < < " / " < < ( distance + horizonDistance ) < < " \n " ;
obj . drawSize = { 64 * perspectiveRange , 64 * perspectiveRange } ;
obj . rendered = true ;
}
}
//olc::Pixel road_col = (TrackSection - 1) == 0 ? olc::GREY : olc::DARK_GREY; // checkerboard line
}
SetDecalStructure ( olc : : DecalStructure : : STRIP ) ;
DrawPolygonDecal ( road , pos , uv ) ;
SetDecalStructure ( olc : : DecalStructure : : FAN ) ;
for ( Object & obj : gameObjects ) {
if ( obj . rendered ) {
FillRectDecal ( obj . drawPos , obj . drawSize , olc : : BLUE ) ;
}
}
//----------------------------------------
// move forward
if ( GetKey ( olc : : Key : : W ) . bHeld | | GetKey ( olc : : Key : : UP ) . bHeld )
{
speed + = 2.0f * fElapsedTime ;
}
else // might remove this in a later stage of development
{
speed - = 1.0f * fElapsedTime ;
}
// move back ?
if ( GetKey ( olc : : Key : : S ) . bHeld | | GetKey ( olc : : Key : : DOWN ) . bHeld )
{
distance - = 10.0f * fElapsedTime ;
if ( GetKey ( olc : : SHIFT ) . bHeld & & GetKey ( olc : : A ) . bHeld & & ! bothKeysPressed ) {
bothKeysPressed = true ;
std : : cout < < " Both Keys pressed \n " ;
}
int car_dir = 0 ;
// move left
if ( GetKey ( olc : : Key : : A ) . bHeld | | GetKey ( olc : : Key : : LEFT ) . bHeld )
{
car_curve - = 0.7f * fElapsedTime ;
car_dir = - 1 ;
}
// move right
if ( GetKey ( olc : : Key : : D ) . bHeld | | GetKey ( olc : : Key : : RIGHT ) . bHeld )
{
car_curve + = 0.7f * fElapsedTime ;
car_dir = + 1 ;
if ( bothKeysPressed & & ( GetKey ( olc : : SHIFT ) . bReleased | | GetKey ( olc : : A ) . bReleased ) ) {
bothKeysPressed = false ;
std : : cout < < " Both Keys released \n " ;
}
// slow car if on grass
if ( fabs ( car_curve - track_curve ) > = 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);
Clear ( olc : : VERY_DARK_BLUE ) ;
DrawRect ( { 32 , 32 } , { 32 , 32 } , ( bothKeysPressed ) ? olc : : YELLOW : olc : : BLACK ) ;
return true ;
}
} ;
//--------------------------------------------------------------------------------------------------
int main ( )
{
std : : cout < < ( - 265 % 50 ) < < " \n " ;
std : : cout < < ( - 26 % 50 ) < < " \n " ;
Racer game ;
if ( game . Construct ( 1280 , 720 , 1 , 1 ) )
PressDetect game ;
if ( game . Construct ( 256 , 240 , 4 , 4 ) )
game . Start ( ) ;
return 0 ;
}
//--------------------------------------------------------------------------------------------------
// END OF FILE
//--------------------------------------------------------------------------------------------------