#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "random.h" using namespace std; //loads a bitmap from file and converts it to screen properties SDL_Surface* loadBMP(std::string filename) { SDL_Surface* loadedImage = NULL; SDL_Surface* convertedImage = NULL; loadedImage = IMG_Load(filename.c_str()); if(loadedImage != NULL) { convertedImage = SDL_DisplayFormat(loadedImage); if(convertedImage) { Uint32 colorkey = SDL_MapRGB(convertedImage->format, 10, 10, 10); SDL_SetColorKey(convertedImage, SDL_SRCCOLORKEY, colorkey); SDL_FreeSurface(loadedImage); return convertedImage; } cout << "Error: Could not convert Image" << filename << '.' << endl; } cout << "Error: Could not load bitmap from file " << filename << endl; return NULL; } string lltostr(const long long& l) { stringstream str; str << l; return str.str(); } class Label { protected: string caption; SDL_Surface* image; // int textSize; SDL_Color textColor; int render(); public: SDL_Rect pos; Label(); Label(string ncaption, SDL_Rect& npos); ~Label(); void draw(SDL_Surface* screen); int setTextSize(int ntextSize); void setTextColor(SDL_Color textColor); int setCaption(string ncaption); }; Label::Label() { pos.x = 0; pos.y = 0; pos.w = 0; pos.h = 14; caption = ""; textColor.r = 255; textColor.g = 255; textColor.b = 255; render(); } Label::Label(string ncaption, SDL_Rect& npos) { pos = npos; textColor.r = 255; textColor.g = 255; textColor.b = 255; caption = ncaption; npos.w = render(); } int Label::setTextSize(int ntextSize) { pos.h = ntextSize; SDL_FreeSurface(image); return render(); } void Label::setTextColor(SDL_Color ntextColor) { textColor = ntextColor; SDL_FreeSurface(image); render(); } int Label::setCaption(string ncaption) { if(caption == ncaption) return pos.w; caption = ncaption; SDL_FreeSurface(image); return render(); } int Label::render() { TTF_Font *font = TTF_OpenFont("fonts/OpenSans-Semibold.ttf",pos.h); image = NULL; image = TTF_RenderText_Solid(font, caption.c_str(),textColor); if(caption.size() == 0) cout << "empty caption!!!" << endl; if(image == NULL) { cout << "Error rendering Label with caption " << caption << endl; return 0; } TTF_CloseFont(font); pos.w = image->w; return image->w; } void Label::draw(SDL_Surface* screen) { SDL_Rect temp = pos; SDL_BlitSurface(image, NULL, screen, &temp); } Label::~Label() { SDL_FreeSurface(image); } int xres = 600; int yres = 450; SDL_Surface *screen; bool inBounds(int x, int y) { if(x >= 0 && x < xres && y >= 0 && y < yres) return true; return false; } void drawPixel(SDL_Surface *screen,int x, int y, Uint8 R, Uint8 G, Uint8 B) { Uint32 color = SDL_MapRGB(screen->format, R, G, B); SDL_Rect r; r.x = x; r.y = y; r.w = 1; r.h = 1; SDL_FillRect(screen,&r,color); } SDL_Surface* preBall; void drawCircle(SDL_Surface* screen, double x, double y, double angle, double radius, Uint8 R, Uint8 G, Uint8 B) { int tempseed = rand(); srand(87); Uint32 colorkey = SDL_MapRGB(preBall->format, 10, 10, 10); SDL_FillRect(preBall,NULL,colorkey); for(int i = 0; i <= 2*radius; ++i) for(int j = 0; j <= 2*radius; ++j) if(((i-radius+0.5)*(i-radius+0.5)+(j-radius+0.5)*(j-radius+0.5) <= radius*radius)) { int texturkonstante = 60; int alt1 = rand()%texturkonstante-texturkonstante/2; int alt2 = rand()%texturkonstante-texturkonstante/2; int alt3 = rand()%texturkonstante-texturkonstante/2; drawPixel(preBall, i,j,R+alt1,G+alt2,B+alt3); } SDL_Rect drawpos; SDL_Surface* temp = preBall; temp = rotozoomSurface(temp,angle/M_PI*180,1,0); drawpos.x = x-temp->w/2; drawpos.y = y - temp->h/2; SDL_BlitSurface(temp,NULL,screen,&drawpos); SDL_FreeSurface(temp); srand(tempseed); } void blacken(SDL_Surface* screen) { SDL_FillRect(screen,NULL,0); } Uint8 playerR = 100; Uint8 playerG = 100; Uint8 playerB = 100; Uint8 obstacleR = 255; Uint8 obstacleG = 100; Uint8 obstacleB = 100; class Obstacle { public: SDL_Rect r; int vx; Obstacle(double xn, double yn, double width, double height) { r.x = xn; r.y = yn; r.h = height; r.w = width; vx = 0; } bool check_death(double x_pos, double y_pos, double radius) { if(x_pos + radius < r.x || x_pos - radius > r.x + r.w || y_pos + radius < r.y || y_pos - radius > r.y + r.h) return false; return true; } void draw(SDL_Surface* screen,double levelx, double levely) { SDL_Rect temp = r; temp.x -= levelx; temp.y -= levely; temp.y = yres - temp.y- temp.h; SDL_FillRect(screen, &temp, SDL_MapRGB(screen->format, obstacleR, obstacleG, obstacleB)); } void step(double time) { r.x += time*vx; } }; class Particle { public: double x; double y; double vx; double vy; double life; // 0 = static, 1 = strife, 2 = randomwalk, 3 = xrandomwalk int mode; Uint8 R,G,B; Particle() { x = rand()%xres; y = rand()%yres; life = rand()%20; R = rand()%256; G = rand()%256; B = rand()%256; } Particle(double xn, double yn, int nmode, Uint8 Rn, Uint8 Gn, Uint8 Bn) { mode = nmode; x = xn; y = yn; R = Rn; G = Gn; B = Bn; life = rand()%20; } void draw(SDL_Surface* screen,double levelx,double levely) { if(inBounds(x-levelx,y-levely)) drawPixel(screen, x-levelx, yres- (y-levely), R, G, B); } bool step(double time) { life -= time; // 0 = static, 1 = strife, 2 = randomwalk, 3 = xrandomwalk if(mode == 1){ x += vx*time; y += vy*time; } else if(mode == 2) { x += (rand()%3-1)/2.0; y += (rand()%3-1)/2.0; } else if(mode == 3) { x += (rand()%3-1)/8.0; y += vy*time; } return (life >= 0); } }; vector makeDeathAnimation(double x, double y, double r, double vxb, double vyb, int mode) { vector result; for(int i = 0; i < 2000; ++i) { double tx = rand()%((int) (2*r+1))-r; double ty = rand()%((int) (2*r+1))-r; if(tx*tx + ty * ty > r*r) continue; tx += x; ty += y; Particle temp = Particle(tx, ty, 1, playerR, playerG, playerB); double vb = (rand()%5000)/30.0; double vp = ((rand()%10000)/10000.0)*2*M_PI; if(!mode) { temp.vx = cos(vp)*vb+vxb; temp.vy = sin(vp)*vb+vyb; } else { temp.vx = cos(vp)*vb+vxb*(rand()%1000)/1000.0; temp.vy = sin(vp)*vb+vyb*(rand()%1000)/1000.0; } temp.life = (rand()%100)/50.0; result.push_back(temp); } return result; } double x_pos = 0; double x_vel = 0; double phi = 0; double vphi = 0; double ground_level = 20; double y_vel = 0; double ball_rad = 8; double y_pos = ground_level + ball_rad; double g = 300.0; double c_r = 0.004; double highscore = 1000; double position_multiplier = 3; double win_bonus = 5000; bool hardcore = false; void loadConstants() { ifstream ins; ins.open("settings.dat"); int i = 0; ins >> i; playerR = i; ins >> i; playerG = i; ins >> i; playerB = i; ins >> i; obstacleR = i; ins >> i; obstacleG = i; ins >> i; obstacleB = i; ins.close(); } int main() { loadConstants(); string name; cout << "This is a simple jump and run" << endl; cout << "Please enter your name:"; cin >> name; cout << "Please enter difficulty (0-100):"; int difficulty; cin >> difficulty; cout << "Do you want to play in hardcore mode(0/1)?"; cin >> hardcore; if(hardcore) { highscore *= 1.5; cout << "You are insane. +50% score!" << endl; } else cout << "Very sane decision..." << endl; if(difficulty >= 0) cout << "solvability not guarenteed! Have fun!" << endl; if(difficulty < 0) cout << "This should be a piece of cake and you should feel bad!" << endl; difficulty = max(-50,difficulty); if(difficulty > 100) difficulty = 100; bool wantEnd = false; cout << "difficulty = " << difficulty << endl; if(SDL_Init(SDL_INIT_VIDEO) == -1) { cout << "Error: Could not initialize SDL" << endl; return 1; } screen = SDL_SetVideoMode(xres,yres,32,SDL_SWSURFACE); if(!screen) { cout << "could not initialize screen" << endl; return 1; } if(TTF_Init() == -1) { cout << "could not initialize True Fonts" << endl; return 1; } SDL_WM_SetCaption("Ballroller - v0.3", NULL); while(!wantEnd) { //SEED srandn(2334508 + difficulty); srand(2334508 + difficulty); highscore = 1000; position_multiplier = 3; x_pos = 0; y_pos = 0; y_vel = 0; x_vel = 0; position_multiplier += difficulty/40.0; preBall = loadBMP("blank.bmp"); bool Game_Quit = false; int down = 0; int right = 0; vector obstacles; obstacles.push_back(Obstacle(-50,ground_level,10,200)); vector particles; bool quickquit = false; for(int i = 0; i < 10*60*5; ++i) { Particle p = Particle(rand()%11000 - 300,ground_level + rand()%((int)(yres-ground_level)),3,255,255,255); p.life = 1000; p.vy = -5-rand()%30/9.0; particles.push_back(p); } //Longest Jump: 608 //Highest Jump: 150 int opos = 200; while(opos < 10000) { int blub = 4+randn()%(192+difficulty/4-4); obstacles.push_back(Obstacle(opos,ground_level,blub,(196 + difficulty/4)/2-blub/2)); opos += randn()%(900-4*difficulty); } if(hardcore) for(int i = 1; i < 110; ++i) { Obstacle tempo = Obstacle(i*300,ground_level, 10, 10); tempo.vx = -60; obstacles.push_back(tempo); } vector deathanimation; bool lost = false; long long steps = 0; SDL_Rect lpos; lpos.x = 300; lpos.y = 10; lpos.w = 300; lpos.h = 20; Label scoreLabel = Label("Score: " + lltostr((long long)((1+0.5*hardcore)*(highscore + x_pos*position_multiplier))), lpos); double maxjumpx = 0; double maxjumpy = 0; double lastjumppos = 0; while(!Game_Quit) { steps++; Uint32 start = SDL_GetTicks(); if(!lost) highscore--; blacken(screen); SDL_Event event; while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) { Game_Quit = true; quickquit = true; wantEnd = true; break; } } Uint8 *keyState = SDL_GetKeyState(NULL); down = -keyState[SDLK_UP]+keyState[SDLK_DOWN]; vector nparticles; for(int i = 0; i < (int) particles.size(); ++i) { if(particles[i].step(1/60.0) && particles[i].y > ground_level) { particles[i].draw(screen,x_pos-xres/4,0); nparticles.push_back(particles[i]); } } if(!(steps%300) && hardcore) { Obstacle tempo = Obstacle(110*100,ground_level, 10, 10); tempo.vx = -60; obstacles.push_back(tempo); } for(int i = 0; i < (int) obstacles.size(); ++i) { obstacles[i].step(1/60.0); obstacles[i].draw(screen,x_pos-xres/4,0); if(!lost) if(obstacles[i].check_death(x_pos,y_pos,ball_rad)) { cout << "Collision: You lost the game" << endl; cout << "Better luck next time!" << endl; highscore = (int)((1+0.5*hardcore)*(highscore + x_pos*position_multiplier)); scoreLabel.setCaption("Score: " + lltostr(highscore)); cout << "Your highscore: " << highscore << endl; lost = true; deathanimation = makeDeathAnimation(x_pos,y_pos,ball_rad,x_vel, y_vel,1); } } particles = nparticles; for(int i = 0; i < 1; ++i) { Particle p = Particle(-300 + rand()%11001,yres,3,255,255,255); p.vy = -5-rand()%30/9.0; p.life = 1000; particles.push_back(p); } if(!lost) { x_pos = x_pos + x_vel/60.0; y_pos = y_pos + y_vel/60.0; phi = phi + vphi/60.0; drawCircle(screen, xres/4, fabs(yres-y_pos), phi, ball_rad, playerR, playerG, playerB); scoreLabel.setCaption("Score: " + lltostr((long long)((1+0.5*hardcore)*(highscore + x_pos*position_multiplier)))); } right = -keyState[SDLK_LEFT]+keyState[SDLK_RIGHT]; if(!right) { right = -keyState[SDLK_LEFT]+keyState[SDLK_RIGHT]; } if(y_pos > ground_level+ball_rad) { y_vel = y_vel*(1.0-c_r) - g/60.0; x_vel = x_vel*(1.0-c_r) + right*80/60.0; maxjumpy = max(maxjumpy,y_pos); } if(y_pos <= ground_level+ball_rad) { maxjumpx = max(maxjumpx,x_pos-lastjumppos); lastjumppos = x_pos; x_vel = x_vel*(1.0-c_r) + right*140./60.0; y_pos = ground_level+ball_rad; y_vel = fabs(y_vel); if(down == -1) y_vel += 900; y_vel *= 0.25; vphi = -x_vel/ball_rad; } if(!lost) if(highscore+x_pos*position_multiplier <= 0) { cout << "TIMEOUT: You lost the game." << endl; cout << "Better luck next time!" << endl; quickquit = true; Game_Quit = true; deathanimation = makeDeathAnimation(x_pos,y_pos,ball_rad,x_vel, y_vel,0); } if(x_pos >= 10000) { cout << "You win the game!" << endl; highscore = (int)((1+0.5*hardcore)*(highscore + x_pos*position_multiplier + win_bonus)); cout << "Your highscore: " << highscore << endl; scoreLabel.setCaption("Score: " + lltostr(highscore)); Game_Quit = true; } for(int i = 0; i < xres; ++i) drawPixel(screen,i,yres-ground_level,255,255,255); bool animation_term = true; for(int i = 0; i < (int) deathanimation.size(); ++i) { if(deathanimation[i].step(1/60.0)) { animation_term = false; deathanimation[i].draw(screen,x_pos-xres/4,0); } } if(animation_term && lost) Game_Quit = true; scoreLabel.draw(screen); SDL_Flip(screen); Uint32 time = SDL_GetTicks()-start; if(1000/60.0 - time > 0) SDL_Delay(1000/60.0 - time); } cout << "Longest Jump: " << maxjumpx << endl; cout << "Highest Jump: " << maxjumpy << endl; /*The Game has ended*/ if(!quickquit) { ifstream ins; ins.open("highscore.dat"); vector > highlist; for(int i = 0; i < 10; ++i) { pair temp; ins >> temp.first; if(!ins.good()) break; ins >> temp.second; if(ins.good()) { highlist.push_back(temp); } else break; } ins.close(); sort(highlist.begin(), highlist.end()); if(highlist.size() < 10 || highlist[0].first < highscore) { cout << "Congratulations! You made a new highscore." << endl; pair youscore; youscore.first = highscore; youscore.second = name; highlist.push_back(youscore); sort(highlist.begin(), highlist.end()); ofstream ofs; ofs.open("highscore.dat"); if(highlist.size() == 11) { for(int i = 0; i < 10; ++i) { ofs << highlist[i+1].first << " " << highlist[i+1].second << endl; } } else { for(int i = 0; i < (int)highlist.size(); ++i) { ofs << highlist[i].first << " " << highlist[i].second << endl; } } ofs.close(); } cout << "\n**HIGHSCORE**\n"; for(int i = min(10,(int) highlist.size()-1); i > 0; --i) { cout << highlist[i].second << ": " << highlist[i].first << '\n'; } if(highlist.size() < 11) cout << highlist[0].second << ": " << highlist[0].first << '\n'; cout << endl; } SDL_Rect mpos; mpos.x = 25; mpos.y = 180; mpos.w = 300; mpos.h = 32; Label message = Label("GAME OVER - Press space to restart", mpos); message.draw(screen); SDL_Flip(screen); while(true) { SDL_Event event; SDL_PollEvent(&event); Uint8 *keyState = SDL_GetKeyState(NULL); if(event.type == SDL_QUIT || keyState[SDLK_ESCAPE]) { Game_Quit = true; quickquit = true; wantEnd = true; break; } if(keyState[SDLK_SPACE]) break; } } SDL_FreeSurface(preBall); atexit(SDL_Quit); return 0; }