summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--SC.cpp809
2 files changed, 814 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index 4bb9d9b..51f09f5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
1.PHONY: all 1.PHONY: all
2 2
3all: JnR 3all: SC
4
5JnR: JnR.cpp
6 g++ JnR.cpp -O2 -Wall -ggdb -lSDL -lSDL_gfx -lSDL_ttf -lSDL_image -o JnR
7 4
5SC: SC.cpp
6 g++ SC.cpp -O0 -Wall -ggdb -lSDL -lSDL_ttf -o SC
7
8clean: 8clean:
9 rm -f JnR 9 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 @@
1#include <iostream>
2#include <math.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <SDL/SDL.h>
6#include <SDL/SDL_ttf.h>
7#include <algorithm>
8#include <fstream>
9#include <sstream>
10#include <ctime>
11#include <cstdio>
12#include <vector>
13#include <list>
14
15#define RE(i,n) for(int (i) = 0; (i) < (int) n; ++i)
16
17using namespace std;
18
19
20string lltostr(const long long& l)
21{
22 stringstream str;
23 str << l;
24 return str.str();
25}
26
27class Label
28{
29protected:
30 string caption;
31 SDL_Surface* image;
32// int textSize;
33 SDL_Color textColor;
34 int render();
35public:
36 SDL_Rect pos;
37 Label();
38 Label(string ncaption, SDL_Rect& npos);
39 ~Label();
40 void draw(SDL_Surface* screen);
41 int setTextSize(int ntextSize);
42 void setTextColor(SDL_Color textColor);
43 int setCaption(string ncaption);
44};
45Label::Label()
46{
47 pos.x = 0;
48 pos.y = 0;
49 pos.w = 0;
50 pos.h = 14;
51 caption = "";
52 textColor.r = 255;
53 textColor.g = 255;
54 textColor.b = 255;
55 render();
56}
57
58Label::Label(string ncaption, SDL_Rect& npos)
59{
60 pos = npos;
61 textColor.r = 255;
62 textColor.g = 255;
63 textColor.b = 255;
64 caption = ncaption;
65 npos.w = render();
66}
67
68int Label::setTextSize(int ntextSize)
69{
70 pos.h = ntextSize;
71 SDL_FreeSurface(image);
72 return render();
73}
74
75void Label::setTextColor(SDL_Color ntextColor)
76{
77 textColor = ntextColor;
78 SDL_FreeSurface(image);
79 render();
80}
81
82int Label::setCaption(string ncaption)
83{
84 if(caption == ncaption)
85 return pos.w;
86 caption = ncaption;
87 SDL_FreeSurface(image);
88 return render();
89}
90
91int Label::render()
92{
93 TTF_Font *font = TTF_OpenFont("fonts/OpenSans-Semibold.ttf",pos.h);
94 image = NULL;
95 image = TTF_RenderText_Solid(font, caption.c_str(),textColor);
96 if(caption.size() == 0)
97 cout << "empty caption!!!" << endl;
98 if(image == NULL)
99 {
100 cout << "Error rendering Label with caption " << caption << endl;
101 return 0;
102 }
103 TTF_CloseFont(font);
104 pos.w = image->w;
105 return image->w;
106}
107
108
109void Label::draw(SDL_Surface* screen)
110{
111 SDL_Rect temp = pos;
112 SDL_BlitSurface(image, NULL, screen, &temp);
113}
114
115Label::~Label()
116{
117 SDL_FreeSurface(image);
118}
119
120
121int xres = 600;
122int yres = 450;
123SDL_Surface *screen;
124
125double sqr(double x)
126{
127 return x*x;
128}
129
130//euclidean distance
131double dist(double x1, double x2, double y1, double y2)
132{
133 return sqrt(sqr(x2-x1) + sqr(y2-y1));
134}
135
136bool inBounds(int x, int y)
137{
138 if(x >= 0 && x < xres && y >= 0 && y < yres)
139 return true;
140 return false;
141}
142
143void drawPixel(SDL_Surface *screen,int x, int y, Uint8 R, Uint8 G, Uint8 B)
144{
145 Uint32 color = SDL_MapRGB(screen->format, R, G, B);
146
147 SDL_Rect r;
148 r.x = x;
149 r.y = y;
150 r.w = 1;
151 r.h = 1;
152 SDL_FillRect(screen,&r,color);
153}
154
155void drawLine(SDL_Surface* screen,double x0,double y0,double x1, double y1, Uint8 R, Uint8 G, Uint8 B)
156{
157 double x = x0;
158 double y = y0;
159 double dir_x = x1 - x0;
160 double dir_y = y1 - y0;
161 double norm = dir_x*dir_x + dir_y*dir_y;
162 dir_x /= sqrt(2*norm);
163 dir_y /= sqrt(2*norm);
164 while((x1-x)*dir_x + (y1-y)*dir_y > 0)
165 {
166 drawPixel(screen, x, y, R,G,B);
167 x += dir_x;
168 y += dir_y;
169 }
170}
171
172void drawCircle(SDL_Surface* screen, double x, double y, double radius, Uint8 R, Uint8 G, Uint8 B)
173{
174 if(fabs(radius) < 9000)
175 for(int i = -1-radius + x; i <= x + 1 + radius; ++i)
176 for(int j = y -radius - 1; j <= radius + 1 + y; ++j)
177 if(dist(i,x,j,y) < radius && inBounds(i,j))
178 {
179 drawPixel(screen, i,j,R,G,B);
180 }
181}
182
183void blacken(SDL_Surface* screen)
184{
185 SDL_FillRect(screen,NULL,0);
186}
187
188Uint8 playerR = 100;
189Uint8 playerG = 100;
190Uint8 playerB = 100;
191
192Uint8 obstacleR = 255;
193Uint8 obstacleG = 100;
194Uint8 obstacleB = 100;
195
196class Ball
197{
198public:
199 double x;
200 double y;
201 double r;
202 double vx;
203 double vy;
204 int R;
205 int G;
206 int B;
207 double score;
208 double health;
209 double damage;
210 Ball(double xn, double yn, double nr, double nvy)
211 {
212 x = xn;
213 y = yn;
214 r = nr;
215 vy = nvy;
216 R = 255;
217 G = 0;
218 B = 0;
219 vx = 0;
220 damage = 1;
221 health = 1;
222 }
223
224 void color()
225 {
226 const int ncolors = 6;
227 const int cmapR[ncolors] = {255,0,0,255,255,255};
228 const int cmapG[ncolors] = {0,0,255,255,0,255};
229 const int cmapB[ncolors] = {0,255,0,0, 255,255};
230 R = cmapR[((int) health-1)%ncolors];
231 G = cmapG[((int) health-1)%ncolors];
232 B = cmapB[((int) health-1)%ncolors];
233 }
234
235 bool check_collision(Ball* b)
236 {
237 if(b == NULL)
238 return false;
239 if(dist(b->x, x, b->y, y) < b->r + r)
240 return true;
241 return false;
242 }
243 void draw(SDL_Surface* screen)
244 {
245 drawCircle(screen, x,y,r,R,G,B);
246 }
247 void step(double time)
248 {
249 x += time*vx;
250 y += time*vy;
251 }
252};
253
254
255class Particle
256{
257public:
258 double x;
259 double y;
260 double vx;
261 double vy;
262 double life;
263 // 0 = static, 1 = strife, 2 = randomwalk, 3 = xrandomwalk
264 int mode;
265 Uint8 R,G,B;
266 Particle()
267 {
268 x = rand()%xres;
269 y = rand()%yres;
270 life = rand()%20;
271 R = rand()%256;
272 G = rand()%256;
273 B = rand()%256;
274 }
275 Particle(double xn, double yn, int nmode, Uint8 Rn, Uint8 Gn, Uint8 Bn)
276 {
277 mode = nmode;
278 x = xn;
279 y = yn;
280 R = Rn;
281 G = Gn;
282 B = Bn;
283 life = rand()%20;
284 }
285 void draw(SDL_Surface* screen)
286 {
287 if(inBounds(x,y))
288 drawPixel(screen, x, y, R, G, B);
289 }
290 bool step(double time)
291 {
292 life -= time;
293 // 0 = static, 1 = strife, 2 = randomwalk, 3 = xrandomwalk
294 if(mode == 1){
295 x += vx*time;
296 y += vy*time;
297 }
298 else if(mode == 2)
299 {
300 x += (rand()%3-1)/2.0;
301 y += (rand()%3-1)/2.0;
302 }
303 else if(mode == 3)
304 {
305 x += (rand()%3-1)/8.0;
306 y += vy*time;
307 }
308
309 return (life >= 0);
310 }
311};
312
313
314vector<Particle*> makeDeathAnimation(Ball* b)
315{
316 vector<Particle*> result;
317 if(b == NULL)
318 return result;
319 for(int i = 0; i < 300; ++i)
320 {
321 double tx = (rand()%((int) (2*b->r+1)*100))/100.0-b->r;
322 double ty = (rand()%((int) (2*b->r+1)*100))/100.0-b->r;
323 if(tx*tx + ty * ty > sqr(b->r))
324 continue;
325 double vr = 200*dist(tx,0,ty,0)/b->r;
326 double ex = tx/dist(tx,0,ty,0);
327 double ey = ty/dist(tx,0,ty,0);
328 tx += b->x;
329 ty += b->y;
330 Particle* temp = new Particle(tx, ty, 1, b->R, b->G, b->B);
331
332 temp->vx = ex*vr+b->vx;
333 temp->vy = ey*vr+b->vy;
334
335 temp->life = (rand()%100)/50.0;
336 result.push_back(temp);
337 }
338 return result;
339}
340
341double ground_level = yres - 20;
342double g = 300.0;
343string name;
344
345//loads the "settings" (color sceme)
346void loadConstants()
347{
348 ifstream ins;
349 ins.open("settings.dat");
350//not used
351 ins.close();
352}
353
354
355
356//initializes the imported libs and opens a window
357int init_libs(SDL_Surface **screen)
358{
359 if(SDL_Init(SDL_INIT_VIDEO) == -1)
360 {
361 cout << "Error: Could not initialize SDL" << endl;
362 return 1;
363 }
364 *screen = SDL_SetVideoMode(xres,yres,32,SDL_SWSURFACE);
365 if(!screen)
366 {
367 cout << "could not initialize screen" << endl;
368 return 1;
369 }
370
371 if(TTF_Init() == -1)
372 {
373 cout << "could not initialize True Fonts" << endl;
374 return 1;
375 }
376 SDL_WM_SetCaption("Space Canon - v0.02a", NULL);
377 return 0;
378}
379
380double draw_rand()
381{
382 double result = rand()%10000-5000;
383 result += rand()%10000 - 5000;
384 result /= 7000.0;
385 return result;
386}
387
388class Weapon
389{
390 public:
391 double next_shot;
392 double reload_time;
393 int Nprojectiles;
394 double projectileRad;
395 int projectile_hp;
396 double projectile_damage;
397 double angle;
398 int x;
399 int y;
400 double Evel;
401 double dvel;
402 double dphi;
403 double transit_vel;
404
405 Weapon(int nx, int ny)
406 {
407 transit_vel = 2;
408 Evel = 400;
409 dvel = 60;
410 dphi = 0.2;
411 Nprojectiles = 1;
412 projectileRad = 1.9;
413 projectile_hp = 1;
414 projectile_damage = 1;
415 x = nx;
416 y = ny;
417 next_shot = 0;
418 reload_time = 1;
419 angle = M_PI/2;
420 }
421
422 void step(double t, int right)
423 {
424 if(next_shot > 0)
425 next_shot -= t;
426 angle -= right*t*transit_vel;
427 if(angle < 0.1)
428 angle = 0.1;
429 if(angle > M_PI-0.1)
430 angle = M_PI-0.1;
431 }
432
433 void draw(SDL_Surface* screen)
434 {
435 //draw cannon;
436 drawCircle(screen, x, y, 10, 255,255,255);
437 double x1 = cos(angle)*15;
438 double y1 = -sin(angle)*15;
439 drawLine(screen, x, y, x + x1, y + y1, 255,255,255);
440 }
441
442 vector<Ball*> shoot()
443 {
444 vector<Ball*> result;
445 if(next_shot <= 0)
446 {
447 next_shot += reload_time;
448 double sx = x + cos(angle)*15;
449 double sy = y-sin(angle)*15;
450 for(int i = 0; i < Nprojectiles; ++i)
451 {
452 Ball* tempe = new Ball(sx, sy, projectileRad, 0);
453 double angle1 = angle + draw_rand()*dphi;
454 double vel = Evel + draw_rand()*dvel;
455 tempe->vx = cos(angle1) * vel;
456 tempe->vy = -sin(angle1) * vel;
457 tempe->G = 255;
458 tempe->health = projectile_hp;
459 tempe->damage = projectile_damage;
460 result.push_back(tempe);
461 }
462 }
463 return result;
464 }
465};
466
467
468class GameHandle
469{
470 //will always contain the CURRENT highscore
471 double highscore;
472 //level number
473 vector<Ball*> enemies;
474 vector<Ball*> projectiles;
475 vector<Particle*> particles;
476 SDL_Surface* screen;
477 bool game_Quit;
478 bool quickquit;
479 Label* scoreLabel;
480 Label* message;
481 Label* lifeLabel;
482 //-1,0,1 respectively depending on the status of ther arrow keys
483 int down;
484 int right;
485 int space;
486 int lifes;
487 bool game_Over;
488 vector<Weapon*> weapons;
489 int current_weapon;
490
491 void game_reset()
492 {
493 //SEED
494 srand(42+197641283);
495
496 down = 0;
497 current_weapon = 0;
498 RE(i, weapons.size())
499 delete weapons[i];
500 weapons = vector<Weapon*>();
501 Weapon* mg = new Weapon(xres/2, ground_level);
502 mg->reload_time = 0.12;
503 mg->projectile_damage = 1;
504 mg->transit_vel = 4;
505 weapons.push_back(mg);
506 Weapon* shotgun = new Weapon(xres/2, ground_level);
507 shotgun->reload_time = 1;
508 shotgun->projectile_damage = 1;
509 shotgun->Nprojectiles = 12;
510 shotgun->projectileRad = 1.2;
511 shotgun->Evel = 600;
512 shotgun->transit_vel = 4;
513 weapons.push_back(shotgun);
514 Weapon* canon = new Weapon(xres/2, ground_level);
515 canon->reload_time = 1.1;
516 canon->projectile_damage = 3;
517 canon->projectile_hp = 5;
518 canon->projectileRad = 32;
519 canon->transit_vel = 2;
520 canon->Evel = 300;
521 canon->dvel = 20;
522 canon->dphi = 0.07;
523 weapons.push_back(canon);
524 lifes = 5;
525 highscore = 0;
526 game_Quit = false;
527 quickquit = false;
528// for(int i = 0)
529 }
530public:
531 ~GameHandle()
532 {
533 delete scoreLabel;
534// delete message;
535 delete lifeLabel;
536 atexit(SDL_Quit);
537 RE(i, weapons.size())
538 delete weapons[i];
539 }
540
541 GameHandle(SDL_Surface* Nscreen)
542 {
543 highscore = 0;
544 screen = Nscreen;
545 SDL_Rect lpos;
546 lpos.x = 100;
547 lpos.y = 10;
548 lpos.w = 300;
549 lpos.h = 20;
550 lifeLabel = new Label(lltostr(lifes) + " life", lpos);
551 lpos.x = 300;
552 lpos.y = 10;
553 lpos.w = 300;
554 lpos.h = 20;
555 scoreLabel = new Label("Score: " + lltostr(highscore), lpos);
556 }
557
558 void update_Label()
559 {
560 scoreLabel->setCaption("Score: " + lltostr(highscore));
561 lifeLabel->setCaption(lltostr(lifes) + " life");
562 }
563
564 void paint(bool win, bool showmessage)
565 {
566 blacken(screen);
567 for(int i = 0; i < (int) particles.size(); ++i)
568 particles[i]->draw(screen);
569 for(int i = 0; i < (int) enemies.size(); ++i)
570 enemies[i]->draw(screen);
571 for(int i = 0; i < (int) projectiles.size(); ++i)
572 projectiles[i]->draw(screen);
573 for(int i = 0; i < xres; ++i)
574 drawPixel(screen,i,ground_level,255,255,255);
575 weapons[current_weapon]->draw(screen);
576
577 SDL_Rect r;
578 r.x = 0;
579 r.y = ground_level+1;
580 r.w = xres;
581 r.h = yres - ground_level;
582 SDL_FillRect(screen, &r, 0);
583
584 scoreLabel->draw(screen);
585 lifeLabel->draw(screen);
586 if(showmessage)
587 message->draw(screen);
588
589 SDL_Flip(screen);
590 }
591
592 void step(int steps, bool inGame, double t)
593 {
594 if(inGame)
595 {
596// RE(i,weapons.size())
597 weapons[current_weapon]->step(1/60.0,right);
598 if(space)
599 {
600 vector<Ball*> nproj = weapons[current_weapon]->shoot();
601 RE(i, nproj.size())
602 projectiles.push_back(nproj[i]);
603 }
604 //spawning a new Enemy every few steps
605 int lvl = steps/3000 + 1;
606 if(!(steps % 3000))
607 cout << "reached level " << lvl << "! " << endl;
608 double progression = steps % 3000;
609 if(rand()%70000 < progression/2 + 500)
610 {
611 double rad = max(rand()%300/(5.0+lvl),50.0/(3+lvl)+2);
612 double vel = 10*lvl + rand()%50;
613 Ball* tempe = new Ball(rand()%xres,0-rad, rad, vel);
614 for(int i = 1; i < lvl; ++i)
615 if(rand()%2)
616 tempe->health++;
617 tempe->score = tempe->health*(2000.0/tempe->r + tempe->vy);
618 tempe->color();
619 enemies.push_back(tempe);
620 }
621 vector<Ball*> nenemies;
622 for(int i = 0; i < (int) enemies.size(); ++i)
623 {
624 enemies[i]->step(1/60.0);
625 //checking wether an enemy was killed
626 bool shot = false;
627 for(int j = 0; j < (int) projectiles.size(); ++j)
628 if(!shot)
629 if(enemies[i]->check_collision(projectiles[j]))
630 {
631 enemies[i]->health -= projectiles[j]->damage;
632 projectiles[j]->health -= enemies[i]->damage;
633 if(enemies[i]->health <= 0)
634 {
635 shot = true;
636 highscore += enemies[i]->score;
637 vector<Particle*> tempP = makeDeathAnimation(enemies[i]);
638 for(int k = 0; k < (int) tempP.size(); ++k)
639 particles.push_back(tempP[k]);
640 delete enemies[i];
641 }
642 if(projectiles[j]->health <= 0)
643 {
644 vector<Particle*> tempP = makeDeathAnimation(projectiles[j]);
645 for(int k = 0; k < (int) tempP.size(); ++k)
646 particles.push_back(tempP[k]);
647 projectiles[j]->x = -10000;
648 }
649 }
650 if(shot)
651 continue;
652 //checking wether an enemy has reached the bottom line
653 if(enemies[i]->y + enemies[i]->r > ground_level)
654 {
655 lifes -= 1;
656 vector<Particle*> tempP = makeDeathAnimation(enemies[i]);
657 for(int j = 0; j < (int) tempP.size(); ++j)
658 particles.push_back(tempP[j]);
659 delete enemies[i];
660 continue;
661 }
662 nenemies.push_back(enemies[i]);
663 }
664 enemies = nenemies;
665 vector<Ball*> nprojectiles;
666 for(int i = 0; i < (int) projectiles.size(); ++i)
667 {
668 if(projectiles[i]->x == -10000)
669 {
670 delete projectiles[i];
671 continue;
672 }
673 projectiles[i]->step(1/60.0);
674 //checking wether a projectile has reached the edge
675 if(!inBounds(projectiles[i]->x, projectiles[i]->y))
676 {
677 vector<Particle*> tempP = makeDeathAnimation(projectiles[i]);
678 for(int j = 0; j < (int) tempP.size(); ++j)
679 particles.push_back(tempP[j]);
680 delete projectiles[i];
681 continue;
682 }
683 nprojectiles.push_back(projectiles[i]);
684 }
685 projectiles = nprojectiles;
686
687 }
688
689 //deleting old particles
690 vector<Particle*> nparticles;
691 for(int i = 0; i < (int) particles.size(); ++i)
692 {
693 if(particles[i]->step(1/60.0) && inBounds(particles[i]->x,particles[i]->y))
694 {
695 nparticles.push_back(particles[i]);
696 }
697 else
698 {
699 delete particles[i];
700 }
701 }
702
703 particles = nparticles;
704
705
706 if(lifes <= 0)
707 game_Over = true;
708 }
709
710 void handle_Events(bool &game_Quit, int &down, int& right)
711 {
712 SDL_Event event;
713 while(SDL_PollEvent(&event))
714 {
715 if(event.type == SDL_QUIT)
716 {
717 game_Quit = true;
718 break;
719 }
720 }
721 Uint8 *keyState = SDL_GetKeyState(NULL);
722 int ndown = -keyState[SDLK_UP]+keyState[SDLK_DOWN];
723 if(ndown != down)
724 {
725 if(down == -1)
726 {
727 int n = (current_weapon + 1)%weapons.size();
728 weapons[n]->angle = weapons[current_weapon]->angle;
729 current_weapon = n;
730 }
731 if(down == 1)
732 {
733 int n = (current_weapon - 1 + weapons.size())%weapons.size();
734 weapons[n]->angle = weapons[current_weapon]->angle;
735 current_weapon = n;
736 }
737 }
738 down = ndown;
739 right = -keyState[SDLK_LEFT]+keyState[SDLK_RIGHT];
740 space = keyState[SDLK_SPACE];
741 }
742
743// void animate_death()
744// {
745// vector<Particle> deathanimation = makeDeathAnimation(x_pos,y_pos,ball_rad,x_vel, y_vel);
746// for(int i = 0; i < (int) deathanimation.size(); ++i)
747// particles.push_back(deathanimation[i]);
748// }
749
750 void play()
751 {
752 //won or lost the game
753 game_Over = false;
754 //resets the game variables to startpoint
755 game_reset();
756
757 double time = 0;
758 int steps = 0;
759
760 while(!game_Over)
761 {
762 Uint32 start = SDL_GetTicks();
763 handle_Events(game_Quit,down, right);
764 if(game_Quit)
765 {
766 game_Over = true;
767 break;
768 }
769
770 step(steps, true,time);
771
772 if(game_Over)
773 break;
774 update_Label();
775 steps++;
776 time += 1/60.0;
777 paint(true,false);
778 Uint32 time = SDL_GetTicks()-start;
779 if(1000/60.0 - time > 0)
780 SDL_Delay(1000/60.0 - time);
781 }
782 cout << "You died! Your highscore was " << highscore << endl;
783 }
784};
785
786
787//a console io menu
788void pregame_menu(string& name)
789{
790 cout << "This is a simple space game" << endl;
791 cout << "Please enter your name:";
792 cin >> name;
793// cout << "Please enter difficulty (0-100):";
794// cin >> difficulty;
795}
796
797int main()
798{
799 loadConstants();
800 pregame_menu(name);
801 if(init_libs(&screen))
802 return 1;
803 GameHandle game = GameHandle(screen);
804 game.play();
805
806
807 return 0;
808}
809