текстуры, память и общая организация игры
  • DovakiinDovakiin May 2012
    Доброго времени суток. Много луркал на форуме по поводу и без него, в итоге натолкнулся на эту (http://relishgames.com/forum/index.php?p=/discussion/5836/problema-s-vesom-tekstur#Item_12)
    статью. Почитал, но не совсем понял что за форматы DDS и как их получить из, например, .png изображения?
    И также вопросы по реализации:
    1.Везде пишут что можно как-то контролировать самому подгрузку и выгрузку текстур, но я что-то не совсем понимаю, как программа без фатальных эрроров будет спокойно удалять текстуры до ф-ции hge->System_Start();.
    Ведь чистить надо обычно после неё, или это не так?
    2. Если разбивать игру например на 5 уровней, каждый в своём .cpp файле, в main.cpp их все соеденить, то как будет дело обстоять в том же winmain? То есть, допустим, я сделаю какую-нибудь переменную-инфу о текущем уровне и в зависимости от его буду подгружать свои текстуры(которые для всех уровней придётся называть одинаково)? Или если так разбивать то в каждом файле уровня надо писать свой winmain,renderfunc,etc. с блекджеком и шлюхами?
    3. Возможно ли вставить любую картинку во время загрузки всего уровня? А то обычно после HGE_SHOWSPLASH проходит 2-3 секунды до загрузки всех спрайтов,а это не очень красиво.
    4. Возможно ли как-нибудь включить блокировку определённых клавиш клавиатуры, например для реализации прыжка (чтоб не было ощущения свободного полёта)?
  • kvakvskvakvs May 2012
    DDS это сжатый формат текстур с которым видеокарты умеют работать напрямую без распаковки. В отличие от DDS обычные JPG/PNG файлы должны быть распакованы и закачаны в видеокарту в форме таблицы из отдельных пикселей. Чтобы создать DDS надо скачать один из инструментов которые умеют с ним работать, я использовал NVidia Texture Tools. А для просмотра скачал какой-то DDS Viewer, в гугле нашёлся очень быстро.

    1. Все работы по подгрузке и удалению проводятся в FrameFunc, это внутри System_Start(). Твоя программа загружает мир и понимает, что нужны несколько текстур, стартует сразу их загрузку. При покидании мира программа понимает что текстуры уже не нужны и выгружает их.
    2. Сделай один рендерфунк который будет брать текущий уровень и рисовать его неважно что в нём. А логику уже можно разнести по разным файлам.
    3. Да но непросто, придётся поиграться с машиной состояний (это такая переменная которая хранит номер текущего состояния, а Framefunc по этой переменной определяет что делать дальше через switch(state) { ... } ). Например state=10 - Framefunc загружает твою заставку. state=11 - Следующий Renderfunc выводит картинку. state=12 - Следующий Framefunc загружает всё остальное что относится к уровню, state=20 - началась игра.
  • DovakiinDovakiin May 2012
    Что-то всё равно не понятно про то, как следует контролировать загрузку и выгрузку текстур. Судя по тому, что ты написал подгружать текстуры, выделять на них память можно в фреймфунке. Но ведь по шаблонам не совсем так? Вот то,как у меня это организовано (пользовался туториалами):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int)
    {...
    if(hge->System_Initiate())
    {... background1_lvl1_tex=hge->Texture_Load("background1_lvl1.png"); ...
    background1_lvl1_spr=new hgeSprite(background1_lvl1_tex, 0, 1, 5440, 800); ...
    hge->System_Start();
    delete background1_lvl1_spr;
    hge->Texture_Free(background1_lvl1_tex);
    }
    hge->System_Shutdown();
    hge->Release();
    return 0;
    }

    Судя по этому коду можно сказать, что до того, как запуститься фреймфунк сначала программа подгрузит все текстуры, выделит на них память, затем запустит игровой цикл после которого удалит всё, что было загружено. Но меня интересует не совсем то.
    Я лично придумал далеко не самый эффективный способ, но он подходит мне. Суть в том, что когда мы проходим любой уровень и показываем картинки-заставки, в то же время следует перегружать адреса всех текстур на нужные (то есть и в 1 и в 10 уровне будут использоваться одни и те же спрайты,лежащие в основном на одних и тех же местах). Вот я не совсем пойму этот момент. То есть если я просто захочу перегрузить адрес к картинке мне придётся её удалять и опять выделять память в какой-либо моей функции? И это означает, что я в winmaine могу написать для 10 разных уровней 10 ф-ций, которые загружают и удаляют одни и те же текстуры и спрайты и использовать их в зависимости от уровня?
    Если эта идея правильна, то примерно такой код должен быть в ф-ции?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int)
    {...if(hge->System_Initiate())
    {... MyLvl1(); // тут вызываем в зависимости от уровня нужную ф-цию подгрузки текстур
    ... hge->System_Start(); /* далее всё остаётся таким же,т.к. в конце работы надо удалить все спрайты\текстуры*/
    }}
    void MyLvl1()
    { if (background1_lvl1_tex!=NULL) // тут проверяем, существует ли вообще такая переменная (не уверен насчёт правильности проверки)
    {hge->Texture_Free(background1_lvl1_tex);
    delete background1_lvl1_spr;
    background1_lvl1_tex=hge->Texture_Load("background1_lvl1.png");
    background1_lvl1_spr=new hgeSprite(background1_lvl1_tex, 0, 1, 5440, 800);
    }}
  • kvakvskvakvs May 2012
    Что значит "перегрузить адрес" ты может что-то имеешь в виду что называется иначе? Выгрузить из памяти старые текстуры и загрузить новые это не называется "перегрузкой". Да при смене уровня тебе придётся удалить все старые спрайты и все ненужные или просто все текстуры, и загрузить те, что нужны в новом уровне и снова создать все спрайты. Обычно такое решение называется "менеджером текстур".

    Судя по твоему подходу "в лоб" я с ужасом представляю сотни строк одинакового копипаста который загрузит каждую текстуру. Сделай одну функцию загрузки для одной текстуры и одну функцию освобождения всех сразу текстур.

    Скобки {} у тебя расставлены ужасно, код вообще не читается. Посмотри какой-нибудь гайд по стилю кодирования, хотя бы даже этот http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Function_Declarations_and_Definitions
  • DovakiinDovakiin May 2012
    Т.е. в этой ф-ции высвобождения всех текстур мы банально спрашиваем для каждой текстуры для того что-бы не было вылетов if (texture_name!=NULL) {...} и удаляем её?
    По поводу "одну функцию загрузки для одной текстуры": смысла то в этом я особо не вижу, разве что читаемость. Или тут что-то ещё?
    И ещё раз всё-таки спрошу: загрузку и освобождение текстур делать в FrameFunc?
    P.S. Нет, я то знаю что такое перегрузка операторов и прочее, но просто по-привычке назвал это действие перегрузкой :) Я под этим подразумевал смену адреса текстуры, которая подгружается (была bg1.png стала bg2.png).
    Со скобками я это делал для компактности, извиняюсь если уж сильно не читаемо сделал, в следующий раз буду демонстрировать как "для себя" код :)
    Да, подход "в лоб" не самый лучший, но, имхо, самый простой для моего понимания. Ну пусть будут одни и те же строки, абы написал игру и она работала нормально. А дальше уже буду совершенствоваться по ходу написания ещё разных приложений и прочего.
    P.P.S. Спасибо за хорошие и быстрые ответы на вопросы!(которые, я надеюсь, Вас не сильно достают) :)
  • kvakvskvakvs May 2012
    Нет чёткого места где лучше всего делать то или иное действие. Я делал в фреймфунке во время смены сцен.

    Сделай менеджер текстур - словарь, в котором ключами были бы имена текстур:
    1
    2
    typedef std::map<std::string, HTEXTURE> tex_map_t;
    tex_map_t glob_textures;


    Сделай функцию загрузки, в которую передаётся имя, функция сама дописывает PNG и пытается загрузить из папки текстур:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    HTEXTURE get_texture(const std::string & name) {
    tex_map_t::iterator i = glob_textures.find(name);
    if (i != glob_textures.end()) return i.second;
    // тут грузим текстуру
    std::string filename = "data/" + name + ".png";
    HTEXTURE tex = hge->Texture_Load(filename.c_str());
    glob_textures[name] = tex;
    return tex;
    }


    Запрашивай текстуры вызовом get_texture("floor") например. Пока не догадаешься хранить имена текстур в файле описании уровня такой подход прокатит. По завершении уровня весь словарь glob_textures чистится и грузится заново.
    1
    2
    3
    4
    5
    6
    void clean_all_textures() {
    for (tex_map_t::iterator i = glob_textures.begin(), iend = glob_textures.end(); i != iend; ++i) {
    hge->Texture_Free(i.second);
    }
    glob_textures.clear().
    }
  • oktatoroktator May 2012
    Вообще, в HGE есть свой менеджер ресурсов hgeResourceManager, который "automates creation of complex resource objects and their management in the memory". Но многие, я смотрю, упорно продолжают загружать/выгружать текстуры и создавать/удалять спрайты вручную в коде. Может это я чего-то не понимаю и зря пользуюсь хге-шным менеджером?
  • DovakiinDovakiin May 2012
    Спасибо, kvakvs, буду потиху оптимизировать код :)
    oktator said:

    Вообще, в HGE есть свой менеджер ресурсов hgeResourceManager, который "automates creation of complex resource objects and their management in the memory". Но многие, я смотрю, упорно продолжают загружать/выгружать текстуры и создавать/удалять спрайты вручную в коде. Может это я чего-то не понимаю и зря пользуюсь хге-шным менеджером?


    ИМХО советуют делать всё вручную для так называемого "полного контроля" над всеми текстурами,а то кто знает, как захочет себя вести ресурсменеджер тогда, когда ты захочешь удалить ту или иную текстуру. Хотя это всего-лишь догадки, т.к. я им не очень часто пользуюсь чтобы говорить наверняка :)
  • DovakiinDovakiin May 2012
    Ещё вопрос:
    Как можно плавно затемнить\осветлить текстуру до полностью чёрного\белого цвета? Есть идея нарисовать текстуру, сделать её полностью прозрачной и как-то по мере выполнения программы менять её прозрачность. Можно ли так делать?
  • kvakvskvakvs May 2012
    До чёрного легко. Спрайту или кваду которым рисуется текстура ставишь цвет плавно убывающий от белого к чёрному. Текстура темнеет до чёрного.

    До белого сложнее. Рисуешь белый полигон той же формы что твоя белеющая текстура с прозрачностью от 0 до 255.
  • DovakiinDovakiin May 2012
    kvakvs said:

    До чёрного легко. Спрайту или кваду которым рисуется текстура ставишь цвет плавно убывающий от белого к чёрному. Текстура темнеет до чёрного.

    До белого сложнее. Рисуешь белый полигон той же формы что твоя белеющая текстура с прозрачностью от 0 до 255.


    Насчёт осветления - можете сказать, что я неправильно делаю? Если просто выставить dark_q.v[i].col = ARGB(255, ...) то рисует, но сразу всё белым (пардон за мою очевидность) :) А хотелось бы плавно.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    inline void SetQuad()
    {
    dark_q.v[0].x=0; dark_q.v[0].y=800;
    dark_q.v[1].x=1280; dark_q.v[1].y=800;
    dark_q.v[2].x=1280; dark_q.v[2].y=0;
    dark_q.v[3].x=0; dark_q.v[3].y=0;
    }
     
    inline int RendLight(int m)
    {
    if (m<=255) return m++;
    return 0;
    }
     
    bool FrameFunc() {
    ...
    SetQuad();
    return false;
    }
     
    bool RenderFunc() {
    hge->Gfx_BeginScene();
    ...
    int n = 0, x;
     
    if (draw_darkness==1)
    {
    for ( int i = 0; i < 255; i++ )
    x = RendLight(n);
    for( int i = 0; i < 4; i++ )
    dark_q.v[i].col = ARGB( x, 255, 255, 255);
     
    hge->Gfx_RenderQuad(&dark_q);
    }
    hge->Gfx_EndScene();
    return false;
    }
     
    int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int) {
    ...
    dark_q.blend=BLEND_ALPHAADD | BLEND_COLORADD | BLEND_NOZWRITE;
    ...
    hge->System_Start();
    hge->System_Shutdown();
    hge->Release();
    return 0;
    }
  • kvakvskvakvs June 2012
    Вот это что такое? Фигня какая-то, где фигурные скобки?
    1
    2
    3
    4
    5
    6
    		for ( int i = 0; i < 255; i++ )
    x = RendLight(n);
    for( int i = 0; i < 4; i++ )
    dark_q.v[i].col = ARGB( x, 255, 255, 255);
     
    hge->Gfx_RenderQuad(&dark_q);

    Менять цвет надо каждый RenderFunc, постепенно, а не все сразу.
  • DovakiinDovakiin June 2012
    Я понимаю что постепенно, но как-то моих знаний ещё не достаточно в hge для того, чтобы представить то, где какую переменную стоит наращивать и где менять прозрачность. Если не сложно помогите пожалст :)
  • kvakvskvakvs June 2012
    Привяжемся к таймеру. Допустим, мы хотим чтоб за 1 секунду (1000 мс) цвет квада стал чёрным. Заводишь переменную в твоём игровом классе или глобальную (так проще). Называешь её unsigned int glob_fade_start, и присваиваешь 0. Пока она 0, ничего не происходит.

    Когда пришла пора погаснуть кваду, пишешь glob_fade_start = GetTickCount(); - это функция в Windows.h, возвращает число миллисекунд со старта Windows, это значение постоянно увеличивается, что нам и требуется. Ненулевое значение в glob_fade_start отмечает начало действия угасания (код идёт в RenderFunc, например):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    bool RenderFunc() {
    ...
    if (glob_fade_start) {
    unsigned int delta = GetTickCount() - glob_fade_start;
    unsigned char fade = 255;
    if (delta < 1000) {
    fade = delta * 255 / 1000;
    } else {
    glob_fade_start = 0; // конец действия
    }
    // чёрный с прозрачностью fade
    for( int i = 0; i < 4; i++ ) dark_q.v[i].col = ARGB(fade, 0, 0, 0);
    }
    // тут рисуем зачернение dark_q
    ...
    } конец
  • DovakiinDovakiin June 2012
    Спасибо большое! :)
  • DovakiinDovakiin June 2012
    Адаптировал немного твой код под свою программу, но эффект получается почти тот же - только после 2х секунд квад начинает рендерится, и все вычисления fade идут в никуда. Пробовал for запихивать в проверку delta - безрезультатно. Пробовал там же после фора рендерить - то же самое. Почему дельту изменил - да потому что GetTickCount() уж слишком заоблачные значения мне возвращает и если мы от них отнимаем 1 - то никак не получается войти в диапазон 2000.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	if (draw_darkness != 0) 
    {
     
    delta += hge->Timer_GetDelta();
    unsigned char fade = 255;
    if (delta < 2) {
    fade = delta * 255 / 2000;
    } else {
    draw_darkness = 0; // конец действия
    }
    // чёрный с прозрачностью fade
    for( int i = 0; i < 4; i++ ) dark_q.v[i].col = ARGB(fade, 0, 0, 0);
    hge->Gfx_RenderQuad(&dark_q);
    }
  • kvakvskvakvs June 2012
    Зачем от тик каунта отнимать 1?
    Тебе нужна разница между двумя разными тиккаунтами, она в миллисекундах и очень удобная.
  • DovakiinDovakiin June 2012
    Извиняюсь за свою же невнимательность. Плохо прочёл твой ответ и думал, что glob_fade_start всё равно что присваивать.
    В общем сделал всё нормально, но оно немного странно работает :) Всё плавно потухает и красотень вообще, но почему-то не в тот момент, который нужно.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    if (glob_fade_start != 0) 
    {
    unsigned int delta = GetTickCount() - glob_fade_start;
    unsigned char fade = 255;
    if (delta < 1000) {
    fade = delta * 255 / 1000;
    } else {
    glob_fade_start= 0; // конец действия
    }
    for( int i = 0; i < 4; i++ ) dark_q.v[i].col = ARGB(fade, 0, 0, 0);
    hge->Gfx_RenderQuad(&dark_q);
    }
     
    if ((w_p_x>=500)&&(w_p_x<=800)) // в этот момент мне нужно, чтобы экран потухал, а ф-ция не срабатывает до того времени, покуда не войдёшь и не выйдешь из этих координат
    glob_fade_start = GetTickCount();
  • kvakvskvakvs June 2012
    Тебе надо сделать так, чтоб glob_fade_start присваивался ровно один раз. А у тебя он будет присваиваться каждый кадр пока условие true. Добавь туда ещё проверку && glob_fade_start == 0

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In Apply for Membership

In this Discussion

Who's Online (0)