1 /* ************************************************************************* *
2 Simplevaders space-invaders like game that is not like space-invaders
3 Copyright (C) 2007 DusteD
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * ************************************************************************* */
18
19 /* Disclamer (2): This was my first computergame, my first experience with opengl,
20 sdl and my first C++ program. I learned a lot from all the mistakes and
21 design-flaws I made here. So, go easy on me, I know there are lots of errors in
22 here, but I only learn by doing, and by making mistakes. */
23
24 //FIXME: needz moar bullutz
25
26 #include <iostream>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <GL/gl.h>
30 #include <GL/glu.h>
31 #include <SDL/SDL.h>
32 #include <SDL/SDL_ttf.h>
33 #include <SDL/SDL_mixer.h>
34 #include <SDL/SDL_image.h>
35 #include <math.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #define ALIEN_SHOOT_DELAY rand() % 5000/(level/5.0f);
40 #define NUM_PSYS 20
41 #define NUM_PARTICLES 50
42 #define NUM_BULLETS 200
43
44 using namespace std;
45 SDL_Surface *screen = NULL;
46 SDL_Surface *texture = NULL;
47
48 TTF_Font *font = NULL;
49 SDL_Surface *textureb = NULL;
50 SDL_Surface *welcomeimg = NULL;
51
52 SDL_Event event;
53
54 //sounds
55 bool sound=1;
56 Mix_Chunk *SND_playerbullet = NULL;
57 Mix_Chunk *SND_nmedie = NULL;
58 Mix_Chunk *SND_gameover = NULL;
59 Mix_Chunk *SND_playerhit = NULL;
60
61 int bestScore=0;
62
63 int level=1;
64 int playerbullets=0;
65 int nextlevblocks=0;
66
67 int alienrows = 3;
68 #define aliensInrow 15
69 #define MAX_ALIEN_ROWS 5
70
71 void spawnbullet(GLfloat x, GLfloat y,bool dir);
72 float rndflt(float total, float negative);
73 void initGameObjects(bool ng);
74 void txt();
75 void exitgame(bool status);
76 void game_over();
77 void newgame();
78 void spawnPsystem(GLfloat x, GLfloat y, GLfloat scale, int life, GLfloat maxvel);
79 void renderParticlesystems();
80 void renderAlienRows();
81
82 long aRowLastTick=0;
83 int aRowTicks=0;
84
85 long drawLastTick;
86 bool glBlink=0;
87 bool glBlinkOff=0;
88 bool enablePs=1;
89
90 float scale = 0.4f;
91
92 bool starfield=1;
93 GLuint glTexture[5]; // 0 = score 1 = welcome 2 = gameover 3 = flare 4=credits
94 GLint glAlienMesh = 0;
95
96 //closeness = sqrt(pow(pos[0] - aliens[alienr].pos[0],2) + pow(pos[1] - aliens[alienr].pos[1],2));
97 class particleSystem {
98 public:
99 int numparticles, liveparticles, life[NUM_PARTICLES];
100 bool initialized,l[NUM_PARTICLES];
101 GLfloat x[NUM_PARTICLES], y[NUM_PARTICLES], vel[NUM_PARTICLES], rot[NUM_PARTICLES], col[NUM_PARTICLES][3], scale,ox,oy,maxvel;
102 uint32_t lastTick;
103 uint32_t lifeTicks;
104 int syslife;
105
init()106 void init()
107 {
108 int p=0;
109 if(liveparticles != 0)
110 {
111 cout << "trying to init live ps\n";
112 exitgame(1);
113 }
114 while(p<numparticles)
115 {
116 x[p]=0.0f;
117 y[p]=0.0f;
118 rot[p]=rndflt(360,0);
119 vel[p]=rndflt(maxvel,0)+0.1;
120 l[p]=1;
121 life[p]=rand() % syslife;
122 col[p][0]=rndflt(1,0);
123 col[p][1]=rndflt(1,0);
124 col[p][2]=rndflt(1,0);
125 p++;
126 }
127 liveparticles=p;
128 lastTick=SDL_GetTicks();
129 lifeTicks=lastTick;
130 initialized=1;
131 }
132
update()133 void update()
134 {
135 int p=0;
136 int ticks = SDL_GetTicks() - lastTick;
137 GLfloat d;
138 while(p<numparticles)
139 {
140 if(l[p])
141 {
142 d = vel[p] * (ticks / 1000.0f);
143
144 x[p] = x[p]+d;
145 //Nulstil cursor
146 glLoadIdentity();
147 //Roter
148 GLfloat g = (1.f/rndflt(life[p],0))*(SDL_GetTicks() - lifeTicks);
149
150 glTranslatef( ox, oy, -5.0 );
151 glRotatef( rot[p],0.0,0.0,1.0 );
152 glTranslatef( x[p],0.0,0.0);
153 //Placer
154
155 //Farv
156 glColor4f( 1.0, 1.0-(g/2), 1.0f-g, 1.0f-g );
157 //Tegn
158 glEnable(GL_TEXTURE_2D);
159 glBindTexture(GL_TEXTURE_2D, glTexture[3]);
160 glEnable(GL_BLEND);
161 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
162 glBegin ( GL_QUADS );
163 glTexCoord2f(0.0f,-1.0f);glVertex3f(-0.1f*scale, 0.1f*scale, 0.0f);
164 glTexCoord2f(1.0f,-1.0f);glVertex3f( 0.1f*scale, 0.1f*scale, 0.0f);
165 glTexCoord2f(1.0f,0.0f); glVertex3f( 0.1f*scale, -0.1f*scale, 0.0f);
166 glTexCoord2f(0.0f,0.0f); glVertex3f(-0.1f*scale, -0.1f*scale, 0.0f);
167 glEnd();
168 glDisable(GL_TEXTURE_2D);
169 glDisable(GL_BLEND);
170 glPopMatrix();
171 //Hvis den er død?
172 if(x[p] > 3.0 || x[p] < -3.0 || y[p] > 3.0 || y[p] < -3.0 || (lifeTicks+life[p]) < SDL_GetTicks())
173 {
174 liveparticles--;
175 l[p]=0;
176 }
177 }
178 p++;
179 }
180
181 lastTick = SDL_GetTicks();
182 }
183 };
184
185
186 particleSystem psys[NUM_PSYS];
187
188 /* function to reset our viewport after a window resize */
resizeWindow(int width,int height)189 void resizeWindow( int width, int height )
190 {
191 /* Height / width ration */
192 GLfloat ratio;
193
194 /* Protect against a divide by zero */
195 if ( height == 0 )
196 height = 1;
197
198 ratio = ( GLfloat )width / ( GLfloat )height;
199
200 /* Setup our viewport. */
201 glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height );
202
203 /* change to the projection matrix and set our viewing volume. */
204 glMatrixMode( GL_PROJECTION );
205 glLoadIdentity( );
206
207 /* Set our perspective */
208 gluPerspective( 45.0f, ratio, 0.1f, 100.0f );
209
210 /* Make sure we're chaning the model view and not the projection */
211 glMatrixMode( GL_MODELVIEW );
212
213 /* Reset The View */
214 glLoadIdentity();
215 }
216
217 class player {
218 public:
219 int lives;
220 int health;
221 GLfloat pos[3];
222 long lastTick;
223 long lastShotTick;
224 GLfloat xvel;
225 GLfloat yvel;
226 bool shooting;
227 int score;
228
stats()229 void stats()
230 {
231 txt();
232 }
233
move()234 void move()
235 {
236 int ticks;
237 GLfloat xdistance,ydistance;
238
239 ticks = SDL_GetTicks() - lastTick;
240 lastTick = SDL_GetTicks();
241
242 xdistance = xvel * (ticks / 1000.0f);
243 pos[0] = pos[0] + xdistance;
244
245
246 ydistance = yvel * (ticks / 1000.0f);
247 pos[1] = pos[1] + ydistance;
248
249 xvel=0.0f;
250 yvel=0.0f;
251
252 //keep player on screen
253 if(pos[0] > 3.1 || pos[0] < -3.1)
254 pos[0] = pos[0] - xdistance;
255 if(pos[1] > 2.5 || pos[1] < -2.5)
256 pos[1]=pos[1]-ydistance;
257
258 glTranslatef( pos[0], pos[1], pos[2] );
259
260 if(shooting)
261 {
262 if(SDL_GetTicks() - lastShotTick > 100)
263 {
264 if(playerbullets<6)
265 {
266 spawnbullet(pos[0],pos[1],1);
267 lastShotTick=SDL_GetTicks();
268 if(sound)
269 Mix_PlayChannel( -1, SND_playerbullet, 0 );
270 playerbullets++;
271 }
272 }
273 }
274 }
275
gethit()276 void gethit()
277 {
278 lives--;
279 glBlink=1;
280 drawLastTick=SDL_GetTicks();
281 stats();
282 if(sound)
283 Mix_PlayChannel(-1, SND_playerhit, 0);
284
285 if(lives == 0)
286 {
287 game_over();
288 }
289 }
290 };
291
292 player playerobj;
293
294 class alienrow {
295 private:
296 float shootDelay[15];
297 long lastShotTick[15];
298 bool dir; //0 = <-- 1= -->
299 public:
300 bool nextrow;
301 bool active;
302 GLfloat x[15],y,xvel;
303 bool live[15];
304
hit(int a)305 void hit(int a)
306 {
307 live[a]=0;
308 spawnPsystem(x[a],y-0.25,0.3,1000,1.0);
309 playerbullets--;
310 playerobj.score=playerobj.score+(3*level*level);
311 playerobj.stats();
312 if(playerobj.score > bestScore)
313 bestScore = playerobj.score;
314 if(sound)
315 Mix_PlayChannel( -1, SND_nmedie, 0 );
316 }
317
init(GLfloat starty,bool startdir)318 void init(GLfloat starty, bool startdir)
319 {
320 GLfloat width = 0.5*scale;
321 if(active != 1)
322 {
323 int a=0;
324 GLfloat offset=0.0f;
325 GLfloat startx = -2.0f;
326 active=1;
327 dir = startdir;
328 xvel = 10.2f*(level/50.0f);
329 y = starty;
330 nextrow=0;
331
332 while(a < 15)
333 {
334 live[a] = 1;
335 x[a] = startx + offset;
336 shootDelay[a] = ALIEN_SHOOT_DELAY;
337 lastShotTick[a] = SDL_GetTicks()-rand() % 250;
338 offset = offset + width + 0.1;
339 a++;
340 }
341 } else {
342 cout << "Tried to initialize active row.\n";
343 exitgame(1);
344 }
345 }
346
update()347 void update()
348 {
349 int a=0;
350 int tempdir=3;
351 int livealiens=0;
352 GLfloat d = xvel*((aRowTicks - aRowLastTick)/1000.0f);
353
354 if(active==0)
355 return;
356
357 while(a<15)
358 {
359 if(live[a])
360 {
361 livealiens++;
362
363 if(dir)
364 x[a] = x[a] + d;
365 else
366 x[a] = x[a] - d;
367
368 if(x[a] > 3.0f)
369 tempdir=0;
370 else if(x[a] < -3.0f)
371 tempdir=1;
372
373 glPushMatrix();
374 glLoadIdentity();
375 glTranslatef( x[a], y, -6.0f );
376 glCallList(glAlienMesh);
377 glPopMatrix();
378
379 //Skyd
380 if((SDL_GetTicks()-lastShotTick[a]) > shootDelay[a])
381 {
382 spawnbullet(x[a],y,0);
383 lastShotTick[a] = SDL_GetTicks();
384 shootDelay[a]=ALIEN_SHOOT_DELAY;
385 }
386
387 //Coldetc player
388 GLfloat closeness = sqrt(pow(x[a] - playerobj.pos[0],2) + pow(y - playerobj.pos[1],2));
389 if(closeness < 0.26)
390 {
391 hit(a);
392 playerobj.score--;
393 playerobj.gethit();
394 playerobj.stats();
395 }
396
397 }
398 a++;
399 }
400
401 if(tempdir<3)
402 {
403 dir=tempdir;
404 nextrow=1;
405 }
406 if(livealiens==0)
407 {
408 active=0;
409 nextrow=0;
410 }
411 //Game over?
412 if(y < -2.2)
413 game_over();
414 }
415 };
416
417 alienrow arows[MAX_ALIEN_ROWS];
418
419 class bullet {
420 public:
421 bool active;
422 bool dir;
423 float yvel;
424 GLfloat pos[3];
425 long lastTick;
426
move()427 void move()
428 {
429
430 int ticks;
431 GLfloat distance;
432
433 ticks = SDL_GetTicks() - lastTick;
434 distance = yvel * (ticks / 1000.0f);
435 lastTick = SDL_GetTicks();
436
437 if(dir == 0)
438 pos[1] = pos[1] - distance; //0.001f;//distance;
439 else
440 pos[1] = pos[1] + distance; //0.001f;//distance;
441
442 glTranslatef( pos[0], pos[1], pos[2] );
443
444 if(dir == 0)
445 {
446 if(pos[1] < -2.5f)
447 {
448 active=0;
449 }
450 } else {
451 if(pos[1] > 2.5f)
452 {
453 active=0;
454 playerbullets--;
455 }
456 }
457
458 //Collision detection med player
459 if(pos[0] > playerobj.pos[0]-0.15f && pos[0] < playerobj.pos[0]+0.15f && pos[1] < playerobj.pos[1]+0.25f && pos[1] > playerobj.pos[1]-0.25f && dir==0)
460 {
461 playerobj.gethit();
462 active=0;
463 } else if(dir==1) {
464
465 //Gå alle aliens igennem
466 int ar=0;
467 while(ar < alienrows)
468 {
469 if(arows[ar].active == 1)
470 {
471 int a=0;
472 while(a < aliensInrow)
473 {
474 if(arows[ar].live[a] == 1)
475 {
476 if(pos[0] > arows[ar].x[a]-0.18 && pos[0] < arows[ar].x[a]+0.18 && pos[1] > arows[ar].y-0.18 && pos[1] < arows[ar].y+0.18 ) //HACK virker ikke med scale
477 {
478 arows[ar].hit(a);
479 active=0;
480 }
481 }
482 a++;
483 }
484 }
485 ar++;
486 }
487 }
488 }
489 };
490
491
492 bullet bullets[NUM_BULLETS];
493
spawnbullet(GLfloat x,GLfloat y,bool dir)494 void spawnbullet(GLfloat x, GLfloat y,bool dir)
495 {
496 int thisbullet=0;
497 //Loop gennem vores bullets til vi finder en der ikke er aktiv
498 while(thisbullet != NUM_BULLETS)
499 {
500 if(bullets[thisbullet].active != 1)
501 {
502 bullets[thisbullet].active = 1;
503 bullets[thisbullet].pos[0] = x;
504 bullets[thisbullet].dir=dir;
505 if(dir==1)
506 {
507 bullets[thisbullet].yvel=3.5f;
508 bullets[thisbullet].pos[1] = y +0.25f;
509 } else {
510 bullets[thisbullet].yvel=1.5f;
511 bullets[thisbullet].pos[1] = y-0.1f;
512 }
513 bullets[thisbullet].lastTick = SDL_GetTicks();
514 break;
515 }
516 thisbullet++;
517 }
518
519 }
520
521 //lists
522
523 GLint glAlienBulletMesh = 1;
524 //GLint glPlayerMesh = 2 ;
525 GLint glPlayerBullet = 3;
526 //GLint glScores = 4;
527
528
529
530
initGLobjects()531 void initGLobjects()
532 {
533
534
535 glAlienMesh = glGenLists(1);
536 glNewList(glAlienMesh, GL_COMPILE);
537 glColor3f(1.0f,0.0f,0.0f);
538 glBegin( GL_TRIANGLES );
539
540 glVertex3f( -0.25f*scale,0.25f*scale,0.0f*scale );
541 glVertex3f( 0.25f*scale,0.25f*scale,0.0f*scale );
542 glColor3f(1.0f,1.0f,0.0f);
543 glVertex3f( 0.0*scale, -0.25*scale,0.0f*scale );
544
545 glColor3f(1.0f,0.0f,0.0f);
546
547 glVertex3f( -0.30f*scale,0.35f*scale,0.0f*scale );
548 glVertex3f( -0.25f*scale,0.25f*scale,0.0f*scale );
549 glVertex3f( 0.0f*scale,0.25f*scale,0.0f*scale );
550
551
552 glVertex3f( 0.30f*scale,0.35f*scale,0.0f*scale );
553 glVertex3f( 0.25f*scale,0.25f*scale,0.0f*scale );
554 glVertex3f( 0.0f*scale,0.25f*scale,0.0f*scale );
555 glEnd( );
556 glEndList();
557
558 glAlienBulletMesh = glGenLists(1);
559 glNewList(glAlienBulletMesh, GL_COMPILE);
560 glBegin( GL_TRIANGLES );
561 glColor3f(1.0f,1.0f,1.0f);
562 glVertex3f( -0.015f, 0.015f,0.0f );
563 glVertex3f( 0.015f, 0.015f,0.0f);
564 glVertex3f( 0.0f, -0.030f, 0.0f);
565 glEnd( );
566 glEndList();
567
568 //Player bullet mesh (glPlayerBullet)
569 glPlayerBullet = glGenLists(1);
570 glNewList(glPlayerBullet, GL_COMPILE);
571 glBegin( GL_TRIANGLES );
572 glColor3f(0.0f,1.0f,0.0f);
573 glVertex3f( 0.0f, 0.03f, 0.0f );
574 glColor3f(1.0f,1.0f,1.0f);
575 glVertex3f( -0.02f, -0.025f, 0.0f);
576 glVertex3f( 0.02f, -0.025f, 0.0f);
577 glEnd( );
578 glEndList();
579
580 //Texturer
581 welcomeimg = IMG_Load("/usr/local/share/simplevaders/intro.png");
582
583 if(welcomeimg == NULL)
584 exitgame(1);
585
586 glGenTextures(1, &glTexture[1]);
587 glBindTexture(GL_TEXTURE_2D, glTexture[1]);
588 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
589 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
590
591 //Texturer
592 welcomeimg = IMG_Load("/usr/local/share/simplevaders/gameover.png");
593
594 if(welcomeimg == NULL)
595 exitgame(1);
596
597 glGenTextures(1, &glTexture[2]);
598 glBindTexture(GL_TEXTURE_2D, glTexture[2]);
599 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
600 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
601
602 //Texturer
603 welcomeimg = IMG_Load("/usr/local/share/simplevaders/flare.png");
604
605 if(welcomeimg == NULL)
606 exitgame(1);
607
608 glGenTextures(1, &glTexture[3]);
609 glBindTexture(GL_TEXTURE_2D, glTexture[3]);
610 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
611 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
612
613 //Texturer
614 welcomeimg = IMG_Load("/usr/local/share/simplevaders/cred.png");
615
616 if(welcomeimg == NULL)
617 exitgame(1);
618
619 glGenTextures(1, &glTexture[4]);
620 glBindTexture(GL_TEXTURE_2D, glTexture[4]);
621 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, welcomeimg->w, welcomeimg->h, GL_RGBA, GL_UNSIGNED_BYTE, welcomeimg->pixels);
622 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
623
624 SDL_FreeSurface( welcomeimg );
625
626 }
627
initGameObjects(bool ng)628 void initGameObjects(bool ng)
629 {
630 // Player
631 playerobj.pos[0] = 0.0;
632 playerobj.pos[1] = -2.20;
633
634 playerobj.lastTick = SDL_GetTicks();
635 if(ng)
636 {
637 playerobj.score = 0;
638 playerobj.lives = 3;
639 }
640 playerobj.stats();
641
642 //Bullets
643 int thisbullet = 0;
644 while(thisbullet != NUM_BULLETS)
645 {
646 bullets[thisbullet].lastTick = SDL_GetTicks();
647 bullets[thisbullet].active = 0;
648 thisbullet++;
649 }
650
651 int ar=0;
652 GLfloat yofs=2.2;
653
654 while(ar < alienrows)
655 {
656 arows[ar].active=0;
657 arows[ar].init(yofs, 1);
658 yofs=yofs-0.25f;
659 ar++;
660 }
661 aRowLastTick=SDL_GetTicks(); //HACK
662
663 }
664
initTxt()665 void initTxt()
666 {
667 if(!font)
668 {
669 font = TTF_OpenFont( "/usr/local/share/simplevaders/font.ttf", 24 );
670 if(!font)
671 {
672 cout << "Font not loaded!\n";
673 exitgame(1);
674 }
675 }
676 }
677
txt()678 void txt()
679 {
680 SDL_Color textColor = { 255, 255, 255 };
681
682 char msg[25];
683 sprintf(msg,"%i|%i|%i",playerobj.lives,level,playerobj.score);
684
685 texture = TTF_RenderText_Blended( font, msg, textColor );
686 textureb = SDL_CreateRGBSurface(0, 256, 256, 32, 0xff000000, 0x0000ff00, 0x00ff0000, 0x00000000); //FIXME: i cant get
687
688
689 SDL_BlitSurface(texture, 0, textureb, 0);
690
691 if(!texture)
692 {
693 cout << "\nTexture error\n";
694 exitgame(1);
695 }
696
697 if(!texture->pixels)
698 {
699 cout << "\nNo pixulZ! :(\n";
700 exitgame(1);
701 }
702
703 if(!glTexture[0])
704 {
705 glGenTextures(1, &glTexture[0]);
706 }
707 glBindTexture(GL_TEXTURE_2D, glTexture[0]);
708 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureb->w, textureb->h, GL_RGBA, GL_UNSIGNED_BYTE, textureb->pixels);
709 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
710 SDL_FreeSurface( texture );
711 SDL_FreeSurface( textureb );
712 }
713
714
initGL()715 void initGL() {
716
717 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
718 // printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
719 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
720 // printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
721
722 /* Enable smooth shading */
723 glShadeModel( GL_SMOOTH );
724
725 /* Set the background black */
726 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
727
728 /* Depth buffer setup */
729 glClearDepth( 1.0f );
730
731 /* Enables Depth Testing */
732 glEnable( GL_DEPTH_TEST );
733
734 /* The Type Of Depth Test To Do */
735 glDepthFunc( GL_LEQUAL );
736
737 /* Really Nice Perspective Calculations */
738 glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
739
740 initGLobjects();
741
742 }
743 #define NUMSTARS 1000
744 #define STARSTART 3.0f
745
746 GLfloat starsy[NUMSTARS];
747 GLfloat starsx[NUMSTARS];
748 GLfloat starspeed[NUMSTARS];
749 GLfloat starh[NUMSTARS];
750
751 long lastStarTick=0;
752
rndflt(float total,float negative)753 float rndflt(float total, float negative)
754 {
755
756 return (rand()/(float(RAND_MAX)+1)*total)-negative;
757 }
758
initStarField()759 void initStarField()
760 {
761 int star=0;
762 while(star < NUMSTARS)
763 {
764 starsy[star]=rndflt(6.0f,3.0f);
765 starsx[star]=rndflt(6.6f,3.3f); //Random float kthx
766 starspeed[star]=rndflt(2.5f,0.0f)+0.1;//rndflt(2,0); //random speed kthx
767 starh[star] = rndflt(1.0f,0.0f);
768
769 star++;
770 }
771 }
772
glStarfield()773 void glStarfield()
774 {
775 glLoadIdentity();
776 glTranslatef( 0.0f, 0.0f, -6.0f );
777
778 int star=0;
779 GLfloat distance;
780 int ticks = SDL_GetTicks() - lastStarTick;
781
782 glPushMatrix();
783 glBegin( GL_POINTS );
784 while(star<NUMSTARS)
785 {
786 //Uden for skærmen
787 if(starsy[star] <= -3.0f)
788 {
789 starsy[star]=STARSTART;
790 starsx[star]=rndflt(6.6f,3.3f); //Random float kthx
791 starspeed[star]=rndflt(2.5f,0.0f)+0.1; //random speed kthx
792 }
793 else
794 {
795 //Inden for skærmen
796
797
798
799 // cout << "Star"<< star<< " ("<<starsx[star] << ","<<starsy[star]<<") \n";
800 distance = starspeed[star]*(level/2.0f) * (ticks/1000.0f);
801 lastStarTick = SDL_GetTicks();
802 starsy[star]=starsy[star] - distance;
803 }
804 glColor3f(starh[star],starh[star],starh[star]);
805 glVertex3f( starsx[star], starsy[star], 0.0f );
806
807 star++;
808 }
809 glEnd();
810 glPopMatrix();
811 }
812
813
814
815
glScoreboard()816 void glScoreboard()
817 {
818 glPushMatrix();
819 glLoadIdentity();
820 glTranslatef( 2.34f, 2.35f, -6.0f );
821
822 glEnable(GL_TEXTURE_2D);
823 glBindTexture(GL_TEXTURE_2D, glTexture[0]);
824 glEnable(GL_BLEND);
825 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
826 glBegin( GL_QUADS );
827
828 glColor3f(1.0f,1.0f,1.0f);
829
830 glTexCoord2f(0.0f, 0.1125f);
831 glVertex3f( 0.0f, 0.0f, 0.0f );
832
833 glTexCoord2f(1.0f, 0.1125f);
834 glVertex3f( 1.0f, 0.0f, 0.0f );
835
836 glTexCoord2f(1.0f, 0.0f);
837 glVertex3f( 1.0f, 0.1125f, 0.0f );
838
839 glTexCoord2f(0.0f, 0.0f);
840 glVertex3f( 0.0f, 0.1125f, 0.0f );
841 glEnd();
842 glDisable(GL_TEXTURE_2D);
843 glDisable(GL_BLEND);
844 glPopMatrix();
845 }
846
renderAlienRows()847 void renderAlienRows()
848 {
849 int ar=0;
850 nextlevblocks=0;
851 aRowTicks = SDL_GetTicks();
852 while(ar < alienrows)
853 {
854 if(arows[ar].active==1)
855 {
856 // cout << ar << "\n";
857
858 if(arows[ar].nextrow==1)
859 {
860 if(ar < alienrows+1)
861 {
862 if(arows[ar].nextrow==1)
863 {
864 if(arows[ar+1].active==0)
865 {
866 arows[ar].nextrow=0;
867 arows[ar].y =arows[ar].y - 0.25f;
868 }
869 }
870
871 }
872 }
873 arows[ar].update();
874 nextlevblocks = 1;
875 }
876 ar++;
877 }
878 aRowLastTick = SDL_GetTicks();
879 }
880
draw()881 void draw()
882 {
883
884 if(glBlink && !glBlinkOff)
885 {
886 int ticks = SDL_GetTicks() - drawLastTick;
887
888 glClearColor( 1.0f, 0.0f, 0.0f, 0.0f );
889 if(ticks > 50)
890 {
891 glBlink=0;
892 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
893 }
894 }
895
896 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
897
898 if(starfield)
899 {
900 glStarfield();
901 lastStarTick = SDL_GetTicks();
902 }
903
904 //Reset position
905 glLoadIdentity();
906 glTranslatef( 0.0f, 0.0f, -6.0f );
907
908
909 renderAlienRows();
910
911
912 int thisbullet=0;
913 //Vis bullets...
914 while(thisbullet != NUM_BULLETS)
915 {
916 if(bullets[thisbullet].active == 1)
917 {
918 glPushMatrix();
919 glLoadIdentity();
920 glTranslatef( 0.0f, 0.0f, -6.0f );
921 bullets[thisbullet].move();
922 if(bullets[thisbullet].dir==0)
923 glCallList(glAlienBulletMesh);
924 else
925 glCallList(glPlayerBullet);
926 glPopMatrix();
927 }
928 thisbullet++;
929 }
930
931 //Player FIXME: Som det er nu varer det en frame før skibet skyder!
932 glPushMatrix();
933 glLoadIdentity();
934 glTranslatef( 0.0f, 0.0f, -6.0f );
935 playerobj.move();
936 if(playerobj.lives > 0)
937 {
938 glBegin( GL_TRIANGLES );
939 if(playerobj.shooting)
940 glColor3f(1.0f,0.0f,0.0f);
941 else
942 glColor3f(0.0f,1.0f,1.0f);
943 playerobj.shooting=0;
944 glVertex3f( 0.0f, 0.15f,0.0f );
945 glColor3f(0.0f,0.0f,1.0f);
946 glVertex3f( -0.15f, -0.15f,0.0f);
947 glVertex3f( 0.15f, -0.15f,0.0f);
948
949 glVertex3f( 0.15f, -0.15f, 0.0f);
950 glVertex3f( 0.0f, -0.15f, 0.0f);
951 glVertex3f( 0.20f, -0.25f, 0.f);
952
953 glVertex3f( -0.15f, -0.15f, 0.0f);
954 glVertex3f( 0.0f, -0.15f, 0.0f);
955 glVertex3f( -0.20f, -0.25f, 0.f);
956
957 glEnd( );
958 }
959 glPopMatrix();
960
961
962 //Scoreboard
963 glScoreboard();
964
965 renderParticlesystems();
966
967 glPopMatrix();
968 /* Draw it to the screen */
969 SDL_GL_SwapBuffers( );
970 }
971
initSound()972 void initSound()
973 {
974 if(Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 1024 ) == -1)
975 {
976 cout << "\nUnable to initializing sound\n";
977 exitgame(1);
978 }
979 SND_playerbullet = Mix_LoadWAV( "/usr/local/share/simplevaders/playerbullet.wav" );
980 SND_playerhit = Mix_LoadWAV("/usr/local/share/simplevaders/playerhit.wav");
981 SND_nmedie = Mix_LoadWAV( "/usr/local/share/simplevaders/nmedie.wav" );
982 SND_gameover = Mix_LoadWAV("/usr/local/share/simplevaders/gameover.wav");
983
984 if(SND_playerbullet == NULL)
985 {
986 cout << "\nCouldn't load /usr/local/share/simplevaders/playerbullet.wav\n";
987 exitgame(1);
988 }
989
990 if(SND_playerhit == NULL)
991 {
992 cout << "\nCouldn't load /usr/local/share/simplevaders/playerhit.wav\n";
993 exitgame(1);
994 }
995
996 if(SND_nmedie == NULL)
997 {
998 cout << "\nCouldn't load /usr/local/share/simplevaders/nmedie.wav\n";
999 exitgame(1);
1000 }
1001
1002 if(SND_gameover == NULL)
1003 {
1004 cout << "\nCouldn't load /usr/local/share/simplevaders/gameover.wav\n";
1005 exitgame(1);
1006 }
1007 }
1008
1009
spawnPsystem(GLfloat x,GLfloat y,GLfloat scale,int life,GLfloat maxvel)1010 void spawnPsystem(GLfloat x, GLfloat y, GLfloat scale, int life, GLfloat maxvel) {
1011 int ps=0;
1012 if(enablePs)
1013 {
1014 //Find et system der er ledigt
1015 while(ps < NUM_PSYS)
1016 {
1017 if(psys[ps].liveparticles==0)
1018 {
1019 psys[ps].numparticles = NUM_PARTICLES;
1020 psys[ps].scale = scale;
1021 psys[ps].ox = x;
1022 psys[ps].oy = y;
1023 psys[ps].syslife = life;
1024 psys[ps].maxvel = maxvel;
1025 psys[ps].init();
1026 break;
1027 }
1028 ps++;
1029 }
1030 }
1031 }
1032
renderParticlesystems()1033 void renderParticlesystems()
1034 {
1035 int ps=0;
1036 if(enablePs)
1037 {
1038 while(ps < NUM_PSYS)
1039 {
1040 // cout << "\n Rendering particles..\n";
1041 if(psys[ps].liveparticles > 0)
1042 {
1043 psys[ps].update();
1044 // cout << "rendering live particle..\n";
1045 }
1046 ps++;
1047 }
1048 }
1049 }
1050
intro(int playstate)1051 void intro(int playstate)
1052 {
1053 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
1054 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1055
1056 if(starfield)
1057 {
1058 glStarfield();
1059 lastStarTick = SDL_GetTicks();
1060 }
1061
1062
1063
1064 glPushMatrix();
1065 glLoadIdentity();
1066 glTranslatef( 0.0f, 0.0f, -6.0f );
1067
1068 glEnable(GL_TEXTURE_2D);
1069 if(playstate==1)
1070 glBindTexture(GL_TEXTURE_2D, glTexture[1]);
1071 else if(playstate==2)
1072 glBindTexture(GL_TEXTURE_2D, glTexture[2]);
1073 else
1074 glBindTexture(GL_TEXTURE_2D, glTexture[4]);
1075
1076 glEnable(GL_BLEND);
1077 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1078 glBegin( GL_QUADS );
1079
1080 glColor3f(1.0f,1.0f,1.0f);
1081
1082 glTexCoord2f( 0.0f, -1.0f );
1083 glVertex3f( -1.0f, 1.0f, 0.0f );
1084
1085 glTexCoord2f( 1.0f, -1.0f );
1086 glVertex3f( 1.0f, 1.0f, 0.0f );
1087
1088 glTexCoord2f( 1.0f, 0.0f );
1089 glVertex3f( 1.0f, -1.0f, 0.0f );
1090
1091 glTexCoord2f( 0.0f, 0.0f );
1092 glVertex3f( -1.0f, -1.0f, 0.0f );
1093 glEnd();
1094 glDisable(GL_TEXTURE_2D);
1095
1096 glDisable(GL_BLEND);
1097 glPopMatrix();
1098
1099 glScoreboard();
1100
1101 renderParticlesystems();
1102
1103 SDL_GL_SwapBuffers( );
1104
1105 }
1106
1107 SDL_Joystick *joyA = NULL;
1108 int joysticknr=0;
1109 int playstate = 1;
1110 Sint16 x_move=0, y_move=0;
1111 Uint8 btnA=0;
1112
handleInputPlaying()1113 void handleInputPlaying()
1114 {
1115 //Ikke flere aliens? Næste bane
1116 if(nextlevblocks==0)
1117 {
1118 level++;;
1119 playerobj.lives++;
1120 initGameObjects(0);
1121 playerbullets=0;
1122 }
1123
1124 Uint8 *keyStates = SDL_GetKeyState( NULL );
1125 if(keyStates[SDLK_LEFT])
1126 playerobj.xvel=-2.5f;
1127 if(keyStates[SDLK_RIGHT])
1128 playerobj.xvel=2.5f;
1129 if(keyStates[SDLK_UP])
1130 playerobj.yvel=2.5f;
1131 if(keyStates[SDLK_DOWN])
1132 playerobj.yvel=-2.5f;
1133 if(keyStates[SDLK_LCTRL])
1134 playerobj.shooting=1;
1135
1136
1137 if(SDL_JoystickOpened(joysticknr))
1138 {
1139 x_move=SDL_JoystickGetAxis(joyA, 0);
1140 y_move=SDL_JoystickGetAxis(joyA, 1);
1141 btnA = SDL_JoystickGetButton(joyA,0);
1142
1143 if(x_move < -200)
1144 playerobj.xvel=-2.5f;
1145 if(x_move > 200)
1146 playerobj.xvel=2.5f;
1147 if(y_move < -200)
1148 playerobj.yvel=2.5f;
1149 if(y_move > 200)
1150 playerobj.yvel=-2.5f;
1151 if(btnA)
1152 playerobj.shooting=1;
1153 }
1154 }
1155
1156
1157
1158
main(int argc,char * argv[])1159 int main (int argc, char *argv[]) {
1160 bool fullscreen=0;
1161 int resx=1600;
1162 int resy=1200;
1163 int sleepdelay = 10000;
1164
1165 drawLastTick=0;
1166
1167 int arg=0;
1168 while(arg != argc)
1169 {
1170 if(strcmp(argv[arg],"--nosound") == 0)
1171 {
1172 sound=0;
1173 cout << "\nSound disabled.\n";
1174 } else if(strcmp(argv[arg],"--fullscreen") == 0)
1175 {
1176 fullscreen=1;
1177 } else if(strcmp(argv[arg],"--noblink") == 0)
1178 {
1179 glBlinkOff=1;
1180 cout << "\nBlinking disabled.\n";
1181 } else if(strcmp(argv[arg], "--x") == 0)
1182 {
1183 arg++; //det er det næste der er spændende
1184 resx = atoi(argv[arg]);
1185 } else if(strcmp(argv[arg], "--y") == 0)
1186 {
1187 arg++;
1188 resy = atoi(argv[arg]);
1189 } else if(strcmp(argv[arg],"--nostars") == 0) {
1190 starfield=0;
1191 } else if(strcmp(argv[arg],"--noparticles") == 0) {
1192 enablePs=0;
1193 } else if(strcmp(argv[arg],"--sleep") == 0) {
1194 arg++;
1195 sleepdelay = atoi(argv[arg]);
1196 if(sleepdelay < 10)
1197 sleepdelay = 1000;
1198 } else if(strcmp(argv[arg],"--help") == 0 || strcmp(argv[arg],"-help") == 0 || strcmp(argv[arg],"-h") == 0)
1199 {
1200 cout << "\nsimplevaders - a space-invaders like game that is nothing like space-invaders.\nUsage:\n simplevaders [--nosound] [--fullscreen] [--noblink] [--x pixels] [--y pixels] [--nostars] [--noparticles] [--sleep USeconds]\n\nControls:\n s = toggle sound (if enabled)\n f = toggle fullscreen\n a = toggle starfield\n arrows = move ship\n lctrl = shoot\n\nJoystick 0:\n btn0 = shoot\n xy aix.. go figure.\n";
1201 return(0);
1202 }
1203 arg++;
1204 }
1205
1206 if(resx < 1 || resy < 1 || resx > 12000 || resy > 12000)
1207 {
1208 cout << "\nInvalid resolution:" << resx <<"x" << resy << "\n";
1209 exitgame(1);
1210 }
1211
1212
1213 //Initialize SDL
1214 if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK) <0 )
1215 {
1216 printf("\nError: Unable to initialize SDL:%s\n", SDL_GetError());
1217 exitgame(1);
1218 }
1219
1220 SDL_ShowCursor(SDL_DISABLE);
1221
1222 //joysticks?
1223 if(SDL_NumJoysticks() > 0)
1224 {
1225 joyA = SDL_JoystickOpen(joysticknr);
1226 cout << "\n" << SDL_NumJoysticks() << " joysticks found, using '" << SDL_JoystickName(joysticknr) << "' with "<<SDL_JoystickNumButtons(joyA)<<" buttons.\n";
1227 if(!SDL_JoystickOpened(joysticknr))
1228 cout << " error opening joystick, no joystick.\n";
1229
1230 SDL_JoystickEventState (SDL_ENABLE);
1231 }
1232
1233 if(fullscreen)
1234 screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_FULLSCREEN );
1235 else
1236 screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF );
1237
1238 if( screen == NULL )
1239 {
1240 printf("\nError: Unable to set screen to %ix%i: %s\n",resx,resy,SDL_GetError());
1241 exitgame(1);
1242 }
1243
1244 if(TTF_Init() == -1)
1245 {
1246 cout << "\nError: could not init SDL_ttf: "<< TTF_GetError() <<"\n";
1247 exitgame(1);
1248 }
1249
1250 SDL_WM_SetCaption("simplevaders", "simplevaders");
1251
1252 initGL();
1253 initTxt();
1254 initGameObjects(1);
1255 initStarField();
1256
1257 if(sound)
1258 initSound();
1259
1260 /* resize the initial window */
1261 resizeWindow(resx,resy);
1262 int done=0;
1263
1264 while(done == 0)
1265 {
1266
1267 nextlevblocks=0;
1268 if(playstate==0)
1269 draw();
1270 else if(playstate>0)
1271 intro(playstate);
1272
1273 if(playstate==0)
1274 handleInputPlaying();
1275
1276 while (SDL_PollEvent(&event) )
1277 {
1278
1279 if( event.type == SDL_QUIT ) {
1280 done = 1;
1281 }
1282
1283 if( event.type == SDL_KEYDOWN ) {
1284 if(event.key.keysym.sym==SDLK_f)
1285 {
1286 if(!fullscreen)
1287 {
1288 fullscreen=1;
1289 screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_FULLSCREEN );
1290 } else {
1291 fullscreen=0;
1292 screen = SDL_SetVideoMode(resx,resy,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF );
1293 }
1294 resizeWindow(resx,resy);
1295 if( screen == NULL )
1296 {
1297 printf("\nError: Unable to set screen to %ix%i: %s\n",resx,resy,SDL_GetError());
1298 exitgame(1);
1299 }
1300 }
1301
1302 if(event.key.keysym.sym==SDLK_LCTRL && playstate > 0)
1303 {
1304 playstate--;
1305 if(playstate==0)
1306 newgame();
1307 }
1308
1309 if( event.key.keysym.sym==SDLK_s)
1310 sound=!sound;
1311
1312 if( event.key.keysym.sym==SDLK_a)
1313 starfield=!starfield;
1314
1315 if( event.key.keysym.sym==SDLK_ESCAPE)
1316 {
1317 if(playstate==3)
1318 {
1319 playstate=4;
1320 }
1321 else
1322 {
1323 playstate=3;
1324 spawnPsystem(-2.0, 1.8,1.5, 6000, 2.5);
1325 spawnPsystem( 2.0, 1.8,1.5, 6000, 2.5);
1326 spawnPsystem( 2.0,-1.8,1.5, 6000, 2.5);
1327 spawnPsystem(-2.0,-1.8,1.5, 6000, 2.5);
1328 spawnPsystem(0.0,0.0,1.5, 6000, 2.5);
1329 }
1330 }
1331
1332 }
1333
1334 if( event.type == SDL_VIDEORESIZE ) {
1335 screen = SDL_SetVideoMode(event.resize.w, event.resize.h,32,SDL_OPENGL|SDL_RESIZABLE|SDL_DOUBLEBUF );
1336 if( screen == NULL )
1337 {
1338 printf("\nError: Unable to set screen to %ix%i: %s\n",resx,resy,SDL_GetError());
1339 exitgame(1);
1340 }
1341 resizeWindow(event.resize.w, event.resize.h);
1342 }
1343
1344 if(event.type == SDL_JOYBUTTONDOWN)
1345 {
1346 if(event.jbutton.button==0 && playstate > 0)
1347 {
1348 playstate--;
1349 if(playstate==0)
1350 newgame();
1351 }
1352 }
1353 }
1354
1355 if(playstate==4)
1356 done=1;
1357
1358 usleep(sleepdelay);
1359 // SDL_Delay(10);
1360 }
1361
1362 exitgame(0);
1363 }
1364
game_over()1365 void game_over()
1366 {
1367 if(sound)
1368 Mix_PlayChannel(-1, SND_gameover, 0);
1369
1370 spawnPsystem(playerobj.pos[0],playerobj.pos[1]-0.25,3.4f,5000,1.5);
1371 playstate=2;
1372 }
1373
newgame()1374 void newgame()
1375 {
1376 level=1;
1377 playerbullets=0;
1378 initGameObjects(1);
1379 }
1380
exitgame(bool status)1381 void exitgame(bool status) {
1382
1383 //Free SDL surfaces
1384 SDL_FreeSurface( screen );
1385
1386 //Free font
1387 TTF_CloseFont( font );
1388
1389 //Shutdown sdl_ttf
1390 TTF_Quit();
1391
1392 //Sound
1393 if(sound) {
1394 Mix_FreeChunk( SND_playerbullet );
1395 Mix_FreeChunk( SND_nmedie );
1396 Mix_FreeChunk( SND_gameover );
1397 Mix_FreeChunk ( SND_playerhit );
1398 Mix_CloseAudio();
1399 }
1400
1401 //Close joysticks
1402 if(SDL_JoystickOpened(joysticknr))
1403 {
1404 SDL_JoystickClose(joyA);
1405 }
1406
1407 //Shutdown sdl
1408 SDL_ShowCursor(SDL_ENABLE);
1409 SDL_Quit();
1410
1411
1412 if(status)
1413 {
1414 cout << "\nExited with errors.\n";
1415 exit(1);
1416 } else {
1417 cout << "\nThanks for playing, come back soon! ;)\nBest score this game was "<< bestScore << " points.\n";
1418 exit(0);
1419 }
1420 }
1421