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 | < Назад | Оглавление | Далее > |