Правильная модель данных для 2D Tilemap (C++, Qt)

Я сделал небольшой редактор 2D-уровней, в котором вы можете создавать карты на основе 2D-тайлов. Однако производительность внутри моего приложения действительно очень плохая. Сейчас думаю начать все заново.

Проблема в том, что в настоящее время я использую QGraphicsItem для представления одной плитки внутри QGraphicsScene. Плитка имеет некоторые свойства, в том числе изображение. Когда создается карта, я создаю элемент для каждой плитки, который рисует изображение для каждой плитки... что в основном представляет собой множество графических элементов и замедляет работу всего приложения. Это функция, которая заполняет карту после ее создания:

    for(int i=0;i<map->m_rows;i++)
    {
        for(int j=0;j<map->m_cols;j++)
        {
            Tile* thetile=map->getAt(i,j);
            if(thetile)
            {
                if(map->getType()==twoditor::RECTANGLETILE)
                {
                    QGraphicsItem* item= new TileGraphicsItem(thetile);
                    m_scene->addItem(item);
                }
                else if(map->getType()==twoditor::HEXAGONTILE)
                {
                    QGraphicsItem* item= new HexagonGraphicsItem(thetile);
                    m_scene->addItem(item);
                }
            }
        }
    }

Это работает для карты с тайлами 100x100. Но если я хочу создать еще большие карты... время загрузки действительно невыносимо... Может ли кто-нибудь дать мне совет для лучшего представления тайловой карты? Есть ли другие удобные способы отображения карты и редактирования ячеек (тайлов) внутри нее?

РЕДАКТИРОВАТЬ: TileGraphicItem функция рисования:

void TileGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget){

setZValue(0);

if(!m_thetile->getImage().isNull())
{
  painter->drawImage(0,0,m_thetile->getImage());
}
QPainterPath circle_path;

QRect duwagrect(boundingRect().x(),boundingRect().y(),boundingRect().width(),boundingRect().height());
circle_path.addRect(duwagrect);

m_pen.setStyle(Qt::SolidLine);
m_pen.setColor(Qt::black);
m_pen.setWidth(1);
painter->setPen(m_pen);
painter->drawPath(circle_path);

if(m_thetile->getProperty()->getBlocks())
{
    QPainterPath circle_path;
    QRect duwagrect(boundingRect().x()+2,boundingRect().y()+2,boundingRect().width()-3,boundingRect().height()-3);
    circle_path.addRect(duwagrect);
    m_pen.setStyle(Qt::DotLine);
    m_pen.setColor(Qt::red);
    m_pen.setWidth(2);
    painter->setPen(m_pen);
    painter->drawPath(circle_path);
}
if(this->isSelected())
{
  QPainterPath circle_path;
  QRect duwagrect(boundingRect().x()+2,boundingRect().y()+2,boundingRect().width()-3,boundingRect().height()-3);
  circle_path.addRect(duwagrect);
  m_pen.setStyle(Qt::SolidLine);
  m_pen.setColor(Qt::green);
  m_pen.setWidth(3);
  painter->setPen(m_pen);
  painter->drawPath(circle_path);
}

if(option->state & QStyle::State_MouseOver)
{
  QPainterPath circle_path;
  QRect duwagrect(boundingRect().x()+2,boundingRect().y()+2,boundingRect().width()-3,boundingRect().height()-3);
  circle_path.addRect(duwagrect);
  m_pen.setStyle(Qt::SolidLine);
  m_pen.setColor(Qt::cyan);
  m_pen.setWidth(2);
  painter->setPen(m_pen);
  painter->drawPath(circle_path);
}

}


person Amazonasmann    schedule 20.12.2013    source источник
comment
Не могли бы вы показать нам, как вы реализуете TileGraphicsItem?   -  person epsilon    schedule 20.12.2013
comment
Возможно, поэкспериментируйте с ItemIndexMethod и bspTreeDepth   -  person hyde    schedule 20.12.2013
comment
Проблема с созданием элементов или их отображением после создания? При их создании вы можете попробовать использовать QTimer (вероятно, с интервалом 0, чтобы это происходило так быстро, как это может сделать цикл событий Qt), чтобы создавать элементы небольшими партиями, чтобы избежать зависания графического интерфейса.   -  person hyde    schedule 20.12.2013
comment
Еще кое-что проверить. map->getAt(i,j), убедитесь, что это постоянное время. Если вы используете QMap (получение значения O(log N)), рассмотрите возможность переключения на QHash (получение значения O(1)).   -  person hyde    schedule 20.12.2013
comment
что именно вы хотите увидеть от TileGraphicsItem? функция покраски?   -  person Amazonasmann    schedule 20.12.2013
comment
а getAt(i,j) использует std::vector‹ std::vector‹Tile*› › m_map;   -  person Amazonasmann    schedule 20.12.2013


Ответы (1)


Проблема в том, что вы показываете все, даже то, что не нужно.
Вы должны создавать только видимые элементы (элементы в какой-то видимой области).

Другой более быстрый подход заключается в создании пользовательского QGraphicsItem, который рисует карту отверстий и рисует только видимые плитки (без плиток в качестве подэлементов).

person Marek R    schedule 20.12.2013
comment
Звучит как изобретение велосипеда. Предполагается, что QGV справляется с этим довольно хорошо, и, глядя на 40000 чипов demo, он тоже может это делать. - person hyde; 20.12.2013
comment
да, я видел 40 000 чипов. Основная проблема в том, что 40 000 чипов не рисуют изображения. Они рисуют только основные прямоугольники/линии. - person Amazonasmann; 20.12.2013
comment
подход к созданию пользовательского qgraphicsitem, который рисует всю карту, кажется интересным ... но как мне обрабатывать события наведения или щелчка? - person Amazonasmann; 20.12.2013