Навигация
· XNA FAQ
· С чего начать
· Конкурсы
· Обратная связь
· XNA Блоги
Сейчас на сайте
· Гостей: 1

· Пользователей: 0

· Всего пользователей: 3,684
· Новый пользователь: headron
Последние фото
Эх, чуть не проспал закрытие.
Эх, чуть не проспал ...
Альбом: XNA Engine

GB
GB
Альбом: XNA Engine

South Park Coon & Friends
South Park Coon & Fr...
Альбом: XNA Games

Блоги
yavshoke
» XboxOne - интерес...
dampirik
» Push уведомления ...
dampirik
» Реклама,статистик...
Chort
» XNA и StartCoroutine
Chort
» Curve Class
dampirik
» Реклама, статисти...
dampirik
» Увеличение скорос...
dampirik
» Реклама, статисти...
general
» Распаковка DxtCom...
general
» Как работать с XN...
Поддержка
microsoft.com
1gb.ru - Дом для вашего сайта
Статистика посещений:

Игровой мир и освещение

Лабораторная работа №17. Игровой мир, освещение, тени


В этой лабораторной работе мы познакомимся с методиками создания игрового мира.

Цель работы
  • Научиться создавать игровой мир, применять эффекты к его объектам
Задачи работы
  • Рассмотреть подходы к созданию игрового мира
  • Научиться использовать в качестве игрового мира готовые модели
  • Ознакомиться с управлением освещением и с выводом теней в трехмерных играх
Подходы к созданию игрового мира

Для создания игрового мира трехмерной игры используют несколько подходов.
1. Игровой мир можно конструировать из отдельных объектов. Например, для того, чтобы создать комнату, можно использовать плоскости для строительства стен, пола и потолка, различные объекты для создания предметов, находящихся в комнате. При таком подходе для обработки взаимодействия игрового объекта и окружения можно применить уже знакомый вам подход проверки столкновений объектов. Этот подход мы использовали в предыдущих проектах – в примере с передвижением объекта среди группы других объектов, в примере, где нужно было щелкать мышью по объектам для того, чтобы не допустить их падения.
2. Игровой мир можно сконструировать в трехмерном редакторе – например – ту же комнату, или целое здание, или ландшафт – и загрузить в игру в виде отдельной модели.
3. Мир можно сконструировать средствами XNA

Рассмотрим работу с игровым миром, который представлен в виде отдельной модели, содержащей все его элементы.

Загрузка игрового мира

В качестве объекта игрового мира, который мы использовали для демонстрации, применен готовый игровой объект – House – взятый с сайта http://www.turbosquid.com.

Создадим новый игровой проект P17_1. На рис. 17.1. вы можете видеть его окно Project Explorer.


Рис. 17.1. Окно Project Explorer проекта P17_1

В качестве игрового объекта мы используем модель ball.fbx, для построения игрового мира применим модель дома house1.x и плоскость plane.fbx. В этом проекте мы используем уже знакомый вам по предыдущим проектам класс modCls – он применяется для вывода моделей.

В листинге 17.1. вы можете видеть код класса Game1.
Листинг 17.1. Код класса Game1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace P17_1
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        //Матрицы
        Matrix viewMatrix;
        Matrix projMatrix;
        //Модели
        Model ball, house, plane;
        // Позиция объекта, поворот
        Vector3 avatarPosition = new Vector3(0, 0, -10);
        float avatarlRotation;
 
        // Положение камеры
        Vector3 cameraReference = new Vector3(0, 0, 10);
        Vector3 thirdPersonReference = new Vector3(0, 20, 100);
 
        // Скорости поворота и движения
        float rotationSpeed = 1f / 60f;
        float forwardSpeed = 10f / 60f;
 
        //Поле зрения камеры
        float viewAngle = MathHelper.ToRadians(45.0f);
 
        //Расстояние от камеры до переднего и заднего плана
        float nearClip = 1.0f;
        float farClip = 2000.0f;
        //Объекты
        modCls ballObj;
        modCls mHouse;
        modCls mPlane;
 
        //Соотношение сторон экрана
        float aspectRatio;
 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
 
        protected override void LoadContent()
        {
           //Загрузка моделей
           ball = Content.Load<Model>("ball");
           house  = Content.Load<Model>("house1");
           plane = Content.Load<Model>("plane");
            aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
  (float)graphics.GraphicsDevice.Viewport.Height;
 
        }
 
        protected override void Update(GameTime gameTime)
        {
            //обновить положение объекта
            UpdateAvatarPosition();
            base.Update(gameTime);
        }
 
        protected override void Draw(GameTime gameTime)
        {
          graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
            UpdateCameraThirdPerson();
 
            //вывести объекты сцены
            DrawScene();
 
            base.Draw(gameTime);
        }
 
        //Обновляем состояние объекта
        void UpdateAvatarPosition()
        {
            KeyboardState keyboardState = Keyboard.GetState();
 
            //Поворот влево
            if (keyboardState.IsKeyDown(Keys.Left))
            {
                avatarlRotation += rotationSpeed;
            }
            //Поворот вправо
            if (keyboardState.IsKeyDown(Keys.Right))
            {
                avatarlRotation -= rotationSpeed;
            }
            //Движение вперед
            if (keyboardState.IsKeyDown(Keys.Up))
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                Vector3 v = new Vector3(0, 0, -forwardSpeed);
                v = Vector3.Transform(v, forwardMovement);
 
                avatarPosition.Z += v.Z;
                avatarPosition.X += v.X;
 
            }
            //Движение назад
            if (keyboardState.IsKeyDown(Keys.Down))
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                Vector3 v = new Vector3(0, 0, forwardSpeed);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Z += v.Z;
                avatarPosition.X += v.X;
 
            }
            //Движение вверх
            if (keyboardState.IsKeyDown(Keys.W))
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                Vector3 v = new Vector3(0, forwardSpeed, 0);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Y += v.Y;
 
            }
            //Движение вниз
            if (keyboardState.IsKeyDown(Keys.S))
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                Vector3 v = new Vector3(0, -forwardSpeed, 0);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Y += v.Y;
 
            }
 
            //Уменьшение угла обзора камеры
            if (keyboardState.IsKeyDown(Keys.R))
            {
                viewAngle -= MathHelper.ToRadians(1.0f);
            }
            //Увеличение угла обзора камеры
            if (keyboardState.IsKeyDown(Keys.F))
            {
                viewAngle += MathHelper.ToRadians(1.0f);
            }
            //Если новый угол обзора вышел за дозволенные пределы
            //изменяем его
            if (viewAngle > MathHelper.ToRadians(180.0f)) viewAngle = MathHelper.ToRadians(179.9f);
            if (viewAngle < MathHelper.ToRadians(0.0f)) viewAngle = MathHelper.ToRadians(0.1f);
        }
        //Обновляем положение камеры при выбранном виде от третьего лица
        void UpdateCameraThirdPerson()
        {
            //Поворот камеры
            Matrix rotationMatrix = Matrix.CreateRotationY(avatarlRotation);
 
            // Направление камеры
            Vector3 transformedReference = Vector3.Transform(thirdPersonReference, rotationMatrix);
 
            // Позиция камеры
            Vector3 cameraPosition = transformedReference + avatarPosition;
 
            //Матрица вида
            viewMatrix = Matrix.CreateLookAt(cameraPosition, avatarPosition, new Vector3(0.0f, 1.0f, 0.0f));
            //Проецкионная матрица
            projMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio, nearClip, farClip);
        }
 
        //Вывод объектов сцены
        void DrawScene()
        {
            //очистить коллекцию компонентов
            Components.Clear();
            //Вывести дом
            mHouse = new modCls(this, house, graphics);
            mHouse .WorldMatrix = Matrix.CreateTranslation(0, 0, -5)*Matrix .CreateScale (5f);
            mHouse .ViewMatrix = viewMatrix;
            mHouse .ProjectMatrix = projMatrix;
            Components .Add (mHouse );
            //выведем игровой объект
            ballObj = new modCls(this, ball, graphics);
            ballObj.WorldMatrix = Matrix.CreateRotationY(avatarlRotation) * Matrix.CreateTranslation(avatarPosition);
            ballObj.ViewMatrix = viewMatrix;
            ballObj.ProjectMatrix = projMatrix;
            Components.Add(ballObj);
            //Вывести плоскость
            mPlane = new modCls(this, plane, graphics);
            mPlane.WorldMatrix = Matrix.CreateScale(700) * Matrix.CreateRotationY(MathHelper.ToRadians(90)) *
                Matrix.CreateRotationZ(MathHelper.ToRadians(90)) *
                Matrix.CreateTranslation(0, -2, 0);
            mPlane.ViewMatrix = viewMatrix;
            mPlane.ProjectMatrix = projMatrix;
            Components.Add(mPlane);
        }
    }
}

 


На рис. 17.2. вы можете видеть игровой экран проекта P17_1.


Рис. 17.2. Игровой экран проекта P17_1

Управление освещением, тени

Рассмотрим управление освещением и отображением теней в XNA. Существуют различные техники работы с тенями, мы рассмотрим отрисовку теней с использованием так называемого буфера трафаретов, или, по-английски -  Stencil Buffer. В частности, мы модифицируем проект P16_2 таким образом, чтобы шарики, падающие на плоскость, отбрасывали тени.
Stencil Buffer является стандартным устройством, входящим в состав современных видеокарт. Однако, различные видеокарты могут иметь различный размер этого буфера, поэтому, перед его использованием, необходимо определить, какой именно буфер доступен на видеокарте, используемой в данный момент.

Для создания тени мы воспользуемся методом CreateShadow объекта Matrix. Он позволяет создавать тень от объекта на основе информации об источнике освещения и плоскости, на которую должна проецироваться тень.

После того, как сознана матрица, представляющая собой тень, мы используем эту матрицу для вывода тени. Причем, техника работы такова: сначала вывести сцену, освещенную так, как нужно, после этого соответствующим образом настроить буфер трафаретов и вывести ту же сцену без освещения, модифицировав мировую матрицу с помощью полученной матрицы тени.
В этом же примере мы рассмотрим настройку источника света. В частности, мы применим для рисования объектов один направленный источник света, направление которого можно менять с помощью клавиш клавиатуры – координата Z изменяется с помощью клавиш-стрелок вверх-вниз, координата X – клавишами вправо-влево, координата Y – клавишами W и S. Изменение направления освещения влияет не только на освещение объектов, но и на тень.

Создадим новый проект – P17_2.

На рис. 17.3. вы можете видеть его окно Project Explorer.


Рис. 17.3. Окно Project Explorer проекта P17_2

Для представления моделей, выводимых на экран, мы используем класс modCls, в качестве ресурсов игры используем шар ball2 и плоскость plane.

Рассмотрим код класса modCls (листинг. 17.2.) В проекте P16_2 этот класс отвечал за вывод изображений на экран. Сейчас он выполняет ту же функцию, дополнив вывод изображений визуализацией теней.

Листинг 17.2. Код класса modCls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
 
namespace P17_2
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class modCls : Microsoft.Xna.Framework.DrawableGameComponent
    {
        //Модель
        public Model myModel;
        //Мировая матрица, матрицы вида и проекции
        public Matrix WorldMatrix;
        public Matrix ViewMatrix;
        public Matrix ProjectMatrix;
        //Направление света
        public Vector3 LightDirection;
        //Матрица для отображения тени
        Matrix shadow;
        //Плоскость, на которой отображается тень
        Plane sPlane;
        //Соотношение сторон экрана
        public float aspectRatio;
        //Для управления графическим устройством
        GraphicsDeviceManager graphics;
        //Конструктор получает на вход 
        //игровой класс, модель, объект для управления графическим устройством и плоскость для вывода тени
        public modCls(Game game, Model mod, GraphicsDeviceManager grf, Plane pl)
            : base(game)
        {
            myModel = mod;
            graphics = grf;
            sPlane = pl;
            aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
(float)graphics.GraphicsDevice.Viewport.Height;
            LightDirection = new Vector3();
        }
 
        public override void Draw(GameTime gameTime)
        {
            //Выводим объект
            foreach (ModelMesh mesh in myModel.Meshes)
            {
                //Для каждого эффекта в сети
                foreach (BasicEffect effect in mesh.Effects)
                {
                    //Включить источник направленного света №0
                    effect.DirectionalLight0.Enabled = true;
                    //Настроить параметры
                    effect.DirectionalLight0.DiffuseColor = Vector3.One;
                    effect.DirectionalLight0.SpecularColor = Vector3.One;
                    //Направление света - в класса Game1 мы меняем направление
                    //по клавиатурным командам
                    effect.DirectionalLight0.Direction = Vector3.Normalize(LightDirection);
                    //Включить освещение
                    effect.LightingEnabled = true;
                    //Установка матриц
                    effect.World = WorldMatrix;
                    effect.View = ViewMatrix;
                    effect.Projection = ProjectMatrix;
                }
                mesh.Draw();
            }
 
            //Создать матрицу тени
            shadow = Matrix.CreateShadow(-LightDirection, sPlane);
            //Очистить буфер трафаретов
            graphics.GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0, 0);
            //Включть буфер трафаретов
            graphics.GraphicsDevice.RenderState.StencilEnable = true;
            // Вывод на экран элемента буфера в том случае, если он установлен в 0         
            graphics.GraphicsDevice.RenderState.ReferenceStencil = 0;
            graphics.GraphicsDevice.RenderState.StencilFunction = CompareFunction.Equal;
            //При выводе применяем операцию увеличения
            graphics.GraphicsDevice.RenderState.StencilPass = StencilOperation.Increment;
            //Включаем альфа-смешивание для того, чтобы сделать тень полупрозрачной
            graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
            //Выводим тень
            foreach (ModelMesh mesh in myModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.AmbientLightColor = Vector3.Zero;
                    effect.Alpha = 0.5f;
                    effect.DirectionalLight0.Enabled = false;
                    effect.DirectionalLight1.Enabled = false;
                    effect.DirectionalLight2.Enabled = false;
                    effect.View = ViewMatrix;
                    effect.Projection = ProjectMatrix;
                    //При выводе тени умножаем мировую матрицу
                    //на матрицу вывода тени
                    effect.World = WorldMatrix*shadow;
                }
                mesh.Draw();
            }
            //Отключить буфер
            graphics.GraphicsDevice.RenderState.StencilEnable = false;
            //Отключить альфа-смешивание
            graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            base.Draw(gameTime);
        }
    }
}

 


В листинге 17.3. вы можете найти код класса Game1.

Листинг 17.3. Код класса Game1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
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 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);
        }
    }
}

 


На рис. 17.4. вы можете видеть игровой экран проекта P17_2.


Рис. 17.4. Игровой экран проекта P17_2

Задание

Разработайте на основе проекта P17_2 собственную игру, которая реализует следующие возможности:

  1. Систему меню
  2. Систему подсчета очков пользователя
  3. Увеличение сложности игры при прохождении в следующий уровень

Материал публикуется с разрешения авторов - Ю.В. Дашко, А.А. Заика

Студенческий блог MS Russia
Интернет-Университет Информационных технологий - курс разработан по гранту от Microsoft и ИНТУИТ
сайт ИУБиП
Комментарии
#1 | ibraim 18.06.2010 16:00:50
Все понятно. Неясным для меня остается вот что: тени у Вас отбрасываются на плоскость. А как быть если мне необходимо отбрасывать их на другой шар? группу других объектов?
Добавить комментарий
Пожалуйста, залогиньтесь для добавления комментария.
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Авторизация
Логин

Пароль



Вы не зарегистрированы?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Мини-чат
Вы должны авторизироваться, чтобы добавить сообщение.

27.08.2014
Я умею немного на asp.net + html и css

22.08.2014
на ASP mvc 3 есть пару проектов. Могу помочь, если нужно. Обидно, если закроется Frown

21.08.2014
я тоже ноль

21.08.2014
Я в вебе только с php занимался да и то на уровне чтоб работало.

21.08.2014
Я в вебе полный ноль…

21.08.2014
Переводить его надо, хоть на ту же азуру. И двиг менять на что-то современное. Если есть веб-разрабы - можем скооперироваться. Один делать не буду.

21.08.2014
не знаю всех нюансов по оплате и все хорошее когда нибудь заканчивается

21.08.2014
А что случилось?

21.08.2014
похоже сайт будет работать до 28го числа

09.08.2014
Апи пока не видел. Но есть приложение в магазине Live Lock Screen BETA, так что думаю скоро будет

08.08.2014
Я про API для Update1. На нем работает это

08.08.2014
А что именно нужно? Чтото и сейчас открыто http://msdn.micro.
...105).aspx

06.08.2014
Кто-нибудь слышал об открытии доступа к Lock Screen Api?

31.07.2014
VPDExpress на базе MVS 2012, ни в какую не ловит исключения. Даже если их сам создаешь. И всех так?

25.07.2014
С днем системного администратора причастных к этой профессии! По случаю - тортик от жены

RSS каналы сайта
XNA - Новости
XNA - Статьи
XNA - Форум
XNA - Галерея
XNA - Файлы
Время загрузки: 0,05 секунд 8,709,470 уникальных посетителей