OpenGL Pong

Το συγκεκριμένο υποτίθεται πως ήταν εργασία μου για το Δ’ Εξάμηνο αλλά δεν τελείωσε στην ώρα του. Οπότε μιας και άρχισε η νέα χρονιά, θεώρησα καλό να φτιάξω κάτι για να έχουν οι νέοι φοιτητές να χαζέψουν, μιας και τα παραδείγματα δεν ήταν αρκετά. Δεν τους κατηγορώ βέβαια, απ’τους ~20 συναδέλφους μου, ήμουν ο μόνος που μου άρεσε καθαρά ο προγραμματισμός. Οι περισσότεροι έδιναν βάση στο 3D, και από έτοιμη βοήθεια δεν υπήρχε τίποτα.

Οπότε σήμερα αποφάσισα και το έκανα playable. Λάθη υπάρχουν, και σίγουρα θα τα βρείτε αφού είναι εμφανή. Ο κώδικας είναι υπερβολικά απλός, ίσως και ηλίθιος, αλλά προτίμησα να δώσω βάση στην απλότητα ούτως ώστε να τον καταλάβει κάποιος, παρά στην λειτουργικότητά του.

Ο κώδικας είναι μεγάλος για post, οπότε απλά πηγαίντε στην σελίδα της ανάρτησης πατώντας τον τίτλο της για να δείτε τον κώδικα ή απλά πατήστε εδώ για να κατεβάσετε όλο το πακέτο.

Ο κώδικας είναι γραμμένος στο Dev-C++. Για να τον εκτελέσετε εγκαταστήστε από τα πακέτα την freeglut.

Pong screenshot

Pong screenshot


// Pong by Konstantinos Egkarchos (a ka kon_nos)

#include <GL/freeglut.h>   // OpenGL toolkit
#include <stdio.h>

// Πρόωρες δηλώσεις
void drawRect(GLfloat, GLfloat, int, int, float, float, float);
void update();

// Διαστάσεις του παραθύρου.
const int Width = 500;
const int Height = 500;

// Ρακέτες
#define paddleHeight 80
#define paddleWidth 10
#define zAxis 0

float p1 = 220;
float p2 = 220;
// GLfloat player1[4][2] = { 10, p1, 10, p1+paddleHeight, 10+paddleWidth, p1+paddleHeight, 10+paddleWidth, p1 };
// GLfloat player2[4][2] = { 480, p2, 480, p2+paddleHeight, 480+paddleWidth, p2+paddleHeight, 480+paddleWidth, p2 };
const float pspeed = 10;

int score[2];// = {0, 0}; // Σκορ για τον p1 και p2

#define bsize 10
GLdouble bpos[2] = {235,235};
GLfloat bvx = 1; // ball vector in left-right axis
GLfloat bvy = 1; // ball vector in top-bottom axis
// GLfloat ball[4][2] = { pos[0], pos[1], pos[0], pos[1]+bsize, pos[0]+bsize, pos[1]+bsize, pos[0]+bsize, pos[1] };
float bspeed = 2;

// Μεταβλητές χρόνου που θα χρειαστούν στον υπολογισμό της ταχύτητας των αντικειμένων
GLdouble time;
GLdouble prtime;
GLdouble timeDiff;
GLdouble runtime;

// Μεταβλητή κειμένου
static char str[200];
void * font = GLUT_BITMAP_9_BY_15;


/*********************************************
Ζωγραφική
*********************************************/
void renderScene(void)
{
// Ζήτα τον χρόνο που έχει περάσει από την αρχή του προγράμματος
time = glutGet(GLUT_ELAPSED_TIME);
timeDiff = time - prtime; // Χρόνος που πέρασε από το προηγούμενο καρέ
prtime = time;
runtime = timeDiff / 10.0;

update(); // Εκτέλεσε όλες τις συνθήκες
// Καθαρισμός της οθόνης
glClear(GL_COLOR_BUFFER_BIT);


sprintf(str, "Player 1 Score: %d, Player 2 Score: %d", score[0], score[1] );
glRasterPos2f(10, 10);
glutBitmapString(font,(unsigned char*)str);

// Τμήμα που ζωγραφίζει πρώτα την πρώτη ρακέτα και κατόπιν την δεύτερη
drawRect(10.0, p1, paddleHeight, paddleWidth, 0, 0, 1); // Μπλε αριστερή ρακέτα
drawRect(480.0, p2, paddleHeight, paddleWidth, 1, 0, 0); // Κόκκινη δεξιά ρακέτα

drawRect(bpos[0], bpos[1], bsize, bsize, 1, 1, 0); // Κίτρινη μπάλα

glutSwapBuffers(); // Εμφάνισε την νέα εικόνα
}

/*********************************************
Ανανέωση
*********************************************/
void update()
{
// Συγκρούσεις της μπάλας με τα όρια του παραθύρου
if(bpos[0] + bspeed > 500-bsize)
{
bvx = -1;
score[0]++;
}
else if (bpos[0] - bspeed < 0)
{
bvx = 1;
score[1]++;
}
if(bpos[1] + bspeed > 500-bsize)
bvy = -1;
else if (bpos[1] - bspeed < 0)
bvy = 1;

/******** Συγγρούσεις της μπάλας με τις ρακέτες ********/
// Σύγκρουση με την αριστερή ρακέτα
if(bpos[0] <= 10 + paddleWidth && bpos[1] >= p1 && bpos[1] + bsize <= p1 + paddleHeight)
{
bvx *= -1;
// bspeed *= 1.01;
}
// Σύγκρουση με την δεξιά ρακέτα
if(bpos[0] + bsize >= 480 && bpos[1] >= p2 && bpos[1] + bsize <= p2 + paddleHeight)
{
bvx *= -1;
// bspeed *= 1.01;
}

// Νέα θέση της μπάλας ανάλογα με την ταχύτητα ***************
// Επειδή το frame rate δεν μας εγγυάται πως θα είναι πάντα σταθερό
// πολλαπλασιάζουμε την αλλαγή της θέσης με τον χρόνο που πέρασε για την εμφάνιση
// του νέου καρέ. Έτσι η ταχύτητα είναι πάντα ομαλή.
bpos[0] += bspeed * bvx * runtime;
bpos[1] += bspeed * bvy * runtime;
}

/*********************************************
Ορισμός ενός παραλληλόγραμμου, και εμφάνισή του
Ουσιαστικά μόνο το ύψος της ρακέτας (y) μας ενδιαφέρει.
*********************************************/
void drawRect(GLfloat x, GLfloat y, int height, int width, float R, float G, float B)
{
glColor3f(R,G,B);

glBegin(GL_QUADS);
glVertex2f( x, y);                    // Top Left
glVertex2f( x, y + height);            // Bottom Left
glVertex2f( x + width, y + height);      // Bottom Right
glVertex2f( x + width, y);            // Top Right
glEnd();
}


/*********************************************
Είσοδος χρήστη

*Σημείωση: Δεν με ενδιαφέρει η ομαλή κίνηση όπως στην μπάλα
*********************************************/
void keyPress(unsigned char key, int x, int y)
{
switch (key)
{
case 'w':
case 'W':
if(420>=p1+pspeed)
{p1 += pspeed;}
break;
case 's':
case 'S':
if(0<=p1-pspeed)
{p1 -= pspeed;}
break;
case 27 :
exit(0);
}
}

/*********************************************
Είσοδος εικικών πλήκτρων

*Σημείωση: Δεν με ενδιαφέρει η ομαλή κίνηση όπως στην μπάλα
*********************************************/
void specialKeyPress(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_UP:
if(420>=p2+pspeed)
{p2 += pspeed;}
break;
case GLUT_KEY_DOWN:
if(0<=p2-pspeed)
{p2 -= pspeed;}
break;
}
}

/*********************************************
Εν αρχή ην οι αρχικές τιμές
*********************************************/
void init(void)
{
// Καθορισμός χρώματος στο οποίο θα καθαρίζεται το παράθυρο
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

// Όρισε γραμμική προβολή
gluOrtho2D(0,500,0,500);

// Αρχικοποίησε τους χρόνους
prtime = time = glutGet(GLUT_ELAPSED_TIME);

// Αρχικοποίηση σκορ
score[0] = score[1] = 0;
}

/* κεντρική συνάρτηση */
int main(int argc, char *argv[])
{
// Αρχικοποίηση με double buffer, και χρώμα χωρίς διαφάνεια
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

// Άνοιγμα παραθύρου
glutInitWindowSize(Width, Height);
glutInitWindowPosition(150,50);
glutCreateWindow("Pong by kon_nos");

// Ορισμός της συνάρτησης εμφάνισης στην οθόνη
glutDisplayFunc(renderScene);

// Δήλωση συνάρτησης εισόδους του χρήστη
glutKeyboardFunc(keyPress);
// Δήλωση συνάρτησης εισόδους του χρήστη
glutSpecialFunc(specialKeyPress);

// Δεν υπάρχει περίπτωση να θέλουμε το συγκεκριμένο παιχνίδι να μην κάνει τίποτα.
glutIdleFunc(renderScene);

init();

glutMainLoop();

return 0;
}



Advertisements

Posted on 23 October, 2010, in Games, OpenGL and tagged , , . Bookmark the permalink. 2 Comments.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: