Всем привет! Что-то последнее время много уроков по конструкторам игр, и не так много по различным языкам программирования. Что бы устранить эту не справедливость, я решил запилить урок по OpenGL C++, надеюсь вы оцените)
Сразу же перейдем к геймдеву и будем писать маленькую игрульку нашего детства.
Для начала подключаем библиотеку OpenGL к своей среде разработки, я лично программирую в Microsoft Visual Studio 2013.
Код
#include "stdafx.h" #include <GL/glut.h> #include <time.h> #include <random> #include <iostream> // подключаем все необходимые инклюды.
int N = 30, M = 20; // т.к. змейка будем ездить по квадратикам, создадим их, для нашего окна в идеале будет 30x20 квадратов int scale = 25; // размер квадрата. Когда OpenGL будет расчерчивать поле для игры, расстояние между гранями квадрата будет 25 пикселей
int w = scale*N; // ширина поля int h = scale*M; // его высота
int dir, num = 4; // 4 направления и начальный размер змеи. struct { int x; int y; } s[100]; // структура змеи, X и Y координаты, массив с длинной.
class fruct // класс фруктов, тех самых, которые будет есть наша змея { public: int x, y; //координаты фруктов, что и где будет находится
void New() // паблик с новыми фруктами. Он будет вызываться в начале игры и в тот момент, когда змея съест один из фруктов { x = rand() % N; // вычисление X координаты через рандом y = rand() % M; // вычисление Y координаты через рандом }
void DrawFruct() // паблик, отрисовывающий фрукты { glColor3f(0.0, 1.0, 1.0); // цвет фруктов. в openGL он задается от 0 до 1, а не от 0 до 256, как многие привыкли glRectf(x*scale, y*scale, (x + 1)*scale, (y + 1)*scale); // "Закрашиваем" квадрат выбранным цветом, таким образом в нем "появляется" фрукт } } m[5]; // масив с фруктами, таким образом, у нас появится одновременно 5 фруктов в разных местах, а не один, как мы привыкли <img src="http://s27.ucoz.net/sm/1/smile.gif" border="0" align="absmiddle" alt="smile" />
void Draw() // функция, которая отрисовывает линии { glColor3f(1.0, 0.0, 0.0); // цвет наших линий, в данном слуае - красный glBegin(GL_LINES); // начинаем рисовать и указываем, что это линии for (int i = 0; i < w; i+= scale) // отрисовываем линии в ширину { glVertex2f(i, 0); glVertex2f(i, h); // рисуем прямую } for (int j = 0; j < h; j += scale) //отрисовываем линии в высоту { glVertex2f(0, j); glVertex2f(w, j); // рисуем ту же самую прямую, но в другом направлении }
glEnd(); // конец отрисовки }
void tick() // функция в которой будет все обновляться (двигаться змея и т.д.) { for (int i = num; i > 0; --i) // движение змеи. Система остроумна и проста : блок перемешается вперед, а остальные X блоков, на X+1( 2 блок встанет на место 1, 3 на место 2 и т.д...) { s[i].x = s[i - 1].x; // задаем Х координату i блока координатой i - 1 s[i].y = s[i - 1].y; // то же самое делаем и с Y координатой } // далее у нас система направлений. if (dir == 0) s[0].y += 1; // если направление равно 0, то первый фрагмент массива перемещается на один по Y if (dir == 1) s[0].x -= 1; // если направление равно 1, то первый фрагмент массива перемещается на минус один по X if (dir == 2) s[0].x += 1; // аналогиная система if (dir == 3) s[0].y -= 1; // аналогичная система
for (int i = 0; i < 10; i++) //цикл, в котором наша змея будет расти { if ((s[0].x == m[i].x) && (s[0].y == m[i].y)) // Если голова нашей змеи находится в одном блоке с фруктом, то... { num++; //...увеличиваем размер нашей змеи на 1 m[i].New(); // ... запускаем функцию отрисовки нового фрукта. } } // Следующее нужно, что бы змея не выходила за рамка поля. Действует это просто : если змея выходит за рамки поля, то задаем if (s[0].x > N) dir = 1; // Ей обратное направление. Например, если она выйдет за экран по высоте, то задаем ей направление, при котором она ползет if (s[0].y > M) dir = 3; // вниз if (s[0].x < 0) dir = 2; if (s[0].y < 0) dir = 0;
for (int i = 1; i < num; i++) // с помощью этого цикла мы "обрежем" змею, если она заползет сама на себя if (s[0].x == s[i].x && s[0].y == s[i].y) // проверка координат частей змеи, если X и Y координата головной части равно координате любого num = i; // другого блока змеи, то задаем ей длину, при которой "откушенная" часть отпадает. }
void Snake() // выводим змейку на экран { glColor3f(0.1, 1.0, 0.0); //цвет змеи for (int i = 0; i < num; i++) // цикл отрисовки. { glRectf(s[i].x*scale, s[i].y*scale, (s[i].x + 0.9)*scale, (s[i].y + 0.9)*scale); //Рисуем квадраты, те самые "блоки" змеи } }
void Key(int key, int a, int b) // функция нажатия клавиш { switch (key) // используем оператор switch { case 101: dir = 0; break; // при нажатии клавиш, задаем направление змеи(вверх, вниз, влево, вправо) case 102: dir = 2; break; case 100: dir = 1; break; case 103: dir = 3; break; } }
void Display() //функция общий отрисовки { glClear(GL_COLOR_BUFFER_BIT); // очищаем окно перед началом отрисовки
Draw(); // вызов функции Draw, отвечающей за отрисовку фруктов Snake(); // вызов функции Snake, отвечающей за отрисовку змейки
for (int i = 0; i < 5; i++) // заполнение карты фруктами m[i].DrawFruct();
glFlush(); // выводим на экран все вышеописанное glutSwapBuffers(); }
void timer(int = 0) // Таймер игры(промежуток времени, в котором будет производится все процессы) { Display(); // Вызов функций tick(); glutTimerFunc(100, timer, 0); // новый вызов таймера( 100 - промежуток времени(в милисекундах), через который он будет вызыватся, timer - вызываемый паблик) }
int main(int argc, char **argv) // Главная функция { std::cout << "Snake by Alexey Ovchinnikov :P\n Loading..."; // крутой текст в консоле при загрузке srand(time(0)); for (int i = 0; i<10; i++) // начальная, самая первая отрисовка фруктов m[i].New();
s[0].x = 10; // начальное положение змейки по X s[0].y = 10; // и Y координате // следующие функции абсолютно идиентичных почти во всех программах на OpenGL, так то запоминать их не обязательно, кроме ... glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(w, h); // ... этой, она создаем окно (w - ширина, h - высота) glutCreateWindow("Game"); // ... этой, она задает название окна glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, 640, 0, 480); glutDisplayFunc (Display); // ... и этой, она вызывает начальную функцию, в нашем случае это главная функция отрисовки - Display glutSpecialFunc(Key); glutTimerFunc(50, timer, 0); // ... Ну и в начале программы задаем рекурсивный таймер. glutMainLoop();
return 0; }
И так, на этом все, запускаем, играем. Постарался объяснить максимально понятно, если будут вопросы - задавайте. P.S. И пожалуйста, не кидайтесь тапками если что-то не понятно или не так написал, первый урок в моей жизни.
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «[OpenGL С++] Пишем змейку на C++», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.