Урок 4: Игровой цикл. Часть 2 (Silverlight анимация и xaml)

Ладно продолжем.

Анимация с использованием Blend’а, красиво, легко, но, к сожалению, в случае написания игр не сильно жизнеспособна. Поэтому попытаемся поковырять анимацию руками. Будем ковырять DoubleAnimation как самую распространенную.

Если вы создадите простейшую анимацию в Blend’e. То, получите, что ни будь подобное следующему:

  1:  <UserControl
  2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      x:Class="SilverlightApplication4.Page"
   5:      Width="640" Height="480">
   6:  
   7:      <UserControl.Resources>
   8:          <Storyboard x:Name="Storyboard1">
   9:              <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
  10:                  <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
  11:                  <SplineDoubleKeyFrame KeyTime="00:00:02" Value="45"/>
  12:              </DoubleAnimationUsingKeyFrames>
  13:          </Storyboard>
  14:      </UserControl.Resources>
  15:  
  16:      <Grid x:Name="LayoutRoot" Background="White" >
  17:          <Rectangle HorizontalAlignment="Stretch" Margin="261,200,279,180" VerticalAlignment="Stretch" Fill="#FFFF0000" Stroke="#FF000000" x:Name="rectangle" RenderTransformOrigin="0.5,0.5">
  18:              <Rectangle.RenderTransform>
  19:                  <TransformGroup>
  20:                      <ScaleTransform/>
  21:                      <SkewTransform/>
  22:                      <RotateTransform/>
  23:                      <TranslateTransform/>
  24:                  </TransformGroup>
  25:              </Rectangle.RenderTransform>
  26:          </Rectangle>
  27:      </Grid>
  28:  </UserControl>

Для дальнейшей работы загрузим проект в VS2008 и добавим старт таймера при создании страницы:

   1:  public Page()
   2:  {
   3:       // Required to initialize variables
   4:       InitializeComponent();
   5:       Storyboard1.Begin();
   6:  }

Посмотрим же внимательно на данное произведение, и увидим что ничего особо военного здесь нет. Собственно страница (юзер контрол). В ресурсы которого добавлен таймер. А также прямоугольник в котором добавлена пока неизвестный нам тег RenderTransform, и все что в нем. И раз уж в предыдущей части мы начинали разговор за таймер, давайте и в этой начнем с него.

Итак, в ресурсы юзер контрола (нашей страницы) добавлен тег Storyboard и присвоено ему имя, надеюсь все поняли, для чего? Конечно для того чтобы иметь доступ из программного кода. Дальше используя DoubleAnimationUsingKeyFrames, мы указываем, что будем работать со свойством double, используяKey-Frames анимацию. Собственно дальше идет наша анимация с перечислением кадров по порядку и указанием величины анимируемого свойства в каждом кадре. Самым интересным в теге таймера, по моему мнению, является Storyboard.TargetProperty = «(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)». Именно эта строка указывает, какое свойство у нас будет анимироваться. В кавычках указывается по очереди все теги описание свойства через точку, а именно что это RenderTransform, группа трансформации(TransformGroup), третий член массива, преобразование RotateTransform и наконец, его свойство Angle.

Помните в первой части мы еще мы еще говорили, что в Silverlight’e существует еще один тип анимации кроме Key-Framе, а именно From/To/By. Давайте попробуем использовать другой тип анимации. Для этого мы поменяем тег анимации на следующий:

   1:              <DoubleAnimation
   2:                  Storyboard.TargetName="rectangle"
   3:                  Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"
   4:                  From="0" To="45" Duration="00:00:02">
   5:              </DoubleAnimation>

Работает, даже эффект тот же.

Меня лично смущает еще присвоение TargetProperty, уж очень оно длинное и не сильно прозрачное. Для исправления данной ситуации воспользуемся xaml’ом – давайте присвоим имя нужной нам трансформации: <RotateTransform x:Name=»rectangle_rotate»/>

И тогда уже наша анимация приобретет вид:

   1:              <DoubleAnimation
   2:                  Storyboard.TargetName="rectangle_rotate"
   3:                  Storyboard.TargetProperty="Angle"
   4:                  From="0" To="45" Duration="00:00:02">
   5:              </DoubleAnimation>

Согласитесь, теперь код стал намного более наглядным и коротким. Самое интересное, что получив более наглядный код, нам проще будет добавить еще одно свойство в аниамцию – просто вставьте еще один тег с другой анимации в таймер. Например, чтобы получить движение по Х нашего квадрата, надо будет добавить:

   1:              <DoubleAnimation
   2:                  Storyboard.TargetName="rectangle_move"
   3:                  Storyboard.TargetProperty="X"
   4:                  From="261" To="450" BeginTime="00:00:07" Duration="00:00:10">
   5:              </DoubleAnimation>

Только не забудьте присвоить имя для трансформации TranslateTransform в соответствующий тег. Заметьте, что мы увеличили время анимации для этого вида трансформации и выставили стартовое время. И если проиграть наш ролик, то увидим не сильно простую анимацию.

Я виду к тому, что не всегда необходимо использовать Key-Framе анимацию или несколько таймеров – иногда нужный эффект можно получить и более простыми способами.

А что же за Key-Framе анимацию, то её есть смысл использовать только в ДВУХ случаях:

1) Если Вам необходимо указать более 2(как в From/To от-до) величин анимируемого свойства, и если эти величины не получаются линейной интерполяцией.

2) Между величинами вам необходима не линейная интерполяция (Дискретная, Сплайновая или их смесь с Линейной).

Заметьте, что Key-Framе подход также позволяет использовать различную интерполяцию между кадрами в одной анимации:

   1:  <DoubleAnimationUsingKeyFrames
   2:             Storyboard.TargetName="rectangle_move"
   3:             Storyboard.TargetProperty="X"
   4:             Duration="0:0:10">
   5:      <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3" />
   6:      <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4" />
   7:      <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6" />
   8:  </DoubleAnimationUsingKeyFrames>

Мы вовсю начали работать с трансформациями, поэтому считаю, что не лишне бы было небольшое объяснение:

· TranslateTransform – позволяет рисовать фигуру в другом месте, задав новые значения свойств X,Y. Свойства X,Y.

· RotateTransform – поворачивает внутреннюю координатную сетку (объект) объекта, вокруг указанного вами центра на указанный угол. Свойства Angle, CenterX, CenterY.

· ScaleTransform – масштабирует координатную сетку объекта(объект). Позволяя сжать или растянуть объект. Свойства ScaleX, ScaleY, CenterX, CenterY.

· SkewTransform – искривляет объект. Свойства AngleX, AngleY, CenterX, CenterY.

· MatrixTransform – модифицирует координатную сету объекта используя перемножения матриц. Наверное самый сложный тип трансформации с точки зрения математики. Свойство Matrix.

· TransformGroup – комбинирует несколько преобразований объекта для того чтобы их можно было применить. Заметьте что очередность, с которой вы применяете трансформации в указанной группе, влияет на конечный результат. Например, повернув и переместив объект, вы получите совершенно другой результат, чем, если бы сначала вы переместили, а потом повернули объект. В первом случае вы получите то что ожидали, во втором же – движение по спирали.

Я думаю, что у Вас не возникнет трудностей с трансформацией, она достаточно подробноо описана в справке к Silverlighte. К тому же с трансформацией перемещения и поворота мы столкнемся в следующей части урока – процедурной анимации.

А чтобы окончательно закончить общее описание анимации на основе xaml в Silverlight’e. Необходимо затронуть еще одну вещь, а именно триггеры. Вы наверняка заметили, что мы вписывали в C# файл одну строчу. Которая запускает нашу анимацию. Давайте попробуем сделать так чтобы описание события запуска нашего таймера происходило в xaml файле:

   1:              <Rectangle.Triggers>
   2:                  <EventTrigger RoutedEvent="Rectangle.Loaded">
   3:                      <EventTrigger.Actions>
   4:                          <BeginStoryboard>
   5:                              <Storyboard x:Name="Storyboard1">
   6:                                  <DoubleAnimation
   7:  Storyboard.TargetName="rectangle_rotate"                                    Storyboard.TargetProperty="Angle"
   8:                                      From="0" To="45" Duration="00:00:02">
   9:                                  </DoubleAnimation>
  10:                              </Storyboard>
  11:                          </BeginStoryboard>
  12:                      </EventTrigger.Actions>
  13:                  </EventTrigger>
  14:              </Rectangle.Triggers>

Небольшое замечание на данный момент(Бета 2) почему-то не все события поддерживаемые объектами билдятся без ошибок в xaml’e. Кроме этого заметьте, что сам таймер и анимацию нам пришлось перенести в само тело триггера. И вопрос: если то знает, как запустить из тега BeginStoryboard уже существующий в ресурсах страницы таймер, поделитесь, пожалуйста.

Тригеры достаточно мощная вещь, заслуживающая отдельной статьи, но, к сожалению, выходящая за рамки данного урока. Так, что продолжим гнуть свою линию в сторону игростроя ;-) .


Комментариев пока нет

Ответить