Midpoint displacement

Основная суть алгоритма (который впоследствии плавно перерастет в Diamond square через двумерный Midpoint displacement):

// vector — массив точек, изначально заполнены только первая и последняя
// left, right — индексы первого и последнего элемента
// len = длина изначального отрезка(в пикселах)
// r -  шероховатость. Чем меньше тем более плавная кривая будет в результате.
function midpoint(vector, left, right, len, r) {
    if (right - left < 2)
        return;
    var hl = vector[left]; //высота левой точки
    var hr = vector[right]; //высота правой
    var h = (hl + hr) / 2 + rand(-r * len, +r * len); //считаем высоту
    var index = Math.floor(left + (right - left) / 2); //ищем середину
    vector[index] = h;
    //выполняем алгоритм для получившихся половин
    midpoint(vector, left, index, len / 2, r);
    midpoint(vector, index, right, len / 2, r);
}

ДемоИсходники

Ограничение скорости кадров

Что может работать на вашем компьютере на скорости 60 кадров в секунду, на другом может работать на 200. Так как скорость меняется от компьютера к компьютеру, вам необходимо регулировать фреймрейт (скорость кадров), для того, чтобы игра не работала слишком быстро. Если игра работает слишком быстро, в нее становится невозможно играть. Для предотвращения этого, вам нужно ограничить скорость кадров. Этот урок научит вас этому.

//Кадров в секунду
const int FRAMES_PER_SECOND = 20;

Мы определяем количество кадров в секунду как глобальную константу.

    //Количество отрисованных кадров
    int frame = 0;

    //Ограничивать ли фреймрейт (количество кадров в секунду)
    bool cap = true;

    //Таймер для регулирования фреймрейта
    Timer fps;

В функции main() мы объявляем несколько переменных. Переменная frame хранит количество отрисованных кадров, что важно для определения положения, в котором нужно отрисовать сообщение в этой программе. Так же тут есть переменная cap, которая определяет, хочет ли пользователь ограничивать фреймрейт. Затем мы объявляем объект таймера, который мы используем для ограничения фреймрейта.

    //Генерируем поверхность с сообщением
    message = TTF_RenderText_Solid( font, "Testing Frame Rate", textColor );

Теперь мы рендерим поверхность с сообщением, которая будет двигаться по экрану.

    //Пока пользователь не вышел
    while( quit == false )
    {
        //Запускаем таймер
        fps.start();

Далее мы входим в главный цикл. В начале каждого кадра мы запускаем таймер кадра.

        //Пока есть события для обработки
        while( SDL_PollEvent( &event ) )
        {
            //Если нажали клавишу
            if( event.type == SDL_KEYDOWN )
            {
                //Если нажали ввод
                if( event.key.keysym.sym == SDLK_RETURN )
                {
                    //Switch cap
                    cap = ( !cap );
                }
            }

            //Если пользователь вышел
            else if( event.type == SDL_QUIT )
            {
                //Выйти
                quit = true;
            }
        }

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

        //Отрисовать фон
        apply_surface( 0, 0, background, screen );

        //Отрисовать сообщение
        apply_surface(
           ( SCREEN_WIDTH - message->w ) / 2,
           ( ( SCREEN_HEIGHT + message->h * 2 ) / FRAMES_PER_SECOND ) *
           ( frame % FRAMES_PER_SECOND ) - message->h,
           message,
           screen
        );

Затем мы отрисовываем фон и сообщение. Не беспокойтесь обо всем этом коде, рисующем сообщение. Это просто более короткий спобоб записи для:

if( frame % FRAMES_PER_SECOND == 0 )
{
//Отрисовать тут
}
if( frame % FRAMES_PER_SECOND == 1 )
{
//Отрисовать тут
}

И т.д.

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

        //Увеличить количество отрисованных кадров
        frame++;

Далее мы обновляем экран и увеличиваем счетчик кадров. Теперь мы закончили все, что нужно было сделать в этом кадре.

        //Если мы хотим ограничить фреймрейт
        if( ( cap == true ) && ( fps.get_ticks() < 1000 / FRAMES_PER_SECOND ) )
        {
            //Ждем оставшееся время
            SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
        }

В этом месте мы на фактически ограничиваем фреймрейт. Когда мы начали обрабатывать кадр, мы запустили таймер, для того чтобы знать, сколько времени ушло на вывод кадра. Для того, чтобы программа не работала слишком быстро, каждый кадр должен отображаться в течение определенного времени. Так как мы показываем 20 кадров в секунду, каждый кадр должен отображаться не меньше чем 1/20-ую секунды. При фреймрейте 60, каждый кадр должен отображаться не менее 1/60-ой секунды. А так как демо запускается при 20 кадрах в секунду, мы должны тратить 50 миллисекунд (1000 мс / 20 кадров) на кадр. Для контроля над фреймрейтом, для начала мы проверяем, что кадр отображается меньше времени, отпущенного на один кадр. Если оно больше, это означает что нам или уже пора отрисовывать следующий кадр, или мы опаздываем с отрисовкой, таким образом у нас нет времени ждать. Если же оно меньше, мы используем SDL_Delay() засыпая до конца времени, отведенного под текущий кадр. Например, если на отрисовку кадра ушло 20 мс, мы прождем 30 мс. Если ушло 40 мс, прождем 10 мс и т.д.

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