Список використаних джерел
-
Бьерн Страуструп. Язык программирования С++.[Текст] Специальное издание - «Бином», ISBN 5-7989-0226-2, 5-7940-0064-3, 0-201-70073-5; 2008 г – 1054 с.
-
Уроки по opengl от NeHe. [Електронний ресурс]. Режим доступу: http://pmg.org.ru/nehe/
-
Электронное пособие по С++ . [Електронний ресурс]. Режим доступу: http://valera.asf.ru/cpp/book/
-
Центр разработки на Visual C++. [Електронний ресурс]. Режим доступу: http://msdn.microsoft.com/ru-ru/
Додаток а
Зміст файлу classes.h:
#include <gl\glut.h> //основная библиотека opengl
#include <glaux.h>
#pragma comment(lib, "glaux.lib") //библиотека требуемая для отрисовки битмапа
#include <time.h>
#include <Windows.h>
#include <iostream>
using namespace std;
const float pi=3.141592653589793238;
float bs=2; //BLOCKSIZE
const float wheight=500, wwidth=500; //WINDOW SIZE
const float ortho=50; //размер окна
const int roadwidth=30, exrand=roadwidth-bs*6; //левая и правая стенки
const int wallwidth=10; //ширина стенки 5 блоков 5*2=10
const int playercolor=8; //цвет машинки игрока
bool crashblink=false, goblink=true;
float foncolor[3]={0.5, 0.5, 1}; //цвет фона
int car_i=0, go_i=0; //перменные требуемые для моргания при аварии
//----------------CLASSES------------------------------
class Tshape
{
public:
float x, y;
int color;
void switch_color(int scolor) //метод смены цвета
{
switch(scolor)
{
case -2: glColor3f(0.19215686, 0.60784314, 0.8705882); break; //фон меню голубой
case -1: glColor3f(0.5, 0.5, 1); break; //лиловый ФОН
case 0: glColor3f(0,0,0); break; //черный
case 1: glColor3f(1,0,0); break; //красный
case 2: glColor3f(0,1,0); break; //зеленый
case 3: glColor3f(0,0,1); break; //синий
case 7: glColor3f(1,1,0); break; //желтый
case 8: glColor3f(1,0.5,0); break; //оранжевый
case 9: glColor3f(0.5,0.25,0); break; //коричневый
case 21: glColor3f(0,0.2,0); break; //темно-зеленый
}
}
};
class Tblock: virtual public Tshape //квадратик
{
public:
void block(); // рисуем квадратик
};
class car: public Tblock //машинка
{
public:
float cx, cy, ccolor;
bool crash, godmode;
car(float, float, int, bool, bool); //отрисовует машинку
~car(void); //закрашивает машинку
//void car();
};
class grass: public Tblock
{
public:
float gwidth, gm;
grass(float, float);
~grass (void);
};
class wall: public Tblock
{
public:
float wy;
float wx;
int wpos;
int wcolor;
wall(float, int, int);
~wall(void);
};
class game_over: public Tblock
{
public:
float gox, goy;
int ocolor;
game_over(float, float, int);
~game_over(void) {};
};
class text: virtual public Tshape
{
public:
const char* itext;
void drawtext(const char*, int, float, float);
void hidetext();
};
class Tmenu: public Tblock, public text
{
public:
bool selection;
void show();
void draw_select(bool);
};
//------------------FUNCTIONS---------------------
void Tblock::block()
{
switch_color(color);
glBegin(GL_QUADS);
glVertex2f(x-bs/2, y+bs/2);
glVertex2f(x-bs/2, y-bs/2); //рисует прямоугольник
glVertex2f(x+bs/2, y-bs/2);
glVertex2f(x+bs/2, y+bs/2);
glEnd();
switch_color(0);
glBegin(GL_LINE_LOOP);
glVertex2f(x-bs/2, y+bs/2-0.1);
glVertex2f(x-bs/2, y-bs/2-0.1); //рисует черный ободок
glVertex2f(x+bs/2, y-bs/2);
glVertex2f(x+bs/2, y+bs/2);
glEnd();
switch_color(color);
}
//------CAR------------------
car::car(float _cx, float _cy, int _ccolor, bool _crash, bool _godmode): cx(_cx), cy(_cy), ccolor(_ccolor), crash(_crash), godmode(_godmode)
{
color=ccolor;
if(crash==true) {
switch(crashblink) //моргание машинки при аварии
{
case true: { color=0; car_i++; if(car_i==15) { crashblink=false; car_i=0;} break; }
case false: { color=1; car_i++; if(car_i==15) { crashblink=true; car_i=0;} break; }
}
}
if(godmode==true) bs=3; //увеличение размера блока если включен полет
x=cx;
y=cy;
//----
block();
//----
y=cy+bs;
block();
x=cx-bs;
block();
x=cx+bs;
block();
x=cx;
//----
y=cy+2*bs;
block();
//------
y=cy-bs;
block();
x=cx-bs;
block();
x=cx+bs;
block();
x=cx;
y=cy;
}
//===========
car::~car() //закрашиваем машинку прямоугольником цвета фона
{
glColor3f(foncolor[0], foncolor[1], foncolor[2]);
glBegin(GL_QUADS);
glVertex2f(cx-1.6*bs, cy+2.6*bs);
glVertex2f(cx-1.6*bs, cy-1.6*bs);
glVertex2f(cx+1.6*bs, cy-1.6*bs);
glVertex2f(cx+1.6*bs, cy+2.6*bs);
glEnd();
if(godmode==true) bs=2; //возвращаем размер блока в начальное положение
}
//----GRASS----
grass::grass(float _gwidth=0.0, float _gm=0.0): gwidth(_gwidth), gm(_gm)
{
x=gwidth/2;
bool k=true;
for(y=-ortho-bs/2+gm; y<=ortho+bs; y+=bs)
{
switch(k) //смена цвета блока через один
{
case true: color=2; k=false; break;
case false: color=21; k=true; break;
}
block(); //рисуем справа от центра
x=-x; //отражаем Х
block(); //рисуем слева от центра
x=-x; //отражаем Х обратно
}
}
grass::~grass() {
glColor3f(foncolor[0], foncolor[1], foncolor[2]);
x=gwidth/2;
glBegin(GL_QUADS);
glVertex2f(x-0.6*bs, +ortho);
glVertex2f(x-0.6*bs, -ortho);
glVertex2f(x+0.6*bs, -ortho);
glVertex2f(x+0.6*bs, +ortho);
glEnd();
x=-gwidth/2;
glBegin(GL_QUADS);
glVertex2f(x-0.6*bs, +ortho);
glVertex2f(x-0.6*bs, -ortho);
glVertex2f(x+0.6*bs, -ortho);
glVertex2f(x+0.6*bs, +ortho);
glEnd();
}
//----WALL---- рисуем стенку
wall::wall(float _wy, int _wpos, int _wcolor): wy(_wy), wpos(_wpos), wcolor(_wcolor) {
color=wcolor;
y=wy;
switch(wpos) //устанавливаем координаты по Х в зависимости от положения стенки (слева или справа)
{
case 0: wx=-roadwidth/2+wallwidth/2+bs/2; break;
case 1: wx=roadwidth/2-wallwidth/2-bs/2; break;
}
for(x=wx-wallwidth/2+bs/2; x<=wx+wallwidth/2-bs/2; x+=bs) block(); //ставим 5 блоков
}
wall::~wall() {
glColor3f(foncolor[0], foncolor[1], foncolor[2]);
glBegin(GL_QUADS); //закрашиваем стенку прямоугольником цвета фона
glVertex2f(wx-wallwidth/2-1, wy+0.6*bs);
glVertex2f(wx-wallwidth/2-1, wy-0.6*bs);
glVertex2f(wx+wallwidth/2+1, wy-0.6*bs);
glVertex2f(wx+wallwidth/2+1, wy+0.6*bs);
glEnd();
}
//-----GAME OVER-----
game_over::game_over(float _gox, float _goy, int _ocolor): gox(_gox), goy(_goy), ocolor(_ocolor) {
switch(goblink) //изменяем цвет каждые 15 отрисовок (черный/красный) так дистигается эффект моргания
{
case true: { color=0; go_i++; if(go_i==15) { goblink=false; go_i=0;} break; }
case false: { color=1; go_i++; if(go_i==15) { goblink=true; go_i=0;} break; }
}
int i;
//===== G ===== //устанавливаем координатые блоков, чтобы получилась надпись GAME OVER
int gx[12]={-42, -42, -42, -40, -40, -38, -38, -36, -36, -36, -34, -34 };
int gy[12]={2, 4, 6, 0, 8, 0, 8, 0, 4, 8, 2, 4 };
for (i=0; i<12; i++) { x=gox+gx[i]; y=goy+gy[i]; block(); }
//===== A ======
int ax[10]={-30, -30, -30, -30, -28, -28, -26, -26, -26, -26};
int ay[10]={0, 2, 4, 6, 4, 8, 0, 2, 4, 6};
for (i=0; i<10; i++) { x=gox+ax[i]; y=goy+ay[i]; block(); }
//==== M ======
int mx[13]={-22, -22, -22, -22, -22, -20, -18, -16, -14, -14, -14, -14, -14} ;
int my[13]={0, 2, 4, 6, 8, 6, 4, 6, 0, 2, 4, 6, 8};
for (i=0; i<13; i++) { x=gox+mx[i]; y=goy+my[i]; block(); }
//==== E ======
int ex[14]={-10, -10, -10, -10, -10, -8, -8, -8, -6, -6, -6, -4, -4, -4};
int ey[14]={0, 2, 4, 6, 8, 0, 4, 8, 0, 4, 8, 0, 4, 8};
for (i=0; i<14; i++) { x=gox+ex[i]; y=goy+ey[i]; block(); }
//==== O =====
int ox[12]={2, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 10};
int oy[12]={2, 4, 6, 0, 8, 0, 8, 0, 8, 2, 4, 6};
for (i=0; i<12; i++) { x=gox+ox[i]; y=goy+oy[i]; block(); }
//==== V ====
int vx[9]={14, 14, 16, 16, 18, 20, 20, 22, 22};
int vy[9]={6, 8, 2, 4, 0, 2, 4, 6, 8};
for (i=0; i<9; i++) { x=gox+vx[i]; y=goy+vy[i]; block(); }
//==== E ====
for (i=0; i<14; i++) { x=gox+ex[i]+36; y=goy+ey[i]; block(); }
//==== R ====
int rx[12]={36, 36, 36, 36, 36, 38, 38, 40, 40, 40, 42, 42};
int ry[12]={0, 2, 4, 6, 8, 4, 8, 2, 4, 8, 0, 6};
for (i=0; i<14; i++) { x=gox+rx[i]; y=goy+ry[i]; block(); }
}
//------TEXT------
void text::drawtext(const char* ftext, int _color, float _x, float _y)
{ //метод выводящий текст на экран
x=_x; y=_y; color=_color; itext=ftext;
switch_color(color);
std::string stext;
stext=itext;
int length=stext.size();
glRasterPos2i(x,y);
for(int i=0; i<=length; i++) glutBitmapCharacter(GLUT_BITMAP_9_BY_15, (int)stext.data()[i]);
}
void text::hidetext()
{ //закрашивает текст полигоном в виде шестиугольника
switch_color(7);
glBegin(GL_POLYGON);
glVertex2f(x-0.5, y-0.5);
glVertex2f(x-3.5, y+1.4);
glVertex2f(x-0.5, y+2.5);
glVertex2f(x+23, y+2.5);
glVertex2f(x+26, y+1.4);
glVertex2f(x+23, y-0.5);
glEnd();
}
//--------- MENU -------------
void Tmenu::show() {
x=-49;
y=49;
for(int i=1; i<=2500; i++) //рисует 2500 блоков рандомного цвета на фоне
{
color=(rand()%10)-1;
block();
x+=2;
if(x>50) {x=-49; y-=2;}
}
AUX_RGBImageRec* image; //создаем битмап
image=auxDIBImageLoad("name.bmp"); //полгружаем в него картинку
glRasterPos2d(-30,22); //выбираем место для отрисовки (координаты левого нижнего угла)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, 1.0); //утсанавливаем масштаб
glDrawPixels(image->sizeX, image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image->data); //отрисовуем массив пикселей
image=auxDIBImageLoad("controls.bmp");
glRasterPos2d(-46,-46);
glDrawPixels(image->sizeX, image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image->data);
image=auxDIBImageLoad("menu.bmp");
glRasterPos2d(-26,-30);
glDrawPixels(image->sizeX, image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image->data);
draw_select(true);
}
void Tmenu::draw_select(bool _selection)
{
selection=_selection;
switch(selection) //рисуем подчеркивания в меню
{
case true:
switch_color(-2);
glBegin(GL_QUADS);
glVertex2f(-11, -18);
glVertex2f(-11, -19);
glVertex2f(9, -19);
glVertex2f(9, -18);
glEnd();
switch_color(1);
glBegin(GL_QUADS);
glVertex2f(-20, -5);
glVertex2f(-20, -6);
glVertex2f(20, -6);
glVertex2f(20, -5);
glEnd();
break;
case false:
switch_color(-2);
glBegin(GL_QUADS);
glVertex2f(-20, -5);
glVertex2f(-20, -6);
glVertex2f(20, -6);
glVertex2f(20, -5);
glEnd();
switch_color(1);
glBegin(GL_QUADS);
glVertex2f(-11, -18);
glVertex2f(-11, -19);
glVertex2f(9, -19);
glVertex2f(9, -18);
glEnd();
break;
}
glFlush();
}
Зміст файлу 1.cpp:
#include "classes.h"
long gtc=GetTickCount();
float x, y=-45, m=bs/2, ey=ortho+bs*3, ex=((gtc%(exrand*66+1))/66)-exrand/2, wy=1.5*ortho;
int wpos=gtc%2;
bool godmode=false;
float score_point_float=0;
char score_point_char[30];
grass gr(roadwidth, m);
car player(x, -45, 1, false, false);
car enemy(ex, ey, 1, false, false); //инициализируем обьекты классов с началным положением
wall wa(wy, wpos, 9);
text score;
Tmenu menu;
bool gameover=false;
bool enemycrash=false;
bool KeyDown[256] = {false}; //массив для нажатых кнопочек
int firststart=0;
AUX_RGBImageRec* control; //битмап для картинки
void display() //основная функция отрисовки происходящего
{
if(firststart<5) //первые пять отрисовок чистим экран, позволяет избравиться от некоторых глюков на медленных компьюетрах
{
glClear(GL_COLOR_BUFFER_BIT);
firststart++;
}
wa.~wall();
enemy.~car();
player.~car(); //зарисовуем объекты
gr.~grass();
score.hidetext();
wall wa(wy, wpos, 9); //рисуем стену
grass gr(roadwidth, m); //траву
car enemy(ex, ey, 7, enemycrash, false); //вражескую машинку
score.drawtext(score_point_char , 1, -45, 45); //выводим очки
car player(x, y, playercolor, gameover, godmode); //рисуем нашу машинку
glFlush(); //и наконец выводим всё из буфера на экран
}
void display_over() //функция отрисовки при прогрыше
{
game_over o(0, 0, 1); //рисуем надпись гейм овер
o.~game_over(); //просто используем деструктор для экономии ресурсов
glRasterPos2d(-46,-46); //рисуем помощь об управлении
glDrawPixels(control->sizeX, control->sizeY, GL_RGB, GL_UNSIGNED_BYTE, control->data);
glFlush(); //выводим все из буфера на экран
}
void timer(int=0) //функция-таймер
{
if(gameover==false)
{
if(m==-8) m=0; //зациклим движение травы
m-=1.6; //двигаем траву
if(ey<-ortho-bs*3) //если вражеская машинка уехала за экран создадим новую
{
ey=-ey+5*bs;
gtc=GetTickCount();
ex=((gtc%(exrand*66+1))/66)-exrand/2;
enemycrash=false;
}
if(enemycrash==false) ey-=1.2; //двигаем вражескую машинку
else ey-=1.6;
if(wy<-ortho-bs*3) //если стенка уехала за экран создадим новую
{
wy=-wy;
gtc=GetTickCount();
wpos=gtc%2;
}
wy-=1.6; //двигаем стенку
if(godmode==false) score_point_float+=0.2; //прибавляем очки
else score_point_float-=1; //отнимаем если игрок летит, притом в 5 раз бстрее
sprintf(score_point_char, "SCORE: %.0f", score_point_float); //конвертируем очки в char
if(KeyDown['a']==true && x>-roadwidth/2+bs*2.5) x-=0.8; //двигаем машинку в зависимости от нажатых кнопок
if(KeyDown['d']==true && x<roadwidth/2-bs*2.5) x+=0.8;
if(KeyDown['w']==true && y<ortho-bs*3) y+=0.6;
if(KeyDown['s']==true && y>-ortho+bs*2.5) y-=0.6;
display(); //отрисовуем
//проверяем на столкновения себя и врага
if(godmode==false) if((wpos==0 && wy>y-2*bs && wy<y+3*bs+0.2 && -roadwidth/2+wallwidth/2+bs/2>x-4*bs && -roadwidth/2+wallwidth/2+bs/2<x+4*bs) || (wpos==1 && wy>y-2*bs && wy<y+3*bs+0.2 && roadwidth/2-wallwidth/2-bs/2>x-4*bs && roadwidth/2-wallwidth/2-bs/2<x+4*bs) || (ey>(y-4*bs) && ey<(y+4*bs+0.2) && ex>(x-3*bs) && ex<(x+3*bs))) gameover=true;
if((wpos==0 && wy>ey-2*bs && wy<ey+3*bs+0.2 && -roadwidth/2+wallwidth/2+bs/2>ex-4*bs && -roadwidth/2+wallwidth/2+bs/2<ex+4*bs) || (wpos==1 && wy>ey-2*bs && wy<ey+3*bs+0.2 && roadwidth/2-wallwidth/2-bs/2>ex-4*bs && roadwidth/2-wallwidth/2-bs/2<ex+4*bs)) enemycrash=true;
}
else //gameover
{
display_over(); //отрисовуем проигрыш
if(KeyDown['r']==true) //делаем рестарт при нажатии R
{
x=0;
y=-45;
m=bs/2;
ey=ortho+bs*3;
gtc=GetTickCount();
ex=((gtc%(exrand*66+1))/66)-exrand/2; wy=1.5*ortho;
score_point_float=0;
KeyDown['r']=false; //"отжимаем" кнопку
gameover=false;
glClear(GL_COLOR_BUFFER_BIT); //чистим экран
}
}
if(KeyDown['f']==true) glutTimerFunc(10, timer, 0); //ускоряем таймер при нажатой F
else glutTimerFunc(20, timer, 0);
}
void Keyboard(unsigned char key, int _x, int _y) //проверяем нажатие кнопок
{
if(key!='r')
{
KeyDown[key] = true; //и вносим в булевый массив значения нажатых кнопок
if(KeyDown['e']==true) godmode=true;
}
else if(gameover==true) KeyDown[key] = true;
}
void KeyboardUp(unsigned char key, int _x, int _y)
{
if(key!='r')
{
KeyDown[key] = false; //"отжимаем кнопки"
if(KeyDown['e']==false) godmode=false;
}
}
void menu_select(bool select)
{
if(select==true) //начинаем игру при выборе NEW GAME
{
glutKeyboardFunc(Keyboard);
glutKeyboardUpFunc(KeyboardUp);
glutIgnoreKeyRepeat(true);
firststart=true;
glutDisplayFunc(display_over);
glutDisplayFunc(display); //вызов функции Дисплей
timer();
}
else //либо вызодим при выборе EXIT
{
exit(0);
}
}
void MKeyboard(unsigned char key, int _x, int _y) //проверяем нажатые кнопки в меню
{
if(key==13) menu_select(menu.selection);
}
void SKeyboard(int key, int x, int y) //проверяем нажатые кнопки в меню
{
if(key==GLUT_KEY_UP || key==GLUT_KEY_DOWN)
{
switch(menu.selection)
{
case true: menu.draw_select(false); break;
case false: menu.draw_select(true); break;
}
}
}
void draw_menu() //отрисовуем меню
{
menu.show();
glutSpecialFunc(SKeyboard); //регистрируем функции мониторящие клавиатуру
glutKeyboardFunc(MKeyboard);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //выбираем режим отображеия, у нас одинарная буферизация и 3 цвета
glutInitWindowSize(wwidth, wheight); //размер окна
glutCreateWindow("SQ CaRs"); //инициализируем окошко
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glClearColor(foncolor[0], foncolor[1], foncolor[2], 1.0); //цвет фона
glOrtho(-ortho, ortho, -ortho, ortho, -0.5, 0.5); //размеры окон
FreeConsole(); //убираем консоль
glutDisplayFunc(draw_menu); //вызов функции draw_menu
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
control=auxDIBImageLoad("controls.bmp"); //хагружаем в битмап картинку
glutMainLoop();
}