MVC в Silverlight 2
Виды
Все визуальные элементы нашей игры относятся к компоненту Вид, который включает внешнее оформление, диалоги, сцены заставки и концовки игры, и такие элементы, как парашютисты, вертолеты, орудие и снаряды.
Модель
Для правильного MVC разделения мы должны сделать нашу модель абсолютно независимой от вида и контроллера. Модель не должна содержать экземпляры двух других компонент паттерна. При проектировании модели можно применять две стратегии:
Пассивная модель – в такой реализации вид получает уведомление об изменениях от контроллера только тогда, когда контроллер узнал об изменениях в соответствующей модели.
Активная модель – в этой реализации модель уведомляет о своих изменениях соответствующий вид, используя паттерн обозреватель. Простейшая реализация паттерна обозреватель на .NET заключается в использовании делегатов и событий. Для разработки игр подобная техника вполне подходит: вид подписывается на события, которые возбуждаются моделью при каких-либо изменениях в состоянии (новое положение или столкновение).
Контроллер
Последний компонент паттерна –контроллер. Мы будем использовать один контроллер, который будет служить в качестве центральной нервной системы игры. Контроллер будет ответственен за обслуживание основного цикла игры используемый для перемещения спрайтов и отслеживания коллизий. Рисунки 3 и 4 демонстрируют, как происходит создание контроллер и его инициализация из нашего page.xaml.
Когда контроллер создан, мы можем вызвать его метод Initialize(), чтобы задать компоненту все дополнительные параметры. В рамках метода Initialize() мы установим таймер и загрузим наш стартовый диалог. Было много споров по поводу того, что целесообразнее использовать: контролирующий таймер(DispatcherTimer) или раскадровку(Storyboard), и был сделан довольно неожиданный выбор в пользу Storyboard с короткими задержками. Storyboard будет тикать более эффективно и равномерно.
public partial class Page : UserControl
{
private Controllers.Controller _controller;
public Page()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
_controller = new Controllers.Controller(this);
_controller.Initialize();
}
}
рис. 3 – код из page.xaml.cs
public Controller(Page pageView)
{
_pageView = pageView;
_shellView = new Game.Views.Shell(new Models.Shell());
_pageView.LayoutRoot.Children.Add(_shellView);
}
private Storyboard _sbTick = new Storyboard();
public void Initialize()
{
//setup my game timer
_sbTick.Duration = TimeSpan.FromMilliseconds(10);
_sbTick.Completed += new EventHandler(_sbTick_Completed);
//place the start dialog into the shell
_startView = new Views.Start();
//attach to the start event of the view
_startView.Begin += new
Game.Views.Start.BeginHandler(_startView_Begin);
//add the view to the shell
_shellView.LayoutRoot.Children.Add(_startView);
}
рис. 4 – инициализация контроллера
Запуск Игры
Теперь, когда мы уже знаем, как и что должно работать, давайте-ка взглянем на то, как наш вид взаимодействует с контроллером. При первой загрузке игры пользователь увидит начальный вид, который представлен нашим Start.xaml. Этот Вид содержит некоторый инструктаж и кнопку запуска игры. Рисунок 4 иллюстрирует то, как мы добавляем этот вид в наше окружение(shell), и добавляем обработчик кнопки «начать игру».
Заглядывая вперед: в 5-ой части мы покажем, как создать загрузочный проект, который будет загружаться вперед игры, и асинхронно загружать более тяжелую сборку игры.
Когда пользователь нажимает кнопку «Старт», наш контроллер подготавливает игру – он подключает обработчики событий мыши к окружению(shell). Мы будем использовать мышь для контроля направления и начальной скорости выстрела снаряда из нашего орудия. Когда курсор находится в приделах нашего окружения, мы начинаем отслеживать угол, образованный орудием и курсором. Левый клик мыши производит выстрел снаряда в соответствии с полученным направлением. Для того, чтобы видеть куда мы прицеливаемся, мы заменим стандартный указатель мыши картинкой в виде перекрестия. Скорость выстрела будет вычисляться исходя из расстояния между перекрестием курсора и стволом орудия. В части 2 мы покажем, как отслеживать подобное движение и вычислять угол траектории. На рисунке 7 представлен код, используемый для отслеживания и реагирования на движение мыши. Продолжая разработку, мы расширим наш метод StartGame(), чтобы он размещал игрока, запускал цикл игры, а также инициировал активность вертолетов.
public void StartGame()
{
....
_shellView.MouseEnter += new MouseEventHandler(_shellView_MouseEnter);
_shellView.MouseLeave += new MouseEventHandler(_shellView_MouseLeave);
_shellView.MouseMove += new MouseEventHandler(_shellView_MouseMove);
_shellView.MouseLeftButtonDown +=
new MouseButtonEventHandler(_shellView_MouseLeftButtonDown);
//add the crosshair
Crosshair cross = new Crosshair(new Vector(0.0, 0.0));
_crosshair = new Game.Views.Crosshair(cross);
_shellView.Container.Children.Add(_crosshair);
....
}
void _shellView_MouseMove(object sender, MouseEventArgs e)
{
Point m = e.GetPosition(_shellView.Container);
_crosshair.Model.Move(_shellView.Container, m);
_player.Model.ChangeAngle(m);
}
void _shellView_MouseLeave(object sender, MouseEventArgs e)
{
_shellView.CaptureMouse();
}
void _shellView_MouseEnter(object sender, MouseEventArgs e)
{
_shellView.CaptureMouse();
}
void _shellView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
. . . .
}
рис. 8 - отслеживание движения мыши
Теперь, когда у нас есть необходимый каркас самое время начать создавать элементы нашей игры! В следующей статье мы сосредоточимся на перемещениях и определимся с тем, как заставить наших парашютистов спускаться, вертолеты летать, а орудия стрелять. Приготовьтесь вкусить немного тригонометрии и элементарной физики. Ничего сложного, ровно столько, сколько необходимо, чтобы движения и столкновения в нашей игрушке казались реалистичными, и чтобы в нее было приятно играть.
Чтобы скачать готовые исходники или оставить комментарий, посетите мой блог:
http://joel.neubeck.net/2008/09/casual-
ewsletter/
Благодарю за внимание и до скорых встреч.
(прямая ссылка на исходиники)
(оригинал статьи: Module 1: Getting Started – Architecture/framework)