Эмуляция олдскульного мерцания спрайта (теория и понятие)

Я пытаюсь разработать oldschool видеоигру стиля NES с мерцанием спрайта и графическим замедлением. Я думал, какую логику я должен использовать для включения таких эффектов.

Я должен рассмотреть следующие ограничения, если я хочу пойти олдскульный стиль NES:

  • Не больше, чем 64 спрайта на экране за один раз
  • Не больше, чем 8 спрайтов на строку развертки, или для каждой строки на оси Y
  • Если существует слишком много действия, идущего на экран, система замораживает изображение для кадра, чтобы позволить процессору догнать действие

Из того, что я читал, если бы было больше чем 64 спрайта на экране, то разработчик только потянул бы первоочередные спрайты при игнорировании низкоприоритетных. Они могли также чередоваться, таща каждый четный спрайт на противоположных кадрах от нечетных.

Проблема строки развертки интересна. От моего тестирования невозможно получить хорошую скорость на платформе XBOX 360 XNA путем рисования спрайтов попиксельно, как NES сделал. Поэтому в олдскульных играх, если бы было слишком много спрайтов на одной строке, некоторые появились бы, если бы они были сокращены в половине. Во всех целях для этого проекта я заставляю строки развертки быть 8 пикселей высотой, и собираю в группу спрайты на строку развертки их расположением Y.

Для разъяснения я потянул бы спрайты на экран в пакетах 8x8 пикселей, не 1x1.

Так, dumbed вниз я должен предложить решение это....

  • 64 спрайта на экране сразу
  • 8 спрайтов на 'строку развертки'
  • Может потянуть спрайты на основе приоритета
  • Может чередоваться между спрайтами на кадр
  • Эмулируйте замедление

Вот моя текущая теория

Прежде всего фундаментальная идея, которую я придумал, обращается к приоритету спрайта. Принимая значения между 0-255 (0 являющийся низким), я могу присвоить приоритетные уровни спрайтов, например:

  • От 0 до 63 являющийся низким
  • 63 - 127 являющийся средним
  • 128 - 191 являющийся высоким
  • 192 - 255 являющийся максимальным

В рамках моих файлов данных я могу присвоить каждый спрайт, чтобы быть определенным приоритетом. Когда родительский объект создается, спрайту случайным образом присвоить номер между его обозначенным диапазоном. Я затем потянул бы спрайты в порядке от высоко до низкого с конечной целью рисования каждого спрайта.

Теперь, когда спрайт оттянут в кадре, я затем случайным образом генерировал бы его новое приоритетное значение в его начальном приоритетном уровне. Однако, если спрайт не становится оттянутым в кадре, я мог бы добавить 32 к его текущему приоритету. Например, если система может только опустить спрайты к приоритетному уровню 135, спрайт с начальным приоритетом 45 мог затем быть оттянут после 3 кадров того, чтобы не быть оттянутым (45+32+32+32=141)

Это, в теории, позволило бы спрайтам чередовать кадры, позволять приоритетные уровни и предельные спрайты к 64 на экран.

Теперь, интересный вопрос состоит в том, как я ограничиваю спрайты только 8 на строку развертки?

Я думаю, что, если я сортирую высокий приоритет спрайтов к низкому приоритету, выполните итерации через цикл, пока я не поразил 64 оттянутые спрайта. Однако я не должен только брать первые 64 спрайта в списке.

Прежде, чем потянуть каждый спрайт, я мог проверить для наблюдения, в скольких были оттянуты спрайты, он - соответствующая строка развертки через переменные счетчика. Например:

  • Y-значения между от 0 до 7 принадлежат Строке развертки 0, scanlineCount[0] = 0
  • Y-значения между 8 - 15 принадлежат Строке развертки 1, scanlineCount[1] = 0
  • и т.д.

Я мог сбросить значения на строку развертки для каждого оттянутого кадра. При потере работоспособности по списку спрайта добавьте 1 к соответствующему счетчику строки развертки, если спрайт оттянут в той строке развертки. Если это равняется 8, не тяните тот спрайт и переходите к спрайту со следующим самым низким приоритетом.

ЗАМЕДЛЕНИЕ

Последняя вещь, которую я должен сделать, эмулируют замедление. Моя начальная идея состояла в том, что, если я - спрайты рисунка 64 на кадр и существует еще больше спрайтов, которые должны быть оттянуты, я мог приостановить рендеринг на 16 мс или около этого. Однако в играх NES я играл, иногда существует замедление, если нет никакого продолжения мерцания спрайта, тогда как игра перемещается красиво, даже если существует некоторое мерцание спрайта.

Возможно, дайте значение каждому объекту, который использует спрайты на экране (как приоритетные значения выше), и если общая стоимость всех объектов w/спрайты превосходит порог, представляет замедление?

В ЗАКЛЮЧЕНИИ...

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

20
задан Jeffrey Kern 5 June 2010 в 12:02
поделиться

2 ответа

Во-первых, мне нравится идея. При создании ретро-игры все было бы иначе, если бы вы проигнорировали ограничения сложности. Написание фреймворка, подобного , - это отличная идея.

Могу я просто сказать, что если бы вы абстрагировали движок как графический движок «Ретро-игра» с открытым исходным кодом, это было бы действительно круто, и я обязательно присоединюсь!

  • Что касается ваших спрайтов с наивысшим приоритетом, возможно, Priority Queue упростит эту часть, поскольку вы можете просто извлечь 64 спрайта с наивысшим приоритетом.

  • С замедлением, возможно, в движке у вас может быть limitValue . Каждый спрайт как соответствующий предел Используйте . Сложите все limitUse vars, и если это ниже limitValue , замедления не будет. Теперь для slowDelay = f (limitUseTotal - limitValue) , где f - функция, которая преобразует избыточное количество спрайтов в вычисленное значение замедления. Это общая идея, которую вы предлагаете, или я неправильно ее понял?

3
ответ дан 30 November 2019 в 01:35
поделиться

Для приоритета просто используйте Z-индекс. По крайней мере, это то, что делает GBA; приоритет 0 отображается на переднем плане, поэтому имеет самый слабый приоритет. Итак, рендеринг от высокого к низкому, и если вы отрендерили слишком много спрайтов, остановитесь.

Приоритет спрайта определяется его индексом в таблице спрайтов. GBA имеет 128 записей [0,127], организованных как последовательные четыре h-слова (по 16 байтов каждая). Для XNA вы, вероятно, использовали бы вместо этого List или аналогичный. Может быть, Sprite [256] , чтобы немного упростить.

Ограничение рендеринга спрайтов естественно вытекает из этого механизма. Поскольку вы выполняете рендеринг от 255 до 0, вы можете отслеживать, каких строк развертки вы коснулись. Итак, в основном:

int[] numPixelsDrawnPerScanline = new int[Graphics.ScreenHeight];

foreach(Sprite sprite in SpriteTable.Reverse()) {
    int top = Math.Max(0, sprite.Y);
    int bottom = Math.Min(Graphics.ScreenHeight, sprite.Y + sprite.Height);

    // Could be rewritten to store number of pixels to draw per line, starting from the left.
    bool[] shouldDrawOnScanline = new bool[Graphics.ScreenHeight];

    for(int y = top; y < bottom; ++y) {
        bool shouldDraw = numPixelsDrawnPerScanline[y] + sprite.Width <= PixelsPerScanlineThreshold;

        shouldDrawOnScanline[y] = shouldDraw;

        if(shouldDraw) {
            numPixelsDrawnPerScanline[y] += sprite.Width;
        }
    }

    Graphics.Draw(sprite, shouldDrawOnScanline); // shouldDrawOnScanline defines clipping

    skipDrawingSprite:
}

Я не совсем понимаю, что вы имеете в виду под замедлением, поэтому не могу ответить на эту часть вашего вопроса. Извините.

Надеюсь, это поможет.

3
ответ дан 30 November 2019 в 01:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: