Во-первых, я точно знаю, в чем заключается моя проблема рисования, и у меня есть разные идеи о том, как подойти к ее решению. Я здесь, чтобы выяснить, как отрегулировать, какой кадр нарисован, чтобы сохранить изометрическую «иллюзию».
Я пишу 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 Красная линия всегда должна быть направлена точно в том же направлении, что и корабль, но, как вы можете видеть, проблема проецирования вызывает проблему. Я надеюсь, что я описываю проблему достаточно хорошо.
РЕДАКТИРОВАТЬ: красная линия вращается на плоскости экрана, в то время как космический корабль вращается на «плоскости корабля», следовательно, большая разница между углом корабля и углом экрана при его рисовании. КОНЕЦ РЕДАКТИРОВАНИЯ
Это выглядит довольно странно, когда этот корабль стреляет лазерным лучом по цели, которая отклонена в сторону, когда он должен стрелять прямо вперед.
Итак ... решения, которые я придумал:
- Прекратите пытаться подделать изометрический вид, идите дальше или идите домой. Поверни мой мир уже. (PS: это решит мою проблему, верно?)
- Измените мой лист спрайта (каким-то образом), чтобы иметь рамки, представляющие «угол экрана», под которым будет просматриваться модель. Поэтому, когда я запрашиваю изображение под углом 45 градусов, оно на самом деле будет выглядеть так, будто оно направлено на экран под углом 45 градусов.
- Измените мою систему рендеринга спрайтов, чтобы захватить другой кадр из листа спрайта (каким-то образом), зная, что захват "нормального" кадра будет выглядеть забавно. Таким образом, вместо захвата кадра в 45 градусов, он будет захватывать кадр в 33 градуса (просто угадывая), чтобы он выглядел правильно для пользователя.
- Просто используйте 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);
}
Вот и все! Изменение этих двух методов повлияло на все остальное: на что я смотрю, где объекты нарисованы, где я щелкаю, на все. Мой космический корабль теперь смотрит прямо на цель, которую он стреляет, и все становится на свои места. Я буду экспериментировать с ортографической проекцией, посмотрим, заставит ли она все казаться более «реальной».