Как известно, в xna не предусмотрен типовой GUI, поэтому каждому разработчику приходится решать — рисовать его самим, подключать готовые GUI библиотеки разработанные специально для xna (коих не так уж много), либо пытаться подключить стандартные winform / wpf (по подключению wpf уже есть замечательная статья).
Я не стал разбираться в многочисленных вариантах решения данной задачи и решил пойти как мне казалось наиболее простым путем — подключением winform. Как оказалось, winform имеет ряд нюансов и ограничений.
В итоге после активного поиска я пришел к двум возможным реализациям интерфейса:
1. Весь интерфейс без участия клавиатуры, т.е. кнопки, списки и т.п. Если необходимо ввести что-то с клавиатуры — создавать внешнюю форму и получать с нее данные.
2. Интерфейс полностью работоспособен и можно вводить данные с клавиатуры. Но создание внешних форм невозможно + еще пара нюансов.
Подробнее:
1
В проект xna необходимо добавить ссылки на System.Windows.Forms и System.Drawing. Затем прописать код создания необходимых контролов. Контролы не будут реагировать на нажатия кнопок клавиатуры. Причину подобного поведения я смог найти в интернете, но удовлетворительного решения к сожалению не нашел, цитата:
XNA использует свой класс для прослушивания состояния клавиатуры, в то время как textbox использует Windows.Form.Input.
Автор цитаты решил данный вопрос созданием метода, который напрямую получает нажатые кнопки через встроенный класс xna и напрямую передает в поле ввода выделенного контрола. Недостаток данного подхода — нет простого способа узнать нажата клавиша «Q» или «Й» (Подробнее о методе по ссылке 1 внизу статьи).
Подключение контрола к форме:
using Size_ = System.Drawing.Size; // В обозреватель решений добавлена ссылка на System.Drawing, но тут из всего пространства имен нужен только размер и положение
using Point_ = System.Drawing.Point;
…
…
// Создаем контрол
NumericUpDown nm = new NumericUpDown();
nm.Location = new Point_(0, 50);
nm.Size = new Size_(125, 20);
nm.Value = (decimal)text2;
nm.KeyUp += new KeyEventHandler(nm_ValueChanged_f);
nm.ValueChanged += new EventHandler(nm_ValueChanged_f);
// Получаем текущую форму
Form general_form = (Form)Control.FromHandle(Window.Handle);
// Подключаем контрол к текущей форме
general_form.Controls.Add(nm);
* This source code was highlighted with Source Code Highlighter.
Исходники простого приложения с контролами внутри формы и созданием внешней формы в конце статьи.
2
Метод описанный выше к сожалению нельзя применить к приложениям, требующих от пользователя ввода текста. Продолжая поиски я нашел иной метод подключения winform (ссылка 2 в конце статьи). Суть его заключается в том, что происходит инициализация формы, контролов и лишь затем — самой игры. Особенность в том, что таким образом игра не сможет сама вызывать методы update() и draw() — их необходимо будет вызывать отдельно.
Данный способ подходит под многие задачи, т.к. все созданные контролы будут верно реагировать на нажатия клавиатуры.
Однако и этот способ имеет нюансы. Все контролы должны быть созданы после (во время) инициализации формы, но до инициализации самой игры (ненужные в конкретный момент просто скрыть через Visible). Контролы созданные после инициализации игровой формы (форма приложения и игровая форма это разные формы, хоть этого визуально и не видно), не будут принимать нажатия клавиш, причину этого мне выяснить к сожалению не удалось. Это так же относится и к созданию форм, подчиненных игровой форме — они будут видны, но textbox и подобные контролы не будут работоспособны. Так же, контролы созданные после инициализации игровой формы могут быть не видны вообще, если подчинены форме приложения, а не игровой форме.
Создавать же формы верхнего уровня при данном подходе бесполезно — они будут фактически неработоспособны (очень сильно тормозят).
Из недостатков этого подхода так же могу отметить едва заметное падение производительности.
Код относительно большой так что я не стал выкладывать его в статье. Исходный код примера можно скачать ниже (пример 2).
Буду рад дополнениям и конструктивной критике!
Ссылки:
1. Решение недоступности ввода клавиатуры вводом специального метода
2. Способ подключения контролов «наоборот» — сначала инициализация контролов, затем игры.
3. Описание метода аналогичного 1му в русскоязычном сообществе xna
Скачать пример 1
Скачать пример 2