Войти
ФлеймФорумПроЭкты

Contra Force Advance (14 стр)

Страницы: 113 14 15 1620 Следующая »
#195
0:19, 21 сен. 2018

=A=L=X=
В video.cpp ставлю размер фона как и у всех слоёв REG_BG2CNT = [...] BG_SIZE_256x256
В game_states.cpp в прокрутке фонов ставлю REG_BG2HOFS = vpx; и REG_BG2VOFS = vpy; вместо vpx >> 2; и vpy >> 2;, чтобы фон не прокручивался, а стоял на месте
Я так понимаю, нужно ещё обновлять viewport, поэтому в game_states.cpp в GameStateLevel::tick() пишу refreshViewport( TILE_MAP2, false );, но не похоже, что это на что-то влияет в принципе. Везде, где есть refreshViewport( TILE_MAP1, true ); ставлю ещё и refreshViewport( TILE_MAP2, true );, но опять никакого результата и даже стало тормозить в тех местах, где у карты швы. Значит это не оно. Я что-то не понимаю и прошу помочь.

Главное разобраться с раскладкой памяти - с какого адреса что лежит и сколько байт занимает.

Так, у меня на большой карте что-то заходит немного на память спрайтов, это начало происходить после того, как вместо неба стал использовать граунд. Значит, у меня карта слишком большая и её нужно делать меньше, правильно?

#196
3:07, 21 сен. 2018

zcojam

В дополнение к тому что сделал нужно сделать еще следующее:
1. убрать везде вызовы функций fillBackground и emptyBackground - они заполняли бэкграунд неба пустотой или небом собственно, теперь они уже будут делать неправильное.
2. функция refreshViewport это сосредоточие игры со скроллингом фона по принципу олдовых консолей, но вызывать её второй раз для другого фона уже поздно - внутри себя она ориентируется на то насколько сдвинулся вьюпорт и правит глобальное состояние камеры одновременно пододвигая, и обновляя, при необходимости полоску тайлов в переданном ей фоне. второй раз уже сдвигать нечего, т.к. уже всё сдвинуто.
таким образом тебе надо сразу передавать в эту функцию два искомых фона, чтобы она правила их одновременно. то есть переделать её заголовок на:

void refreshViewport( u16 *tileMap, u16 *tileMap2, bool forceRefill )
в video.cpp и video.h и далее в самой этой функции вызывается несколько раз функция refillViewportArea и в ней происходит перенос индексов тайлов из карты в фон:
...
tile32w( tileMap, x & 31, y & 31 ) = wTile( x, y );
...
тут тебе опять проще всего дополнить эту функцию параметров tileMap2 и рядом с этой строкой положить строку её обновления.
Только брать надо не из wTile, а из нового источника данных для твоего фона. Посмотрим на эту функцию:
// Содержимое клетки карты поля (world map)
inline int wTile( int x, int y )
{
  return tilesOpt[ mapTiles[ x + y * mapWidth ] ];
};
mapTiles это глобальный массив карты поля получаемый на этапе компиляциии ресурсов, а tilesOpt это его вспомогательный массив из-за оптимизации тайлов в этой же фазе - это генерируется батником build_graphics из карты поля и подшивается в исходники игры:
..\..\tmx2incl.exe bct ..\images\mts-01.bmp ..\resources\map-01.tmx gr_main
тут получается из карты tmp исходные коды на си в модуле gr_main с картинками тайлов, но при этом на каждый слой (layer) с тайлами в tmx еще создаётся исходник с названием этого слоя (gr_walls_01 и gr_map_01 в моём случае).
То есть тебе с этим надо  хорошо разобраться и сделать свой слой со своим именем, увидеть что генерируется его модуль и подставить в res_graphics.cpp его подключение и тогда тебе будет возможность написать аналог wTile для
tile32w( tileMap2, x & 31, y & 31 ) = wTile2( x, y );

#197
(Правка: 3:15) 3:15, 21 сен. 2018

P.S.

Раскладка фонов в памяти формируется следующими строками в video.h:

#define TILE_DATA   ((u16*) (VID_RAM_START + 0x0000) )
#define TILE_MAP0   ((u16*) BG_TILE_MAP_ADDR( 28 ) )
#define TILE_MAP1   ((u16*) BG_TILE_MAP_ADDR( 29 ) )
#define TILE_MAP2   ((u16*) BG_TILE_MAP_ADDR( 30 ) )
То есть TILE_DATA это просто начало видеопамяти как таковое, а TILE_MAPx смещены в её конец, чтобы не пересекаться с лежащими с самого начала данными тайлов.
Посмотрим как макрос BG_TILE_MAP_ADDR устроен в gba_defs.h:
// Получить адрес начала карты тайлов, увеличение логического номера
// увеличивает его на 2048 байт, начиная с начала VID_RAM.
#define BG_TILE_MAP_ADDR(x)  (0x6000000 + (x) * 0x800)
То есть он как бы оперирует страницами по 2048 байт - вся память тайлов фонов состоит из 32 таких страниц от 0 до 31.

То есть в моём случае TILE_MAP0 лежит по адресу VID_RAM_START + 28 * 2048 = VID_RAM_START + 57344байт и так далее. Если размер какой то области уменьшился, то остальные можно подвинуть чтобы прижать их больше к потолку.
Но тут получается, что у тебя сократился в 2 раза размер области TILE_MAP2, то есть прижать на одну страницу в 2048 байт вверх желательно все области:

#define TILE_MAP0   ((u16*) BG_TILE_MAP_ADDR( 29 ) )
#define TILE_MAP1   ((u16*) BG_TILE_MAP_ADDR( 30 ) )
#define TILE_MAP2   ((u16*) BG_TILE_MAP_ADDR( 31 ) )

#198
4:52, 21 сен. 2018
// Содержимое клетки карты поля (world map)
inline int wTile( int x, int y )
{
  return tilesOpt[ mapTiles[ x + y * mapWidth ] ];
};
Значит по аналогии с этим пишу wTile2, tilesOpt и mapTiles остаются как есть? Вот я добавил в res_graphics.cpp #include "gr_backgr_02.inc", в res_graphics.h тоже добавил всё что нужно по аналогии с другими слоями, а как игра поймёт, что этот мой gr_backgr относится к mapTiles? Или это один массив для все слоёв?

Когда сместил области всех слоёв на 1, слой текста стал прокручиваться вместе фоном, поэтому сместил только TILE_MAP1 и 2, вроде пока всё хорошо с тайлами спрайтов.

#199
(Правка: 5:07) 5:04, 21 сен. 2018

zcojam

tilesOpt остаётся как есть, потому что он един для всех слоёв и диктуется только битмапом с тайлами .bmp.
А вот mapTiles это массив как раз с содержимым индексов тайлов слоя map_01 и он сейчас описывает слой map_01.
Откуда он берется - в contra_force_advance.h/cpp описан ряд переменных описывающих _текущий_ уровень:

extern int mapWidth, mapHeight;
extern const u16 *mapTiles;
extern const u16 *tilesOpt;
extern const u16 *mapWalls;
extern int fontStartTile;
Они заполняются при вызове функции applyMap из gameStates - всякий раз при активации нового уровня там могут быть разные параметры и потому эти переменные во времени меняются.
Прям по хорошему тебе надо дополнить нужной информацией структуру MapDesc (описание текущего уровня) и далее пропатчить все функции её использующие, чтобы кроме mapTiles и mapWalls была еще mapTiles2 или типа того.
Массив из MapDesc
MapDesc mapDescs[ 1 ] =
{
  {
    gr_map_01_width, gr_map_01_height,
    gr_map_01, gr_walls_01,
    gr_backgr_01_width, gr_backgr_01_height, gr_backgr_01,
    992,
    {
      tileSets + 0,  tileSets + 1
    },
    gr_actors_01
  }
};
сейчас как раз описывает один единственный тестовый уровень - и в каждой его ячейке как раз описаны все основные характеристики уровня, от фона до задника - они ссылаются как раз на те названия в *.inc-файлах что генерируются из ресурсов. Но именно здесь происходит их связывание в описание уровня для движка.

Временно же для проверки правильности ты можешь захардкодить имя ресурса в своей новой wTile2 для скорости.

#200
5:20, 21 сен. 2018

Ладно, спасибо, днём сделаю, а то спать очень хочется уже :3

#201
(Правка: 7:36) 7:19, 21 сен. 2018

=A=L=X=
Уснуть я так и не смог.
В общем, пробовал всё, что только можно, самый задний фон никак не хотел рисоваться. Рисовал его в передний слой - он отображался, значит ссылки все я указал правильно. Потом попробовал у тайловых карт вернуть смещение 28,29,30, как было раньше, в результате всё рисует как надо. На память спрайтов ничего не заезжает - видимо, это я где-то напортачил ранее.

Upd.
Всё, вот теперь вообще ништяк. Наконец-то у меня будут передние объекты на обычном фоновом слое, а не состряпанные из спрайтов. Жаль, придётся отказаться от прокручиваемых фонов, конечно, но придётся чем-то жертвовать.
Вопрос ещё такой. У меня переходы между уровнями осуществляются с помощью актёров. То есть стоит актёр на сцене и он проверяет коллизии, но проверяет пиксели через циклы по Х и Y, ибо я не знаю, можно ли это по-другому сделать. Есть другой вариант - использовать вместо них наклонные стены на слое стен, принцип тот же, к тому же коллизии уже есть изначально в твоём коде, и вообще их стоило использовать изначально. Так вот вопрос в чём - как считаешь, сильно ли переход на эти вот наклонные стены облегчит нагрузку, учитывая что сейчас коллизии слушает актёр 16х16, а это 256 операций за тик, и на экране может быть одновременно несколько таких актёров. Или не облегчит и стены слушают коллизии примерно по такому же принципу?

#202
8:18, 21 сен. 2018

zcojam
> Жаль, придётся отказаться от прокручиваемых фонов
Да не обязательно. В этом видеорежиме у GBA есть еще один слой - четвертый. Можешь его использовать еще.

> У меня переходы между уровнями осуществляются с помощью актёров
Не могу понять о чём речь. Переход между разными локациями типа выйти из дома на улицу?

Вообще актёрам дана способность дёшево "обшаривать" пространство вокруг себя в поисках других актёров, это можно поглядеть например в моих классах пули или гранаты в tick. То есть столкновения актёр-актёр делаются легко и эффективно по их границам самим движком с выборкой только из ближайших соседей по методике sweep&prune. Так же там можно фильтровать по маске какие именно актёры интересуют - внутриигровые фракции или подвижные предметы и т.п.
Если речь про выход из здания на улицу я бы рекомендовал на место двери вставлять невидимого актёра "переход в локацию", который бы активировал переключение при соприкосновении с игроком.

#203
8:50, 21 сен. 2018

=A=L=X=
> Переход между разными локациями типа выйти из дома на улицу?
Да, переходы типа из дома на улицу, на швах, где тайлы подгружаются они стоят, и просто события будут активировать.
Отлично, сделаю как в классах пули или гранаты, это то, что мне нужно.

#204
(Правка: 8:58) 8:57, 21 сен. 2018

zcojam

Конструкция

    for ( auto it: ActorsRange( this, targets ) )
    {
      ...
    };
В коде актёра обшаривает и проходит вокруг по тем актёрам которые соприкасаются с текущим - соприкосновение проверяется по физическим координатам и размерам, плюс еще параметр targets это маска фракции, по ней тоже можно отфильтровать.
Фракции определены в actors.h как битовые маски:
  GameGroupNone    = 1 << 0, // актёры которые не нужны другим актёрам
  GameGroupContra    = 1 << 1, // подразделение Contra
  GameGroupTerrorists  = 1 << 2, // террористы
  GameGroupAliens    = 1 << 3, // чужие
  GameGroupItems    = 1 << 4, // предметы
  GameGroupCorpses    = 1 << 5, // трупы
  GameGroupObstacles  = 1 << 6, // препятствия
т.к. у тебя задача перейти только по игроку то можешь завести маску GameGroupPlayer = 1 << 6, только её надо обязательно прописать при создании объекта класса ActorPlayer в его group.
P.S.

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

#205
1:17, 26 сен. 2018

=A=L=X=
В общем я решил попробовать включить ещё один слой. Пробую вот в этой строке:

#define TILE_MAP1   ((u16*) BG_TILE_MAP_ADDR( 29 ) )
поменять адрес с 29 на 27, чтобы убедиться, что я в принципе могу что-то там рисовать, но фон по такому адресу не рисуется. Это нужно как-то в другом месте ещё указывать?
#206
(Правка: 3:04) 3:03, 26 сен. 2018

zcojam
> Это нужно как-то в другом месте ещё указывать?

Да, в этой строке только создаётся программный идентификатор для ссылки на начало будущего слоя в видеопамяти. Просто для удобства будущего обращения к нему.
Сам же слой создаётся обращениями к портам ввода видеочипа в функции setDefaultVideoMode в модуле video.cpp:

  // Включаем задние фоны:
  REG_BG0CNT =  BG_PRIORITY( 0 ) | BG_TILE_DATA_AT_0000 | BG_COLOR_256 |
      BG_TILE_MAP_AT( 28 ) | BG_SIZE_256x256;

  REG_BG1CNT =  BG_PRIORITY( 2 ) | BG_TILE_DATA_AT_0000 | BG_COLOR_256 |
      BG_TILE_MAP_AT( 29 ) | BG_SIZE_256x256;

  REG_BG2CNT =  BG_PRIORITY( 3 ) | BG_TILE_DATA_AT_0000 | BG_COLOR_256 |
      BG_TILE_MAP_AT( 30 ) | BG_SIZE_512x256;
Заметь, что здесь нужно повторить в макросе BG_TILE_MAP_AT номер слота в видеопамяти где слой начинается такой же как в BG_TILE_MAP_ADDR и именно здесь указывается размер, приоритет отображения и цветность слоя. Вообще поразглядывай содержимое файла gba_defs.h - там я постарался максимально подробно разжевать состав и содержимое портов ввода-вывода видеочипа.

#207
(Правка: 14:34) 0:19, 27 сен. 2018

=A=L=X=
Слушай, такой вопрос. У меня есть длинный тайлсет, из которого я подгружаю нужные куски в память. Для удобства тайлы разбиты по категориям, и между ними есть пустые тайлы. Я так понял, что tmx2incl оптимизирует тайлсет таким образом, что удаляет вообще все одинаковые тайлы, а из-за того, что у меня пробелы между категориями, все тайлы смещаются в оптимизированном тайлсете влево. В результате этого мне трудно высчитывать адрес тайлов, которые я подгружаю из длинного сета - придётся учитывать количество удалённых тайлов, а оно может измениться, если я решу где-то что-то подвзменить. Можно ли как-то аккуратно отрубить оптимизацию тайлов, чтобы не переворачивать кучу кода в tmx2incl?
Upd. Хотя не, оптимизацию отключать всё таки не варик. Но тогда придётся каким-то образом смотреть, чтобы тайлы не повторялись на тайлсете вообще, чтобы нормально считать. Одни запары, в общем. Ладно, не заморачивайся с вопросом, оставлю как есть, буду подбором искать адреса.

+ Показать
#208
1:30, 27 сен. 2018

zcojam

Для решения этой проблемы в процессе оптимизации тайлов tmx2incl создаёт вспомогательный массив opt - информация о том куда оптимизационный процесс поместил тайл в процессе оптимизации.
Например gr_main_opt из gr_main.til.inc содержит информацию о том куда каждый из 2048 исходных тайлов попал в итоговом массиве gr_main_til.
opt[ i ] = номер тайла в оптимизированном тайлсете куда попал тайл номер i изначального изображения в неоптимизированном bmp
Именно поэтому если посмотреть на функцию printString (и многие другие), то в ней все номера тайлов с текстом протягиваются через эту функцию:

      tile32w( TILE_MAP0, x, y ) = c ? tilesOpt[ fontStartTile - ' ' + c ] : 0;
Потому что мы знаем, что тайлы с алфавитом начинаются в исходном битмапе с номера fontStartTile (эта переменная берется из описания уровня как и tilesOpt), а чтобы понять куда она попадает в оптимизированном тайлсете - нужно пропустить информацию через opt.
Так же оптимизацию можно отключить - это контролируется флагами командной строки для tmx2incl - тогда opt вообще не будет генерироваться (как у тайлов спрайтов).

#209
2:33, 27 сен. 2018

zcojam
что ты делаешь?

Страницы: 113 14 15 1620 Следующая »
ФлеймФорумПроЭкты