Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Опубликован: 10.04.2009 | Доступ: свободный | Студентов: 3247 / 243 | Оценка: 4.49 / 4.39 | Длительность: 17:21:00
Темы: Компьютерная графика, Программирование, Игры
Специальности: Программист
Теги:
Самостоятельная работа 17:
Игровой мир, освещение, тени
В листинге 22.3. вы можете найти код класса Game1.
using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace P17_2 { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; //Матрицы Matrix viewMatrix; Matrix projMatrix; //Модели modCls[] cls; //Положение моделей в пространстве Vector3[] offset; //Соотношение сторон окна вывода float aspectRatio; //Плоскость modCls plane; //Направление света Vector3 LightDirection; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; //Установить формат буфера трафаретов graphics.PreferredDepthStencilFormat = SelectStencilMode(); } //Проверка доступного буфера трафаретов и возврат соответствующей переменной типа //DepthFormat. Если буфер трафаретов не найден - выдадим исключение private static DepthFormat SelectStencilMode() { //Графическая карта GraphicsAdapter adapter = GraphicsAdapter.DefaultAdapter; //Формат поверхности SurfaceFormat format = adapter.CurrentDisplayMode.Format; //Проверка имеющихся технических средств карты if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth24Stencil8)) return DepthFormat.Depth24Stencil8; else if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth24Stencil8Single)) return DepthFormat.Depth24Stencil8Single; else if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth24Stencil4)) return DepthFormat.Depth24Stencil4; else if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth15Stencil1)) return DepthFormat.Depth15Stencil1; else throw new InvalidOperationException("Could Not Find Stencil Buffer for Default Adapter"); } protected override void Initialize() { //Отобразим указатель мыши IsMouseVisible = true; base.Initialize(); } protected override void LoadContent() { //Вычислим соотношение сторон aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height; //Матрица вида viewMatrix = Matrix.CreateLookAt(new Vector3(0, 10, 15), new Vector3(0, 0, 0), new Vector3(0.0f, 1.0f, 0.0f)); //Матрица проекции projMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), aspectRatio, 1.0f, 1000.0f); LightDirection = new Vector3(-2, -2, 0); //Создаем плоскость plane = new modCls(this, Content.Load<Model>("plane"), graphics, new Plane ()); //Настраиваем параметры плоскости plane.WorldMatrix = Matrix.CreateScale(25) * Matrix.CreateRotationY(MathHelper.ToRadians(90)) * Matrix.CreateRotationZ(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(0, -4, 0); plane.ViewMatrix = viewMatrix; plane.ProjectMatrix = projMatrix; plane.LightDirection = LightDirection; Components.Add(plane); //Плоскость, на которую проецируется тень //Она немного выше плоскости, которую мы выводим на экран //для того, чтобы тень была видна Plane pl1 = new Plane(new Vector3(0, -3.9f, 0), new Vector3(2, -3.9f, 1), new Vector3(-1, -3.9f, -2)); //Три элемента в массиве объектов cls = new modCls[3]; //Три элемента в массиве положений объектов offset = new Vector3[3]; //Зададим начальные положения моделей offset[0] = new Vector3(0, 2, 0); offset[1] = new Vector3(-6, 3, -4); offset[2] = new Vector3(6, 4, -6); //Создадим модели cls[0] = new modCls(this, Content.Load<Model>("ball2"), graphics,pl1); cls[1] = new modCls(this, Content.Load<Model>("ball2"), graphics, pl1); cls[2] = new modCls(this, Content.Load<Model>("ball2"), graphics, pl1); //Задаем параметры матриц и направления света каждой из моделей for (int i = 0; i < 3; i++) { cls[i].WorldMatrix = Matrix.CreateTranslation(offset[i]); cls[i].ProjectMatrix = projMatrix; cls[i].ViewMatrix = viewMatrix; cls[i].LightDirection = LightDirection; Components.Add(cls[i]); } } protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } protected override void Update(GameTime gameTime) { //Для случайных колебаний моделей Random rand = new Random(); //В каждом проходе цикла //Смещаем каждую модель вниз на 0.04 единицы //И на небольшое случайное число вдоль оси X и Y - модели //слегка колеблются при добавлении этого изменения //Мы не ввели ограничения на изменение X и Z - //При практической реалиации данного примера это //желательно сделать for (int i = 0; i < 3; i++) { offset[i].Y -= 0.04f; offset[i].X -= (0.08f * (float)rand.NextDouble() - 0.08f * (float)rand.NextDouble()); offset[i].Z -= (0.08f * (float)rand.NextDouble() - 0.08f * (float)rand.NextDouble()); cls[i].WorldMatrix = Matrix.CreateTranslation(offset[i]); } //Проверяем попадание мыши по объекту CheckMouseClick(); //Проверяем пересечение с плоскостью CheckPlane(); //Меняем позицию источника света по нажатию клавиш LightSourceControl(); base.Update(gameTime); } //Изменение позиции источника света void LightSourceControl() { //Получим состояние клавиатуры KeyboardState key = Keyboard.GetState(); //Клавиша "вверх" - уменьшим позицию по Z if (key.IsKeyDown(Keys .Up )) { LightDirection.Z -= 0.5f; } //Клавиша "вниз" - увеличим Z if (key.IsKeyDown(Keys.Down)) { LightDirection.Z += 0.5f; } //"Влево" - уменьшим X if (key.IsKeyDown(Keys.Left)) { LightDirection.X -= 0.5f; } //"Вправо" - увеличим X if (key.IsKeyDown(Keys.Right)) { LightDirection.X += 0.5f; } //"W" - увеличим Y if (key.IsKeyDown(Keys.W)) { LightDirection.Y += 0.5f; } //"S" - уменьшим Y if (key.IsKeyDown(Keys.S)) { LightDirection.Y -= 0.5f; } //Изменим направление источника света для плоскости plane.LightDirection = LightDirection; //Изменим направление источника света для моделей for (int i = 0; i < 3; i++) { cls[i].LightDirection = LightDirection; } //Выведем в заголовок окна информацию о направлении this.Window.Title = "Light source: " + LightDirection.ToString(); } //Проверка на нажатие клавиши мыши void CheckMouseClick() { //получим состояние мыши MouseState mouseState = Mouse.GetState(); //если нажата левая кнопка if (mouseState.LeftButton == ButtonState.Pressed) { //Получим луч, идущий от позиции мыши на экране в пространство Ray pickRay = GetPickRay(); //Переменная для хранения сферы, соответствующей объекту BoundingSphere b1; //Переменная для хранения вектора размера модели Vector3 scale; //Переменная для хранения информации о повороте модели Quaternion rotation; //Переменая для хранения информации о позиции модели Vector3 translation; for (int i = 0; i < 3; i++) { //Получить BoundingSphere для текущего объекта b1 = cls[i].myModel.Meshes[0].BoundingSphere; //Получить параметры - размер, поворот, позицию для объекта cls[i].WorldMatrix.Decompose(out scale, out rotation, out translation); //Установить центр сферы в соответствии с позицией объекта b1.Center = translation; //Получить результат пересечения луча и сферы Nullable<float> result = pickRay.Intersects(b1); //Если луч и сфера пересеклись - "поднять" объект до позиции Y=4 if (result.HasValue) { offset[i].Y = 4; cls[i].WorldMatrix = Matrix.CreateTranslation(offset[i]); } } } } //Проверка на столкновение с плоскостью void CheckPlane() { //Создадим плоскость по трем точкам - она пересекает ось Y в точке -4 и не пересекает //другие оси Plane pl = new Plane(new Vector3(0, -4, 0), new Vector3(2, -4, 1), new Vector3(-1, -4, -2)); //Переменная для хранения типа пересечения с плоскостью //Она может сигнализировать о нахождении объекта перед плоскостью (выше в нашем случае) //за плоскостью и о пересечении с плоскостью PlaneIntersectionType plType; //Сфера для объекта BoundingSphere b1; //Переменная для хранения вектора размера модели Vector3 scale; //Переменная для хранения информации о повороте модели Quaternion rotation; //Переменая для хранения информации о позиции модели Vector3 translation; for (int i = 0; i < 3; i++) { //Получить BoundingSphere для текущего объекта b1 = cls[i].myModel.Meshes[0].BoundingSphere; //Получить параметры - размер, поворот, позицию для объекта cls[i].WorldMatrix.Decompose(out scale, out rotation, out translation); //Установить центр сферы в соответствии с позицией объекта b1.Center = translation; //Получить тип пересечения сферы объекта и плоскости plType = pl.Intersects(b1); //Если сфера пересекла плоскость if (plType == PlaneIntersectionType.Intersecting) { //Удалить соответствующий игровой объект из коллекции Components.Remove(cls[i]); } } } //Функция для вычисления луча, исходящего из точки, в которой //находился указатель мыши в момент щелчка Ray GetPickRay() { //получить состояние мыши MouseState mouseState = Mouse.GetState(); //Сохранить координаты int mouseX = mouseState.X; int mouseY = mouseState.Y; //Точки для вычисления направления луча - одна, соответствующая координате мыши //вторая - направленная по оси Z Vector3 nearsource = new Vector3((float)mouseX, (float)mouseY, 0f); Vector3 farsource = new Vector3((float)mouseX, (float)mouseY, 1f); //Мировая матрица для вычислений Matrix world = Matrix.CreateTranslation(0, 0, 0); //Переведем координаты мыши в координаты трехмерного пространства Vector3 nearPoint = graphics.GraphicsDevice.Viewport.Unproject(nearsource, projMatrix, viewMatrix, world); Vector3 farPoint = graphics.GraphicsDevice.Viewport.Unproject(farsource, projMatrix, viewMatrix, world); // Получим направление луча Vector3 direction = farPoint - nearPoint; //Нормализуем его (преобразуем к единичному вектору) direction.Normalize(); //Создадим новый луч, начинающийся в точке, соответствующей координате //указателя мыши в объектном пространстве, с направлением, //соответствующим вычисленному направлению Ray pickRay = new Ray(nearPoint, direction); //возвратим луч в процедуру, вызывавшую данную функцию return pickRay; } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here base.Draw(gameTime); } } }Листинг 22.3. Код класса Game1
На рис. 22.4. вы можете видеть игровой экран проекта P17_2.
Задание
Разработайте на основе проекта P17_2 собственную игру, которая реализует следующие возможности:
- Систему меню
- Систему подсчета очков пользователя
- Увеличение сложности игры при прохождении в следующий уровень