Урок 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 уже существующий в ресурсах страницы таймер, поделитесь, пожалуйста.
Тригеры достаточно мощная вещь, заслуживающая отдельной статьи, но, к сожалению, выходящая за рамки данного урока. Так, что продолжим гнуть свою линию в сторону игростроя
.
Комментариев пока нет
Ответить