Анимация в XAML-графике
Анимация вдоль заданной траектории
Одна из самых интересных возможностей компьютерной анимации – это движение фигуры вдоль произвольно задаваемой траектории (рис. 7.9):

Рис. 7.9. 1. Два отдельных объекта. 2. Эллипс становится траекторией движения. 3. Движение вдоль заданной траектории (иллюстрация из справки Microsoft Expression Blend)
В качестве траектории может использоваться не только замкнутая фигура, но и вообще, любая кривая, нарисованная, например, с помощью инструмента "Кисть". К сожалению, на момент написания этого курса, в Silverlight-проектах не поддерживается привязка движения к траектории. Однако эта возможность реализована в WPF-приложениях. Рассмотрим такой пример на практике. Создаем новый WPF – проект (рис. 7.10):
Сначала нарисуем окружность, которая будет служить траекторией. Для этого выбираем инструмент эллипс и рисуем фигуру – можно даже без всякой заливки (рис. 7.11):
Теперь добавим окружность, которая и будет двигаться. Ее расположение на холсте, цвет заливки и оформления могут быть совершенно произвольными. Но на панели "Properties", в поле "Name " введем имя фигуры, например, "myBall" (рис. 7.12):
увеличить изображение
Рис. 7.12. Фигура, которая будет двигаться по траектории, должна иметь заполненное значение поля Name
Выделяем исходный эллипс, который будет служить траекторией и в главном меню выбираем пункт "Object \ Path \ Convert to Motion Path" (рис. 7.13):
При этом происходит преобразование текущей кривой в траекторию движения. В появившемся диалоговом окне "Convert to Motion Path" нам нужно выбрать объект, который будет привязан к создаваемой траектории. Здесь мы указываем объект "myBall" (рис. 7.14):
Практически все готово. Вид редактора Microsoft Expression Blend меняется – шарик перескакивает на свою стартовую позицию, причем его центр совмещен с траекторией (рис. 7.15):
увеличить изображение
Рис. 7.15. Вид редактора Microsoft Expression Blend после завершения привязки объекта к траектории
Запускаем приложение, нажимая клавишу F5. Объект двигается по замкнутой траектории (рис. 7.16):
Если сделать направляющую нулевой толщины или установить для нее белый цвет контура, то она будет не видна. Дальнейшее оформление ограничено лишь фантазией разработчика. Код, сгенерированный средой, достаточно громоздок:
<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/
  xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Motion_Path.Window1"
  x:Name="Window"
  Title="Window1"
  Width="640" Height="480">
  <Window.Resources>
    <Storyboard x:Key="Storyboard1">
      <DoubleAnimationUsingPath BeginTime="00:00:00" 
Duration="00:00:02" Storyboard.TargetName="myBall" 
Storyboard.TargetProperty="(UIElement.RenderTransform).(
TransformGroup.Children)[3].
(TranslateTransform.X)" Source="X">
  <DoubleAnimationUsingPath.PathGeometry>
    <PathGeometry>
        <PathFigure IsClosed="True" 
        StartPoint="241.5,12">
          <BezierSegment Point1="241.5,53.1452138623941" 
Point2="167.179268471912,86.5" Point3="75.5,86.5" IsSmoothJoin="True"/>
          <BezierSegment Point1="-16.1792684719117,86.5"
 Point2="-90.5,53.1452138623941" Point3="-90.5,12" IsSmoothJoin="True"/>
          <BezierSegment Point1="-90.5,-29.1452138623941"
 Point2="-16.1792684719117,-62.5" Point3="75.5,-62.5" IsSmoothJoin="True"/>
          <BezierSegment Point1="167.179268471912,-62.5" 
Point2="241.5,-29.1452138623941" Point3="241.5,12" IsSmoothJoin="True"/>
          </PathFigure>
        </PathGeometry>
      </DoubleAnimationUsingPath.PathGeometry>
    </DoubleAnimationUsingPath>
    <DoubleAnimationUsingPath 
    BeginTime="00:00:00" Duration="00:00:02" 
    Storyboard.TargetName="myBall" Storyboard.
TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.Y)" Source="Y">
    <DoubleAnimationUsingPath.PathGeometry>
      <PathGeometry>
        <PathFigure IsClosed="True" StartPoint="241.5,12">
          <BezierSegment Point1="241.5,53.1452138623941"
 Point2="167.179268471912,86.5" Point3="75.5,86.5" IsSmoothJoin="True"/>
          <BezierSegment Point1="-16.1792684719117,86.5" 
Point2="-90.5,53.1452138623941" Point3="-90.5,12" IsSmoothJoin="True"/>
          <BezierSegment Point1="-90.5,-29.1452138623941"
 Point2="-16.1792684719117,-62.5" Point3="75.5,-62.5" IsSmoothJoin="True"/>
          <BezierSegment Point1="167.179268471912,-62.5" 
Point2="241.5,-29.1452138623941" Point3="241.5,12" IsSmoothJoin="True"/>
        </PathFigure>
      </PathGeometry>
    </DoubleAnimationUsingPath.PathGeometry>
  </DoubleAnimationUsingPath>
  </Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
  <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
  </EventTrigger>
</Window.Triggers>
<Grid x:Name="LayoutRoot">
  <Ellipse Margin="144,0,147,53" VerticalAlignment="Bottom" 
Height="150" Fill="#FFFFFFFF" Stroke="#FF000000"/>
  <Ellipse HorizontalAlignment="Left" Margin="210,0,0,115" 
  VerticalAlignment="Bottom" Width="50" Height="50" 
Fill="#FFFF0000" 
Stroke="#FF000000" x:Name="myBall" RenderTransformOrigin="0.5,0.5">
  <Ellipse.RenderTransform>
    <TransformGroup>
      <ScaleTransform ScaleX="1" ScaleY="1"/>
      <SkewTransform AngleX="0" AngleY="0"/>
      <RotateTransform Angle="0"/>
      <TranslateTransform X="0" Y="0"/>
    </TransformGroup>
  </Ellipse.RenderTransform>
</Ellipse>
</Grid>
</Window>
7.1.
                    
Его можно упростить, если убрать дробные значения в координатах, а также удалить ненужные команды трансформации:
<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Motion_Path.Window1"
  x:Name="Window"
  Title="Window1"
  Width="640" Height="480">
  <Window.Resources>
  <Storyboard x:Key="Storyboard1">
    <DoubleAnimationUsingPath BeginTime="00:00:00"
 Duration="00:00:02" Storyboard.TargetName="myBall" 
 Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" Source="X">
    <DoubleAnimationUsingPath.PathGeometry>
      <PathGeometry>
        <PathFigure IsClosed="True" StartPoint="241.5,12">
          <BezierSegment Point1="241.5,53.1" 
Point2="167.1,86.5" Point3="75.5,86.5" />
          <BezierSegment Point1="-16.1,86.5" 
Point2="-90.5,53.1" Point3="-90.5,12" />
          <BezierSegment Point1="-90.5,-29.1" 
          Point2="-16.1,-62.5" Point3="75.5,-62.5" />
          <BezierSegment Point1="167.179268471912,-62.5" 
Point2="241.5,-29.1" Point3="241.5,12" />
        </PathFigure>
      </PathGeometry>
    </DoubleAnimationUsingPath.PathGeometry>
  </DoubleAnimationUsingPath>
  <DoubleAnimationUsingPath BeginTime="00:00:00" 
Duration="00:00:02" Storyboard.TargetName="myBall" Storyboard.
TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)" Source="Y">
  <DoubleAnimationUsingPath.PathGeometry>
    <PathGeometry>
      <PathFigure IsClosed="True" StartPoint="241.5,12">
        <BezierSegment Point1="241.5,53.1" 
Point2="167.1,86.5" Point3="75.5,86.5" />
        <BezierSegment Point1="-16.1,86.5" 
Point2="-90.5,53.1" Point3="-90.5,12" />
        <BezierSegment Point1="-90.5,-29.1" 
Point2="-16.1,-62.5" Point3="75.5,-62.5" />
        <BezierSegment Point1="167.179268471912,-62.5" 
Point2="241.5,-29.1" Point3="241.5,12" />    
      </PathFigure>
    </PathGeometry>
  </DoubleAnimationUsingPath.PathGeometry>
</DoubleAnimationUsingPath>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
  <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
  </EventTrigger>
</Window.Triggers>
<Grid x:Name="LayoutRoot">
  <Ellipse Margin="144,0,147,53" VerticalAlignment="Bottom" 
Height="150" Fill="Transparent" Stroke="Black"/>
  <Ellipse HorizontalAlignment="Left" Margin="210,0,0,115"
 VerticalAlignment="Bottom" Width="50" Height="50"
 Fill="Red" x:Name="myBall" RenderTransformOrigin="0.5,0.5">
    <Ellipse.RenderTransform>    
      
      <TranslateTransform X="0" Y="0"/>
    </Ellipse.RenderTransform>
  </Ellipse>
</Grid>
</Window>
7.2.
                    
Здесь мы видим, что привязка к траектории, описываемая объектом Path, осуществляется дважды – для команды TranslateTransform.X и TranslateTransform.Y. Вместо данных, подставляемых в объект Path, можно подставлять свои значения, созданные без всяких визуальных средств.
Завершив изучение этой лекции, полезно прочитать статью Деклана Бреннана (Declan Brennan) "Создание сложной трехмерной анимации с помощью Silverlight 2.0" http://msdn.microsoft.com/ru-ru/magazine/cc500570.aspx.
                             





