Анимация в 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.