Сегодня у вас на компьютере появится новая игра, которую вы сами и сделаете. В прошлый раз мы нарисовали линию (был простой статический рисунок). Но в любой игре должна быть анимация. Для анимации нам нужно использовать двойную буферизацию (о том, что это такое, писалось раньше). Вы, конечно, можете попробовать написать игру и с одиночным буфером (очень даже красиво получается :-)).

В этой статье мы научимся рисовать сферы (это будет наш мячик), четырехугольники (ракетки), обрабатывать клавиатуру (нам же нужно как-то управлять ракетками), ну и еще некоторые мелочи. Но обо всем по порядку. Итак, начнем с сфер. Для рисования сферы нам нужно создать объект типа GLUquadricObj с помощью функции gluNewQuadric. Сама функция для создания сферы выглядит так:

gluSphere(quadObj, 0.5, 10, 10);

Где quadObj — это указатель на объект типа GLUquadricObj. 2-й параметр — это радиус сферы, а два последних параметра — число разбиений вокруг оси Z и число разбиений вдоль оси Z (ведь все сложные фигуры состоят из более простых, вроде точек, линий, треугольников). Чем большее будет разбиение, тем лучше будут выглядеть фигуры, но тем сложнее компьютеру будет нарисовать эту фигуру, соответственно, и картинка будет притормаживать при анимации.

Давайте сейчас разберем нашу функцию main(), которая теперь намного жирнее, чем была в предыдущий раз (ведь она уже готова для игры). Посмотрим на код:

#include #include #include #include int main(int argv, char **argc) { float pos[4] = {-1,-1,1}; //указываем источник света {x,y,z} float dir[3] = {-1,-1,-1}; //указываем направление света (луч, который выходит из точки pos[4] и направлен к точке dir[3] //Инициализация glutInit(&argv,argc); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); //здесь мы уже используем двойную буферизацию, а также буфер глубины (Z-буфер). glutInitWindowPosition(10,10); glutInitWindowSize(780,500); glutCreateWindow("MyComputer game"); glClearColor(0.2,0.3,0.5,1); //Определиение функций glutDisplayFunc(Display); //Отображение glutReshapeFunc(Reshape); //Изменение окна glutKeyboardFunc(Keyboard); //Обработка клавиатуры glutIdleFunc(Display); //Обработка простоя //Настройка параметров glEnable(GL_DEPTH_TEST); //включить Z буфер glEnable(GL_COLOR_MATERIAL); //отображение цвета материалов glEnable(GL_LIGHTING); //включаем освещение glEnable(GL_LIGHT0); //включаем источник света ///настройка освещения glLightfv(GL_LIGHT0, GL_POSITION, pos); //позиция источника света glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir); //направление луча света glutMainLoop(); return 0; }

Здесь должно быть все понятно. Теперь давайте займемся рисованием наших ракеток. Для этого мы будем использовать функцию auxSolidBox(int w,int h,1); из библиотеки GLAUX, где int w — это ширина коробки, int h — ее высота. Итак, напишем функцию для отображения наших ракеток, но вначале в самом верху программы (после всех #include) определим все переменные:

double bw=0.5, bh=2, left=-4.7, bottom=-4.5, right=4.7, top=4.5, bitaStep=0.8, stepX=0.09, stepY=0.04, rocket_y1=0, rocket_y2, x=0, y=0;

Все просто и по существу: bw —ширина ракетки, bh — высота ракетки, left — левый край окна, bottom — низ окна, right — правый край окна, top — верх окна, bitaStep — шаг ракетки (при нажатии на клавишу ракетка перемещается на данный промежуток), StepY, StepX — шаг мячика по оси X и Y (при большем числе скорость шарика будет быстрее), rocket_y1, rocket_y2 — положение 1-й и 2-й ракетки, x, y — координаты мячика.

Отображение ракеток:

void DrawBita1() { glPushMatrix(); //сохраняем текующие координаты glColor3d(1,1,1); glTranslated(left,rocket_y1,0); //переходим в левый край экрана auxSolidBox(bw,bh,1); glPopMatrix(); //возвращаемся к старым координатам }

Все объекты рисуются с точки (0,0), но иногда нам нужно нарисовать фигуру с другой точки — для этого мы должны перейти к новым координатам с помощью функции glTranslated(x,y,z). Но перед этим нужно сохранить информацию о старых координатах с помощью функции glPushMatrix(). Наконец, после всех операций над данным объектом вам нужно вернуться к старой системе координат с помощью функции glPopMatrix().

Аналогично рисуем вторую ракетку:

void DrawBita2() { glPushMatrix(); //сохраняем текующие координаты glColor3d(1,1,1); glTranslated(right,rocket_y2,0); auxSolidBox(bw,bh,1); glPopMatrix(); //возвращаемся к старым координатам }

Теперь научимся обрабатывать клавиатуру. Для этого мы напишем функцию Keyboard(unsigned char key, int x, int y), где key — это нажатая клавиша, а x, y — положение мышки. Наша функция выглядит так:

void Keyboard(unsigned char key, int x, int y) { //Управление левой ракетки if (key=='a'){ //если нажата клавиша а if ((rocket_y1+rocket_y1/2)>=top) //если координаты ракетки выходят за верхний край экрана… rocket_y1=top-rocket_y1/2; //…тогда ракетку не двигать вверх rocket_y1+=bitaStep; //иначе — поднять ракетку вверх } if (key=='z'){ //если нажата клавиша z if ((rocket_y1+rocket_y1/2)<=bottom) //то же самое, только вниз rocket_y1=bottom-rocket_y1/2; rocket_y1-=bitaStep; } //Управление правой ракетки if (key=='k'){ //если нажата клавиша k if ((rocket_y2+rocket_y2/2)>=top) //аналогично rocket_y2=top-rocket_y2/2; rocket_y2+=bitaStep; } if (key=='m'){ //если нажата клавиша m if ((rocket_y2+rocket_y2/2)<=bottom) //все аналогично, как для правой ракетки rocket_y2=bottom-rocket_y2/2; rocket_y2-=bitaStep; } }

Теперь нам осталось написать функцию для вычисления координат мячика (мячик ведь будет все время летать по экрану), а также функцию рисования самого мячика. Ниже написана функция для вычисления координат мячика:

int Kik2() //отбился ли мячик от правой ракетки { if(y>rocket_y2-1.5 && yrocket_y1-1.5 && ytop || y=4.3 && Kik2()==1){ //Если мячик долетел до правой границы, проверяем, попал ли он на ракетку stepX=-stepX; //шаг делаем в противоположную сторону } if (x<=-4.3 && Kik1()==1) //Если до левой границы долетел… { stepX=-stepX; //…шаг делаем в противоположную сторону } }

А теперь рисуем сам мячик:

void DrawBall() { GLUquadricObj *qobj; //смотрите выше, как рисуется сфера qobj=gluNewQuadric(); glPushMatrix(); //сохраняем координаты glColor3d(0.2,0.8,0.5); //цвет мячика glTranslated(x,y,0); //сдвигаем его по оси x,y gluSphere(qobj,0.5,20,20); //мячик с радиусом 0,5 glPopMatrix(); //возвращаемся к старым координатам }

И последнее: давайте напишем маленькую функцию Display().

void Display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //закрашиваем фон DrawBita1(); //рисуем 1-ю ракетку DrawBita2(); //рисуем 2-ю ракетку GetXY(); //вычисляем координаты мячика DrawBall(); //рисуем сам мячик glutSwapBuffers(); //Меняем буфера местами }

Теперь откомпилируем код, и… наконец-то у нас получилась игра! :-)