From 1f14b9649f5e025d00537e0b7284442ab0e1f894 Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 1 Dec 2015 20:54:28 +0100 Subject: initial commit --- Makefile | 10 +- SC.cpp | 809 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 814 insertions(+), 5 deletions(-) create mode 100644 SC.cpp diff --git a/Makefile b/Makefile index 4bb9d9b..51f09f5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ .PHONY: all -all: JnR - -JnR: JnR.cpp - g++ JnR.cpp -O2 -Wall -ggdb -lSDL -lSDL_gfx -lSDL_ttf -lSDL_image -o JnR +all: SC +SC: SC.cpp + g++ SC.cpp -O0 -Wall -ggdb -lSDL -lSDL_ttf -o SC + clean: - rm -f JnR + rm -f SC diff --git a/SC.cpp b/SC.cpp new file mode 100644 index 0000000..8efb99a --- /dev/null +++ b/SC.cpp @@ -0,0 +1,809 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RE(i,n) for(int (i) = 0; (i) < (int) n; ++i) + +using namespace std; + + +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; + +double sqr(double x) +{ + return x*x; +} + +//euclidean distance +double dist(double x1, double x2, double y1, double y2) +{ + return sqrt(sqr(x2-x1) + sqr(y2-y1)); +} + +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); +} + +void drawLine(SDL_Surface* screen,double x0,double y0,double x1, double y1, Uint8 R, Uint8 G, Uint8 B) +{ + double x = x0; + double y = y0; + double dir_x = x1 - x0; + double dir_y = y1 - y0; + double norm = dir_x*dir_x + dir_y*dir_y; + dir_x /= sqrt(2*norm); + dir_y /= sqrt(2*norm); + while((x1-x)*dir_x + (y1-y)*dir_y > 0) + { + drawPixel(screen, x, y, R,G,B); + x += dir_x; + y += dir_y; + } +} + +void drawCircle(SDL_Surface* screen, double x, double y, double radius, Uint8 R, Uint8 G, Uint8 B) +{ + if(fabs(radius) < 9000) + for(int i = -1-radius + x; i <= x + 1 + radius; ++i) + for(int j = y -radius - 1; j <= radius + 1 + y; ++j) + if(dist(i,x,j,y) < radius && inBounds(i,j)) + { + drawPixel(screen, i,j,R,G,B); + } +} + +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 Ball +{ +public: + double x; + double y; + double r; + double vx; + double vy; + int R; + int G; + int B; + double score; + double health; + double damage; + Ball(double xn, double yn, double nr, double nvy) + { + x = xn; + y = yn; + r = nr; + vy = nvy; + R = 255; + G = 0; + B = 0; + vx = 0; + damage = 1; + health = 1; + } + + void color() + { + const int ncolors = 6; + const int cmapR[ncolors] = {255,0,0,255,255,255}; + const int cmapG[ncolors] = {0,0,255,255,0,255}; + const int cmapB[ncolors] = {0,255,0,0, 255,255}; + R = cmapR[((int) health-1)%ncolors]; + G = cmapG[((int) health-1)%ncolors]; + B = cmapB[((int) health-1)%ncolors]; + } + + bool check_collision(Ball* b) + { + if(b == NULL) + return false; + if(dist(b->x, x, b->y, y) < b->r + r) + return true; + return false; + } + void draw(SDL_Surface* screen) + { + drawCircle(screen, x,y,r,R,G,B); + } + void step(double time) + { + x += time*vx; + y += time*vy; + } +}; + + +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) + { + if(inBounds(x,y)) + drawPixel(screen, x, y, 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(Ball* b) +{ + vector result; + if(b == NULL) + return result; + for(int i = 0; i < 300; ++i) + { + double tx = (rand()%((int) (2*b->r+1)*100))/100.0-b->r; + double ty = (rand()%((int) (2*b->r+1)*100))/100.0-b->r; + if(tx*tx + ty * ty > sqr(b->r)) + continue; + double vr = 200*dist(tx,0,ty,0)/b->r; + double ex = tx/dist(tx,0,ty,0); + double ey = ty/dist(tx,0,ty,0); + tx += b->x; + ty += b->y; + Particle* temp = new Particle(tx, ty, 1, b->R, b->G, b->B); + + temp->vx = ex*vr+b->vx; + temp->vy = ey*vr+b->vy; + + temp->life = (rand()%100)/50.0; + result.push_back(temp); + } + return result; +} + +double ground_level = yres - 20; +double g = 300.0; +string name; + +//loads the "settings" (color sceme) +void loadConstants() +{ + ifstream ins; + ins.open("settings.dat"); +//not used + ins.close(); +} + + + +//initializes the imported libs and opens a window +int init_libs(SDL_Surface **screen) +{ + 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("Space Canon - v0.02a", NULL); + return 0; +} + +double draw_rand() +{ + double result = rand()%10000-5000; + result += rand()%10000 - 5000; + result /= 7000.0; + return result; +} + +class Weapon +{ + public: + double next_shot; + double reload_time; + int Nprojectiles; + double projectileRad; + int projectile_hp; + double projectile_damage; + double angle; + int x; + int y; + double Evel; + double dvel; + double dphi; + double transit_vel; + + Weapon(int nx, int ny) + { + transit_vel = 2; + Evel = 400; + dvel = 60; + dphi = 0.2; + Nprojectiles = 1; + projectileRad = 1.9; + projectile_hp = 1; + projectile_damage = 1; + x = nx; + y = ny; + next_shot = 0; + reload_time = 1; + angle = M_PI/2; + } + + void step(double t, int right) + { + if(next_shot > 0) + next_shot -= t; + angle -= right*t*transit_vel; + if(angle < 0.1) + angle = 0.1; + if(angle > M_PI-0.1) + angle = M_PI-0.1; + } + + void draw(SDL_Surface* screen) + { + //draw cannon; + drawCircle(screen, x, y, 10, 255,255,255); + double x1 = cos(angle)*15; + double y1 = -sin(angle)*15; + drawLine(screen, x, y, x + x1, y + y1, 255,255,255); + } + + vector shoot() + { + vector result; + if(next_shot <= 0) + { + next_shot += reload_time; + double sx = x + cos(angle)*15; + double sy = y-sin(angle)*15; + for(int i = 0; i < Nprojectiles; ++i) + { + Ball* tempe = new Ball(sx, sy, projectileRad, 0); + double angle1 = angle + draw_rand()*dphi; + double vel = Evel + draw_rand()*dvel; + tempe->vx = cos(angle1) * vel; + tempe->vy = -sin(angle1) * vel; + tempe->G = 255; + tempe->health = projectile_hp; + tempe->damage = projectile_damage; + result.push_back(tempe); + } + } + return result; + } +}; + + +class GameHandle +{ + //will always contain the CURRENT highscore + double highscore; + //level number + vector enemies; + vector projectiles; + vector particles; + SDL_Surface* screen; + bool game_Quit; + bool quickquit; + Label* scoreLabel; + Label* message; + Label* lifeLabel; + //-1,0,1 respectively depending on the status of ther arrow keys + int down; + int right; + int space; + int lifes; + bool game_Over; + vector weapons; + int current_weapon; + + void game_reset() + { + //SEED + srand(42+197641283); + + down = 0; + current_weapon = 0; + RE(i, weapons.size()) + delete weapons[i]; + weapons = vector(); + Weapon* mg = new Weapon(xres/2, ground_level); + mg->reload_time = 0.12; + mg->projectile_damage = 1; + mg->transit_vel = 4; + weapons.push_back(mg); + Weapon* shotgun = new Weapon(xres/2, ground_level); + shotgun->reload_time = 1; + shotgun->projectile_damage = 1; + shotgun->Nprojectiles = 12; + shotgun->projectileRad = 1.2; + shotgun->Evel = 600; + shotgun->transit_vel = 4; + weapons.push_back(shotgun); + Weapon* canon = new Weapon(xres/2, ground_level); + canon->reload_time = 1.1; + canon->projectile_damage = 3; + canon->projectile_hp = 5; + canon->projectileRad = 32; + canon->transit_vel = 2; + canon->Evel = 300; + canon->dvel = 20; + canon->dphi = 0.07; + weapons.push_back(canon); + lifes = 5; + highscore = 0; + game_Quit = false; + quickquit = false; +// for(int i = 0) + } +public: + ~GameHandle() + { + delete scoreLabel; +// delete message; + delete lifeLabel; + atexit(SDL_Quit); + RE(i, weapons.size()) + delete weapons[i]; + } + + GameHandle(SDL_Surface* Nscreen) + { + highscore = 0; + screen = Nscreen; + SDL_Rect lpos; + lpos.x = 100; + lpos.y = 10; + lpos.w = 300; + lpos.h = 20; + lifeLabel = new Label(lltostr(lifes) + " life", lpos); + lpos.x = 300; + lpos.y = 10; + lpos.w = 300; + lpos.h = 20; + scoreLabel = new Label("Score: " + lltostr(highscore), lpos); + } + + void update_Label() + { + scoreLabel->setCaption("Score: " + lltostr(highscore)); + lifeLabel->setCaption(lltostr(lifes) + " life"); + } + + void paint(bool win, bool showmessage) + { + blacken(screen); + for(int i = 0; i < (int) particles.size(); ++i) + particles[i]->draw(screen); + for(int i = 0; i < (int) enemies.size(); ++i) + enemies[i]->draw(screen); + for(int i = 0; i < (int) projectiles.size(); ++i) + projectiles[i]->draw(screen); + for(int i = 0; i < xres; ++i) + drawPixel(screen,i,ground_level,255,255,255); + weapons[current_weapon]->draw(screen); + + SDL_Rect r; + r.x = 0; + r.y = ground_level+1; + r.w = xres; + r.h = yres - ground_level; + SDL_FillRect(screen, &r, 0); + + scoreLabel->draw(screen); + lifeLabel->draw(screen); + if(showmessage) + message->draw(screen); + + SDL_Flip(screen); + } + + void step(int steps, bool inGame, double t) + { + if(inGame) + { +// RE(i,weapons.size()) + weapons[current_weapon]->step(1/60.0,right); + if(space) + { + vector nproj = weapons[current_weapon]->shoot(); + RE(i, nproj.size()) + projectiles.push_back(nproj[i]); + } + //spawning a new Enemy every few steps + int lvl = steps/3000 + 1; + if(!(steps % 3000)) + cout << "reached level " << lvl << "! " << endl; + double progression = steps % 3000; + if(rand()%70000 < progression/2 + 500) + { + double rad = max(rand()%300/(5.0+lvl),50.0/(3+lvl)+2); + double vel = 10*lvl + rand()%50; + Ball* tempe = new Ball(rand()%xres,0-rad, rad, vel); + for(int i = 1; i < lvl; ++i) + if(rand()%2) + tempe->health++; + tempe->score = tempe->health*(2000.0/tempe->r + tempe->vy); + tempe->color(); + enemies.push_back(tempe); + } + vector nenemies; + for(int i = 0; i < (int) enemies.size(); ++i) + { + enemies[i]->step(1/60.0); + //checking wether an enemy was killed + bool shot = false; + for(int j = 0; j < (int) projectiles.size(); ++j) + if(!shot) + if(enemies[i]->check_collision(projectiles[j])) + { + enemies[i]->health -= projectiles[j]->damage; + projectiles[j]->health -= enemies[i]->damage; + if(enemies[i]->health <= 0) + { + shot = true; + highscore += enemies[i]->score; + vector tempP = makeDeathAnimation(enemies[i]); + for(int k = 0; k < (int) tempP.size(); ++k) + particles.push_back(tempP[k]); + delete enemies[i]; + } + if(projectiles[j]->health <= 0) + { + vector tempP = makeDeathAnimation(projectiles[j]); + for(int k = 0; k < (int) tempP.size(); ++k) + particles.push_back(tempP[k]); + projectiles[j]->x = -10000; + } + } + if(shot) + continue; + //checking wether an enemy has reached the bottom line + if(enemies[i]->y + enemies[i]->r > ground_level) + { + lifes -= 1; + vector tempP = makeDeathAnimation(enemies[i]); + for(int j = 0; j < (int) tempP.size(); ++j) + particles.push_back(tempP[j]); + delete enemies[i]; + continue; + } + nenemies.push_back(enemies[i]); + } + enemies = nenemies; + vector nprojectiles; + for(int i = 0; i < (int) projectiles.size(); ++i) + { + if(projectiles[i]->x == -10000) + { + delete projectiles[i]; + continue; + } + projectiles[i]->step(1/60.0); + //checking wether a projectile has reached the edge + if(!inBounds(projectiles[i]->x, projectiles[i]->y)) + { + vector tempP = makeDeathAnimation(projectiles[i]); + for(int j = 0; j < (int) tempP.size(); ++j) + particles.push_back(tempP[j]); + delete projectiles[i]; + continue; + } + nprojectiles.push_back(projectiles[i]); + } + projectiles = nprojectiles; + + } + + //deleting old particles + vector nparticles; + for(int i = 0; i < (int) particles.size(); ++i) + { + if(particles[i]->step(1/60.0) && inBounds(particles[i]->x,particles[i]->y)) + { + nparticles.push_back(particles[i]); + } + else + { + delete particles[i]; + } + } + + particles = nparticles; + + + if(lifes <= 0) + game_Over = true; + } + + void handle_Events(bool &game_Quit, int &down, int& right) + { + SDL_Event event; + while(SDL_PollEvent(&event)) + { + if(event.type == SDL_QUIT) + { + game_Quit = true; + break; + } + } + Uint8 *keyState = SDL_GetKeyState(NULL); + int ndown = -keyState[SDLK_UP]+keyState[SDLK_DOWN]; + if(ndown != down) + { + if(down == -1) + { + int n = (current_weapon + 1)%weapons.size(); + weapons[n]->angle = weapons[current_weapon]->angle; + current_weapon = n; + } + if(down == 1) + { + int n = (current_weapon - 1 + weapons.size())%weapons.size(); + weapons[n]->angle = weapons[current_weapon]->angle; + current_weapon = n; + } + } + down = ndown; + right = -keyState[SDLK_LEFT]+keyState[SDLK_RIGHT]; + space = keyState[SDLK_SPACE]; + } + +// void animate_death() +// { +// vector deathanimation = makeDeathAnimation(x_pos,y_pos,ball_rad,x_vel, y_vel); +// for(int i = 0; i < (int) deathanimation.size(); ++i) +// particles.push_back(deathanimation[i]); +// } + + void play() + { + //won or lost the game + game_Over = false; + //resets the game variables to startpoint + game_reset(); + + double time = 0; + int steps = 0; + + while(!game_Over) + { + Uint32 start = SDL_GetTicks(); + handle_Events(game_Quit,down, right); + if(game_Quit) + { + game_Over = true; + break; + } + + step(steps, true,time); + + if(game_Over) + break; + update_Label(); + steps++; + time += 1/60.0; + paint(true,false); + Uint32 time = SDL_GetTicks()-start; + if(1000/60.0 - time > 0) + SDL_Delay(1000/60.0 - time); + } + cout << "You died! Your highscore was " << highscore << endl; + } +}; + + +//a console io menu +void pregame_menu(string& name) +{ + cout << "This is a simple space game" << endl; + cout << "Please enter your name:"; + cin >> name; +// cout << "Please enter difficulty (0-100):"; +// cin >> difficulty; +} + +int main() +{ + loadConstants(); + pregame_menu(name); + if(init_libs(&screen)) + return 1; + GameHandle game = GameHandle(screen); + game.play(); + + + return 0; +} + -- cgit v1.2.3