Подделка изометрической графики в 2D космической игре

15

Во-первых, я точно знаю, в чем заключается моя проблема рисования, и у меня есть разные идеи о том, как подойти к ее решению. Я здесь, чтобы выяснить, как отрегулировать, какой кадр нарисован, чтобы сохранить изометрическую «иллюзию».

Я пишу 2D игру с высоты птичьего полета, которая происходит в космосе. Я пытаюсь использовать изометрическую графику в мире, где Up - это север, а вращение игрового мира не происходит, как в традиционных изометрических играх (помните, что игра происходит в космосе, без ландшафта). Вот пример спрайта, который я пытаюсь использовать: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64.png Поворот 64 раза вокруг своей вертикальной оси с углом обзора 35 градусов (иначе изо). Изображение было сгенерировано, так что это можно изменить.

Для ясности я продиктовал, что север (вверх) равен 0 градусам, а восток (справа) равен 90.

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

http://cell.stat-life.com/images/stories/AsteroidOutpost/ProjectionIssue.png Слева у меня вид сбоку, справа - сверху вниз. На вершине, у меня есть космический корабль / спрайт лист мира. Внизу у меня есть то, как выглядит спрайт, когда он рисуется на экране.

В верхнем правом углу приведен упрощенный вариант поворота моего космического корабля (четное разделение градусов между каждым кадром). В правом нижнем углу - угол, на который спрайт выглядит так, как будто он направлен на экран под конкретным углом. Проблема наиболее очевидна при температуре около 45 градусов. Вот изображение, наложенное линией «плоскости экрана», которая указана в направлении, в котором должен стоять корабль: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLine.png Красная линия всегда должна быть направлена ​​точно в том же направлении, что и корабль, но, как вы можете видеть, проблема проецирования вызывает проблему. Я надеюсь, что я описываю проблему достаточно хорошо.

РЕДАКТИРОВАТЬ: красная линия вращается на плоскости экрана, в то время как космический корабль вращается на «плоскости корабля», следовательно, большая разница между углом корабля и углом экрана при его рисовании. КОНЕЦ РЕДАКТИРОВАНИЯ

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

Итак ... решения, которые я придумал:

  1. Прекратите пытаться подделать изометрический вид, идите дальше или идите домой. Поверни мой мир уже. (PS: это решит мою проблему, верно?)
  2. Измените мой лист спрайта (каким-то образом), чтобы иметь рамки, представляющие «угол экрана», под которым будет просматриваться модель. Поэтому, когда я запрашиваю изображение под углом 45 градусов, оно на самом деле будет выглядеть так, будто оно направлено на экран под углом 45 градусов.
  3. Измените мою систему рендеринга спрайтов, чтобы захватить другой кадр из листа спрайта (каким-то образом), зная, что захват "нормального" кадра будет выглядеть забавно. Таким образом, вместо захвата кадра в 45 градусов, он будет захватывать кадр в 33 градуса (просто угадывая), чтобы он выглядел правильно для пользователя.
  4. Просто используйте 3D! Это намного проще, мужик

Для одного: какое решение вы бы порекомендовали? Я склоняюсь к 2, хотя я знаю, что это неправильно. Помните, что у меня есть полный доступ к инструменту генерации спрайтов. Метод 3 будет моим вторым выбором. Оба эти метода просто требуют, чтобы я применил некоторую математику к углу (ам), чтобы получить желаемый результат. Кстати, я добавил в качестве шутки № 4, я не хочу переходить на 3D.

Для двоих: используя методы 2 или 3, как мне настроить входной или выходной углы? Я не очень хорош с 3D-проекциями и 3D-матрицами (не говоря уже о 2D-матрицах) и любой другой математикой, которая может быть использована для достижения желаемого результата.

Думая здесь вслух: если я возьму единичный вектор, обращенный в направлении, которое я хочу, чтобы корабль смотрел (на плоскость экрана), то спроецируем это на плоскость корабля, а затем выясним, какой угол между этой спроецированной линией и плоскостью север, я должен иметь угол наклона графика корабля, который я хочу отобразить. Правильно? (решение для № 3?) Человек ... Я не могу решить это.

РЕДАКТИРОВАТЬ:

Я знаю , что проблема трудно визуализировать со статическими изображениями, так что я выполнил свою Sprite Library Визуальный Tester для отображения вопроса: http://cell.stat-life.com/downloads/SpriteLibVisualTest.zip Это требует XNA 4.0 Это приложение просто вращая спрайт и рисуя линию от его центральной точки наружу под углом, по которому игра думает, что корабль должен быть направлен.

РЕДАКТИРОВАТЬ 8 сентября

Продолжая мой абзац «мысли вслух»: вместо того, чтобы использовать проекцию (потому что она выглядит сложно), я думаю, я мог бы взять вектор единиц измерения, обращенный на север (0x, 1y, 0z), использовать матрицу, чтобы повернуть его на угол спрайт на самом деле обращен, затем поверните его снова из «плоскости просмотра» наружу в «плоскость спрайта» вокруг оси X, затем ... сгладить? вектор (по сути, проецируя его) обратно на плоскость просмотра, используя только X и Y (игнорируя Z). Затем, используя этот новый плоский вектор, я мог определить его угол и использовать его для ... чего-то. Я подумаю позже.

РЕДАКТИРОВАТЬ 8 сентября (2)

Я попытался следовать своей идее сверху с некоторым успехом, ура! Итак ... чтобы красная линия выглядела так, будто она идет прямо с моего космического корабля (только в целях тестирования), я сделал следующее:

Vector3 vect = new Vector3(0, 1, 0);
vect = Vector3.Transform(vect, Matrix.CreateRotationZ(rotation));
vect = Vector3.Transform(vect, Matrix.CreateRotationY((float)((Math.PI / 2) - MathHelper.ToRadians(AngleFromHorizon))));
Vector2 flattenedVect = new Vector2(vect.X, vect.Y);

float adjustedRotation = (float)(getAngle(flattenedVect.X, flattenedVect.Y));

Где rotationнаходится угол экрана и adjustedRotationтеперь этот угол экрана смотрит на плоскость спрайта. Я не знаю, почему мне нужно было вращать Y вместо X, но, вероятно, это что-то связанное с 3D, о котором я не знаю.

Итак, теперь у меня есть дополнительная часть информации, но как я могу использовать это, чтобы выбрать более подходящий кадр? Возможно, вместо того, чтобы вращаться из плоскости обзора в плоскость спрайта, а затем проецироваться назад, я должен попытаться сделать это наоборот. Вот мой спрайт с отрегулированной красной линией, но я действительно хочу настроить модель, а не линию: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLineCorrected.png

РЕДАКТИРОВАТЬ 9 сентября

HORAY! Это фиксированная! Я опишу, что я сделал, чтобы это исправить:

Я последовал совету электронного бизнеса и «сжал» мировую систему координат (или растянулся ...?). По сути, это решение № 1, хотя у меня сложилось впечатление, что мне придется повернуть свою мировую систему координат относительно системы координат экрана. Не правда! Вверх по-прежнему + у, а справа по-прежнему + х. Я изменил свои методы WorldToScreen и ScreenToWorld, чтобы правильно преобразовывать координаты мира и экрана. Эти методы могут быть неоптимальными, но вот только два метода в моей кодовой базе, которые пришлось изменить.

public Vector2 ScreenToWorld(float x, float y)
{
    float deltaX = x - (size.Width / 2f);
    float deltaY = y - (size.Height / 2f);

    deltaX = deltaX * scaleFactor / (float)Math.Sqrt(3);
    deltaY = deltaY * scaleFactor;

    return new Vector2(focusWorldPoint.X + deltaX, focusWorldPoint.Y + deltaY);
}

public Vector2 WorldToScreen(float x, float y)
{
    float deltaX = x - focusWorldPoint.X;
    float deltaY = y - focusWorldPoint.Y;

    deltaX = deltaX / scaleFactor * (float)Math.Sqrt(3);
    deltaY = deltaY / scaleFactor;

    return new Vector2(size.Width / 2f + deltaX, size.Height / 2f + deltaY);
}

Вот и все! Изменение этих двух методов повлияло на все остальное: на что я смотрю, где объекты нарисованы, где я щелкаю, на все. Мой космический корабль теперь смотрит прямо на цель, которую он стреляет, и все становится на свои места. Я буду экспериментировать с ортографической проекцией, посмотрим, заставит ли она все казаться более «реальной».

Джон Макдональд
источник
Поздравляю. Не забудь ткнуть меня, как только у тебя появится что-нибудь играбельное, я бы хотел посмотреть, к чему это приведет
аааааааааааа
@eBusiness Как и было обещано: cell.stat-life.com/images/stories/AsteroidOutpost/… и cell.stat-life.com/images/stories/AsteroidOutpost/AOOhNoes.png Заметьте, как выглядит корабль , смотрящий на эту башню? : D Спасибо!
Джон Макдональд
@eBusiness, видео youtube.com/watch?v=Q8pR9KDBsCo Там также есть ссылка для скачивания, так как вы спросили.
Джон Макдональд

Ответы:

4

Когда вы выбрали изометрическую перспективу, вам необходимо скорректировать масштаб между осями X и Y. Если заданное расстояние проецируется на 1 на оси Y экранов, то такое же расстояние проецируется на sqrt (3) на оси X экранов. Так что, если вы рисуете вещи на экране, вы бы сделали что-то вроде:

draw(object.image, object.x*sqrt(3), object.y)

Примечания без ответа:

  • Зачем вам связываться со спрайт-листами и прочим? Вы можете заставить 3D-рендеринг делать изометрию, если хотите.
  • Поскольку вы используете спрайт-листы, почему они не сглажены?
  • Изометрические в пространстве, я не думаю, что когда-либо видел игру, использующую это, я не уверен, насколько хорошо она будет работать, учитывая отсутствие четко изометрической основы для визуальной привязки.
AAAAAAAAAAAA
источник
1
Я думаю ... Это может исправить все. Это легко исправить, и я могу оставить лист в покое. Я попробую это как можно скорее и дам вам знать, как это происходит. Чтобы ответить на ваши заметки: 1) Я использую 2D, потому что это то, с чем я знаком, и я генерирую свои листы из 3D моделей. 2) Края должны быть острыми, но внутри жестких краев я мог бы использовать альфа-канал для сглаживания, которое придет. 3) Я не планирую моделировать третье измерение (много), я в основном хочу, чтобы 2D-графика не была сверху вниз и позволяла вам видеть стороны вещей.
Джон Макдональд
5

Как генерируется повернутый спрайт? Это скриншоты вращающейся 3D-модели? Угол наклона может быть отключен из-за перспективы камеры инструмента трехмерного моделирования. Изометрическая перспектива не является точным представлением трехмерного пространства. Материал далеко от «камеры» не становится меньше.

Если вы просто хотите быстро исправить. Решение 2 может быть трудно понять правильно. Решение 3 кажется простым, просто поменяйте местами кадры, не соответствующие углу, с тем, который лучше соответствует углу.

Лазеры все еще иногда будут выключены. Поскольку вы не делаете плавное вращение, но показывает различные кадры для определенных диапазонов градусов.

РЕДАКТИРОВАТЬ:

Ваша проблема в том, что сгенерированные снимки экрана не в изометрической перспективе, а в обычном трехмерном виде.

введите описание изображения здесь

Изометрический вид имитирует трехмерное пространство, но не является точным представлением. Вещи становятся меньше с увеличением расстояния от камеры. Это не сделано для изометрической перспективы, так как это приведет к появлению уродливых артефактов масштабирования в спрайте.

Снимки экрана вашего космического корабля сделаны с трехмерной перспективы. Вот почему лазерная съемка отключена. Сравните красную линию в «изометрии» и «перспективе».

Ваш генератор спрайтов должен использовать Matrix.CreateOrthographic () вместо Matrix.CreatePerspective () для матрицы проекции.

Стивен
источник
Спрайт генерируется с помощью инструмента 3D-2D, который я разрабатываю, поэтому проблема вполне может быть в этом инструменте. Инструмент просто загружает 3D-модель, затем, чтобы получить Spaceship64.png (выше), он поворачивает модель на (360/64) = 5,625 градусов, сохраняет ее как рамку, затем снова поворачивает на ту же величину, пока не получит все 64 кадра. Код, используемый для визуализации модели, находится здесь: code.google.com/p/sprite-maker/source/browse/trunk/XNAWindow/… Поворот выполняется в другом классе. Я также думал, что решения 2 и 3 были обратными друг другу, нет?
Джон Макдональд
Отредактировал мой ответ. Смотри выше.
Стивен
Я думаю, что мне может понадобиться сделать и то и другое: заставить мой генератор спрайтов использовать ортогональную проекцию И изменить мою мировую систему координат, как то, что говорит @eBusiness. Вчера вечером я попробовал проекцию на орфографию, и это, безусловно, изменило внешний вид моего корабля, но одно это не помогло решить проблему с углом, с которой я столкнулся.
Джон Макдональд
Только что увидел ваши правки. Исправленный спрайт выглядит так, будто центр корабля смещен от центра красной линии. Может быть, этого достаточно, чтобы нарисовать корабль на один или два пикселя выше, чем начальная точка красной линии. Изменится ли видимая ошибка при удалении корабля от вашего мира? Тогда масштабирование по оси X может исправить это.
Стивен
1

Я думаю, что у вас здесь просто выглядит изометрия. Вы правы в том, что, визуально говоря, разница между 0deg и 10deg, по-видимому, больше, чем между 90deg и 100deg. , , но это потому, что изометрия внутренне сжимает одну ось. Если вы не хотите этот вид, вы не хотите изометрии.

Тем не менее, я думаю, что визуальные проблемы у вас возникают из-за отсутствия визуального ориентира. Ваш мозг предполагает, что вы смотрите на него сверху вниз - эй, это пространство, почему бы вам не быть - и поэтому интерпретирует его как стандартный вид сверху вниз. Для тестирования попробуйте добавить несколько плавающих голографических ориентиров. Например, 45-градусная угловая сетка или набор кругов вокруг вашего космического корабля. Убедитесь, что они соответствующим образом искажены, как если бы они находились на одной изометрической плоскости, на которой изображен ваш космический корабль. Держу пари, что ваш мозг определит перспективу, и она внезапно будет выглядеть правильно.

Теперь выясним, как донести это до ваших пользователей. , , это совсем другое дело.

ZorbaTHut
источник
Не нужно ли мне также вращать мировую ось, чтобы завершить иллюзию, используя этот метод (метод № 1 в вопросе)?
Джон Макдональд
Насколько я могу судить, корабль уже правильно отрисован - боковые виды показывают его под углом, который должен быть изометрическим, чтобы он выглядел "правильным". Я полагаю, я не уверен, что вы подразумеваете под «вращением мировой оси».
ZorbaTHut
Под «поворотом мировой оси» я подразумеваю поворот мира относительно камеры на 45 градусов, чтобы «север» был направлен к верхнему правому или левому верхнему углу экрана по диагонали, а не «север» был направлен вверх. к верхней части экрана.
Джон Макдональд
Например: imprimus.net/Images/Page%20Images/Downloadable%20Files/…
Джон Макдональд
Это может помочь, но в космосе это не должно иметь большого значения в любом случае. Если у вас нет сетки, наложенной на мир, это просто не должно иметь значения.
ZorbaTHut