Формируем трехмерную сцену Способов создания полноценных трехмерных сцен очень много. Выбор того или иного способа целиком зависит от игровых задач. В игре «Футбольный стрелок» наша камера статична и находится в одном положении, поэтому для организации сцены был выбран механизм загрузки в игру модели стадиона. Суть этого способа заключается в том, чтобы загрузить в игру модель стадиона и установить камеру под определенным углом, а затем на фоне стадиона развернуть все игровые действия. Для текущего примера был создан новый проект под названием Plane, который находится на компакт-диске в папке Code\Chapter20\Plane. Начиная с раздела 20.1, мы приступим к его изучению. Дополнительно в папке Code\Chapter20\ имеется еще один проект под названием PlaneMove. В нашей игре нет необходимости перемещаться по полю стадиона, но показать вам, как этот это делается, нужно обязательно. После изучения проекта Plane рассмотрите исходный код примера PlaneMove, думается, что этот пример вам обязательно пригодится в своих собственных играх.
20.1. Позиция камеры Переходим к работе над игрой и начнем с того, что улучшим код по представлению позиции камеры на экране телевизора. В исходный код класса Game1 проекта Plane добавим новую переменную camera.
Vector3 camera = new Vector3(0.0f, 0.0f, 150.0f);
Эта переменная будет задавать одинаковую позицию просмотра сцены для мячей и футбольного стадиона в методе Draw().
// метод Draw() view = Matrix.CreateLookAt(camera, Vector3.Zero, Vector3.Up);
А также для вычисления позиции прицела.
// метод GetPickRay() Ray GetPickRay() { … view = Matrix.CreateLookAt(camera, Vector3.Zero, Vector3.Up); … }
Таким образом, мы создаем одну переменную и упрощаем возможность обоюдного изменения точки просмотра сцены в двух и более местах исходного кода. Сама точка просмотра трехмерной сцены удаляется на 150 пикселей от центра экрана. Предложенные значения точки просмотра сцены взяты не с неба, эти значения были сначала опробованы на загружаемой в игру модели стадиона, и только потом был выбран наиболее выгодный ракурс. В этом плане бесплатные модели имеют свою обратную сторону медали. Здесь уже приходится подстраиваться под имеющийся графический контент, вместо того чтобы модельер, делающий модели, подстраивался под ваши требования…
20.2. Загружаем в игру стадион Переходим к загрузке модели стадиона в игру. В качестве основной игровой модели для формирования сцены в игре мы используем модель стадиона, которая была найдена в закромах ресурса Turbosquid.com (рис. 20.1). Эта модель распространяется на бесплатной основе в формате 3ds и создана модельером, зарегистрированным на Turbosquid.com под именем dwallcott (рис. 20.1). К сожалению, в комплекте со стадионом текстуры не идут, поэтому я покрасил все элементы стадиона просто в разные цвета, но при желании можно использовать любые текстуры, созданные специально для этих целей. Итак, перейдем к исходному коду класса Game1 проекта Plane и в области глобальных переменных объявим объект stadium класса ModelClass.
Рис. 20.1. Страница модели стадиона на сайте
private ModelClass stadium;
Затем в конструкторе класса Game1 или в методе Initialize() создаем но- вый объект stadium.
stadium = new ModelClass();
Переходим к телу метода LoadGraphicsContent() и, используя стандарт- ные механизмы, загружаем в игру модель.
В этом же методе выбираем позицию для стадиона на экране телевизора.
stadium.position = new Vector3(0, 0, 0);
Стадион мы ставим на экран в нулевые координаты, а за счет удаления камеры от центра экрана (см. раздел 20.1) получаем хороший ракурс просмотра всей трехмерной сцены. Последние установки, связанные с выводом стадиона на экран, происходят в методе Draw().
world = Matrix.CreateTranslation(stadium.position); stadium.DrawModel(world, view, proj);
Здесь все установки стандартны, а значения матрицы вида и матрицы проекции общие как для мячей, так и для стадиона. Если сейчас запустить проект, то на экране телевизора вы увидите стадион и падающие сверху мячики (рис. 20.2), но прежде нам необходимо сделать еще несколько изменений и нововведений, чтобы трехмерная сцена стала ярче и интереснее.
Рис. 20.2. Стадион в игре
20.3. Падение мячей на поле стадиона Как вы помните, к выбору скоростей в играх нужно подходить взвешенно и осторожно. К слову сказать, в игре «Футбольный стрелок» значение скорости задано жестко, но можно производить выбор скорости объекта на экране непосредственно с созданием этого объекта и далее на каждом уровне игры, внося элемент случайности (в последней главе книги мы так и поступим). В исходном коде класса Game1 и методе MoveBall()на этой стадии нас ждут небольшие изменения, которые выглядят следующим образом:
void MoveBall() { for (int i = 0; ball.Length > i; i++) { if (ball.position.Y 20.4. Небо и тучи Задний фон за стадионом в игре закрашивается цветом. Сейчас это уже неактуально, и для формирования полноценной сцены необходимо создать небо, тучи и другие элементы пейзажа. Механика представления этих элементов в играх достаточно обширна. Поскольку игра «Футбольный стрелок» имеет статичную камеру и точка просмотра сцены не изменяется, то можно воспользоваться текстурой пейзажа и поставить это изображение за элементами сцены. В большинстве игр этот механизм используется повсеместно, но если камера в игре двигается, то добавляется более сложный механизм, основанный либо на прокрутке текстуры фона в разных направлениях, либо на использовании кубических текстур для представления небесной оболочки (Sky Box). У нас вся трехмерная сцена попроще, поэтому вполне достаточно простой текстуры с пейзажем, установленной на заднем фоне игры. Текстура пейзажа была взята с сайта Turbosquid.com. Это графическое изображение в формате JPG распространяется бесплатно. Пейзаж создан художником под именем Hal9000 (рис. 20.3).
Рис. 20.3. Страница изображения hallake001
Графическое изображение этого пейзажа оказалось очень большим по ширине (3000 пикселей), поэтому пришлось обрезать его по бокам, укоротив изображение по ширине до 1500 пикселей. Для добавления фона в игру объявим новую переменную background.
private Texture2D background;
Изображение фона статично, поэтому можно обойтись и без объекта класса Sprite. После объявления объекта background в методе LoadGraphicsContent() загружаем пейзаж в игру.
А затем в методе Draw() рисуем его на экране телевизора.
spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(background, new Vector2(0, -50), Color.White); spriteBatch.End();
При этом само изображение фона мы рисуем самым первым, не забывайте, что каждый последующий рисуемый элемент графики всегда накладывается поверх предыдущего! Изображение hallake001 по высоте равно 500 пикселям. По оси Y мы сместили изображение вверх на 50 пикселей. Сделано это просто для красоты. То есть после того как изображение было загружено, а игра запущенна на приставке, было подобрано оптимальное местоположение фона, исходя из общей картинки на экране телевизора. В листинге 20.1 вы найдете полный исходный код текущего примера, где все нововведения выделены жирным шрифтом. Сам проект располагается на компакт-диске в папке Code\Chapter20\Plane.