Reference = add reference, в висуал студия 2010 не могу найти в вкладке Solution Explorer, Microsoft.Xna.Framework. Его нету. |
Усложненные технологии визуализации
Любому разработчику периодически приходится решать множество типовых задач визуализации:
- Как ограничить область вывода изображения определенным участком формы?
- Как осуществить визуализацию в полноэкранном режиме с заданным разрешением экрана?
- Как реализовать анимацию объектов?
- Как визуализировать полупрозрачные примитивы?
Ответы на все эти вопросы будут даны в этой лекции. Начнем с решения первой проблемы.
3.1. Вывод на элементы управления .NET средствами XNA Framework
До сих пор все наши приложения осуществляли монопольный вывод графической информации на поверхность формы. Такой подход не позволяет размещать на форме элементы управления .NET, что значительно ограничивает свободу разработчика. Конечно, можно попробовать использовать различные вспомогательные диалоговые окна и плавающие панели инструментов, но это не очень красивое решение проблемы, хотя и вполне работоспособное1Подобный подход применяется, к примеру, в редакторе сценариев (Activity Editor) игры Microsoft Train Simulator . Гораздо интереснее было бы научиться выводить информацию не на саму форму, а на элементы управления, размещенные на ней (к примеру, на элемент управления Panel ). Это позволило бы нам легко ограничить область вывода XNA Framework определенной областью формы, а освободившееся пространство использовать для размещения различных элементов управления Windows Forms.
Вывод на поверхность элемента управления практически не отличается от вывода на поверхность формы, ведь в Windows Forms форма является частным случаем элементом управления. Более, форму можно поместить на другую форму или компонент в качестве элемента управления2Этот прием используется в редакторе форм Visual Studio . Это возможно благодаря тому, что любая форма или элемент управления напрямую или косвенно наследуется от общего предка - класса Control. Как следствие, любой элемент управления Windows Forms обладает свойствами Handle, Width, Height, методами SetWidth, Show, Hide, обработчиками событий Paint, Click, Resize и так далее3Полный перечень свойств и методов класса Control можно найти в MSDN .
Примечание
Класс Control является полноценным элементом управления, по функциональности отдаленно напоминающий элемент Panel с немного ограниченными возможностями.
Но вот незадача, некоторые члены класса Control объявлены как protected. Это не создает никаких проблем при создании новой формы путем наследования от класса Form, так как в этом случае вы автоматически получаете полный доступ к защищенным (protected) членам класса. Однако при использовании готовых компонентов, помещаемых на форму средствами визуального редактора форм Visual Studio, все намного серьезнее. Например, вы не сможете получить доступ к такому важному методу как SetStyle, чтобы установить стиль ControlStyles.Opaque. А ведь без этого невозможно запретить самовольную перерисовку элемента управления, приводящую к мерцанию изображения в XNA -приложениях (раздел 1.2.3).
Наиболее красивое решение этой проблемы - создание на базе класса Control собственного элемента управления, изменяющего статус метода SetStyle с protected на public. Для этого запустите Visual Studio и создайте новый проект библиотеки классов XnaPanel (File | New Project… | Class Library, в текстовом поле Name введите XnaPane и нажмите OK). Установите флажок Create directory for solution, так как в решении будет еще один проект, предназначенный для тестирования созданного компонента. Подключите к проекту сборку System.Windows. Forms и введите код из листинга 3.1.
using System; using System.Collections.Generic; using System.Text; using System.Windows. Forms; namespace GSP.XNA { выделялся среди других элементов формы // Объявляем класс (элемент управления) XnaPanel, наследуемый непосредственно public class XnaPanel : Control { // Конструктор элемента управления public XnaPanel() { // Изменяем цвет элемента управления, чтобы он 1x1 пикселей BackColor = Color.CornflowerBlue; // Размер элемента управления не должен быть меньше MinimumSize = new Size(1, 1); } SetStyle метода Control как public SetStyle(ControlStyles flag, bool value) // // Переопределяем метод public new void { Вызываем оригинальный метод класса Control base.SetStyle(flag, value); } } }Листинг 3.1.
Важно
Для предотвращения неконтролируемого уменьшения размера компонента xnaPanel до размеров меньше одного пикселя, его свойству MinimumSize необходимо присвоить значение Size(1, 1) . Если этого не сделать, площадь области визуализации теоретически может достигнуть нуля, что приведет к генерации исключения при сбросе устройства
После компиляции проекта Visual Studi o самостоятельно создаст в окне Components и добавит в нее полученный элемент управления (рисунок 3.1).
Toolbox группу XnaPanel
Для тестирования нашего компонента мы создадим простое приложение, визуализирующее треугольник. В правой части формы будет расположена панель с элементами управления, позволяющими изменять цвета вершин треугольника (рисунок 3.2).
Чтобы добавить к решению еще один проект щелкните правой кнопкой мыши на названии решения в окне Solution Explorer и выберите в контекстом меню пункт Add | New Project… (рисунок 3.3). В появившемся диалоговом окне выберите элемент Windows Application, введите в поле Name название приложения (например, Test ) и нажмите кнопку Ok. Как всегда, подключите к проекту необходимые сборки XNA Framework и добавьте необходимые директивы using.
Поместите на форму компонент SplitContainer, расширьте его на всю форму путем присвоения параметру Dock значения Fill и зафиксируйте размер правой панели, присвоив свойству FixedPanel значение Panel2. В правой панели компонента SplitContainer разместите группу ( Group ) "Параметры " и тоже расширьте ее на всю панель при помощи свойства Dock. В группе создайте три метки ( Label ) расположенные друг под другом: Цвет вершины №1, Цвет вершины №2, Цвет вершины №3. Поместите напротив этих меток три панели ( Panel ) и присвойте им имена vertex1Panel, vertex2Panel и vertex3Panel. Чтобы создать черные рамки вокруг панелей, установите свойство BorderStyle в значение FixedSingle. Поместите в левой панели компонента SplitContainer наш компонент XnaPanel, назовите его xnaPanel и расширьте его на всю свободную область формы, присвоив свойству Dock значение Fill. В заключение, поместите на форму невизуальный компонент ColorDialog.
Следующий этап - "оживление " формы путем создания обработчиков событий. Для начала мы добавим в форму несколько вспомогательных полей и обработчики событий Load/ и FormClosed (листинг 3.2).
// Различные вспомогательные поля GraphicsDevice device = null; PresentationParameters presentParams; Effect effect = null; VertexDeclaration decl = null; VertexPositionColor[] vertices = null; bool closing = false; new XnaGraphics.Color(vertex2Panel.BackColor.R, vertex2Panel.BackColor.G, vertex2Panel.BackColor.B)); vertices[2] = new VertexPositionColor(new Vector3(-0.4f, -0.4f, 0.0f), new XnaGraphics.Color(vertex3Panel.BackColor.R, vertex3Panel.BackColor.G, vertex3Panel.BackColor.B)); // Рисуем треугольник effect.Begin(); foreach(EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); device.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3); pass.End(); } effect.End(); // Переключаем экранные буферы device.Present(); } // Обрабатываем ситуацию внезапной потери устройства catch (DeviceNotResetException) { Invalidate() ; } catch (DeviceLostException) { } } private void xnaPanelResize(object sender, EventArgs e) { // Если форма не минимизирована if (WindowState != FormWindowState.Minimized) { // Обновляем размер формы presentParams.BackBufferWidth = xnaPanel.ClientSize. Width; presentParams.BackBufferHeight = xnaPanel.ClientSize.Height; // Сбрасываем устройство device.Reset(presentParams); } }Листинг 3.2.
В заключении мы создадим обработчик щелчка мышью на панели выбора цвета вершины: при щелчке левой кнопкой мыши будет открываться стандартное диалоговое окно Windows выбора цвета, после чего панель окрасится цветом, выбранным пользователем, а изображение в компоненте xnaPanel будет перерисовано с учетом нового цвета вершины. Для этого выделите панель vertex1Panel и создайте следующий обработчик события Click:
private void vertex1Panel_Click(object sender, EventArgs e) { // Преобразовываем параметр sender к Panel Panel panel = (Panel)sender; // Выбираем в диалоговом окне текущий цвет вершины colorDialog1.Color = panel.BackColor; // Показываем стандартный диалог выбора цвета if (colorDialog1.ShowDialog() == DialogResult.OK) { // Если пользователь выбрал цвет, изменяем цвет панели на выбраный panel.BackColor = colorDialog1.Color; // Обновляем содержимое нашего компонента xnaPanel panelDX.Invalidate(); } }
Как видно, обработчик получает информацию о нажатой панели из параметра sender, что позволяет без изменений использовать этот обработчик для панелей vertex2Panel и vertex3Panel: просто выделите эти панели и назначьте в качестве обработчика события Click метод vertex1Panel_Click.
Остается лишь откомпилировать программу и посмотреть результат. Готовое приложение можно найти в ../1/example.zip в каталоге Examples\Ch03\Ex01.
Примечание
В Visual Studio выбор активного проекта4Проект, который запускается при нажатии клавиши F5 осуществляется при помощи контекстного меню: щелкните на названии проекта в окне Solution Explorer и выберите в появившемся контекстном меню пункт Set as StartUp Project (рисунок 3.4).