![]() |
Модераторы: Rickert |
![]() ![]() ![]() |
|
Rickert |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() Ситхи не пройдут! ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3356 Регистрация: 11.7.2006 Где: Лакрима Репутация: 6 Всего: 52 |
После длительного застоя, за который я прошу прощения, мы продолжаем. Заправляйтесь хорошенько, сегодняшний перелёт обещает быть длинным:
Строим кузню для ковки нашего Глемдринга Сейчас мы создадим рабочее место для нашего движка: чтобы было удобно тестить и дебажить. Сначала сформируем дерево каталогов. Выберете себе место на диске, где будет заложен наш проект. В этой папке сгенерируйте след. каталоги: 0) inc - тут будут лежать все заголовочные файлы проектов. 1) out - сюда будет бросаться результат всей компиляции. 2) libs - здесь все скомпилированные библиотеки залегать будут. 3) library - тут проекты всех библиотек. 4) prj - здесь проекты, которые будут использовать ту, или иную часть движка. Что за библиотеки? Мы разобьём весь движок на составные части: класс общего назначения, классы системного типа, классы работы с геометрией, классы работы с миром и объектами. Ну и там ещё по ходу дела будем добавлять другие ![]() Moving on! Итак, у вас на руках запущенный Visual Studio (далее VS): 0) File -> New -> Project. 1) Project types: Other project types -> Visual Studio Solutions -> Blank Solution. Имя указываем любое, а местоположение солюшена - наша папка/library. 2) Создаём в солюшене разделы(Add -> New Solution Folder): Projects, Library. В первом будут лежать проекты, которые юзают наш двигл, а во втором сам двигл. 3) Теперь в solution explorer добавляем Add -> New Project... 4) Visual C++ -> Win32 application. Местоположение наша папка/library, имя doCommon. 5) В выпавших предварительных параметрах создаваемого проекта выбираем Static Library и снимаем галку с Precompiled header. 6) Вот у нас девственный проект, который мы сразу же перетаскиваем в раздел Library. 7) Идём в наша папка/library/doCommon и создаём тама папку cpp Этот проект будет содержать в себе классы общего назначения: aAux, aVector, aString, aList. Что мы сейчас делаем? Помните, в первой части я говорил что мы будем держать заголовочные файлы в папке inc, а файлы описаний в cpp? Сейчас возьмите заголовочные файлы перечисленных выше классов и перетащите их в наша папка/inc, а файлы описания в наша папка/library/doCommon/cpp. Вернитесь в VS, и в проекте doCommon создаёте подпапки, каждая из которых будет носить название класса: aAux, aList и т.п. В каждую из этих папок добавьте файл описания и файл реализации соответствующего класса. 8) Последний шаг - это создание файла, который бы позволял нормально работать с нашей либой. Добавляем новый заголовочный файл doCommon.h, в проект, ложем его в наша папка/inc. Тело у него примерно такое:
Теперь, если мы захотим использовать один из наших классов, нам нужно будет подключить эту библиотеку для проекта. Дальше маза: оттопырить водолаза! 0) Заходим в свойства пока единственного проекта: Configuration Properties -> Librarian -> General. 1) Значение Output file меняем на ..\..\libs\$(ProjectName).lib. Ах да, не забывайте переключить Configuration с Active(Debug) на All Configurations. 2) Теперь попробуйте скомпилировать... 3) Упс? 4) Или не упс? 5) Если 3 - то всё нормально и вам самостоятельно надо только правильно подправить пути в файлах описаний к файлам заголовочным каждого класса. 6) Если 4 - то вы уже это сделали сразу. Молоток! Теперь что получается? Вся вторичная хренотень лежит у нас в папке с проектом, а чистая откомпиленая статик либа в наша папка/libs Самоё время её по-пежить! Давайте добавим тестовый консольный проект, который будет первым, кто начнёт юзать начало фундамента нашего "движка". 0) В раздел солюшена Projects добавляем консольный Win32 проект, все настройки при создании как обычно, акромя пути куда его ложить: наша папка/prj 1) В папке проекта заводим также папку cpp, куда добавляем файл описания, где будет лежать код консольного приложения. 2) Тыкаем правой кнопкой на нашем консольном проекте в "solution explorer" и "Set as StartUp Project" - теперь, при запуске нашего солюшена (например, по F5) будет стартовать консольное приложение. 3) В том же "solution explorer" правой кнопкой по опять консольному проекту и "Project Dependencies..." - тут ставим галку на нашем "doCommon". Таким образом мы установили зависимость нашего консольного проекта от проекта "doCommon". Зачем? Затем что это определяет последовательность компиляции и теперь VS знает, что сначала надо будет собрать "doCommon", а уже затем консольный проект. И соответственно, если появятся изменения в "doCommon", то он пересоберёт и консольный проект. 4) Идём свойства консольного проекта Configurations properties -> Linker -> General -> Output File меняем на ..\..\out\$(ProjectName).exe. Да, и не забываем переключить Configuration с Active(Debug) на All Configurations. Теперь идём в наш консольный проект, в его ед. файл описания и заносим исходный код:
Аминь! Всегда помните!
Далее мы будем всё делать на основе этого солюшена и именно таким образом. Разберитесь со всем! Что непонятно - спрашивайте! Начнём с профилей игроков. Частенько за одной машиной играет несколько человек и у каждого, конечно, свои настройки управления, графики, звука. Лично меня всегда накаляли игры, где не было возможности хоть как-то быстро сохранять/загружать настройки, а приходилось после брата всё перенастраивать. Поэтому наша задача в данный момент написать класс, который по сути был бы контейнером всех системных параметров/настроек клавиатуры/мыши. В идеале он все данные будет получать из файлов, которые будут лежать в определённой папке, но на данный момент мы создадим некоторый набор минимума, чтобы просто инжектить класс в нашу работу, а уже потом мочь наращивать мясо на его костях. aProfile.h
Это перечисление содержит набор действий, которые будут вешаться на клавиши. Сейчас мы их использовать не будем, но когда прикрутим камеру, то обязательно найдём им применение ![]()
Класс клавиши, чтобы хранить какой кнопе какое действие соответствует.
Основной класс профиля. “caption” – ник игрока Единственную фукнцию опишем далее, в реализации aProfile.cpp:
Ну тут думаю всё ясно: “key ” параметр – это код клавиши, на которую будет повешено дейсвтие “act”.
Тут тупо проверяем какая клавиша сейчас нажата и возвращаем результат. Чем плох такой метод? Медленный и + если вешать его на событие окна «нажатие клавиши», то тут больше одной клавиши за раз не нажмёшь. Один из тех самых «черновых» моментов.
Очень сложный код, подумайте над ним… Системный синглтон для связи окна и OGL контекста Сейчас набросаем основной системный класс, который завяжет настройки текущего профиля (изначально единственного) и настройки OpenGL + будет ответственный за все основные события: типа отрисовки сцены, обработки надавливания кнопок и прочего… Задание: Помните как мы создали статик либу doCommon.lib ? Вернитесь, перечитайте и добавьте новый проект библиотеки под названием doSystem – тут у нас будут все классы, так сказать «системного назначения». Добавляем туда след. файл, не забываем делить файлы на папки. Поехали - aSystem.h
Подрубаем необходимые библиотеки + пару наших. Заводим опеределение для “SYS”: так проще работать с синглтоном. Задание: Вернитесь к описанию класса aAux и заведите такой же define для него.
Если функция должна возвращать что-то, то все значения должны описываться через опред. перечисление.
Кто не работал с графикой, некоторые переменные не знает. Пока забейте, сейчас будем проводить инициализацию – я всё раскажу подробно. По идее теперь надо было бы дать описание aSystem.cpp, но на этот раз я сначала опишу другой файл. Рожаем окно. 0) Итак, пришло время добавить в наш солюшен второй проект, который будет пежить движок (первым был тестовый - консольный). Добавялем в подраздел Projects - win32 Application. В параметрах создания выбираем Empty Project. 1) Теперь сделаем этот проект стартовым. 2) Далее тыкаем на нашем консольном проекте правой кнопкой и выбираем пункт меня Unload Project. Таким образом проект остаётся включёным в слюшен, но никак не участвует в компиляции – не нужен нам лишний баласт. 3) В папке вновь созданного проекта добавляем файл описания. Этот самый файл будет содержать инициализацию окна, основной рабочий цикл. По-сути он будет единственным файлом, и он же будет брать всё из движка, поэтому мы не будем создавать папку cpp, а запишем файл main.cpp прямо в папку с проектом win32 Application, который только что создали. 4) Конечно название может быть любым. 5) Пристегнитесь, взлетаем main.cpp:
Подключили файл библиотеки, которого ещё не создали. Создадим, не торопитесь компилить ![]()
Эта функция принимает и обрабатывает все приходящие окну сообщения. Первый параметр функции – хэндл окна, второй – само сообщение, ну и собственно два параметра этого сообщения. Далее идёт заведение переменной PixelFormat – Задание: глянуть в msdn по функции ChosePixelFormat и понять что же это такое. Затем мы заполняем структуру дескриптора для нашего OpenGL контекста отображения. Так же поройтесь и разберитесь что это такое!
Наше первое сообщение. Как ясно из названия: сообщение создания окна.
Далее идёт самая заглавная функция. Аля int main() в консольных приложениях. Начало конца короче 8)
Как вы думаете есть ошибки? Наверное - есть ![]() Вы уже порядочно утомились и хотите увидеть уже хоть что-нибудь, я прав? Вот сейчас мы создадим последний класс описания, который пропсутили и будет вам ваша маленькая вселенная, где вы сможете сотворить всё, aSystem.cpp (незабываем куда его надо ложить!):
Угол обзора. Представьте что ваши глаза – это вершина пирамиды, идущая от вас и основание которой лежит параллельно плоскости экрана. Так вот fov – это угол расхождения граней от вершины к основанию, которые характеризуют области видимости камеры.
В OpenGL есть две плоскости параллельные вашему экрану, которые ограничивают сцену. За ними ничего нет, есть только то, что между ними. Переменная nearClip – задаёт расстояние между ближней плоскостью отсечения и камерой, а farClip – далней и камерой.
После каждого кадра нам нужно отчищать буферы, коих несколько. Тут мы указываем, что сейчас будем отчищать буфер цвета (по сути сбрасывать всё что нарисованно) и буфер глубины.
Инициализация OpenGL. Разрешаем тест глубины, чтобы OpenGL мог оценить: какой объект ближе, а какой дальше. Включаем возможность использования текстур. И делаем точки сглаженными (будут выглядить как круглешки. Создаёт доп. нагрузку, но зато прикольно. Пусть пока будет: потом отключем 8))
Вся наша геометрия будет выводи ться через массивы отображения. Что это такое и с чем всё это курят – будем разбираться, когда дойдём до вывода моделей (думаю это будет где-то в 5 части).
Отчистили экран, сбросили матрицу вида в ноль и устоновили камеру в координаты (3.0, 5.0, 4.0), заставили смотреть в начало координат. Последние три параметра – указывают ось (абсцисс, ординат, аппликат) которая будет направлена вверх. Сейчас мы сказали, что это - ось Y(0.0, 1.0, 0.0).
Подсчёт времени между кадрами. Необходимо для контроля за работой физики, исходя из скорости работы машины. Кстати, мы не заводили переменной dt типа float, у синглтона aAux?
У вас вопрос по поводу второй строки последней функции? Вроде у нас нет такого метода aString::asGetWords(aList<aString>& list) ? Этот метод разбирает строку на слова и записывает их в список, который передан в качестве параметра. Задание: реализуйте этот метод. Подсказка: код пробела – 32.
«Лев два скачка сделал, и сел под пальму отдыхать…» А лошадь-то всё бежит! Последних выдох – doSystem.h:
Наверное вы ещё не сразу запустите приложение, потому что придётся сделать задания, придётся найти ошибки, самим подумать, почитать, разобраться, что-то спросить у меня. Дорогу осилит идущий! Вот теперь всем и каждому ещё одно задание – начать читать перевод красной книги OpenGL на progz.ru – все основные функции разбираются до мелочей, с кучей примеров. Ссылку я давал в нулевой части цикла, которая закреплена в топе раздела. Всё: «И да прибудет с вам великая сила!» Это сообщение отредактировал(а) Rickert - 10.2.2009, 18:55 -------------------- Ни что не внушает сна крепче, чем день приисполненный трудов! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rpahut |
|
|||
![]() 0xdeadbeef ![]() Профиль Группа: Участник Сообщений: 243 Регистрация: 9.4.2006 Репутация: 5 Всего: 7 |
Я бы создание окна и инициализацию ogl спрятал в отдельный класс. Вообще-то, именно так я и делаю
![]() --------------------
C/C++ GameDevRSS Раздела программирования игрOpenGL - уроки от NeHeКак продать идею? |
|||
|
||||
Rickert |
|
|||
![]() Ситхи не пройдут! ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3356 Регистрация: 11.7.2006 Где: Лакрима Репутация: 6 Всего: 52 |
Rpahut, они ведь inline - на производительность не влияют, зато держат интерфейс. Было много дискуссий о том КАК надо писать код. В конечном итоге, когда устриваешься на работу, на твой код смотрят и если он оформлен как-то "не по - правилам" - тебе же минус. Я б рад сделать многие параметры открытыми и избавиться от тучи функций.
Это сообщение отредактировал(а) Rickert - 11.2.2009, 02:27 -------------------- Ни что не внушает сна крепче, чем день приисполненный трудов! |
|||
|
||||
Rpahut |
|
|||
![]() 0xdeadbeef ![]() Профиль Группа: Участник Сообщений: 243 Регистрация: 9.4.2006 Репутация: 5 Всего: 7 |
Я имел ввиду - если создание окна поместить внутри aSystem, или что еще лучше, в aOGLWindow. asSetWnd() например будет в таком случае не нужен, asGetWnd() мало полезен.
Если движок будет расти, все равно то, что сейчас лежит в WinMain(), придется куда-то заворачивать. --------------------
C/C++ GameDevRSS Раздела программирования игрOpenGL - уроки от NeHeКак продать идею? |
|||
|
||||
Rickert |
|
|||
![]() Ситхи не пройдут! ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3356 Регистрация: 11.7.2006 Где: Лакрима Репутация: 6 Всего: 52 |
А, теперь понял твою мысль.
Возможно, увидим ![]() -------------------- Ни что не внушает сна крепче, чем день приисполненный трудов! |
|||
|
||||
arilou |
|
|||
![]() Великий МунаБудвин ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2646 Регистрация: 15.7.2004 Где: город-герой Минск Репутация: 6 Всего: 61 |
Rpahut, +1.
Rickert, следи, чтобы классы не были перегружены функционалом ![]() |
|||
|
||||
Rickert |
|
|||
![]() Ситхи не пройдут! ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3356 Регистрация: 11.7.2006 Где: Лакрима Репутация: 6 Всего: 52 |
Да, стараюсь. Будем потом модернизировать. Вот, первые предложения пошли
![]() -------------------- Ни что не внушает сна крепче, чем день приисполненный трудов! |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Программирование игр, графики и искуственного интеллекта" | |
|
НА ЗЛОБУ ДНЯ: Дорогие посетители, прошу обратить внимание что новые темы касающиеся новых вопросов создаются кнопкой "Новая тема" а не "Ответить"! Любые оффтопиковые вопросы, заданные в текущих тематических темах будут удалены а их авторы, при рецедиве, забанены.
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rickert. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Программирование игр, графики и искусственного интеллекта | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |