Download
xna game studio express casual games pc xbox 360 n.
Skip this Video
Loading SlideShow in 5 Seconds..
XNA Game Studio Express: разработка casual games для PC и Xbox 360 PowerPoint Presentation
Download Presentation
XNA Game Studio Express: разработка casual games для PC и Xbox 360

XNA Game Studio Express: разработка casual games для PC и Xbox 360

228 Vues Download Presentation
Télécharger la présentation

XNA Game Studio Express: разработка casual games для PC и Xbox 360

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. XNA Game Studio Express: разработка casual games для PC и Xbox 360 Александр Ложечкин Сергей Гайдуков

  2. Содержание • XNA Framework на платформе Windows • .NET Compact Framework for Xbox 360 • Компоненты XNA Framework • Оптимизация XNA-приложений • XNA Framework и Windows Forms

  3. XNA Game Studio Express • Инструментарий разработки игровых приложений для платформ • Windows • Windows XP x86 Home/Pro/MCE/Tablet • Windows XP x64 (посредством WOW64) • Windows Vista (с Visual C# 2005 Express SP1) • Windows Server 2003 (*) • Xbox 360 • Сферы применения • Casual Games • Прототипы игр • Demo • Утилиты • Образование

  4. Marblets

  5. XNA Framework • Кроссплатформенный API для разработки игровых приложений • Не привязан к Windows • Основан на платформе .NET Framework • .NET Framework 2.0(Windows) • .NET Compact Framework for Xbox 360 • Mono (Linux)

  6. XNA на платформе Windows • Компоненты для разработки приложений • Компоненты для распространения приложений • Очень просто интегрируются в дистрибутив приложения средствами Visual Studio 2005 Pro

  7. .NET Compact Framework 2.0 • Отличия от .NET Framework 2.0: • Значительно меньшие требования к ресурсам компьютера • Является подмножеством .NET Framework (содержит примерно 30% классов) • Ограниченная поддержка web-приложений и баз данных • Ограниченная поддержка Windows Forms • Не поддерживается генерация кода на лету (System.Reflection.Emit) • Ограниченная поддержка JIT аппаратных вычислений с плавающей точкой • Более простой сборщик мусора

  8. .NET Compact Framework /Xbox 360 • Подмножество .NET Compact Framework • Нет поддержки Windows Forms • В настоящее время отсутствует поддержка сетевых технологий • Дополнительные возможности • Аппаратные вычисления с плавающей точкой • Но нет поддержки векторных инструкций VMX128 • Привязка потоков к одному из четырех (всего 6) логических процессоров (Hardware threads) • Метод Thread.SetProcessorAffinity задаёт логический процессоры, предпочтительные для выполнения потока

  9. Кроссплатформенные приложения • Создаются отдельные проекты для PC и Xbox 360 • Проекты могут использовать общий исходный код и контент (Add As Link) • Поддерживается только C# • При создания кода, специфичного для Windows и Xbox 360, используйте директивы условной компиляции #if/#else/#endif и [Conditional] [Conditional("XBOX360"] void XboxCode() { // Код, специфичный для Xbox } #if !XBOX360 // Код, специфичный для Windows #endif

  10. Content Code Components Storage Math Input Audio Graphics XContent Starter Kits Content Pipeline XINPUT XACT Direct3D Application Model Компоненты XNA Framework Games Extended Framework Core Framework Platform

  11. Компонент Application Model • Каркас приложения • Управление оконной подсистемой • Управление графическим устройством Direct3D • Управление контентом (текстуры, модели, звуки) • Расширяемая функциональность за счет пользовательских компонентов

  12. Компонент Application Model

  13. Простейшее приложение(Ex01)

  14. Простейшее приложение namespace MyGame { // Наследник класса Game public class Game1 : Microsoft.Xna.Framework.Game { // Объекты графического устройства и менеджера контента GraphicsDeviceManager graphics; ContentManager content; public Game1() { graphics = new GraphicsDeviceManager(this); content = new ContentManager(Services); } // Инициализация приложения protected override void Initialize() { • IsFixedTimeStep = true; • TargetElapsedTime = new TimeSpan(166667); // Инициализация пользовательских компонентов base.Initialize(); } // Загрузка контента protected override void LoadGraphicsContent(boolloadAllContent) { … } // Освобождение ресурсов protected override void UnloadGraphicsContent(boolunloadAllContent) { if (unloadAllContent == true) { content.Unload(); } } // Обновление состояния игры protected override void Update(GameTimegameTime) { ... base.Update(gameTime); } // Визуализация изображения protected override void Draw(GameTimegameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // Визуализация всех пользовательских DrawableGameComponent base.Draw(gameTime); } } }

  15. Компонент Input Работа с устройствами ввода-вывода

  16. Компонент Input

  17. Пример использования компонента Input(Ex02)

  18. Пример использования компонента Input protected override void Update(GameTimegameTime) { // Если нажата кнопка Back геймпада if (GamePad.GetState(PlayerIndex.One). Buttons.Back == ButtonState.Pressed) { Exit(); } // Если на клавиатуре нажата клавиша Esc if (Keyboard.GetState().IsKeyDown(Keys.Escape)) { Exit(); } base.Update(gameTime); }

  19. Компонент Math

  20. Компонент Math • Больше не является настройкой над D3DX • Поиск компромисса между удобством и производительностью • public staticMatrixoperator*(Matrix matrix1, Matrix matrix2); • public staticMatrixMultiply(Matrix matrix1, Matrix matrix2); • public static void Multiply(ref Matrix matrix1, ref Matrix matrix2, out Matrix result); • Производительность операторов и обычных методов в два раза ниже C++ without SSE • c = a * b • При использовании ref методов производительность примерно равна C++ without SSE • Matrix.Multiply(ref a, ref b, ref c) • Поддерживается только правосторонняя система координат

  21. Использования компонента Math на примере встраивания камеры(Ex03)

  22. Пример компонента «камера»Каркас компонента public partial class Camera : Microsoft.Xna.Framework.GameComponent { public Camera(Game game) : base(game) { } // Инициализация компонента и загрузка контента public override void Initialize() { base.Initialize(); } // Обновление состояния компонента public override void Update(GameTimegameTime) { base.Update(gameTime); } }

  23. Пример компонента «камера»Расчет матриц трансформации // Углы и положение камеры public Vector2 angles = Vector2.Zero; public Vector3 translate = new Vector3(0.0f, 0.0f, -500.0f); // Угол обзора и плоскости отсечения public float fov = MathHelper.Pi / 4.0f; public float zNear = 0.1f; public float zFar = 10000.0f; // Расчет матриц проекции, вида public Matrix Projection { get { float aspect = (float)Game.Window.ClientBounds.Width / (float)Game.Window.ClientBounds.Height; return Matrix.CreatePerspectiveFieldOfView(fov, aspect, zNear, zFar); } } public Matrix View { get { return Matrix.CreateRotationY(angles.X) * Matrix.CreateRotationX(angles.Y) * Matrix.CreateTranslation(translate); } } public Matrix ViewProjection { get { return View * Projection; } }

  24. Пример компонента «камера»Взаимодействие с геймпадом using Microsoft.Xna.Framework.Input; public override void Update(GameTimegameTime) { // Джойстик не должен воздействовать приложение, потерявшее фокус if (Game.IsActive) { // Получаем состояние миниджойстиков GamePadThumbSticksThumbSticks = GamePad.GetState(PlayerIndex.One).ThumbSticks; // Правый министик используется для вращения камеры angles.X -= ThumbSticks.Right.X * 0.01f; angles.Y += ThumbSticks.Right.Y * 0.01f; // Левый джойстик приближает/удаляет камеру translate.Z += ThumbSticks.Left.Y * 5f; base.Update(gameTime); }

  25. Пример компонента «камера»Взаимодействие с клавиатурой // Получаем состояние клавиатуры KeyboardState keyboardState = Keyboard.GetState(); // Корректируем углы поворота камеры if (keyboardState.IsKeyDown(Keys.Left)) angles.X += 0.01f; if (keyboardState.IsKeyDown(Keys.Right)) angles.X -= 0.01f; if (keyboardState.IsKeyDown(Keys.Up)) angles.Y += 0.01f; if (keyboardState.IsKeyDown(Keys.Down)) angles.Y -= 0.01f; // Корректируем положение камеры if (keyboardState.IsKeyDown(Keys.PageDown)) translate.Z -= 3.0f; if (keyboardState.IsKeyDown(Keys.PageUp)) translate.Z += 3.0f;

  26. Пример компонента «камера»Взаимодействие с мышью boolleftButton = false; Point lastMousePos; intlastMouseWheel; public override void Update(GameTimegameTime) { ... // Класс Mouse не поддерживается Xbox 360 #if !XBOX360 MouseStatemouseState = Mouse.GetState(); Rectangle rect = Game.Window.ClientBounds; // Приблежение/удаление камеры осуществляется колесиком intnewMouseWheel = mouseState.ScrollWheelValue; intdeltaMouseScroll = newMouseWheel - lastMouseWheel; translate.Z += (float)deltaMouseScroll * 0.1f; lastMouseWheel = newMouseWheel; // Вращение камеры осуществляется посредством перемещения // мыши при зажатой левой кнопке if (mouseState.LeftButton == ButtonState.Pressed) { if (leftButton == false) { lastMousePos = new Point(mouseState.X, mouseState.Y); // Если в момент нажатия левой кнопки указатель мыши //находится за пределами клиентской области окна, вращение // начинать не следует if ((lastMousePos.X >= 0) && (lastMousePos.Y >= 0) && (lastMousePos.X < rect.Width) && (lastMousePos.Y < rect.Height)) {leftButton = true;} else leftButton = false; } else { Point newMousePos = new Point(mouseState.X, mouseState.Y); Vector2 delta = new Vector2(lastMousePos.X - newMousePos.X, lastMousePos.Y - newMousePos.Y); angles += delta * 0.005f; // Центрируем указатель во избежание блокировки if (mouseState.X != rect.Width / 2) { newMousePos.X = rect.Width / 2; Mouse.SetPosition(newMousePos.X, newMousePos.Y); } if (mouseState.Y != rect.Height / 2) { newMousePos.Y = rect.Height / 2; Mouse.SetPosition(newMousePos.X, newMousePos.Y); } lastMousePos = newMousePos; } } else leftButton = false; #endif }

  27. Пример компонента «камера»Интеграция в приложение public class Game1 : Microsoft.Xna.Framework.Game { Camera camera; public Game1() { graphics = new GraphicsDeviceManager(this); content = new ContentManager(Services); // Создаем компонент камера и добавляем его в список // компонентов camera = new Camera(this); Components.Add(camera); } }

  28. Экспорт сцены из 3DS MAX 9

  29. Загрузка модели(Ex04)

  30. Загрузка модели public class Game1 : Microsoft.Xna.Framework.Game { // Информация о модели Model biplane; protected override void LoadGraphicsContent(boolloadAllContent) { if (loadAllContent) { // Загружаем модель biplane = content.Load<Model>("Content\\Biplane"); } } }

  31. Класс Model

  32. Анимация винта самолета(Ex05)

  33. Анимация винтасамолета public class Game1 : Microsoft.Xna.Framework.Game { // Матрицы трансформации Matrix[] biplaneTransforms; protected override void LoadGraphicsContent(boolloadAllContent) { … // Выделяем память для хранения матриц трансформациии biplaneTransforms = new Matrix[biplane.Bones.Count]; } protected override void Update(GameTimegameTime) { … // Получаем значение матриц трасформации biplane.CopyBoneTransformsTo(biplaneTransforms); // Ищем вал винта for (inti = 0; i < biplane.Meshes.Count; i++) { ModelMesh mesh = biplane.Meshes[i]; if (mesh.Name == "Prop head") { // Поворачиваем вал винта biplaneTransforms[mesh.ParentBone.Index] *= Matrix.CreateRotationX(0.05f); } } // Копируем измененные матрицы обратно в модель biplane.CopyBoneTransformsFrom(biplaneTransforms); // Вычисляем итоговые матрицы трансформации для каждого меша biplane.CopyAbsoluteBoneTransformsTo(biplaneTransforms); … } }

  34. Компонент Graphics • Объектная надстройка над Direct3D 9 • В отличии от MDX не является тонкой оберткой над интерфейсами Direct3D • Нет поддержки fixed function pipeline • Часть функциональности FFP реализуется посредством класса BasicEffect • Пока только вершинное освещение • До трех источников света • Одна текстура • Туман • Класс SpriteBatch инкапсулирует спрайтовую графику • Нет встроенных базовых объектов вроде куба, сферы и чайника • Нет поддержки визуализации вершин без трансформации вершинным шейдером и т.д.

  35. Компонент Graphics

  36. Визуализация самолета(Ex06)

  37. Визуализация самолета protected override void Draw(GameTimegameTime) { // Закарска экрана синим цветом graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // Перебираем все меши сцены for (inti = 0; i < biplane.Meshes.Count; i++) { ModelMesh mesh = biplane.Meshes[i]; // Перебираем все эффекты меша и устанавливаем параметры for (int j = 0; j < mesh.Effects.Count; j++) { BasicEffect effect = (BasicEffect)mesh.Effects[j]; // Включаем освещение по умолчанию (3 источника) effect.EnableDefaultLighting(); // Задаем матрицы мира, вида и проекции effect.World = biplaneTransforms[mesh.ParentBone.Index]; effect.View = camera.View; effect.Projection = camera.Projection; } // Визуализируем Mesh mesh.Draw(); } base.Draw(gameTime); }

  38. Компонент Content Pipeline DDC контент Content Importer Content DOM Content Processor Content DOM XNB Content Manager Node Content Model Content Model Reader X Importer Model Processor .X Fbx Importer Terrain Processor .FBX Texture Content .XNB Texture2D Reader Texture Content Texture Importer Sprite Texture Processor .JPG .PNG Texture Processor Procedure Texture Importer .XML Model Texture Processor

  39. Компонент Content PipelineStandart Importers

  40. Попиксельное освещение(Ex07)

  41. Попиксельное освещениеЭффект const static intLightCount = 3; // Текстура texture diffuseTexture; // Матрицы трасформации float4x4 worldViewProj : WorldViewProjection; float4x4 worldView : WorldView; //Направления источников света float3 lightDirView[LightCount]; // Цвета источников света float4 lightColor[LightCount]; // Цвет диффузной составляющей материала float4 materialDiffuse; // Цвет зеркальной составляющей материла float4 materialSpecular; // Глянцевитость float shininess; // Накладывается ли текстура bool textured; structvertexInput { float3 position : POSITION; float3 normal : NORMAL; float2texCoordDiffuse: TEXCOORD0; }; structvertexOutput { float4 hPosition : POSITION; float2texCoordDiffuse : TEXCOORD0; float3 eye : TEXCOORD1; float3 N : TEXCOORD2; float3 L[LightCount] : TEXCOORD3; }; sampler TextureSampler = sampler_state { texture = <diffuseTexture>; … }; vertexOutputVS_PerPixelLighting(vertexInput IN) { vertexOutput OUT; OUT.hPosition = mul( float4(IN.position , 1.0) , worldViewProj); OUT.texCoordDiffuse = IN.texCoordDiffuse; float3 vertPos = mul(float4(IN.position.xyz, 1.0), worldView).xyz; OUT.N = normalize(mul(IN.normal, (float3x3)worldView)); OUT.eye = -normalize(vertPos); for (inti = 0; i < LightCount; i++) { OUT.L[i] = lightDirView[i]; } return OUT; } float4 PS_PerPixelLighting( vertexOutput IN): COLOR { float3 normN = normalize(IN.N); float3 normEye = normalize(IN.eye); float4 color = float4(0.0, 0.0, 0.0, 0.0); float4 diffuseTexture; if (textured) diffuseTexture = tex2D( TextureSampler, IN.texCoordDiffuse ); else diffuseTexture = float4(1.0, 1.0, 1.0, 1.0); for (inti = 0; i < LightCount; i++) { float3 normL = normalize(IN.L[i]); float diff = max(0, dot(normN, normL)); float3 H = normalize(normEye + normL); float spec = pow(max(0 , dot(normN,H) ) , shininess ); float4 diffColor = materialDiffuse * diff * lightColor[i] * diffuseTexture; float4 specColor = materialSpecular * lightColor[i] * spec; color += diffColor + specColor; } return color; } technique textured { pass p0 { CullMode = None; VertexShader = compile vs_1_1 VS_PerPixelLighting(); PixelShader = compile ps_2_0 PS_PerPixelLighting(); } }

  42. Попиксельное освещениеContent Processor using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Processors; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; ... [ContentProcessor] public class ModelPerpixelLightingProcessor : ModelProcessor { // Конвертирует материалы модели protected override MaterialContentConvertMaterial(MaterialContent material, ContentProcessorContext context) { // Создаем материал, использующий наш эффект perpixel.fx EffectMaterialContentmyMaterial = new EffectMaterialContent(); string effectPath = Path.GetFullPath("Content\\perpixel.fx"); myMaterial.Effect = new ExternalReference<EffectContent>(effectPath); // Формируем параметры эффекта на основе объекта материала // BasicMaterialConten, созданного XNA if (material is BasicMaterialContent) { BasicMaterialContentbasicMaterial = (BasicMaterialContent)material; // Текстура материала if (basicMaterial.Texture != null) { myMaterial.Textures.Add("diffuseTexture", basicMaterial.Texture); myMaterial.OpaqueData.Add("textured", true); } else myMaterial.OpaqueData.Add("textured", false); // Диффузный цвет if (basicMaterial.DiffuseColor != null) { myMaterial.OpaqueData.Add("materialDiffuse", new Vector4(basicMaterial.DiffuseColor.Value, 1.0f)); } else myMaterial.OpaqueData.Add("materialDiffuse", Vector4.One); // Цвет бликов и глянцевитость if ((basicMaterial.SpecularColor != null) && (basicMaterial.SpecularPower != null)) { myMaterial.OpaqueData.Add("shininess", basicMaterial.SpecularPower.Value); myMaterial.OpaqueData.Add("materialSpecular", new Vector4(basicMaterial.SpecularColor.Value, 1.0f)); } else { myMaterial.OpaqueData.Add("materialSpecular", Vector4.One); myMaterial.OpaqueData.Add("shininess", 128.0f); } } else throw new NotImplementedException(); return base.ConvertMaterial(myMaterial, context); } }

  43. Использование нового Content Processor в C# Express

  44. Попиксельное освещениеИнтеграция в приложение Vector4[] lightColor = new Vector4[] {Vector4.One, new Vector4(0.5f, 0.5f, 0.5f, 1.0f), new Vector4(0.5f, 0.5f, 0.5f, 1.0f)}; Vector3[] lightDir = new Vector3[]{ new Vector3(-0.5265408f, -0.5735765f, -0.6275069f), new Vector3(0.7198464f, 0.3420201f, 0.6040227f), new Vector3(-0.4545195f, 0.7660444f, 0.9545195f)}; Vector3[] lightDirView = new Vector3[3]; protected override void Draw(GameTimegameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // Переводим векторы направления источников света в // систему координат камеры for (int k = 0; k < lightDir.Length; k++) { Matrix normalTransform = camera.View; normalTransform.Translation = Vector3.Zero; lightDirView[k] = Vector3.Normalize( Vector3.Transform(-lightDir[k], normalTransform)); } for (inti = 0; i < biplane.Meshes.Count; i++) { ModelMesh mesh = biplane.Meshes[i]; for (int j = 0; j < mesh.Effects.Count; j++) { // Получаем доступ к объекту эффекта Effect effect = (Effect)mesh.Effects[j]; // Задаем матрицы трансформации effect.Parameters.GetParameterBySemantic( "WorldViewProjection"). SetValue(biplaneTransforms[mesh.ParentBone.Index] * camera.ViewProjection); effect.Parameters.GetParameterBySemantic("WorldView"). SetValue(biplaneTransforms[mesh.ParentBone.Index] * camera.View); // Цвет источников света effect.Parameters["lightColor"].SetValue(lightColor); // Направление источников света (в системе координат // камеры) effect.Parameters["lightDirView"].SetValue( lightDirView); } mesh.Draw(); } base.Draw(gameTime); }

  45. Content Processors из XNA Creators Club • Работа со шрифтами и визуализация текста • Генерация ландшафта на основе карты высот • Height Map -> Normal Map • Bump mapping • Скелетная анимация http://creators.xna.com/

  46. Компонент Storage • Кроссплатформенная надстройка над System.IO • Доступ к файлам данных приложения • Сохранение конфигурации приложения и сохраненных игр

  47. Сохранение конфигурации(Ex08)

  48. Сохранение конфигурацииСериализация данных public class Config { public Vector2 angles; public Vector3 translate; // Сохранение объекта в файла public void Save(string filename) { using (TextWriterfs = new StreamWriter(filename)) { XmlSerializerxmlSerializer = new XmlSerializer(typeof(Config)); xmlSerializer.Serialize(fs, this); } } // Загрузка данных из файла public static Config Load(string filename) { Config config; try { using (FileStreamfs = new FileStream(filename, FileMode.Open)) { XmlSerializerxmlSerilizer = new XmlSerializer(typeof(Config)); config = (Config)xmlSerilizer.Deserialize(fs); } } // При возникновении проблем используем // настройки по умолчанию catch (IOException) { config = new Config(); } catch (InvalidOperationException) { config = new Config(); } return config; } }

  49. Сохранение конфигурацииРабота с носителями информации protected override void Update(GameTimegameTime) { KeyboardState keyboadState = Keyboard.GetState(); GamePadStategamePadState = GamePad.GetState(PlayerIndex.One); // Если нажата клавиша S клавиатуры или кнопка B геймпада if (keyboadState.IsKeyDown(Keys.S) || (gamePadState.Buttons.B == ButtonState.Pressed)) { // Отображаем диалоговое окно выбора устройства хранения // информации StorageDevicestorageDevice = StorageDevice.ShowStorageDeviceGuide(); // Проверяем, подключено ли это устройство if (!storageDevice.IsConnected) return; // Получаем доступ к файлам приложения на устройстве using (StorageContainerstorageContainer = storageDevice.OpenContainer("GSP.Biplane")) { // Формируем полное имя файла конфигурации string configFile = Path.Combine(storageContainer.Path, "config.xml"); Config config = new Config(); config.angles = camera.angles; config.translate = camera.translate; /Сохраняем конфигурацию приложения config.Save(configFile); } } // Если нажата клавиша L клавиатуры или кнопка A геймпада if (Keyboard.GetState().IsKeyDown(Keys.L) || (gamePadState.Buttons.A == ButtonState.Pressed)) { // Отображаем диалоговое окно выбора устройства хранения // информации StorageDevicestorageDevice = StorageDevice.ShowStorageDeviceGuide(); // Проверяем, подключено ли это устройство if (!storageDevice.IsConnected) return; // Получаем доступ к файлам приложения на устройстве using (StorageContainerstorageContainer = storageDevice.OpenContainer("GSP.Biplane")) { // Формируем полное имя файла конфигурации string configFile = Path.Combine(storageContainer.Path, "config.xml"); // Загружаем конфигурацию приложения Config config = Config.Load(configFile); camera.angles = config.angles; camera.translate = config.translate; } } }

  50. Компонент Audio / XACT • Основан на Microsoft Cross-Platform Audio Creation Tool (XACT) • Визуальный windows-инструментарий для создания аудио контента • Позволяет создавать именованные последовательности wave-файлов с возможностью организации циклов, изменения громкости и т.п., и привязывать их к событиям приложения без перекомпиляции • Высокоуровневая кросс-платформенная библиотека для работы с аудио подсистемой PC и Xbox 360