Rx:SSSsssss...(Так звучат Reactive Extensions, Windows Phone 7 и змея...)

Грег Дункан

Reactive Extensions – это нечто, о чем я писал не много (хм…совсем… хм). Reactive Extensions (Rx) – это вид, сорт, не совсем так, но один из способов представления этого – "LINQ для событий".

Вот краткое описание из статьи MSDN «Reactive Extensions для .NET. Обзор для Windows Phone»:

Reactive Extensions для .NET Framework – это управляемая библиотека, обеспечивающая API для написания реагирующих приложений. Реагирующие приложения управляются своим окружением. В модели реагирования потоки данных, асинхронные запросы и события представляются наблюдаемыми последовательностями. Приложение может подписаться на эти наблюдаемые последовательности для получения асинхронных сообщений при поступлении новых данных. Reactive Extensions позволяют приложению комбинировать эти последовательности с помощью операторов запросов.

Если приложение взаимодействует со множественными источниками данных, такими как события пользовательского ввода, запросы веб-сервисов и системные предупреждения, обычным способом управления является реализация раздельных обработчиков для каждого из этих потоков данных. Внутри каждого обработчика требуется создать код для координации взаимодействия между всеми различными потоками данных и их обработки в пригодную форму. Reactive Extensions позволяют создать запрос, объединяющий все потоки данных в единый поток, запускающий единый обработчик. Работу по фильтрации, синхронизации и преобразованию данных выполняет запрос Reactive Extensions, так что обработчик должен только реагировать на получаемые данные и что-то делать с ними.

...

Итак где же удовольствие? Как будет выглядеть простая игра, использующая Rx? Скажем игра на Windows Phone 7?

Андреа Бошин (Andrea Boschin), Реактивная змея для Windows Phone 7

Продолжая свои эксперименты с Reactive Extension, я собрал небольшой пример, демонстрирующий альтернативное использование библиотеки для создания небольшой игры. Игра известна под названием «Змея», в нее играли многие из нас на телефонах Nokia, когда она была единственной игрой в устаревших моделях. Пожалуйста, отметьте, что игра, которую я написал, не закончена, так как она, прежде всего, – пример использования технологии и того, как можно упростить разработку слегка усложненной логики, вроде той, что стоит за данной игрой.

Ядро игры основано на двух раздельных использованиях Reactive Extensions. С одной стороны есть главный цикл, базирующийся на частых таймаутах, которые в полной версии игры должны использоваться для изменения скорости игры. В этой версии таймаут установлен в 75 мсек. Каждый раз когда истекает таймаут я передвигаю змею на одну позицию вперед, сохраненную в переменных XDirection и YDirection. Эти переменные принимают значения 1 или -1, если змея движется в этом направлении и 0, если она движется перпендикулярно.

...

Цель игры (заметьте, как сказал Андреа, это не завершенная игра, с меню, историей и т.п.) – управлять змеей так, чтобы она двигалась к обозначаемым местам экрана. Вы управляете змеей, которая постоянно двигается, путем касаний разных частей экрана, которые изменяют направление движения змеи.

clip_image002

Звучит просто, но это действительно проблема.

Итак, что же вызывает восхищение? Количество кода, который вы не должны писать. Объем кода в игре удивительно мал. 95% относится к установке, снесению и инфраструктурному коду. Ядро, главная логика, имеющая дело с движением змеи и обработкой взаимодействия с пользователем содержит удивительно мало кода.

 void MainPage_Loaded(object sender, RoutedEventArgs e)
  {
      this.Pulse.Begin();
      this.RandomizeGem();

      // GESTIONE DEL TOUCH DELLO SCHERMO
 Observable.FromEvent<ManipulationStartedEventArgs>(
          ev => this.ManipulationStarted += ev,
          ev => this.ManipulationStarted -= ev)
          .Select(
          o =>
          {
              return new
 { 
                  X = Math.Sign(o.EventArgs.ManipulationOrigin.X - 240), 
                  Y = Math.Sign(o.EventArgs.ManipulationOrigin.Y - 400) 
              };
          })
          .Subscribe(
          o =>
          {
              if (this.XDirection != 0 && this.YDirection == 0)
              {
                  this.XDirection = 0;
                  this.YDirection = o.Y != 0 ? o.Y : this.YDirection;
              }
              else if (this.XDirection == 0 && this.YDirection != 0)
              {
                  this.XDirection = o.X != 0 ? o.X : this.XDirection;
                  this.YDirection = 0;
              }
          });

      // GESTIONE DELLO SNAKE
 Observable.GenerateWithTime(
          new Point(0, 0),
          p => this.IsRunning,
          p => p,
          p => TimeSpan.FromMilliseconds(75),
          p => this.NewPoint(p))
          .ObserveOnDispatcher()
          .TrailWhile(o => o > this.Lenght)
          .Subscribe(this.EvaluateAndDrawSnake);
  }

Это действительно вся главная логика игры. Конечно, есть еще методы рисования, и несколько вспомогательных блоков, но весь рабочий код можно видеть на фрагменте выше.

В настоящий момент Rx мало используются, недооценены и отсутствуют в поле зрения большинства разработчиков. Но если вы что-то делаете с событиями, будь то пользовательские воздействия, внешние события, аппаратные прерывания и т. д. и т. д. (и не большинство программ?), то Rx стоит посмотреть.

Несколько ссылок, которые могут быть интересны: