OPENGL ile PONG OYUNU

Aşağıdaki kod opengl ile programlanmış basit bir pong oyunudur. Bir ev ödevi olarak yazdığım bu program temel openGL fonksiyonlarını kullanır ve oyun fare ile oynanmaktadır.

Programı derlemek için komut satırına basitçe:

gcc assignment2.c -o assignment2 -I/usr/X11R6/include/ -L/usr/X11R6/lib -lGL -lGLU -lglut -lm

Yazmak yeterli olmaktadır. Ancak bunun için ilgili glu ve glut kütüphanelerinin sistemde kurulu olması gerekmektedir. Bunun için örneğin ubuntu'da Synaptik paket kurma yardımcısı ile freeglut3-dev gibi güncel openGL kod geliştirme kütüphanelerinin kurulması gerekmektedir. Program içerisinde yer alan bip sesini elde edebilmek için:

http://www.kodmanya.com/2009/11/c-ile-beep-bip-sesi-vermek.html


Linkindeki kodu da bu kodla aynı klasörde derlemek gerekmektedir.





/**********************************************************************
* By Şükrü OZAN sukruozan.at.gmail.com
**********************************************************************/
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>//time library inorder to use random function
#include <math.h>//math library inorder to use math functions

/*Definitipn of Pi*/
#define PI 3.14
/* ascii codes for various special keys */
#define ESC 27
/**********************************************************************
* Configuration
**********************************************************************/
#define INITIAL_X_POS 50
#define INITIAL_Y_POS 400
#define INITIAL_WIDTH 800
#define INITIAL_HEIGHT 600
#define MARGIN_SIZE 10
#define BORDER_SIZE 25
#define SCORE_BOARD_SIZE 30
#define PADDLE_LENGTH 140
#define BALL_SIZE 25
//#define BALL_STEP BALL_SIZE /* how far ball travels per time step */
#define WINDOW_NAME "PING-PONG"
/**********************************************************************
* Globals
**********************************************************************/
GLsizei window_width;
GLsizei window_height;

GLfloat initial_paddle_y_pos;
GLfloat initial_ball_x_pos;
GLfloat initial_ball_y_pos;
GLfloat initial_ball_trajectory;
GLfloat paddle_y_pos;
GLfloat ball_x_pos;
GLfloat ball_y_pos;
GLfloat ball_trajectory;
GLuint ball_delay = 30; /* time between ball position updates in msecs */
GLfloat ball_speed[2];//ball speed matrix,

/*Some Globally defined variables*/
float BALL_STEP=BALL_SIZE;
int game_over = 1;
int current_game = 0;
int left_button_state = GLUT_UP;
int left_button_lasty;
int lives=3;
int score=0;
float difficulty=1.0;
int diff_cntr=0;
char skor[30];
int ball_x,ball_y, paddle_y;
float trajectory;



/**********************************************************************
* Bitmap Font output
**********************************************************************/
void stroke_output(GLfloat x, GLfloat y, int scale, char *format,...)
{
va_list args;
char buffer[200], *p;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
glPushMatrix();
glTranslatef(x, y, 0);
glScalef(0.1*scale, 0.1*scale, 0.1*scale);
for (p = buffer; *p; p++)
glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
glPopMatrix();
}
/**********************************************************************
* Set the new size of the window
**********************************************************************/
void resize_scene(GLsizei width, GLsizei height)
{
glViewport(0, 0, width, height); /* reset the current viewport and
* perspective transformation */

window_width = width;
window_height = height;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* for the purposes of this assignment, we are making the world
* coordinate system have a 1-1 correspondence with screen space
* (in pixels). The origin maps to the lower-left corner of the screen.*/
glOrtho(0, width, 0, height, -1, 1);
glMatrixMode(GL_MODELVIEW);
}
/**********************************************************************
* The main drawing functions.
**********************************************************************/
void draw_border(void)
{
const GLfloat border = MARGIN_SIZE + BORDER_SIZE;

glBegin(GL_QUADS);
/* top bar */
glVertex3f(MARGIN_SIZE,(window_height-MARGIN_SIZE),0);
glVertex3f(MARGIN_SIZE,(window_height-border),0);
glVertex3f((window_width-MARGIN_SIZE),(window_height-border),0);
glVertex3f((window_width-MARGIN_SIZE),(window_height-MARGIN_SIZE),0);
/*left side bar */
glVertex3f(MARGIN_SIZE,(window_height-border),0);
glVertex3f(MARGIN_SIZE,border+SCORE_BOARD_SIZE,0);
glVertex3f(border,border+SCORE_BOARD_SIZE,0);
glVertex3f(border,(window_height-border),0);
/* bottom bar */
glVertex3f(MARGIN_SIZE,border+SCORE_BOARD_SIZE,0);
glVertex3f(MARGIN_SIZE,MARGIN_SIZE+SCORE_BOARD_SIZE,0);
glVertex3f((window_width-MARGIN_SIZE),MARGIN_SIZE+SCORE_BOARD_SIZE,0);
glVertex3f((window_width-MARGIN_SIZE),border+SCORE_BOARD_SIZE,0);
glEnd();
}

void draw_paddle(void)
{
const GLfloat xpos = window_width - (MARGIN_SIZE+3*BORDER_SIZE);
const GLfloat yoff = PADDLE_LENGTH / 2;
/* the paddle is always drawn at a fixed location within its own
* coordinate space. its actual world-space position is determined
* by the modelview matrix (as affected by any glTranslatef(), glRotatef(),
* or other function calls) */
glBegin(GL_QUADS);
glVertex3f(xpos,-yoff,0);
glVertex3f(xpos,yoff,0);
glVertex3f(xpos+BORDER_SIZE,yoff,0);
glVertex3f(xpos+BORDER_SIZE,-yoff,0);
glEnd();
}

void draw_ball(void)
{
/* the ball is always drawn at the origin of its own coordinate
* system. its real position in world-space is determined by the
* modelview matrix, just as with the paddle */
glBegin(GL_POINTS);
glVertex3f(0,0,0);
glEnd();
}
/*A function to write necessary thing on the game screen*/
void write_score(void)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glLineWidth(2.0);
glColor3f(1.0,0.0,1.0);

diff_cntr++;
if (diff_cntr<=1000) difficulty=1.0;
else if (diff_cntr<=2000) difficulty=1.25;
else if (diff_cntr<=3000) difficulty=1.50;
else if (diff_cntr<=4000) difficulty=1.75;
else if (diff_cntr<=5000) {difficulty=1.90;}
else diff_cntr=0;

BALL_STEP=BALL_SIZE*difficulty;

if (score<10) sprintf(skor,"SCORE:0000%d",score);
else if (score>=10 && score < 100 ) sprintf(skor,"SCORE:000%d",score);
else if (score>=100 && score < 1000 ) sprintf(skor,"SCORE:00%d",score);
else if (score>=1000 && score < 10000 ) sprintf(skor,"SCORE:0%d",score);
else if (score>=10000 && score < 100000 ) sprintf(skor,"SCORE:%d",score);


glColor3f(1.0,0.0,1.0);
stroke_output(10,10, 2,skor);
glColor3f(0.0,1.0,1.0);
sprintf(skor,"Lives Left:%d",lives-current_game);
stroke_output(250,10, 2,skor);
glColor3f(1.0,1.0,0.0);
sprintf(skor,"Difficulty Level:%d",1+(int)(diff_cntr/1000));
stroke_output(450,10, 2,skor);

if (lives==current_game)
{
glLineWidth(3.0);
glColor3f(1.0,0.0,0.0);
stroke_output(50,400, 7,"GAME OVER");
system("./beep 200 500");
}

glColor3f(1.0,1.0,1.0);
}



void draw_scene(void)
{
/* clear the screen and the depth buffer */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

/* reset modelview matrix */
glLoadIdentity();

/* draw the border */
draw_border();

/* draw the paddle */
glPushMatrix();
if (paddle_y_pos > (window_height-(MARGIN_SIZE+BORDER_SIZE+PADDLE_LENGTH/2)))
{
paddle_y_pos=(window_height-(MARGIN_SIZE+BORDER_SIZE+PADDLE_LENGTH/2));
}
else if (paddle_y_pos < (MARGIN_SIZE+BORDER_SIZE+PADDLE_LENGTH/2+SCORE_BOARD_SIZE))
{
paddle_y_pos=(MARGIN_SIZE+BORDER_SIZE+PADDLE_LENGTH/2+SCORE_BOARD_SIZE);
}
glTranslatef(0, paddle_y_pos, 0);
draw_paddle();
glPopMatrix();

/* draw the ball */
glPushMatrix();
glTranslatef(ball_x_pos, ball_y_pos, 0);
draw_ball();
glPopMatrix();

/* since this is double buffered, swap the
* buffers to display what just got drawn */
/* Put a text to screen */
write_score();

glutSwapBuffers();
}
/*Speed initialization part*/
void init_speed()
{
time_t seconds;
/*initialize speed*/
time(&seconds);
srand((unsigned int) seconds);
ball_speed[0]=cos(trajectory*PI/180);
ball_speed[1]=sin(trajectory*PI/180);
}

void move_ball(int game)
{
const GLfloat border = MARGIN_SIZE + BORDER_SIZE;
/* this allows a game reset in the middle of a game, since
* once a ball move timer function is registered on the old
* game, it cannot be cancelled */
if (game != current_game)
return;


//checking boundary conditions
if (ball_x_pos<=(border+(BALL_SIZE/2)))
{
system("./beep 2000 100");
ball_x_pos=border+(BALL_SIZE/2);
ball_speed[0]*=-1;
score++;
}//left
else if ((ball_x_pos>=window_width - (MARGIN_SIZE+3*BORDER_SIZE+(BALL_SIZE/2))) && (ball_y_pos > paddle_y_pos-(PADDLE_LENGTH/2) && ball_y_pos < paddle_y_pos+(PADDLE_LENGTH/2)))
{
system("./beep 3000 100");
ball_x_pos=window_width-(MARGIN_SIZE+3*BORDER_SIZE+(BALL_SIZE/2));
/*ball speed is modified when it hits the paddle (a random process)*/
if (ball_speed[0]<0) ball_speed[0]=((float)(5+rand()%5)/10);
else ball_speed[0]=-((float)(5+rand()%5)/10);
if (ball_speed[1]<0) ball_speed[1]=(-1)*sqrt(1.0-pow(ball_speed[0],2));
else ball_speed[1]=sqrt(1.0-pow(ball_speed[0],2));
score+=2;
}
else if (ball_x_pos>=window_width-(MARGIN_SIZE+2*BORDER_SIZE)+(BALL_SIZE/2))
{
system("./beep 500 200");
current_game++;
init_speed();
ball_x_pos = initial_ball_x_pos;
ball_y_pos = initial_ball_y_pos;
paddle_y_pos = initial_paddle_y_pos;
ball_trajectory = initial_ball_trajectory;
game_over = 1;
glutPostRedisplay();
}
else if (ball_y_pos>=(window_height-(border+(BALL_SIZE/2))))
{
system("./beep 1000 100");
ball_y_pos=(window_height-(border+(BALL_SIZE/2)));
ball_speed[1]*=-1;
score++;
}//top
else if (ball_y_pos<=(border+(BALL_SIZE/2)+SCORE_BOARD_SIZE))
{
system("./beep 1000 100");
ball_y_pos=(border+(BALL_SIZE/2)+SCORE_BOARD_SIZE);
ball_speed[1]*=-1;
score++;
}//bottom

/*ball position is modified according to the ball speed*/
ball_x_pos +=ball_speed[0]*BALL_STEP;
ball_y_pos +=ball_speed[1]*BALL_STEP;

if (!game_over) {
/* tell glut when next to update the ball's position */
glutTimerFunc(ball_delay, move_ball, current_game);
}
glutPostRedisplay();
}



/**********************************************************************
* BEWARE: in the following functions, y=0 is at the TOP of the screen,
* which is the exact opposite of our world which has y=0 at the
* bottom of the screen. It shouldn't matter much for the purposes of
* this assignment, but you have been warned.
**********************************************************************/

/**********************************************************************
* the function called whenever a normal key is pressed.
**********************************************************************/
void key_press(unsigned char key, int x, int y)
{
switch (key) {
case 's': /* start game */
if (game_over && lives>current_game) {
system("./beep 4000 100");
game_over = 0;
//current_game++;
move_ball(current_game);
}
break;
case 'r': /* reset game */
current_game=0;
lives=3;score=0;
game_over=0;
init_speed();
ball_x_pos = initial_ball_x_pos;
ball_y_pos = initial_ball_y_pos;
paddle_y_pos = initial_paddle_y_pos;
ball_trajectory = initial_ball_trajectory;
game_over = 1;
glutPostRedisplay();
break;
case ESC: /* exit the program...normal termination. */
exit(0);
}
}

/**********************************************************************
* this function is called whenever a mouse button is pressed and moved
**********************************************************************/
void handle_mouse_motion(int x, int y)
{
if (left_button_state == GLUT_DOWN) {
/* FIXME: make sure paddle does not go outside court! */
paddle_y_pos += left_button_lasty - y;
left_button_lasty = y;
glutPostRedisplay();
}
}

/**********************************************************************
* this function is called whenever a mouse button is pressed or released
**********************************************************************/
void handle_mouse_click(int btn, int state, int x, int y)
{
switch (btn) {
case GLUT_LEFT_BUTTON:
left_button_state = state;
left_button_lasty = y;
break;
}
}

int main(int argc, char **argv)
{
/*Program reads user input and exits if there is an error in the user input*/
if (argc != 5) {
fprintf (stderr, "Usage: beep <ball_x_position> <ball_y_position> <paddle_y_position> <trajectory>\n" );
exit (1);
}

ball_x = atoi (argv [1]);
if (ball_x > 700 || ball_x<100)
{
fprintf (stderr, "enter balls x position between 100 and 700\n" );
exit (1);
}

ball_y = atoi (argv [2]);
if (ball_y > 500 || ball_y<100)
{
fprintf (stderr, "enter balls y position between 100 and 500\n" );
exit (1);
}
paddle_y = atoi (argv [3]);
if (paddle_y > 500 || paddle_y<100)
{
fprintf (stderr, "enter balls y position between 100 and 500\n" );
exit (1);
}
trajectory=atof(argv[4]);
if (trajectory > 360.0 || trajectory < 0.0)
{
fprintf (stderr, "enter initial trajectory between 0 and 360\n" );
exit (1);
}
printf("%d %d %d %f\n",ball_x,ball_y,paddle_y,trajectory);

init_speed();
/* Initialize GLUT */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(INITIAL_WIDTH, INITIAL_HEIGHT);
glutInitWindowPosition(INITIAL_X_POS, INITIAL_Y_POS);
glutCreateWindow(WINDOW_NAME);
/* Register callback functions */
glutDisplayFunc(draw_scene);
glutReshapeFunc(resize_scene);
glutKeyboardFunc(key_press);
glutMouseFunc(handle_mouse_click);
glutMotionFunc(handle_mouse_motion);

/* Initialize GL */
glPointSize(BALL_SIZE);


paddle_y_pos = initial_paddle_y_pos = paddle_y;//INITIAL_HEIGHT / 2;
ball_x_pos = initial_ball_x_pos = ball_x;//INITIAL_WIDTH / 2;
ball_y_pos = initial_ball_y_pos = ball_y;//INITIAL_HEIGHT / 2;
ball_trajectory = initial_ball_trajectory = trajectory;

/* Enter event processing loop */
glutMainLoop();

return 1;
}

Comments

Popular posts from this blog

Latex'te Denklem İçerisine Ufak Boşluklar Koymak

LaTeX'te Sunum Hazırlamak

Octave'da Grafik Çizdirme