Время

Мы уже разобрались с событиями. Теперь пришло время разобраться с временем. Знание того, как обращаться с временем — ключевой момент при создании игр. В этом уроке мы создадим простой таймер, который можно запускать и останавливать.Предположим что вам нужно отмерить 30\-секундный интервал, но у вас нет таймера. Если бы на стене висели часы с секундной стрелкой, вы бы дождались пока она достигнет положения кратного 15 секундам: и ждали бы до тех пор, пока она не пройдет 30 секунд от точки отсчета. Наш таймер работает по этому же принципу. `SDL` запускает внутренний таймер в нашей программе, и мы можем получить время в миллисекундах используя `SDL_GetTIcks()`. Если вам нужно отмерить 1000 миллисекунд, вы сохраняете время когда вы начали ожидание и ждете до тех пор, пока разница между временем начала и текущем не будет равна 1000.
//Заголовки
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include
#include

Наряду со стандартными заголовками, мы подключаем строковые потоки. Я объясню что это такое чуть позже.

int main( int argc, char* args[] )
{
    //Флаг выхода
    bool quit = false;

    //Время начала отсчета таймера
    Uint32 start = 0;

    //Флаг старта/остановки таймера
    bool running = true;

В начале функции main мы объявляем две переменные, которые мы будем использовать для реализации нашего таймера. start будет хранить время запуска таймера, а running — флаг, отслеживающий запущен ли таймер.

    //Инициализируем таймер
    start = SDL_GetTicks();

    //Пока пользователь не решил выйти
    while( quit == false )
    {

После того, как мы инициализировали и загрузили поверхности, пришло время запустить таймер. Мы начинаем с того, что сохраняем текущее время, используя SDL_GetTicks(). После этого мы входим в главный цикл.

        //Пока есть события для обработки
        while( SDL_PollEvent( &event ) )
        {
            //Если нажали клавишу
            if( event.type == SDL_KEYDOWN )
            {
                //Если нажали клавишу 's'
                if( event.key.keysym.sym == SDLK_s )
                {
                    //Если таймер запущен
                    if( running == true )
                    {
                        //Остановить таймер
                        running = false;
                        start = 0;  
                    }
                    else
                    {
                        //Запустить таймер
                        running = true;
                        start = SDL_GetTicks();  
                    }
                }
            }

Здесь мы обрабатываем нажатие клавиши 's', которая запускает и останавливает таймер. Если таймер был запущен, мы выставляем флаг running в false, и обнуляем start, просто потому что я не люблю бродячие значения. Если таймер был остановлен, мы, напротив, присваиваем флагу running значение true и запускаем таймер, так же, как мы сделали это до входа в главный цикл.

        //Если таймер запущен
        if( running == true )
        {
            //Время таймера в виде строки
            std::stringstream time;

            //Преобразовать время в строку
            time << "Timer: " << SDL_GetTicks() - start;

После того, как мы выводим фон и сообщение, мы проверяем запущен ли таймер. Если да, то показываем время. Формула для расчета времени таймера такова:время = текущее время - время запускаТо есть, если вы запустили таймер, когда значение SDL_GetTicks() было равно 10 000 и теперь оно 20 000, формула даст нам цифру 10 000, означающую что прошло 10 секунд с момента запуска таймера. Теперь кладем 'Timer: ' + время таймера в строковой поток. Мы создаем строковой поток по имени time, который хранит сообщение содержащее время таймера. Строковые потоки позволяют создавать строки из нескольких переменных. Как вы могли заметить, они очень похожи на cout, но вместо того, чтобы выводить все в консоль, они просто сохраняют текст в строковом потоке, чтобы мы могли воспользоваться им впоследствии. Тем из вас, кто все еще пользуются VC++ 6.0, нужно будет привести (SDL_GetTicks() - start) к int.

            //Отрисовать время
            seconds = TTF_RenderText_Solid( font, time.str().c_str(), textColor );

            //Вывести время
            apply_surface( ( SCREEN_WIDTH - seconds->w ) / 2, 50, seconds, screen );

            //освободить поверхность
            SDL_FreeSurface( seconds );
        }

        //Обновить экран
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;    
        }
    }

После мы отрисовываем поверхность с текстом, показывающую время таймера используя текст из строкового потока. После этого мы выводим текст на экран и освобождаем ресурсы. И, наконец, обновив экран продолжаем главный цикл.

Скачать исходники и материалы

Emacs: раскладка на meta-space

Извечная проблема пользователей емакса (и вима) с переключением раскладки и мне изрядно попортила жизнь. Долгое время выходом из положения, если это так можно назвать, для меня было банальное переключение системной раскладки для ввода небольшого количества русского текста и последующее переключение раскладки обратно. А для случаев когда нужно вводить много кириллических символов вполне подходит встроенный в емакс механизм input-method. Но иметь одну комбинацию для переключения системной раскладки, а другую для переключения раскладки в редакторе (ctrl-\) ну ни как не способсвует психическому спокойствию. Перепробывав миллион методов, я пришел к следующему решению. Для начала, чтобы кисти рук не выгибались я перенес ctrl на место caps'a. С переключением раскладки все интересней. На данный момент все устроено так: переключение на правом alt'e и на meta-space. Плюс за неимением лучших вариантов и для того чтобы не было соблазна пользоваться старыми хоткеями, левый ctrl включает латинскую раскладку, а правый кириллическую. (для ubuntu: правим файлик /etc/default/keyboad

XKBOPTIONS="grp_led:scroll,compose:rwin,grp:toggle,grp:alt_space_toggle,grp:lctrl_rctrl_switch,caps:none,ctrl:nocaps"

Основной хоткей для переключения раскладки — meta-space. Теперь для того чтобы пользоваться им же в емаксе добавляем в ~/.emacs следующий код:

;; for this to work kbdd must be installed
(global-set-key (kbd "M-SPC")
		(lambda ()
		  "Toggle input method"
		  (interactive)
		  (toggle-input-method)
		  (start-process "dbus-send"
				 nil
				 "dbus-send"
				 "--dest=ru.gentoo.KbddService"
				 "/ru/gentoo/KbddService"
				 "ru.gentoo.kbdd.set_layout"
				 "uint32:1")))

Решение требует того, чтобы был услановлен kbdd.

sudo aptitude install kbdd

Который кстати умеет сохранять раскладку для каждого приложения, что тоже весьма удобно, особенно для легких окружений типа Awesome. В результате: системная раскладка переключается по meta-space, зажигая при этом лампочку scroll lock'a при включении кириллической раскладки. В емаксе input-method включается точно так же. При этом, правда, системная раскладка остается английской, и поэтому scroll lock не загорается. Что вполне приемлемо на фоне остальных решений этого вопроса.

Воспроизведение звука

Воспроизведение звука — еще одна ключевая составляющая программирования игр. Штатные функции SDL для проигрывания звука довольно запутанные. Поэтому мы будет разбираться в том, как проигрывать звуки при помощи библиотеки `SDL_mixer`. `SDL_mixer` — библиотека расширений, которая делает использование звука безумно простым делом. Скачать `SDL_mixer` можно [тут](http://www.libsdl.org/projects/SDL_mixer/). Для того, чтобы установить ее просто следуйте [инструкции](http://tatrix.org/sdl-tutorial/3/). Ставится `SDL_mixer` так же просто, как и `SDL_image`: просто замените в тексте инструкции `SDL_image` на `SDL_mixer` Этот туториал раскрывает основы проигрыванию музыки и звуков при помощи `SDL_mixer` на примере "музыки", которую я создал барабаня по моему монитору.
//Музыка, которую будем проигрывать
Mix_Music *music = NULL;
//Звуки, которые будут использоваться
Mix_Chunk *scratch = NULL;
Mix_Chunk *high = NULL;
Mix_Chunk *med = NULL;
Mix_Chunk *low = NULL;

Здесь мы можем видеть новые типы данных, с которыми мы будем работать.Mix_Music тип данные который мы используем для музыки, и Mix_Chunk для звука соответственно.

bool init() {
    //Инициализировать все подсистемы SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) {
        return false;
    }
    //Подготовить экран
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT,
        SCREEN_BPP, SDL_SWSURFACE );
    //Если при подготовке экрана произошла ошибка
    if( screen == NULL ) {
        return false;
    }
    //Инициализировать SDL_mixer
    if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ) {
        return false;
    }
    //Установить заголовок окна
    SDL_WM_SetCaption( "Monitor Music", NULL );
    //Если все прошло хорошо
    return true;
}

В функции инициализации мы вызываем Mix_OpenAudio() для инициализации аудио функций SDL_mixer Первый аргумент Mix_OpenAudio() это используемая частота звука, в данном случае равная 22050, что является рекомендуемым значением. Второй аргумент это формат звука, который мы выставим в значение по умолчанию. Третий аргумент — сколько использовать каналов. Мы задаем его равным двум, чтобы получить стерео звук. Если бы мы передали единицу, получился бы моно звук. Последний аргумент — размер сэмпла, в данном случае 4096. Если вы используете OGG, MOD или другие форматы, отличные от WAV, взгляните на Mix_Init() для инициализации декодеров и Mix_Quit() для их закрытия. Мы будем использовать только WAV файлы, так что не будем писать код для чего-то, чем мы не будем пользоваться.

{
    //Загрузить фоновое изображение
    background = load_image( "background.png" );

    //Открыть файл шрифта
    font = TTF_OpenFont( "lazy.ttf", 30 );

    //Если не загрузился фон
    if( background == NULL )
    {
        return false;    
    }

    //Если не загрузился шрифт
    if( font == NULL )
    {
        return false;
    }

    //Загружаем музыку
    music = Mix_LoadMUS( "beat.wav" );

    //Если не получилось
    if( music == NULL )
    {
        return false;    
    }

    //Загружаем звуковые эффекты
    scratch = Mix_LoadWAV( "scratch.wav" );
    high = Mix_LoadWAV( "high.wav" );
    med = Mix_LoadWAV( "medium.wav" );
    low = Mix_LoadWAV( "low.wav" );

    //Если что-то пошло не так
    if( ( scratch == NULL ) || ( high == NULL ) || ( med == NULL ) || ( low == NULL ) )
    {
        return false;    
    }

    //Все прошло удачно
    return true;    
}

Тут мы видим нашу функцию загрузки. Для загрузки музыки мы используем Mix_LoadMUS(). Mix_LoadMUS() принимает имя файла с музыкой и возвращает соответствующие данные или NULL в случае ошибки. Для загрузки звуковых эффектов мы применяем Mix_LoadWAV(). Она работает аналогично, возвращая Mix_Chunk в случае успеха и NULL в противном случае.

void clean_up()
{
    //Освобождаем поверхность фона
    SDL_FreeSurface( background );

    //Освобождаем звуковые эффекты
    Mix_FreeChunk( scratch );
    Mix_FreeChunk( high );
    Mix_FreeChunk( med );
    Mix_FreeChunk( low );

    //Освобождаем музыку
    Mix_FreeMusic( music );

    //Закрывает шрифт
    TTF_CloseFont( font );

    //Закрываем SDL_mixer
    Mix_CloseAudio();

    //Закрываем SDL_ttf
    TTF_Quit();

    //Закрываем SDL
    SDL_Quit();
}

В функции очистки мы вызываем Mix_FreeChunk(), чтобы избавится от загруженных звуковых эффектов и Mix_FreeMusic(), чтобы освободить ресурсы занятые музыкой. После того как мы закончили использовать SDL_mixer вызывается Mix_CloseAudio.

    //Пока пользователь не вышел
    while( quit == false )
    {
        //Пока есть события для обработки
        while( SDL_PollEvent( &event ) )
        {
            //Если нажали клавишу
            if( event.type == SDL_KEYDOWN )
            {

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

                //Если нажали 1
                if( event.key.keysym.sym == SDLK_1 )
                {
                    //Проиграть эффект скрипа
                    if( Mix_PlayChannel( -1, scratch, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }
                //Если нажали 2
                else if( event.key.keysym.sym == SDLK_2 )
                {
                    //Проиграть звук удара высокой частоты
                    if( Mix_PlayChannel( -1, high, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }
                //Если нажали 3
                else if( event.key.keysym.sym == SDLK_3 )
                {
                    //Проиграть звук удара средней частоты
                    if( Mix_PlayChannel( -1, med, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }
                //Если нажали 4
                else if( event.key.keysym.sym == SDLK_4 )
                {
                    //Проиграть звук удара низкой частоты
                    if( Mix_PlayChannel( -1, low, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }

При проверки нажатий на клавиши, сначала мы проверяем были ли нажаты 1, 2, 3 или 4. Эти клавиши проигрывают звуковые эффекты. Если одна из этих клавиш была нажата, мы вызываем Mix_PlayChannel(), чтобы проиграть звук, ассоциированный с данной клавишей. Первый аргумент Mix_PlayChannel() это канал, в который нужно проиграть звук. Так как мы передаем -1 Mix_PlayChannel() просто берет первый доступный канал и проигрывает звук. Второй аргумент это Mix_Chunk, который нужно проиграть. Третий — сколько раз нужно повторить проигрывание. В случае если он равен 0, звук будет проигран единожды. В случае проблем с проигрыванием звука, Mix_PlayChannel() возвращает -1.

                //Если нажали 9
                else if( event.key.keysym.sym == SDLK_9 )
                {
                    //Если музыка не играет
                    if( Mix_PlayingMusic() == 0 )
                    {
                        //Запускаем проигрываение музыки
                        if( Mix_PlayMusic( music, -1 ) == -1 )
                        {
                            return 1;
                        }    
                    }

Дальше мы обрабатываем нажатие клавиши 9, которая используется для проигрывания или приостановки музыки. Сначала мы проверяем, не играет ли уже музыка при помощи Mix_PlayingMusic(). Если нет, мы вызываем Mix_PlayMusic для запуска проигрывания. Первый аргумент Mix_PlayMusic это музыка, которые мы собираемся проигрывать. Второй — сколько раз ее повторять. В нашем случае, -1 означает играть до тех пор, пока проигрывание не будет остановлено вручную. В случае проблем с проигрыванием музыки, Mix_PlayMusic() возвращает -1.

                    //Если музыка играет
                    else
                    {
                        //Если музыка на паузе
                        if( Mix_PausedMusic() == 1 )
                        {
                            //Продолжить играть
                            Mix_ResumeMusic();
                        }
                        //Если музыка играет
                        else
                        {
                            //Приостановить проигрывание
                            Mix_PauseMusic();
                        }
                    }
                }

Теперь, если музыка играла и пользователь нажимает 9, мы либо приостанавливаем либо возобновляем проигрывание. Сначала мы проверяем на паузе ли музыка при помощи Mix_PausedMusic(). Если это так, то мы возобновляем проигрываение вызывая Mix_ResumeMusic(). В противном случае мы приостанавливаем ее при помощи Mix_PauseMusic()

                //Если нажали 0
                else if( event.key.keysym.sym == SDLK_0 )
                {
                    //Остановить музыку
                    Mix_HaltMusic();
                }
            }

В конце концов, мы проверяем не нажал ли пользователь 0. И в этом случае останавливаем проигрывание музыки вызовом Mix_HaltMusic()

Скачать исходники и материалы

urxvt + vim 256 цветов (debian/ubuntu)

  1. Ставим urxvt

    sudo aptitude install rxvt-unicode-256color
    
  2. Если терминал ругается при запуске (setterm: ***: unknown terminal type), то делаем следующее:

    echo 'URxvt.termName: rxvt-unicode' >> ~/.Xresources
    xrdb -merge ~/.Xresources
    

    И перезапускаем терминал.

  3. В .vimrc добавляем:

    set t_Co=256
    

    и радуемся полученному результату

Как начать писать игры

Оригинал: Starting out on Game ProgrammingПост на хабре. Путь в индустрию игровых разработок не близок. Эта статья призвана помочь понять с чего лучше начать это путешествие.Вы только что закончили ваш первый курс по С++ и хотите начать делать игры. Кто-то указал вам на этот сайт и вы, возможно, поэкспериментировали немного с руководством. Вы изучили несколько лаконичных примеров, но не нашли руководства о том, как сделать целую игру. И на то есть причина. Руководства хороши для обучения чему-то шаг за шагом, например тому, как перемещать изображение точки по экрану. Для того чтобы собрать игру воедино, вам нужны навыки решения возникающих проблем, приобретаемые лишь с опытом. Это не то, чему можно научиться из руководств. Лучший способ научиться делать игры — это начать их делать.

Выбор проекта

Итак, с чем же начать? Проще ответить с чего начинать не стоит, а именно с больших проектов, типа полноценной 3D FPS, MMO или даже длинного платформера 16-битной эпохи. Самая распространенная ошибка начинающих разработчиков это начать с большого проекта основанного на Крутой Идее или взять проект, который кажется простым, и закончить с полузаконченной кучей спагетти-кода. Поначалу следует создавать небольшие проекты. В ранних проектах ваша основная цель учеба, а не реализация Крутых Идей. Поддерживая проект небольшим, вы можете сфокусироваться на изучении новых техник, а не тратить кучу времени на управление кодом и рефакторинг. Несмотря на то, что ваша Крутая Идея может быть офигительно офигенной, реальность индустрии разработки такова, что чем больше проект, тем больше вероятность совершить ошибку в архитектуре. И чем больше проект, тем дороже обходится эта ошибка. Помните историю Дедала и его сына Икара? Дедал создал крылья из воска и перьев для своего сына. Он предупредил Икара не подлетать на них слишком близко к солнцу. Но Икар проигнорировал предупреждение и крылья расплавились, и тогда-то гравитация и настигла его. Поэтому помните: не подлетайте слишком близко к солнцу на ваших новых программистких крыльях. Принимая во внимание все выше написанное, вот пара советов с чего начать.

Графика и обработка событий

Если вы никогда не программировали ничего связанного с графикой или GUI, вам следует начать с чего то маленького, чтобы "обмочить ноги". Моим первым проектом были крестики-нолики, так что даже у меня было скромное начало. Пара идей для первого проекта:

  • Симулятор однорукого бандита

  • Black Jack

  • Крестики-нолики

  • Четыре в ряд

Цель вашего первого проекта перейти от консольной разработки к разработки событийных графических приложений. Он так же научит вас фундаментальным основам игровой логики и архитектуры. Я рекомендую что-нибудь пошаговое, потому что игры с движением это совсем другой зверь. Старайтесь сохранять проект простым, чтобы вы могли его завершить и не потерять интерес на полпути, так никогда и не закончив игру. Важно довести игру до конца, потому что вы не учитесь процессу разработки, если у вас несколько недоделанных игр на жестком диске. Есть один момент, на который я хочу указать тем, кто будет делать крестики-нолики или четыре в ряд. Не стоит сейчас сильно беспокоиться об искусственном интеллекте. Сделать игру только для двух игроков или для игры с компьютером, который делает случайные ходы вполне достаточно для начала. Если до этого вы имели дело с графикой и обработкой событий и чувствуете себя комфортно в этой области, можете приступить прямиком к следующему шагу.

Синхронизация, движение, столкновения, анимация

Теперь, когда вы наигрались с графикой, пора заняться чем-нибудь в реальном времени. Вот пару предложений:

  • Duck Hunt

  • Pong

  • Space Invaders

  • Galaga

  • Тетрис

Здесь вы познакомитесь с движением, временем, анимацией, обнаружением столкновений, игровым циклом, вычислениями очков, побед и поражений и другими важными базовыми концепциями используемыми в каждой игре. Duck Hunt и Pong — хорошие проекты для тех, кто уже имеет опыт в программировании графики и событий. В них есть простое обнаружение столкновений и все важные основы игр в реальном времени. Space Invaders и Galaga — хороший выбор для второго/третьего проекта. В них есть уровни, поэтому вам нужно будет узнать как передвигаться от уровня к уровню, при помощи конечного автомата. Вы можете прочитать про конечные автоматы здесь(англ.). Игры в стиле "перестреляй их всех" так же требуют создать простые шаблоны поведения для врагов, что является шагом в сторону искусственного интеллекта. Тетрис хорош для второго/третьего проекта. В нем совсем немного логики нужной для создания игры-головоломки. Это игра приличного размера, так что вам придется научиться разделять вашу программу на несколько исходных файлов, о чем вы можете больше прочитать здесь(англ.). Не недооценивайте Тетрис. Я недооценил и только посмотрите на это жуткое месиво в коде Lazy Blocks.

Переинженеринг

Типичная ошибка новичка это попытка сделать Самую Лучшую Игру Всех Времен, заканчивающаяся переинженерингом. То есть когда он пытается написать самую лучшую игру/движок и это все заканчивается тем, что используется только маленькая часть того что было понаписано. Когда я был начинающим я переинженерил AI для крестиков-ноликов. Я хотел сделать игру с непобедимым AI. Мне удалось достигнуть этого, запрограммировав компьютер на знание всех возможных ловушек. Звучит круто не правда ли? Это заняло почти 40 000 тысяч строк в основном скопированного кода и месяц моего свободного времени. Позже я выучил структуры данных и узнал про алгоритм Минимакс, который при меньшем размере кода не только делал нужное, но еще и делал это лучше. Так что учитесь на моих ошибках и не будьте излишне амбициозны. Концентрируйтесь на обучении тому как делать игры, а не просто делайте их.

Планирование, анализ столкновений, физика, уровни, искусственный интеллект

Теперь, когда у вас за плечами две или три маленьких игры, пришло время сделать первый крупный проект. До сих пор, вы, вероятно, программировали как придется. Это закончится на этом этапе. В реальном мире большинство процессов разработки завершается до того, как будет написана первая строчка кода. Ничто не может быть хуже, чем осознание того, что для того чтобы добавить в вашу игру то, что вы хотите, вам придется выкинуть весь написанный код, потому что вы не спланировали все заранее. Теперь, когда у вас есть опыт создания игр, вы знаете из чего состоит процесс разработки. Теперь вы можете планировать игры, перед тем как начинать их делать. Теперь про вашу следующую игру. Break Out и Puzzle Bobble хороши для третьего проекта, потому что они включают в себя продвинутое распознавание столкновений и физику. Физика важна, поскольку дает игре реалистичное ощущение. Даже в Super Mario Brothers есть ощущение гравитации и инерции. Бильярд отличный проект для тех, кто хочет напрячь извилины физикой. В играх типа бильярда вам нужно не только обнаруживать столкновения, но и обрабатывать их в определенном порядке. Обработка столкновений разительно отличается от их обнаружения. Хотя создание бильярда или 2D платформера может показаться простым делом, анализ столкновений в правильном порядке — запутанный процесс, и не должен быть недооценен. Break out и Puzzle Bobble так же включают дизайн уровней и требуют загрузки и освобождения их ресурсов. Хорошим опытом будет создание редактора уровней для игры. Редакторы позволяют вам легко создавать уровни и не вынуждают впаивать их в приложение. У меня есть статья(англ.) про создание редактора уровней. Так же вы возможно хотите попрактиковаться в написании искусственного интеллекта (AI). Один из вариантов — вернуться к крестикам-ноликам или четырем в ряд и написать непобедимый AI. Теперь вы уже должны знать структуры данных и сможете использовать знания о деревьях для использования алгоритма Минимакс. С этим алгоритмом вы можете просчитать все возможные исходы крестиков-ноликов и создать непобедимый AI. Забавно расстраивать им своих друзей. Так же вы возможно захотите сделать разные уровни сложности. Игра не приносит радости, если в нее нельзя выиграть. Pac Man — отличный способ попрактиковаться в написании AI. Нужно будет знать структуры деревьев/графов и алгоритмы поиска, типа A*, для того чтобы призраки могли пройти через лабиринт. Так же нужно будет сделать чтобы призраки работали в команде. Все это пригодится когда вы будете делать игры со сложным AI, типа стратегий в реальном времени. Об основах AI можно прочитать тут(англ.).

Платформеры, Action/Adventure, RPG, RTS, движки

Теперь, когда вы получили опыт создания хорошо спланированной игры, вы готовы к созданию Action/Adventure/Платформера. Это будет кульминация графики, движения, анимации, анализа/обнаружения столкновений, физики, AI, программной архитектуры и всего остального, что вы изучите к этому моменту. Тем кто более амбициозен, можно предложить сделать стратегию в реальном времени(RTS) или ролевую игру(RPG). Будьте осторожны, потому что RPG и RTS действительно огромные проекты. RPG имеют сложную архитектуру и требуют много планирования. Вам нужно будет спланировать каждое оружие, броню, аксессуар, атаку, предмет, заклинание, призыв, врага, карту, босса, подземелье и т.д. до мельчайших подробностей. Это все должно работать слаженно, и, мягко говоря, это не самая простая задача. Так что если ваш дизайн-проект выглядит как сценарий или комикс, вам потребуется сделать еще много работы. RTS также сложны архитектурно, а так же требуют много AI. Вам нужно будет делать поиск пути для юнитов, получение ими команд, разное поведение в зависимости от полученных команд. Если вы никогда до этого не делали AI, будет лучше начать с клона Pac Man'а для начала. Вероятно вам впервые придется делать движок для вашей игры. Чего следует избегать, так это создания универсального движка. Создавая движок не пытайтесь сделать его подходящем для любой игры. Если ваша игра требует x, y и z, делайте движок который умеет x, y и z. Движки создают исходя из того что нужно для конкретной игры, а не из того что любой игре может потенциально понадобиться. Другая распространенная среди новичков ошибка — это попытка создать движок в качестве первого проекта. И обычно это универсальный движок. Вам не нужен движок с фантастической графикой для создания Pong'а или Space Invaders. Программируя, легко закопаться в деталях. Концентрируйтесь на общей картине и завершайте свои игры.

Сеть

Кажется все хотят сделать следующую большую MMO. Создание онлайн игр не то, во что можно быстро вникнуть. Я понял это когда попытался сделать онлайн покер сразу после завершения крестиков-ноликов. Добавление сети значительно усложняет игру. Когда один игрок что-то делает, вы должны послать информацию об этом всем остальным. Это все равно что если бы ваша правая рука не знала о том, что делает левая. Так же вам придется выбирать между загрузкой сервера и тем что он может контролировать. Чем больше делает серверная часть, тем меньше возможностей жульничать у клиента, но это также означает большую нагрузку на сервер. Для action и других игр с высоким темпом геймплея, вам придется беспокоиться о сетевой задержки и потере пакетов. Вам следует полностью закончить хотя бы одну хорошо спланированную игру, перед тем как пробовать делать сетевую игру. В качестве первого сетевого проекта, попробуйте сделать что-нибудь, что не критично к скорости. Например простой чат-сервер/клиент будет хорошей практикой. Так же можно вернуться к крестикам-ноликам/четырем в ряд и добавить в них возможность играть в по сети. Как вариант попробуйте сделать сетевую карточную или настольную игру. После того как ваш первый сетевой проект готов, попробуйте сделать что-нибудь в реальном времени. В вашем первом сетевом приложении вы, вероятно, использовали TCP, чтобы быть уверенным в том, что данные которые вы принимаете доходят в том порядке, в котором вы их посылали. Для игр в которых происходит много действий, задержки создаваемые TCP вероятно будут слишком велики, так что вам придется использовать UDP. UDP не гарантирует порядок доставки как и саму доставку вообще. Так как UDP не делает дополнительных проверок целостности он быстрее. Вам придется пожертвовать легкостью использования TCP, в обмен на скорость UDP и необходимость самостоятельной проверки целостности данных при создании игры.

3D игры

Перед тем как делать 3D игры, вам следует сделать хотя бы одну хорошо спланированную игру и иметь хорошее понимание трехмерной векторной математики, линейной и Ньютоновской физики. Тут вам придется иметь дело с вершинами, текстурами, освещением, тенями, опредением взаимодействия с объектами в трехмерном пространстве, загрузку моделей и прочими сложно звучащими вещами. Хорошая новость в том, что если вы уже сделали 4 или 5 игр, вы уже знаете основы необходимые для создания игры. Вы уже хорошо знакомы с процессом разработки и знаете свои возможности как программиста. Неважно трехмерный шутер или двухмерный, он по прежнему шутер. 2D RPG или 3D RPG по прежнему RPG. Не считайте это оправданием пропустить 2D и сразу перейти к 3D. Прежде чем научиться бегать, нужно научиться ходить.

Быстрый способ

Говорите, что вы учитесь быстрее если сразу возьметесь за дело и будете просто писать вашу 3D MMOFPSRTSRPG и научитесь тому, что нужно по мере необходимости? Чтож, вот пару советов, которые вам помогут:

  1. Идите на местный рынок
  2. Купите целую рыбину. Рекомендую взять лосося или треску, хотя и сом тоже подойдет. Форель, кстати, тоже довольно эффективна
  3. Идите домой и включите компьютер
  4. Запустите вашу любимую IDE
  5. Теперь возьмите купленную рыбу и влупите себе по голове
  6. Повторите пункт 5, пока мысли о быстром способе не покинут вас

Вы не научитесь алгебре решая вычислительные задачи. Вы учите основы и опираетесь на них. Тоже самое и с программированием. Если вы ищите быстрый способ я тут как тут, чтобы сказать вам что его нет. Не торопите себя. Еще раз: учите основы и опирайтесь на них. Иначе вас ждет фиаско.

Путешествие начинается

Теперь, чтобы у вас было общее понимание того что же все-таки делать, пора начать заниматься игроделом. Я не ожидаю что вы будете следовать этому руководству слово в слово. Все учатся по разному и с разной скоростью. Если вы что-то и должны были вынести из этой статьи, так это три вещи:

  1. Выберите свой темп
  2. Доделывайте игры до конца
  3. Концентрируйтесь на обучение, а не просто на создании

Удачи вам на пути разработки игр!