1) SDL (Simple DirectMedia Layer)-это свободная кроссплатформенная мультимедийная библиотека, реализующая единый программный интерфейс к графической подсистеме, звуковым устройствам и средствам ввода. Официально поддерживаются операционные системы: Linux, Windows, Windows CE, BeOS, Mac OS,*BSD, и т.д. Также, есть неофициальные поддержки AmigaOS, Dreamcast,Symbian OS и др. SDL API доступны для языков: C, C++,Vala, Erlang, Java, Lisp, Lua, Pascal, Python, Ruby и др. SDL создал Сэм Лантинга, будучи ведущим программистом компании Loki Entertainment Software. Работая над программой-эмулятором Macintosh для Microsoft Windows, он заметил, что многие куски кода без проблем могут работать на Linux. И он решил создать небольшую библиотеку, чтобы ей могли воспользоваться другие программисты - SDL распространяется под условиями лицензии GNU LGPL. В октябре 1997 был выпущен первый релиз версии 0.3, Позже, Loki Software вовсю использует эту библиотеку для портирования игр под Linux.
SDL можно рассматривать как тонкую прослойку, обеспечивающую поддержку для 2D-операций над пикселами, звука, доступа к файлам, обработки событий и т. п. Часто используется в дополнение к OpenGL.
SDL сам по себе довольно прост. Библиотека состоит из нескольких подсистем, таких как Video, Audio, CD-ROM, Joystick и Timer. В дополнение к этой базовой низкоуровневой функциональности, существует ряд стандартных библиотек, предоставляющих дополнительную функциональность:
SDL_image — поддержка различных растровых форматов
SDL_mixer — функции для организации сложного аудио, в основном, сведение звука из нескольких источников
SDL_net — поддержка сетевых функций
SDL_ttf — поддержка шрифтов TrueType
SDL_rtf — отрисовка текста в формате RTF
Оффициальный сайт библиотеки http://www.libsdl.org. Помимо самой библиотеки на сайте есть куча примеров и демонстрашек по использованию SDL.
2) OpenGL (Open Graphics Library — открытая графическая библиотека) — спецификация, определяющая независимый от языка программирования кросс-платформенный программный интерфейс для написания приложений, использующих двумерную и трёхмерную компьютерную графику. Включает более 250-ти функций для рисования сложных трёхмерных сцен из простых примитивов. Используется при создании компьютерных игр, САПР, виртуальной реальности, визуализации в научных исследованиях. На платформе Windows конкурирует с Direct3D.
Для создания простеньких 2д-игр можно использовать "сам по себе" - он быстр, не требует наличие видеодрайвера к видеокарте. Но количество возможностей работы с графикой сильно ограничены.В частности Мне не хватало возможности растянуть/сузить, увеличить/уменьшить, повернуть изображение. Этого можно было добится, подлючив дополнительные библиотеки, но тогда придется программе потребуются огромные вычислительные мощности на софтварный просчет, а следовательно - неизбежны тормоза. Потом, используя в качестве вывода графики не SDL а OpenGl, появляется возможность добавить к 2-ух мерной графике сложную 3-х мерную.
О использовании библиотеки SDL с OpenGL прекрасно расжевано во 2-ом номере электронного журнала LinGameTech (http://lingametech.com). В частности - вот в этом номере (2-ой) : http://lingametech.com/index.php?option=com_weblinks&task=view&catid=15&id=12
Также, по работе именно c библиотекой SDL были можно почитать в статьях журнала LinuxFormat, в номерах N98 (http://wiki.linuxformat.ru/index.php/LXF98:%D0%A1%D1%82%D1%80%D0%B5%D0%BB%D1%8F%D0%BB%D0%BA%D0%B0) и N103 (http://wiki.linuxformat.ru/index.php/LXF103:%D0%A1%D1%82%D1%80%D0%B5%D0%BB%D1%8F%D0%BB%D0%BA%D0%B0). Много информации о разработке игр в linux с ипользованием SDL можно найти на сайте http://plg.lrn.ru/, например - вики о SDL на русском языке: http://plg.lrn.ru/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0.
Я "учился" на статьях журанала LinuxFormat и на исходниках игрушки SDL-Ball (http://sdl-ball.sourceforge.net/) и какой-то там матери =)
Много от туда было позаимствовано:). И теперь, для того чтобы показать, как работать с этой связкой SDL+OpenGL в своих игровых проектах - я написал пример простенькой игры - понг:
http://narod.ru/disk/179861001/pong2.tar.gz.html.
Есть 2 ракетки - игрока и оппонента, также, есть мячик. Цель игры - набрать больше количество очков чем у оппонента, забивая голы и не давать забивать голы ему самому.
В статье я буду рассматривать в качестве операционной системы дистрибутив GNI/linux Ubuntu 10.04. Для компиляции и запуска примера необходимо установить следующие пакеты (должны быть в репозитории вашего дистрибутива):
libsdl-ttf2.0-0
libsdl-ttf2.0-dev
libsdl-mixer1.2
libsdl-mixer1.2-dev
libsdl-image1.2
libsdl-image1.2-dev
Возможно, имена пакетов от дистрибутива к дистрибутиву могут слегка изменятся.
Для компиляции в makefile манифесте добавляем библиотеки lGL, lGLU, lSDL_ttf, lSDL_image. он будет иметь следующий вид:
all:
gcc -o pong pong_adv.cpp `sdl-config --libs --cflags` -I/usr/include/GL -lGL -lGLU -lSDL_ttf -lSDL_imageДальше, разберем исходный код моего примера pong_adv.cpp:
//Одна из основных библиотек С
#include <iostream> //В исходный текст программы (pong_adv.cpp), соответственно, подключаем библиотеки: //библиотеки для работы с OpenGL #include <GL/gl.h> #include <GL/glu.h> //библиотеки SDL #include <SDL/SDL.h> #include <SDL/SDL_ttf.h> #include <SDL/SDL_image.h> //Введем следущие переменные для работы с SDL SDL_Surface *screen;//Экран - поверхность, некая 2d плоскость на которой будет происходить игровой действие //для управления клавиатурой вводим SDL_Event event;//для обработки событий, например на клавиатуре нажата клавиша Uint8* keys;//для определения того какая конкретно клавиша нажата using namespace std;//подключаем пространство имён стандартной библиотеки void randomize() { srand(time(NULL));//randomize;-включить счетчик случайных чисел <iostream.h> } int random(int i) { return rand()%i+1; } string IntToStr (int i)//перевод числа в строку-поправить { char buf[16]; snprintf(buf, sizeof(buf), "%i", i); return string(buf); } //1) Функция для инициализации OpenGL средствами SDL. bool init_sdl_opengl (int win_DX,//размеры экрана int win_DY, int pal,//палитра 16 или 32 разрадная int full_screen)//на полный =1 экран или в окне =0 { //Проверка на возможность инициализация видео при помощи SDL //Если чтото не получилось (например не поддерживается заданный видео режим), //то выводим причину сбоя и заканчиваем работу программы if (SDL_Init(SDL_INIT_VIDEO)!=0) { printf("Unable to initialize SDL: %s\n",SDL_GetError()); return false;//функция свою задачу не выполнила (ложь)
} //Иначе if (SDL_Init(SDL_INIT_VIDEO)==0) { //Включаем двойной буфер с OpenGL SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); //И инициализируем флаг SDL_OPENGL (который говорит о том что SDL использует OpenGL). if (full_screen==0)//если оконный режим {screen=SDL_SetVideoMode(win_DX,win_DY,pal,SDL_OPENGL|SDL_RESIZABLE);}//выводим окно OpenGl на "полный экран" if (full_screen==1)//если полноэкранный режим {screen=SDL_SetVideoMode(win_DX,win_DY,pal,SDL_OPENGL|SDL_FULLSCREEN|SDL_RESIZABLE);}//экран OpenGl в окне return true;//функция свою задачу выполнила (истина) } //Если не был установлен заданный видеорежим win_DX, win_DY, то выводим причину if (!screen) { printf("Unable to set video mode: %s\n",SDL_GetError()); return false;//функция свою задачу не выполнила (ложь) } } //2) Следующая процедура не обязательна, но полезна: она необходима //для перерисовки окна при изменении его габаритов win_DX и win_DY //(например в опциях игры). Для перерисовки экрана в новый размер //воспользуемся функцией glViewport //(http://opengl.gamedev.ru/doc/?func=glViewport), //glViewport - задает область просмотра. //При запуске программы в "оконном режиме", размеры такого окна можно //можно изменить при помощи мышки. //но выводимая область при этом останется без изменения. //Эта процедура позимствована из исходников игры sdl-ball. void resize_window (int win_DX, int win_DY) { GLfloat ratio;//соотношение win_DY/win_DY if (win_DY==0)//Защита от деления на ноль при win_DY=0 win_DY = 1; //В таком случае соотношение будет равно ratio = (GLfloat) win_DX / (GLfloat) win_DY; //Устанавливаем наш новый вьюпорт glViewport(0,0,(GLsizei) win_DX,(GLsizei) win_DY); //изменяем проекционные матрицы и устнавливаем видимый объем glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, ratio, 0.1f, 10.0f );//установка перспективы //Убеждаемся в том, что мы меняем вид модели, а не проекции (Make sure we're chaning the model view and not the projection) glMatrixMode(GL_MODELVIEW); glLoadIdentity();//перезагрузка вида } //3) Следущая функция нужна для нициализации 2д в OpenGl. //Для этого будет использована функция glOrtho //(http://www.gamedev.ru/articles/?id=20114): //glOrtho()-устанавливает режим ортогонального (прямоугольного) проецирования. //Это значит, что изображение будет рисоваться как в изометрии. 6 параметров //типа GLdouble (или просто double): left, right, bottom, top, near, far //определяют координаты соответственно левой, правой, нижней, верхней, ближней //и дальней плоскостей отсечения, т.е. всё, что окажется за этими пределами, //рисоваться не будет. На самом деле эта процедура просто устанавливает //масштабы координатных осей. void gl2dMode (int win_DX, int win_DY) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, win_DX, win_DY, 0, -1, 1 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } //4) Функция для загрузки текстуры из графического (jpg,png,bmp) //файла в переменную типа GLuint. Загрузка текстуры происходит с //линейной фильтрацией GL_LINEAR (пиксели текстуры "размываются"). //Эту функцию лучше применять в тех случаях, когда текстура исользуется //в качестве "тайлов" (элементов декораций уровня) или спрайтов с //незначительным содержанием "дырок в альфа канале". При использовании //линейной фильтрации Возможно появление артефактов на свободных участках //и по краям текстуры. Эту функцию желательно использовать при инициализации. bool load_LINEAR(string file, GLuint &tex) { SDL_Surface *temp = NULL;//временная SDL текстура GLint maxTexSize; GLuint glFormat = GL_RGBA;//по умолчанию, подразумеваем использование альфа канала в текстуре
//если файл изображения имеет расширению jpg, то альфа канал не используетсяif(file.substr(file.length()-3,3).compare("jpg") == 0)
{ glFormat = GL_RGB; } //загружаем изображение во временную SDL текстуру temp temp = IMG_Load(file.data()); //проверка 1 if(temp == NULL)//если изображение не удалось загрузить, то выводим причину { cout << "Apshipka managera textur: " << file << " : "<< SDL_GetError() << endl; SDL_FreeSurface(temp);//освобождаем память от временной SDL текстуры return false;//функция свою задачу не выполнила (ложь) } //проверка 2 - на превышение максимально допустимого размера текстуры SDL для использования ее в OpenGL glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); if(temp->w > maxTexSize)//если есть превышение, то функция не срабатывает и пишем сообщение об ошибке { cout << "Apshipka managera textur: " << file << " texturka velika i shiroka." << endl; SDL_FreeSurface(temp);//освобождаем память от временной SDL текстуры return false;//функция свою задачу выполнила (ложь) } //Если все проверки пройдены без проблем, то генерим текстуру с изображением из SDL текстуры temp glGenTextures(1, &tex);//создаем 1 OpenGL текстуру с именем tex glBindTexture(GL_TEXTURE_2D, tex); //передаем изображение из SDL текстуре temp текстуре tex glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_LINEAR задает линейную фильтрацию glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, temp->w, temp->h, 0, glFormat, GL_UNSIGNED_BYTE, temp->pixels); SDL_FreeSurface(temp);//освобождаем память от временной SDL текстуры return true;//функция свою задачу выполнила (истина) } //5) Следущая функция полностью аналогична предыдущей, за иключением того, //что изображение передается в текстуру без линейной фильтрации. //Как следствие, - в текстуре артефакты отсутствуют, //зато присутствует пикселизация при малой детализации исходного //изображения. В "своих" 2д играх Я исользую эту функцию и //для спрайтов, и для тайлов. bool load_NEAREST(string file, GLuint &tex) { SDL_Surface *temp = NULL;//временная SDL текстура GLint maxTexSize; GLuint glFormat = GL_RGBA;//по умолчанию, подразумеваем использование альфа канала в текстуре if(file.substr(file.length()-3,3).compare("jpg") == 0)//если изображение содержит расширению jpg - альфы нет { glFormat = GL_RGB; } //загружаем изображение во временную SDL текстуру temp temp = IMG_Load(file.data()); //проверка 1 if(temp == NULL)//если изображение не удалось загрузить, то выводим причину { cout << "Apshipka managera textur: " << file << " : "<< SDL_GetError() << endl; SDL_FreeSurface(temp);//освобождаем память от временной SDL текстуры return false;//функция свою задачу не выполнила (ложь) } //проверка 2 - напрвышает максимально допустимого размера SDL текстуры для использования ее в OpenGL glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); if(temp->w > maxTexSize)//если есть превышение, то функция не срабатывает и пишем сообщение об ошибке { cout << "Apshipka managera textur: " << file << " texturka velika i shiroka." << endl; SDL_FreeSurface(temp);//освобождаем память от временной SDL текстуры return false;//функция свою задачу не выполнила (ложь) } //Если все проверки пройдены без проблем, то генерим текстуру с изображением из SDL текстуры temp glGenTextures(1, &tex);//создаем 1 OpenGL текстуру с именем tex glBindTexture(GL_TEXTURE_2D, tex); //передаем изображение из SDL текстуре temp текстуре tex glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//GL_NEAREST - текстура загружается как есть glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//без фильтрации. Осторожно - пиксели! :) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, temp->w, temp->h, 0, glFormat, GL_UNSIGNED_BYTE, temp->pixels); SDL_FreeSurface(temp);//освобождаем память от временной SDL текстуры return true;//функция свою задачу выполнила (истина) } //Говорят, для текстур желательно использовать файлы с изображением размерами по //высоте и ширине равные 2 в степени n. Это связано с особенностями работы видеопамяти. //На видеокартах nvidia я глюков особо не замечал, но на видеокартах от Intel (встроенные) //"неправильные" изображения в текстуру просто не загружаются. Вместо спрайта //рисуется только залитый цветом полигон. //6) Процедура для отрисовки затекстурированного полигона в координатах x,y; //размером dX, dY; повернутом на delta градусов. относительно верхней левой точки, //либо - относительно центра. Эту процедуру удобно использовать для рисования фонов //или спрайтов/тайлов, текстура которых использует все исходное изображение целиком. void DrawTXT (float x, float y, float dX, float dY, float delta, int center) { glEnable(GL_TEXTURE_2D); glLoadIdentity(); glTranslatef(x,y,0);//задаем местоположение glRotatef(delta,0,0,-1);//поворачиваемся на delta градусов //Если поворот объекта происходит относительно его центра, то смещаем ось координат на 0.5dX и 0.5dY if (center==1) {glTranslatef(-dX/2,-dY/2,0);} //Рисуем затекстурированный полигон, текстурные координаты glTexCoord2i задаются в %/100 glBegin(GL_QUADS); glTexCoord2i(0,0); glVertex2f(0, 0 );// Верхний левый угол glTexCoord2i(0,1); glVertex2f(0, dY);//Нижний левый угол glTexCoord2i(1,1); glVertex2f(dX,dY);//Нижний правый угол glTexCoord2i(1,0); glVertex2f(dX,0 );//Верхний правый угол glEnd(); glLoadIdentity(); } //7) Процедура для рисования полигона с текстурой, взятой "кусочком" из другой //(исходной) текстуры. Как бы, вырезаем необходимый элемент из одного большого //изображения. Я использую эту процедуру для рисования анимированных спрайтов, //где каждый кадр для анимации берется из одного файла-картинки. void _DrawTXT (float W,//ширина большой текстуры, в пикселях float H,//высота большой текстуры, в пикселях float t_x,//координаты верхнего левого угла "кусочка" float t_y,//в большой текстуре, в пикселях float t_dx,//размер вырезаемого "кусочка", в пикселях float t_dy, float x,//аналогично предыдущей процедуре float y, float dX, float dY, float delta, int center) { glEnable(GL_TEXTURE_2D); glLoadIdentity(); glTranslatef(x,y,0); glRotatef(delta,0,0,-1); if (center==1) {glTranslatef(-dX/2,-dY/2,0);}//смещаем по центре glBegin(GL_QUADS); glTexCoord2f((t_x/W),(t_y/H)); glVertex2f(0, 0); //Верхний левый угол glTexCoord2f((t_x/W),((t_y+t_dy)/H)); glVertex2f(0, dY);//Нижний левый угол glTexCoord2f(((t_x+t_dx)/W),((t_y+t_dy)/H)); glVertex2f(dX,dY);//Нижний правый угол glTexCoord2f(((t_x+t_dx)/W),(t_y/H)); glVertex2f(dX, 0);//Верхний правый угол glEnd(); glLoadIdentity(); } //Так как для текстур нужны изображения "правильных размеров" (2 в степени n, см.выше), //лучше всего использовать _DrawTXT если текстура "не квадратная". //8) Для создания надписей, необходимо сначало создать текстовую текстуру. //Следущая процедура этим и занимается. Сперто из исходников sdl-bаll и не //совсем допилена, но как-то работает. В общем, здесь без подробных комментариев:) void GlTxt(int sdl_dx,//координаты int sdl_dy, TTF_Font *font, SDL_Color textColor, const char text[], GLuint texture) { SDL_Surface *temp,*tempb; int w,h; Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif if(font == NULL) { cout << SDL_GetError() << endl;; SDL_FreeSurface(temp); SDL_FreeSurface(tempb); } temp = TTF_RenderText_Blended(font, text, textColor); SDL_SetAlpha(temp, 0, 0); tempb = SDL_CreateRGBSurface(0, sdl_dx, sdl_dy, 32, rmask,gmask,bmask,amask); TTF_SizeUTF8(font,text, &w,&h); SDL_Rect src,dst; src.x=0; src.y=0; src.w=sdl_dx;//w; - криво но работает src.h=sdl_dy;//h; dst.x=0; dst.y=0; dst.w=sdl_dx;//w; dst.h=sdl_dy;//h; SDL_BlitSurface(temp, &src, tempb, &dst); glBindTexture(GL_TEXTURE_2D, texture); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tempb->w, tempb->h, GL_RGBA, GL_UNSIGNED_BYTE, tempb->pixels); SDL_FreeSurface(temp); SDL_FreeSurface(tempb); } //9) Теперь, напишем процедуру, которая использует предыдущую (8) для вывода текста //на экран. Текст будет выводится, как полигон с нанесенной на него текстовой текстурой. //Все входные параметры аналогичны DrawTXT, за исключением: fonts - используемый фонт и //text - сам выводимый текст. void DrawText(float x, float y, float dX, float dY, TTF_Font *fonts,//используемый *.ttf фонт string text,//сам выводимый текст float delta, int center) { SDL_Color txtColorWhite = {255,255,255};//цвет текста, по умолчанию - белый //Если нужно использовать другой цвет для текста, то лучше окрашивать "текстовый полигон" //перед его выводом на экран (см.ниже) GLuint t_txt;//временная текстовая текстура glGenTextures(1, &t_txt);//генерим текстовую текстуру GlTxt(dX, dY, fonts, txtColorWhite, text.c_str(), t_txt); //Рисуем полигон с текстовой текстурой glBindTexture( GL_TEXTURE_2D, t_txt); DrawTXT(x, y, dX, dY, delta, center); glDeleteTextures(1, &t_txt);//удаляем использованную текстуру } //Для рисования "хвоста" из системы частиц подключаем этот модуль, //в данном примере - особо не нужен. #include "effects.h" //Если проводить анологию с "паскалем", то эта функция, как-бы, главный "BEGIN" int main() { //Задаем основные переменные int win_DX=1024,//параметры экрана, размеры в пикселях win_DY=768, pal=32,//палитра в битах full_screen=0,//программу запускаем в окне done=0;//отвечает за окончание работы основного цикла программы //Создаем окно init_sdl_opengl(win_DX,win_DY,pal,full_screen); resize_window(win_DX,win_DY); //Текст в загаловке окна и текст отображаемый в панеле SDL_WM_SetCaption("Pong title window","pong - example"); //Иконка приложения (в опенбоксе не отображается) SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"),NULL); //Инициализируем 2д gl2dMode(win_DX,win_DY); //Задаем цвет заднего фона (R,G,B,alpha) - черный glClearColor(0,0,0,0); //Включаем режим текстурирования glEnable(GL_TEXTURE_2D); //Включаем использование "альфа-канала" glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); //Инициируем и загружаем шрифт TTF_Init(); TTF_Font *fonts; fonts = TTF_OpenFont("font1.ttf", win_DY/16);//открываем фонт //Включаем счетчик случайных чисел randomize(); Init_Flame();//Инициализируем систему частиц, необязательная часть программы //Отсюда начинается сама игра //Задаем переменные float player_x,player_y,//координаты игрока player_dx,player_dy,//габариты игрока player_a,//шаг игрока при передвижении по оси х enemy_x,enemy_y,//все тоже самое для оппонента enemy_dx,enemy_dy, enemy_a, ball_x,ball_y,//координаты мячика ball_dx,ball_dy,//габариты мячика ball_a,ball_b,//шаг при перемещении мячика по осям x и y ball_vector,ball_teta,//полярные координаты вектор направления движения и угол ball_delta;//угол вращения мячика вокруг своей оси int player_score,enemy_score;//очки, соответственно игрока и оппонента //Текстуры GLuint back,//задний фон sprite;//спрайты //Загрузка текстур load_LINEAR("back.jpg", back);//задний фон load_LINEAR("spr.png", sprite);//игрове спрайты //Значения переменных при старте программы для игрока //Размеры задаются в относительных величинах для того чтобы масштабироваться при //различных размерах окна win_DX, win_DY. По умолчанию, размеры win_DX=1024, //win_DY=768 player_x=win_DX/2;//=512 player_y=win_DY-win_DY/10; player_dx=win_DX/6.83;//=150; player_dy=win_DY/25.6;//=30; player_a=win_DX/341.3;//=3; player_score=0; //Для оппонента enemy_x=win_DX/2;//=512 enemy_y=0+win_DY/10; enemy_dx=win_DX/6.83;//=150; enemy_dy=win_DY/25.6;//=30; enemy_a=win_DX/512;//=2; enemy_score=0; //Для мячика ball_x=win_DX/2;//=512 ball_y=win_DY/2;//=512 ball_dx=win_DX/40.96;//=25 ball_dy=win_DY/30.72;//=25 ball_vector=random(7);//скорость перемещения мячика вдоль вектора направления движения ball_teta=random(360)*(1)*(3.142/180);//угол движения в градусах if (ball_teta==0) {ball_teta=1;} //Преобразование полярных координат в соответствующие проекции на оси x и y ball_a=ball_vector*cos(ball_teta); ball_b=ball_vector*sin(ball_teta); ball_delta=0; //Начинается главный цикл программы, за выход из него отвечает переменная done while(done == 0) { //Обрабатываем события while(SDL_PollEvent(&event)) { //Если пвыходим из SDL то по происходит закрытие всей программы (при нажатии на кнопку закрытия окна тоже самое) if (event.type==SDL_QUIT) {done=1;} //Если единичный случай нажатия на клавиатуру if (event.type==SDL_KEYDOWN) { //Выход из программы по нажатию кнопки ESC if (event.key.keysym.sym==SDLK_ESCAPE) {done=1;} } }//конец обработки событий //Управление с клавиатуры игроком. Учитывается постоянное удержание кнопок, //а не единичное нажатие keys = SDL_GetKeyState(NULL); if (keys[SDLK_LEFT]) {player_x=player_x-player_a;}//перемещение игрока влево if (keys[SDLK_RIGHT]) {player_x=player_x+player_a;}//перемещение игрока вправо //Ограничение на перемещение игрока и оппонента внури экрана if (player_x>=win_DX-0.7*player_dx) {player_x=win_DX-0.7*player_dx;} if (player_x<0+0.7*player_dx) {player_x=0+0.7*player_dx;} if (enemy_x>=win_DX-0.7*enemy_dx) {enemy_x=win_DX-0.7*enemy_dx;} if (enemy_x<0+0.7*enemy_dx) {enemy_x=0+0.7*enemy_dx;} //"АИ оппонента"-ракетка оппонента стремится отразить удар, бегая за мячом if (ball_x>enemy_x) {enemy_x=enemy_x+enemy_a;} if (ball_x<enemy_x) {enemy_x=enemy_x-enemy_a;} //Мячик движется в 2д плоскоти, благодаря изменению 2-х координат ball_x=ball_x+ball_a; ball_y=ball_y+ball_b; //Мячик крутится вокруг своей оси ball_delta=ball_delta+5; if (ball_delta>=360) {ball_delta=0;} //Мячик отскакивает от боковых стенок-проверка осуществляеться только по оси X if (ball_x>win_DX-0.5*ball_dy or ball_x<0+0.5*ball_dy) { ball_a=-ball_a;//изменяем шаг передвижения на противоположный } //Если мячик вылетает верх или низ экрана - значит ктото комуто забил гол if (ball_y>win_DY-0.5*ball_dy or ball_y<0+0.5*ball_dy) { //В зависимости кто кому забил гол, тому начисляются очки //Если это низ экрана, то очко зарабатывает опонент if (ball_y>win_DY-0.5*ball_dy) {enemy_score=enemy_score+1;} //Если это верх экрана - то игрок. if (ball_y<0+0.5*ball_dy) {player_score=player_score+1;} //И мячик респавнится с параметрами как при старте ball_x=win_DX/2; ball_y=win_DY/2; ball_dx=win_DX/40.96;//25 ball_dy=win_DY/30.72;//25 ball_vector=random(7);//скорость перемещения мячика вдоль вектора направления движения ball_teta=random(360)*(1)*(3.142/180);//угол движения в градусах if (ball_teta==0) {ball_teta=1;} //Преобразование полярных координат в соответствующие проекции на оси x и y ball_a=ball_vector*cos(ball_teta); ball_b=ball_vector*sin(ball_teta); ball_delta=0; } //Взаимодействие мячика с ракеткой игрока //Простое отражение от верхней центральной части ракетки и if (player_x-0.4*player_dx<ball_x+0.5*ball_dx and player_x+0.4*player_dx>ball_x-0.5*ball_dx and player_y-0.5*player_dy<ball_y+0.5*ball_dy and player_y+0.5*player_dy>ball_y-0.5*ball_dy) { ball_b=-ball_b; //Симуляция передачи импульса мячику, если игрок движется if (keys[SDLK_LEFT]) {ball_a=ball_a-0.5*player_a;} if (keys[SDLK_RIGHT]) {ball_a=ball_a+0.5*player_a;} } //Отражение от левого бока ракетки if (ball_a>0 and ball_x+0.5*ball_dx>player_x-0.6*player_dx and ball_x+0.5*ball_dx<player_x-0.4*player_dx and ball_y+0.5*ball_dy>player_y-0.5*player_dy and ball_y-0.5*ball_dy<player_y+0.5*player_dy) { ball_a=-ball_a; } //Отражение от правого бока ракетки if (ball_a<0 and ball_x-0.5*ball_dx<player_x+0.6*player_dx and ball_x-0.5*ball_dx>player_x+0.4*player_dx and ball_y+0.5*ball_dy>player_y-0.5*player_dy and ball_y-0.5*ball_dy<player_y+0.5*player_dy) { ball_a=-ball_a; } //Аналогично записываем взаимодействие мячика с ракеткой оппонента //Простое отражение if (enemy_x-0.4*enemy_dx<ball_x+0.5*ball_dx and enemy_x+0.4*enemy_dx>ball_x-0.5*ball_dx and enemy_y-0.5*enemy_dy<ball_y+0.5*ball_dy and enemy_y+0.5*enemy_dy>ball_y-0.5*ball_dy) {ball_b=-ball_b;} //Отражение о левого бока ракетки if (ball_a>0 and ball_x+0.5*ball_dx>enemy_x-0.6*enemy_dx and ball_x+0.5*ball_dx<enemy_x-0.4*enemy_dx and ball_y+0.5*ball_dy>enemy_y-0.5*enemy_dy and ball_y-0.5*ball_dy<enemy_y+0.5*enemy_dy) {ball_a=-ball_a;} //Отражение о правого бока ракетки if (ball_a<0 and ball_x-0.5*ball_dx<enemy_x+0.6*enemy_dx and ball_x-0.5*ball_dx>enemy_x+0.4*enemy_dx and ball_y+0.5*ball_dy>enemy_y-0.5*enemy_dy and ball_y-0.5*ball_dy<enemy_y+0.5*enemy_dy) {ball_a=-ball_a;} //Рисуем задний фон glColor4f(1,1,1,1); glBindTexture(GL_TEXTURE_2D,back);//glBindTexture устанавливает соответствующую текстуру DrawTXT(0,0,win_DX,win_DY,0,0); //Выводим набранные очки в верхнем левом углу экрана glColor4f(0,0,1,1);//рисуем текст синим цветом DrawText(0,//x 0,//y win_DX/8,//dX win_DY/16,//dY fonts,//font IntToStr(player_score)+":"+IntToStr(enemy_score), 0,//delta 0);//center glColor4f(1,1,1,1); //Рисуем мячик glColor4f(1,1,1,1); glBindTexture(GL_TEXTURE_2D,sprite); _DrawTXT(256, 256, 1, 1, 100, 100, ball_x, ball_y, ball_dx, ball_dy, ball_delta,1); glColor4f(1,1,1,1); //Рисуем ракетку игрока одним цетом glColor4f(0,1,1,1); glBindTexture(GL_TEXTURE_2D,sprite); _DrawTXT(256, 256, 0, 103, 150, 30, player_x, player_y, player_dx, player_dy, 0,1); glColor4f(1,1,1,1); //Рисуем ракетку оппонента другим цветом glColor4f(1,0,1,1); glBindTexture(GL_TEXTURE_2D,sprite); _DrawTXT(256, 256, 0, 103, 150, 30, enemy_x, enemy_y, enemy_dx, enemy_dy, 0,1); glColor4f(1,1,1,1); //Рисуем огненный след от мяча. Необязательная часть программы - понты:) //----// Draw_Flame(win_DX, win_DY, 60,//flame_kolvo ball_x,//X, ball_y,//Y, 0.0007,//flame_A 4,//flame_B 7,//flame_C 3, //flame_D 0.000004,//flame_E 0.003,//flame_F 0.0029,//flame_G 0.15,//flame_H 0.15,//flame_I 3,//flame_J 0.01,//x_amp 6,//y_amp 0.07,//y_n 230,// flame_init_life, 100,// flame_init_life_rnd, 0.8,//+0.3*temp_c,//c_R 0.1,//c_G 0.8,//c_B 1, 1);//изменения в c_G glColor4f(1,1,1,1); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); //----// //Задержка, если не обходима //SDL_Delay(10); SDL_GL_SwapBuffers();//Обновляем экран } //Отключаем SDL по окончанию работы SDL_Quit(); }
В итоге:
Для создания окна размерами win_DX, win_DY, с иконкой и надписями средствами SDL и OpenGL в нашей игре достаточно написать:
//Создаем окно init_sdl_opengl(win_DX,win_DY,pal,full_screen); resize_window(win_DX,win_DY); //Текст в загаловке окна и текст отображаемый в панеле SDL_WM_SetCaption("Pong title window","pong - example"); //Иконка приложения (в опенбоксе не отображается) SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"),NULL);
Если, заметили какие-либо ошибки, пожалуйста - дайте мне знать))
using namespace std;
ОтветитьУдалитьподключает пространство имён стандартной библиотеки.
вообще-то хватило бы просто using std::string, using std::cout, using std::endl. Чуть быстрее бы компилялось и вообще не комильфо строка "using namespace std". В цпп не так и страшно, главное, что бы в хедерах не было этого.
Для перевода строки в число можно было i/o streams использовать.
//экран OpenGl на полный экран
//При запуске программы в оконном режиме -окно можно мышкой растягивать мышкой,
//если изображение содержит расширению jpg - альфы нет
return 0;//и функция возвращает 0 (ложь), т.е функцию свою задачу выполнить не может
return 1;//и функция возвращает 1 (истина), т.е функцию свою задачу выполнла
return false/true; и нафиг коммент с implicit cast левым
//проверка 2 - напрвышает максимально допустимого размера SDL текстуры для использования ее в OpenGL
//Если поворот происходит относительно центре, то смещаемся еще немного на 0.5dX b 0.5dY
//Отражение о праого бока ракетки
Ну и ещё отступы поправить, местами просто жесть :)
Хоть на вкус и цвет фломастеры разные, лично мне, не совсем этот стиль отступов нравится.
Плюс всякие магические числа можно было бы и убрать.
Запятых там доброй дюжины не хватает, но я уже забил на это дело.
elfenlaid, спасибо. поправил :)
ОтветитьУдалитьКак выводить true type кирилицу этой связкой?
ОтветитьУдалить