| netlib.narod.ru | < Назад | Оглавление | Далее > |
Вы даже не заметили, как ваш графический движок подрос до солидных размеров и у вас образовалось множество полезных классов, которые упрощают визуализацию двухмерных и трехмерных данных и включают много тестовых модулей, доступных в большинстве классов (рис. 5.14).
![]() |
Рис. 5.14 |
Пока вы не использовали много игровых компонентов и, по-моему, не имеет большого смысла писать базовый графический движок с использованием компонентов. Вы не используете какие-либо методы Update или Draw тем способом, которым это делают игровые компоненты. Да, класс Model использует метод Render, а в классе Input есть метод Update, но помимо этого у вас нет никакой функциональности, совместимой с игровыми компонентами. Методы Render в классах модели и текстуры работают немного по-другому, поскольку ожидают, что пользователь будет вызывать их несколько раз в каждом кадре с различными параметрами. Я предполагаю, что класс Input может быть преобразован в игровой компонент, но эта идея оставляет меня равнодушным.
Вместо этого давайте подумаем о частях игры, которые замечательно соответствуют модели игровых компонентов. Это имеет смысл, если у вас есть класс, который должен быть обновлен и нарисован в каждом кадре. Примерами таких классов могут быть счетчик частоты кадров или класс камеры, которые пока отсутствуют в вашем движке.
Для ваших тестовых модулей не нужна сложная камера, но было бы замечательно получить возможность перемещаться вокруг и иметь возможность рассматривать визуализируемые в тестовых модулях вашего движка объекты с разных сторон. С помощью матрицы вида и метода Matrix.CreateLookAt легко создать подобную функциональность и устанавливать ее там, где она требуется. Еще лучше использовать класс игрового компонента чтобы выполнять все это автоматически; все, что вам потребуется в этом случае, — создать экземпляр класса камеры в классе YourGame, наследуемом от класса BaseGame, и сразу все тестовые модули и другой код трехмерной графики будут использовать класс камеры без какого-либо дополнительного кода, поскольку Update вызывается автоматически для каждого игрового компонента, который есть в вашем классе YourGame.
public YourGame()
{
// Инициализация простой камеры
this.Components.Add(new SimpleCamera(this));
} // YourGame()
В классе SimpleCamera есть конструктор и вызываемые автоматически методы Initialize и Update (рис. 5.15). В классе также есть три поля для координат x, y и z камеры, которые инициализируются значениями 0, 0 и 15 соответственно. Метод Update меняет координаты x и y, основываясь на перемещениях мыши или, если у вас есть игровой пульт, на передвижениях правого джойстика. Кроме того, левым джойстиком вы можете приближать и отдалять камеру.
![]() |
Рис. 5.15 |
Класс весьма прост и достаточно легко прочитать весь его код:
/// <summary>
/// Класс простой, перемещающейся вокруг камеры.
/// Камера всегда направлена на центр и находится на одной высоте.
/// </summary>
class SimpleCamera : GameComponent
{
#region Переменные
float x = 0, y = 0;
float zHeight = 15.0f;
#endregion
#region Конструктор
public SimpleCamera(BaseGame game)
: base(game)
{
} // SimpleCamera(game)
#endregion
#region Initialize
public override void Initialize()
{
base.Initialize();
} // Initialize
#endregion
#region Update
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
// Обновление позиции камеры (поддерживает мышь и пульт)
x += Input.MouseXMovement / 10;
y += Input.MouseYMovement / 10;
x += Input.GamePad.ThumbSticks.Right.X;
y += Input.GamePad.ThumbSticks.Right.Y;
zHeight += Input.GamePad.ThumbSticks.Left.Y;
BaseGame.ViewMatrix = Matrix.CreateLookAt(
new Vector3(x, y, zHeight), Vector3.Zero, Vector3.Up);
} // Update(gameTime)
#endregion
} // class SimpleCamera
Самая важная вещь здесь — это ViewMatrix из класса BaseGame, инициализируемая в конце метода Update. При визуализации шейдера в классе модели или любом другом классе, таком как менеджер линий, вы будете использовать эту матрицу вида и гарантировать, что все ваши трехмерные данные будут преобразованы в ваше пространство вида именно с этой матрицей, пока вы не измените ее снова в следующем кадре.
Теперь вы можете собрать все вместе для тестового модуля TestRenderOurNewGraphicEngine, написанного в начале этой главы, и если вы взглянете на все классы проекта, которые вы импортировали и написали, то увидите хороший движок, который является простым для использования и легко расширяемым, и который мы будем исследовать в нескольких следующих главах.
Вот еще один вспомогательный класс в движке, называемый ScreenshotCapturer, который позволяет вам делать снимки экрана нажатием клавиши Print Screen. Он также реализован как игровой компонент и инициализируется в конструкторе BaseGame. Метод Update вызывается автоматически и просто вызывает MakeScreenshot, если нажата клавиша Print Screen.
public override void Update(GameTime gameTime)
{
if (Input.KeyboardKeyJustPressed(Keys.PrintScreen))
MakeScreenshot();
base.Update(gameTime);
} // Update(gameTime)
Метод MakeScreenshot создает временную текстуру и сохраняет в ней вторичный буфер с помощью метода устройства ResolveBackBuffer. Затем результат сохраняется на диске с помощью других вспомогательных методов класса:
using (Texture2D dstTexture = new Texture2D(
BaseGame.Device, BaseGame.Width, BaseGame.Height, 1,
ResourceUsage.ResolveTarget,
SurfaceFormat.Color,
ResourceManagementMode.Manual))
{
// Получаем данные с помощью метода Resolve
BaseGame.Device.ResolveBackBuffer(dstTexture);
dstTexture.Save(
ScreenshotNameBuilder(screenshotNum),
ImageFileFormat.Jpg);
} // using (dstTexture)
| netlib.narod.ru | < Назад | Оглавление | Далее > |