xna game studio express: разработка casual games для pc и xbox 360

Post on 15-Feb-2016

58 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

XNA Game Studio Express: разработка casual games для PC и Xbox 360. Александр Ложечкин Сергей Гайдуков. Содержание. XNA Framework на платформе Windows .NET Compact Framework for Xbox 360 Компоненты XNA Framework Оптимизация XNA- приложений XNA Framework и Windows Forms. - PowerPoint PPT Presentation

TRANSCRIPT

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

PC и Xbox 360

Александр ЛожечкинСергей Гайдуков

Содержание

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

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– Утилиты– Образование

Marblets

XNA Framework

• Кроссплатформенный API для разработки игровых приложений– Не привязан к Windows

• Основан на платформе .NET Framework– .NET Framework 2.0 (Windows)– .NET Compact Framework for Xbox 360– Mono (Linux)

XNA на платформе Windows

• Компоненты для разработки приложений

• Компоненты для распространения приложений

– Очень просто интегрируются в дистрибутив приложения средствами Visual Studio 2005 Pro

Компонент Размер дистрибутиваVisual C# Express 2005 + SP1 440MB + (24-53MB)XNA Game Studio Express 1.0 81MB.NET Framework 1.1 23MB

Компонент Размер дистрибутива.NET Framework 2.0 22 – 27MBXNA Framework 1.0 2MBОбновление D3DX, XACT, XINPUT

4MB

.NET Compact Framework 2.0

• Отличия от .NET Framework 2.0:– Значительно меньшие требования к ресурсам компьютера– Является подмножеством .NET Framework (содержит

примерно 30% классов)– Ограниченная поддержка web-приложений и баз данных– Ограниченная поддержка Windows Forms– Не поддерживается генерация кода на лету

(System.Reflection.Emit)– Ограниченная поддержка JIT аппаратных вычислений с

плавающей точкой– Более простой сборщик мусора

.NET Compact Framework /Xbox 360

• Подмножество .NET Compact Framework– Нет поддержки Windows Forms – В настоящее время отсутствует поддержка сетевых

технологий• Дополнительные возможности

– Аппаратные вычисления с плавающей точкой• Но нет поддержки векторных инструкций VMX128

– Привязка потоков к одному из четырех (всего 6) логических процессоров (Hardware threads)• Метод Thread.SetProcessorAffinity задаёт логический

процессоры, предпочтительные для выполнения потока

Кроссплатформенные приложения

• Создаются отдельные проекты для PC и Xbox 360

• Проекты могут использовать общий исходный код и контент (Add As Link)• Поддерживается только C#• При создания кода, специфичного для Windows и Xbox 360, используйте

директивы условной компиляции #if/#else/#endif и [Conditional]

#if !XBOX360// Код, специфичный для Windows#endif

[Conditional("XBOX360"]void XboxCode(){// Код, специфичный для Xbox }

Компоненты XNA Framework

Platform

CoreFramework

ExtendedFramework

Games

XACT XINPUT XContentDirect3D

Graphics Audio Input Math Storage

Application Model Content Pipeline

Starter Kits Code Content Components

Компонент Application Model

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

пользовательских компонентов

Компонент Application Model

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

Простейшее приложение

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(bool loadAllContent) {…

}

// Освобождение ресурсов protected override void UnloadGraphicsContent(bool unloadAllContent) { if (unloadAllContent == true) { content.Unload(); } }

// Обновление состояния игры protected override void Update(GameTime gameTime) {... base.Update(gameTime); }

// Визуализация изображения protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

// Визуализация всех пользовательских DrawableGameComponent base.Draw(gameTime); } }}

Компонент Input

Работа с устройствами ввода-вывода

Устройство Класс ПоддержкаWindows Xbox 360

Клавиатура Keyboard X X

Мышь Mouse X

Геймпад GamePad X X

Компонент Input

Пример использования компонента Input

(Ex02)

Пример использования компонента Input

protected override void Update(GameTime gameTime){// Если нажата кнопка Back геймпада if (GamePad.GetState(PlayerIndex.One). Buttons.Back == ButtonState.Pressed) { Exit(); }

// Если на клавиатуре нажата клавиша Esc if (Keyboard.GetState().IsKeyDown(Keys.Escape)) { Exit(); }

base.Update(gameTime);}

Компонент Math

Компонент Math

• Больше не является настройкой над D3DX• Поиск компромисса между удобством и производительностью

– public static Matrix operator *(Matrix matrix1, Matrix matrix2);– public static Matrix Multiply(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)

• Поддерживается только правосторонняя система координат

Использования компонента Math на примере

встраивания камеры(Ex03)

Пример компонента «камера»Каркас компонента

public partial class Camera : Microsoft.Xna.Framework.GameComponent{ public Camera(Game game) : base(game) {

}

// Инициализация компонента и загрузка контента public override void Initialize() {

base.Initialize(); }

// Обновление состояния компонента public override void Update(GameTime gameTime) {

base.Update(gameTime); }}

Пример компонента «камера»Расчет матриц трансформации

// Углы и положение камеры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; }}

Пример компонента «камера»Взаимодействие с геймпадом

using Microsoft.Xna.Framework.Input;

public override void Update(GameTime gameTime){// Джойстик не должен воздействовать приложение, потерявшее фокусif (Game.IsActive) { // Получаем состояние миниджойстиков GamePadThumbSticks ThumbSticks = 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);}

Пример компонента «камера»Взаимодействие с клавиатурой

// Получаем состояние клавиатуры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;

Пример компонента «камера»Взаимодействие с мышьюbool leftButton = false;Point lastMousePos;int lastMouseWheel;

public override void Update(GameTime gameTime){...// Класс Mouse не поддерживается Xbox 360#if !XBOX360

MouseState mouseState = Mouse.GetState();Rectangle rect = Game.Window.ClientBounds;

// Приблежение/удаление камеры осуществляется колесикомint newMouseWheel = mouseState.ScrollWheelValue;int deltaMouseScroll = 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}

Alexander Lozhechkin
Про столкновение с границей не понял

Пример компонента «камера»Интеграция в приложение

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); }}

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

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

Загрузка модели

public class Game1 : Microsoft.Xna.Framework.Game{// Информация о модели Model biplane;

protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) {// Загружаем модель biplane = content.Load<Model>("Content\\Biplane"); } }}

Класс Model

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

Анимация винта самолета

public class Game1 : Microsoft.Xna.Framework.Game{// Матрицы трансформации Matrix[] biplaneTransforms;

protected override void LoadGraphicsContent(bool loadAllContent) {…// Выделяем память для хранения матриц трансформациии biplaneTransforms = new Matrix[biplane.Bones.Count]; }

protected override void Update(GameTime gameTime) {…// Получаем значение матриц трасформации biplane.CopyBoneTransformsTo(biplaneTransforms);// Ищем вал винта for (int i = 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);… }}

Компонент Graphics

• Объектная надстройка над Direct3D 9– В отличии от MDX не является тонкой оберткой над интерфейсами

Direct3D• Нет поддержки fixed function pipeline• Часть функциональности FFP реализуется посредством класса

BasicEffect– Пока только вершинное освещение– До трех источников света– Одна текстура– Туман

• Класс SpriteBatch инкапсулирует спрайтовую графику• Нет встроенных базовых объектов вроде куба, сферы и чайника• Нет поддержки визуализации вершин без трансформации

вершинным шейдером и т.д.

Компонент Graphics

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

Визуализация самолета

protected override void Draw(GameTime gameTime){// Закарска экрана синим цветом graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

// Перебираем все меши сцены for (int i = 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);}

Компонент Content Pipeline

DDC контент

ContentImporter

Content DOM

ContentProcessor

Content DOM

XNB Content Manager

.X

TextureImporter

TextureContent

SpriteTexture

Processor.XNB

Texture2DReader.JPG

.PNG

.XML

Texture Processor

ModelTexture

Processor

ProcedureTextureImporter

TextureContent

XImporter

NodeContent

ModelProcessor

ModelContent

TerrainProcessor

ModelReader

.FBX FbxImporter

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

Типы файлов

Названиеимпортера

Класс импортера

Выходной класс

.bmp, .dds,

.dib, .hdr, .jpg, .pfm, .png, .ppm, .tga.

XNA Texture Importer

TextureImporter TextureContent

.fx XNA Effect Importer

EffectImporter EffectContent

.x XNA X File Importer

Ximporter NodeContent

.fbx XNA Autodesk FBX Importer

FbxImporter NodeContent

.xml XNA XML Importer

XmlImporter Object

.xap XNA XACT Project Importer

- -

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

Попиксельное освещениеЭффект

const static int LightCount = 3;// Текстураtexture diffuseTexture;// Матрицы трасформацииfloat4x4 worldViewProj : WorldViewProjection;float4x4 worldView : WorldView;//Направления источников светаfloat3 lightDirView[LightCount];// Цвета источников светаfloat4 lightColor[LightCount];// Цвет диффузной составляющей материалаfloat4 materialDiffuse;// Цвет зеркальной составляющей материлаfloat4 materialSpecular;// Глянцевитостьfloat shininess;// Накладывается ли текстураbool textured;

struct vertexInput { float3 position : POSITION; float3 normal : NORMAL; float2 texCoordDiffuse: TEXCOORD0;};

struct vertexOutput { float4 hPosition : POSITION; float2 texCoordDiffuse : TEXCOORD0; float3 eye : TEXCOORD1; float3 N : TEXCOORD2; float3 L[LightCount] : TEXCOORD3;};

sampler TextureSampler = sampler_state { texture = <diffuseTexture>;…};

vertexOutput VS_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 (int i = 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 (int i = 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(); }}

Попиксельное освещение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 MaterialContent ConvertMaterial( MaterialContent material,

ContentProcessorContext context) {// Создаем материал, использующий наш эффект perpixel.fx EffectMaterialContent myMaterial = new

EffectMaterialContent(); string effectPath = Path.GetFullPath("Content\\perpixel.fx"); myMaterial.Effect = new ExternalReference<EffectContent>(effectPath);

// Формируем параметры эффекта на основе объекта материала // BasicMaterialConten, созданного XNA if (material is BasicMaterialContent) { BasicMaterialContent basicMaterial =

(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); }}

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

Попиксельное освещениеИнтеграция в приложение

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(GameTime gameTime){ 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 (int i = 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);}

Content Processors из XNA Creators Club

• Работа со шрифтами и визуализация текста• Генерация ландшафта на основе карты высот• Height Map -> Normal Map• Bump mapping• Скелетная анимация

http://creators.xna.com/

Компонент Storage

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

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

Сохранение конфигурацииСериализация данных

public class Config{ public Vector2 angles; public Vector3 translate;

// Сохранение объекта в файла public void Save(string filename) { using (TextWriter fs = new StreamWriter(filename)) { XmlSerializer xmlSerializer = new XmlSerializer(typeof(Config)); xmlSerializer.Serialize(fs, this); } }

// Загрузка данных из файла public static Config Load(string filename) { Config config;

try {

using (FileStream fs = new FileStream(filename, FileMode.Open))

{ XmlSerializer xmlSerilizer = new

XmlSerializer(typeof(Config)); config = (Config)xmlSerilizer.Deserialize(fs); } }// При возникновении проблем используем // настройки по умолчанию catch (IOException) { config = new Config(); } catch (InvalidOperationException) { config = new Config(); }

return config; }}

Сохранение конфигурацииРабота с носителями информации

protected override void Update(GameTime gameTime){ KeyboardState keyboadState = Keyboard.GetState(); GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

// Если нажата клавиша S клавиатуры или кнопка B геймпада if (keyboadState.IsKeyDown(Keys.S) || (gamePadState.Buttons.B == ButtonState.Pressed)) {// Отображаем диалоговое окно выбора устройства хранения // информации StorageDevice storageDevice = StorageDevice.ShowStorageDeviceGuide();

// Проверяем, подключено ли это устройство if (!storageDevice.IsConnected) return;

// Получаем доступ к файлам приложения на устройстве using (StorageContainer storageContainer =

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)) {// Отображаем диалоговое окно выбора устройства хранения // информации StorageDevice storageDevice = StorageDevice.ShowStorageDeviceGuide();

// Проверяем, подключено ли это устройство if (!storageDevice.IsConnected) return;

// Получаем доступ к файлам приложения на устройстве using (StorageContainer storageContainer =

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; } }}

Компонент Audio / XACT

• Основан на Microsoft Cross-Platform Audio Creation Tool (XACT)– Визуальный windows-инструментарий для

создания аудио контента• Позволяет создавать именованные

последовательности wave-файлов с возможностью организации циклов, изменения громкости и т.п., и привязывать их к событиям приложения без перекомпиляции

– Высокоуровневая кросс-платформенная библиотека для работы с аудио подсистемой PC и Xbox 360

Компонент Audio / XACTОсновные компоненты проекта

• Файл проекта .xap. Текстовый файл, с описанием проекта и инструкциями по сборке

• Файл глобальных настроек .gsf, затрагивающих весь проект

• Wave bank – коллекция wave-файлов, логически сгруппированных в один .xwb файл

Компонент Audio / XACTОсновные компоненты проекта

• SoundBank – .xsb файл с набором Sounds и Cues– Sound – инструкции, описывающие как надо проиграть

набор указанных звуков (микширование, последовательность, циклы, громкость)

– Cue – логическая группа Sounds, проигрываемая приложением при наступление определенного события

Компонент AudioОсновные классы

• Надстройка над XACT– AudioEngine – главный объект, управляющий аудио-

подсистемой PC / Xbox 360. Настройки загружаются из .gsf-файла

– WaveBank и SoundBank – работа с .xwb и .xsb файлами соответственно• Доступ к Cue осуществляется методом GetCue класса

SoundBank• Проигрывание звуков управляется стандартным

набором Play/Pause/Resume/Stop и свойствами наподобие IsPlaying

Звук двигателя(Ex09)

Microsoft Cross-Platform Audio Creation Tool (XACT)

Запуск двигателя самолета

AudioEngine audioEngine;WaveBank waveBank;SoundBank soundBank;

protected override void Initialize(){// Загружаем аудио данные audioEngine = new AudioEngine("Content\\audio.xgs"); waveBank = new WaveBank(audioEngine, "Content\\Wave Bank.xwb"); soundBank = new SoundBank(audioEngine, "Content\\Sound Bank.xsb");

// Запускаем проигрывание звука двигателя самолета soundBank.PlayCue("Biplane");… }

protected override void Update(GameTime gameTime){// Периодически вызываем метод Update экземпляра класса AudioEngine audioEngine.Update();... }

Starter Kits

Rocket Commander XNA

Чего нет в текущей версии…но появится в будущем

• Поддержка сетевых приложений• Средства разработки GUI-интерфейса• Низкоуровневая работа с Audio-устройствами• Воспроизведение видеофайлов• IDE для разработки и отладки шейдеров

Производительность сборщика мусора

• Плюсы сборщика мусора– Высокая скорость выделения памяти– Локальность данных, практически отсутствует проблема

фрагментации– Нет утечек памяти

• В том числе и при использовании циклических ссылок• Но не всё так хорошо

– Иногда все же приходится собирать мусор– Частый вызов сборщика мусора может поставить крест на

производительности

Сборщик мусора .NET Framework 2.0

• Сборка мусора похожа на процесс дефрагментации HDD– Затраты на сборку мусора преимущественно определяются количеством “выживших”

объектов• Сборщик мусора с поддержкой поколении (0, 1, 2)

– Куча располагается в непрерывном адресном пространстве, разделенном на поколения

– В каждом поколении объекты имеют примерно одинаковый возраст• Мусор собирается в первую очередь в поколении 0

– Размер поколения 0 примерно равен кэшу L2– При построении графа достижимых объектов как правило игнорируются объекты

поколений 1 и 2– Время сборки мусора в поколении 0 порядка 1 мс

• Старайтесь не допустить перехода кратко живущих объектов в старшие поколения (избегайте Finalize)

Поколение2

Поколение1

Поколение0

Свободная память

Сборщик мусора .NET CF for Xbox 360

• Поколения не поддерживаются– Отличная производительность, если объем выделенной памяти

сопоставим с размером поколения 0 в .NET Framework 2.0 (порядка 1MB)

– С ростом объема выделенной памяти эффективность стремительно снижается

• Заблаговременно выделяйте память перед началом вычислений– Даже незначительное выделение памяти при визуализации каждого

кадра может иметь печальные последствия– Выделяемая памяти предварительно обнуляется, так что пропускная

способность оперативной памяти может стать узким местом• Самостоятельно форсируйте сборку мусора в местах, не

критичных к незначительным провалам производительности

Неявное выделение памятиБоксирование (boxing)

Пример 1 Пример 2

void Add(object item){…}…// Неявное выделение памяти в// управляемой кучеAdd(2.0f);

struct MyItem : IComparable {…}

void Test(IComparable v1){…}

static void Main(string[] args){ MyItem item;// Неявное выделение памяти в// управляемой куче Test(item);}

Неявное выделение памятиЦикл foreach

• Получает Enumerator посредством метода GetEnumerator– Если Enumerator является классом, происходит выделение памяти– Если Enumerator является структуройКоллекция List Коллекция EffectPassCollection

public class List<T> : IList<T>, ...{ public struct Enumerator : IEnumerator<T>, ... { public bool MoveNext(); public T Current { get; } }

public Enumerator<T> GetEnumerator() {// Нет выделения памяти в управляемой куче// Но если использовать коллекцию List<T> через // интерфейс вроде IList<T>, выделение памяти // все же произойдет return new Enumerator<T>((List<T>)this); }}

public sealed class EffectPassCollection : IEnumerable<EffectPass>{ public struct Enumerator : IEnumerator<T>, … {... } public Enumerator<T> GetEnumerator() { return new Enumerator<T>((List<T>)this); } public IEnumerator<EffectPass> GetEnumerator() {// Внимание: боксирование и выделение памяти в куче. return (IEnumerator<EffectPass>)this.pPass.GetEnumerator(); }}

Использование XNA Framework в WinForms

• Всегда используйте Platform Target x86• Класс GraphicsDevice легко интегрируется с визуальными

компонентами и окнами Win32– Для вывода на в заданную область формы просто разместите должным

образом визуальный компонент, унаследованный от Control, запретить Erase Background и передать его Handle в GraphicsDevice

– Не пытайтесь интегрировать Game в приложение Windows Forms. Он для этого не предназначен

• Нет поддержки Content Pipeline– Эффекты и текстуры можно использовать минуя Content Pipeline– Для экспорта моделей используйте Visual C# 2005 Express или MS Build– Необходимо самостоятельно реализовать интерфейсы классов Game и

GraphicsDeviceManage

Пример использования MSBuildдля компиляции модели

• Model.proj<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <UsingTask TaskName="BuildContent" AssemblyName="Microsoft.Xna.Framework.Content.Pipeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" /> <PropertyGroup> <XnaInstall> C:\Program Files (x86)\Microsoft XNA\XNA Game Studio Express\v1.0\References\Windows\x86 </XnaInstall> </PropertyGroup> <ItemGroup> <PipelineAssembly Include="C:\Program Files (x86)\Microsoft XNA\XNA Game Studio Express\v1.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll" /> <PipelineAssembly Include="C:\Program Files (x86)\Microsoft XNA\XNA Game Studio Express\v1.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll" /> </ItemGroup>   <ItemGroup> <Content Include="biplane.FBX"> <Importer>FbxImporter</Importer> <Processor>ModelProcessor</Processor> </Content> </ItemGroup>   <Target Name="Build"> <BuildContent SourceAssets="@(Content)" PipelineAssemblies="@(PipelineAssembly)" TargetPlatform="Windows" /> </Target> </Project>

Пример подмены классовGame и GraphicsDeviceManage

// Реализация класса GraphicsDeviceManage с поддердкой// Windows Formsclass WinFormsGraphicsDeviceService : IGraphicsDeviceService, IGraphicsDeviceManager{ private GraphicsDevice graphicsDevice; private Control renderControl; public PresentationParameters presentParams;

public WinFormsGraphicsDeviceService(Control renderControl) { this.renderControl = renderControl; }

#region IGraphicsDeviceService Members public event EventHandler DeviceCreated; public event EventHandler DeviceDisposing; public event EventHandler DeviceReset; public event EventHandler DeviceResetting;

public GraphicsDevice GraphicsDevice { get { return this.graphicsDevice; } } #endregion

#region IGraphicsDeviceManager Members

public void CreateDevice() { presentParams = new PresentationParameters(); presentParams.IsFullScreen = false; presentParams.BackBufferCount = 1; presentParams.BackBufferHeight = 0; presentParams.BackBufferWidth = 0; presentParams.EnableAutoDepthStencil = true; presentParams.AutoDepthStencilFormat = DepthFormat.Depth24; this.graphicsDevice = new GraphicsDevice( GraphicsAdapter.DefaultAdapter,

DeviceType.Hardware, this.renderControl.Handle, CreateOptions.HardwareVertexProcessing, presentParams); } #endregion}

// Имплементация свойства Services класса Gamepublic partial class MainForm : Form, IServiceProvider { WinFormsGraphicsDeviceService graphics = null; ContentManager contentManager = null;

private void MainForm _Load(object sender, EventArgs e) { SetStyle(ControlStyles.Opaque | ControlStyles.ResizeRedraw, true); MinimumSize = SizeFromClientSize(new Size(1, 1));

this.graphics = new WinFormsGraphicsDeviceService(this); graphics.CreateDevice(); contentManager = new ContentManager(this);

// Загрузка контента biplane = contentManager.Load<Model>("Content\\biplane"); }

#region IServiceProvider Members public object GetService(Type serviceType) { if (serviceType == typeof(IGraphicsDeviceService)) return graphics; else throw new NotImplementedException(); } #endregion}

XNA Game Studio Express 1.1

• Полная поддержка Windows Vista• Поддержка Visual Studio 2005• Поддержка спрайтовых шрифтов• Поддержка 3D звука• BasicEffect поддерживает попиксельное освещение• Расширенная математическая библиотека• Улучшенная технология распространения

приложений• Обратная совместимость с 1.0

Учебная литература

Интернет ресурсы

• http://msdn2.microsoft.com/en-us/xna/default.aspx• http://blogs.msdn.com/xna/• http://creators.xna.com/• http://forums.microsoft.com/msdn/• http://abi.exdream.com/

• www.xnadev.ru • www.gotdotnet.ru

Вопросы

• Александр Ложечкин– allo@microsoft.com– http://blogs.gotdotnet.ru/personal/allo

• Сергей Гайдуков– gsaf@pnz.ru– http://blogs.gotdotnet.ru/personal/gsaf

top related