вторник, 26 февраля 2013 г.

Как помочь художнику справиться с тайлсетом

Я думаю, что самым трудным при разработке графики для Evil In Trouble для художника стала работа над тайлсетом. И это, в общем-то, логично, ведь он(тайлсет) должен быть бесшовным и хорошо смотреться во всех возможных сочетаниях тайлов. Однако, главной проблемой стало то, что у художника был компьютер с MacOS X и он не имел возможности запускать игру для того, чтобы проверить свои изменения.

Как же мы могли облегчить жизнь художнику?

На тот момент cocos2dx не поддерживал macosx и мы стали думать, как бы сделать так, чтобы художник все-таки мог менять текстуру и смотреть как смотрятся уровни. Разрабатывать отдельное приложение для на каком-нибудь .net не хотелось, так как пришлось бы портировать алгоритм построения batch node(весь уровень рисуется за один draw call). Поэтому я подумал, а почему бы не использовать для этого приложение и технологии, которые есть абсолютно у каждого и не привязаны к операционной системе - к браузеру и html+css?

Те, кто знаком с html и css, знают, что при верстке тоже используются спрайты. Точно так же, как и разработчик игры, человек, занимающийся разработкой странички может упаковать в одно изображение несколько небольших. Этого вполне достаточно, чтобы воспроизвести рендер уровня, осуществляемый в игре с помощью cocos2d-x.

Как отрисовать спрайт в html?

Предположим, что я хочу, чтобы на страничке  в координатах (400,250) был отрисован спрайт c текстурными координатами (200,200) и размером (50,50).

Определим стиль tile:

<style type="text/css">
    div.tile {
        display:block;
        background:url(tiles.png);
    }
</style>

Т.к. css позволяет позиционировать элементы в абсолютных координатах, то мы можем добиться желаемого одной строчкой:

<div class="tile" style="position:absolute;left:400px;top:250px;background-position:-200px -200px;width:50px;height:50px;"></div>

Экспортируем уровень в html-представление!

В класс Level был добавлен метод ExportToHTML, который сохранял все спрайты CCSpriteBatchNode в виде div'ов с переопределенным атрибутом style.

void Level::_SaveToHtml(const char* filename)
{
    const char header[] = "\
<?xml version=\"1.0\"?>\n\
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n\
<head>\n\
<style type=\"text/css\">\n\
    div.tile {\n\
        display:block;\n\
        background:url(tiles.png);\n\
    }\n\
</style>\n\
</head>\n\
<body>\n\
<div style=\"position:absolute;left:40px;top:40px;\">\n\
<div style=\"display:block;background:url(background.png);position:absolute;left:0px;top:0px;width:480px;height:320px;\"></div>\n";
    
    const char footer[] = "</div>\n</body>\n</html>";

    FILE* f = fopen(filename, "w");
    fputs(header, f);


    // tiles
    CCObject* object = NULL;
    CCARRAY_FOREACH(mTilesBatchNode->getChildren(), object)
    {
        CCSprite* sprite = (CCSprite*)object;
        CC_ASSERT(sprite->getScaleX() == 1.f && sprite->getScaleY() == 1.f);
        
        CCPoint ap = sprite->getAnchorPointInPoints();
        CCPoint pos = sprite->getPosition();
        CCRect r = sprite->getTextureRect();
        fprintf(f, "<div class=\"tile\" style=\"position:absolute;left:%dpx;top:%dpx;background-position:%dpx %dpx;width:%dpx;height:%dpx;z-index:%d;\"></div>\n", 
            (int)(pos.x - ap.x), (int)(320 - (pos.y - ap.y) - r.size.height),
            (int)-r.origin.x, (int)-r.origin.y,
            (int)r.size.width, (int)r.size.height, sprite->getZOrder());
    }
    // border
    fprintf(f, "<div style=\"position:absolute;left:-2px;top:-2px;width:480px;height:320px;border-width:2px;border-style:solid\"></div>\n");
    fputs(footer, f);
    fclose(f);
}

Вот, например, один из уровней, сохраненный таким способом.


Все, теперь мы(а самое главное - и художник!) получили возможность изменять tiles.png, обновлять страничку и сразу видеть результат точно в таком же виде, как он будет смотреться в игре.

После этого мы объединили, для удобства html-представления нескольких уровней в один файл, отдали художнику, и он быстро исправил все недостатки тайлсета и мы двинулись дальше.

1 комментарий: