Изометрическая прокрутка с полями - PullRequest
2 голосов
/ 08 августа 2011

У меня проблема здесь.Я уже некоторое время ищу ответ на этот вопрос, пытаясь найти решение самостоятельно, но безрезультатно.Этот вопрос, вероятно, задавался много раз, но везде, где я нахожу что-то, всегда есть что-то, что мне не понятно.Итак: я пишу 2D-игру, используя SDL + OpenGL.Игра показана в изометрической проекции.Игрок видит карту, которая состоит из тайлов, скажем, 15х15 тайлов (2D-массив).Выглядит это так: http://i.imgur.com/PVJe4.png

X и Y являются индексами каждой плитки, но кроме этого, у этих плиток есть свои собственные координаты X и Y (северная вершина, отмеченная зеленой точкой для [0] [0] tile), в котором они нарисованы.

Моя проблема в том, что я хочу добавить прокрутку для этого.Если эта карта будет размером 100x100, она будет нарисована очень медленно, потому что все плитки нарисованы за пределами экрана.Я не хочу, чтобы это было сделано.

Давайте посмотрим, например, на это: http://imgur.com/vo3wg

Синий прямоугольник - мой экран (800x600, размер не изменяется).Габаритные размеры карты составляют 8000x6000, а плитки нарисованы так же, как на экране.Я знаю, мне нужно рисовать только те плитки, которые отмечены зеленым, но моя проблема:

Как определить, какие плитки (я имею в виду, с какими индексами) нужно рисовать?

Я ценю все попытки помочь мне.

Ответы [ 3 ]

3 голосов
/ 09 августа 2011

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

Почему бы и нет?Целые треугольники, находящиеся за пределами экрана, отбраковываются, поэтому все, что вы теряете, - это передача вершин и время преобразования.Да, вы должны предпринять разумные шаги, чтобы гарантировать, что вы не отправляете вещи, которые вы могли бы легко отбросить, но, поскольку вы просто рисуете простую 2D карту тайлов, это не будет проблемой производительности.Даже для бюджетного оборудования.

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

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

1 голос
/ 09 августа 2011

Я отвечаю сам, потому что я не могу опубликовать более 2 ссылок (поскольку я новичок), и я не могу публиковать ЛЮБЫЕ изображения.

Я сделал несколько тестов:

для 100x100 он работает хорошо, для 150x150 тоже, для 200x200 он опускается прямо на землю, а для 500x500 это полностью катастрофа: http://imgur.com/msAx4l&EJ9Qw&iKXFZ&ybFt0 (4 экрана в галерее)

Хорошо, я думал о решении, которое не требует какой-либо проверки, а только некоторых математических уравнений. Например, в моей другой игре (написанной давным-давно) с плитками squre, а не с бриллиантами, очень просто определить индексы нарисованных плиток. Это выглядит так: http://i.imgur.com/y9KUv.png

Процедура рисования для него:

//CameraXposition and CameraYposition is position of left-top corner of camera on map.
//Single tile height and width is 100, so if CameraXposition is 1456, then I start drawing from
//tile with index of 14 ((int)(1456/100) == 14).
//CAMERA_WIDTH is 800 and CAMERA_HEIGHT is 600 (screen resolution).
for(int x = (int)CameraXposition/100; x < ((CameraXposition+CAMERA_WIDTH)/100); ++x)
{
    for(int y = (int)CameraYposition/100; y < ((CameraYposition+CAMERA_HEIGHT)/100); y++)
    {
        //Draw(tiles[x][y]);
    }
}

Здесь, в изометрическом виде, не все так просто, но я не знаю, как определить это начальные индексы и диапазоны плиток.

Вот мой текущий код для рисования:

void GraphicEngine::Render(Map &m)
{
    //camX and camY isn't coordinates of camera, they are coordinates of
    //starting point (everything is drawed according to that point)
    //it changes as I move mouse.
    //zoomFactor is basically a zoom variable, it's float and its minimum is 0.5 and maximum is 1.5.
    //It changes as I scroll my mousewheel. The smaller it is, the smaller is everything that's drawed,
    //so more tiles can be drawed on screen (becouse they are smaller) 
    //Not very good, but works.
    glTranslatef(camX*zoomFactor, camY*zoomFactor, 0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glBegin(GL_QUADS);
        for(int i = 0; i < m.get_width(); ++i)
        {
            for(int j = m.get_height()-1; j>=0; --j)
            {
                glTexCoord2f(0, 0);
                glVertex3f((m.get_fields()[i][j]->get_pX()-30)*zoomFactor, (m.get_fields()[i][j]->get_pY()+15)*zoomFactor, 0);
                glTexCoord2f(1, 0);
                glVertex3f((m.get_fields()[i][j]->get_pX())*zoomFactor, (m.get_fields()[i][j]->get_pY())*zoomFactor, 0);
                glTexCoord2f(1, 1);
                glVertex3f((m.get_fields()[i][j]->get_pX()+30)*zoomFactor, (m.get_fields()[i][j]->get_pY()+15)*zoomFactor, 0);
                glTexCoord2f(0, 1);
                glVertex3f((m.get_fields()[i][j]->get_pX())*zoomFactor,( m.get_fields()[i][j]->get_pY()+30)*zoomFactor, 0);
            }
        }
    glEnd();
    glLoadIdentity();
}
0 голосов
/ 09 августа 2011

Я бы выбрал компромиссное решение между рендерингом всех и проверкой каждой плитки.

Найти угловые плитки в координатах экрана.Это даст вам минимальное и максимальное значения X: Y видимых плиток.Теперь рендеринг только тех плиток в этих пределах.GPU будет обрезать невидимые плитки, но вам не нужно будет отправлять все 8000x6000 плиток для рендеринга, а только их часть.

Как отмечалось выше, преждевременная оптимизация неверна, поэтому, если ваша карта не меньше 800x600 плитокСначала я бы попытался найти узкое место в другом месте.Например, группирование листов по текстуре в списки отображения или в VBO кажется более удачной идеей.

...