Орбитальная анимация - PullRequest
       10

Орбитальная анимация

7 голосов
/ 15 апреля 2011

Прежде всего я попытаюсь объяснить, что я пытаюсь сделать. На первый взгляд, задача выглядит довольно простой, но мне потребовалось некоторое время, чтобы понять ее очень сложно. То, что я пытаюсь сделать, - это простая анимация с замедлением в начале и в конце - я знаю, как использовать замедление, сложная часть в том, что я пытаюсь сделать что-то вроде орбиты - эллиптической орбиты, скажем, с 5 прикрепленными прямоугольниками. к этому. Я хочу переместить прямоугольники вдоль эллиптической орбиты (эллиптической траектории) без изменения угла поворота каждого прямоугольника.

Я пробовал с анимацией пути, но кажется, что анимация движения не поддерживает замедление? Я ошибся ? Второе решение состояло в том, чтобы сгруппировать путь и прямоугольники и повернуть всю группу, но это также меняет угол поворота прямоугольников. Есть ли простой способ сделать это? Пожалуйста, укажите мне статью или что-то, или, если у вас есть подобный сценарий, пожалуйста, поделитесь решением. Спасибо.

Ответы [ 2 ]

12 голосов
/ 15 апреля 2011

Попробуйте, это очень весело:

<Canvas Height="100" Width="100" RenderTransformOrigin="0.5,0.5">
    <Canvas.Triggers>
        <EventTrigger RoutedEvent="Canvas.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation From="0" To="360"
                                     RepeatBehavior="Forever"
                                     Duration="0:0:1"
                                     Storyboard.TargetProperty="RenderTransform.Angle">
                        <DoubleAnimation.EasingFunction>
                            <CubicEase EasingMode="EaseInOut"/>
                        </DoubleAnimation.EasingFunction>
                    </DoubleAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Canvas.Triggers>
    <Canvas.RenderTransform>
        <RotateTransform />
    </Canvas.RenderTransform>
    <Canvas.Resources>
        <Style TargetType="{x:Type Rectangle}">
            <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
            <Setter Property="RenderTransform" Value="{Binding RenderTransform.Inverse, RelativeSource={RelativeSource AncestorType=Canvas}}"/>
        </Style>
    </Canvas.Resources>
    <Rectangle Fill="Red" Height="20" Width="20" Canvas.Left="40" Canvas.Top="0"/>
    <Rectangle Fill="Green" Height="20" Width="20" Canvas.Left="40" Canvas.Top="80"/>
</Canvas>

Ключевые моменты:

  1. RotateTransform как RenderTransform на холсте, который анимирован.
  2. Неявный стиль с помощью Canvas.Resources связывает RenderTransform прямоугольников с обратным RotateTransform родительского холста.
  3. ???
  4. Прибыль!
4 голосов
/ 16 апреля 2011

Вот другой подход ...

То, что вы хотите сделать, это на самом деле не вращение, а перемещение по эллиптическому пути. Проблема в том, что TranslateTransform определяется X и Y, а не углом и радиусом ... Но угол легче анимировать, поэтому вам нужно преобразовать полярные координаты в декартовы.

Для этого определим два преобразователя: SinConverter и CosConverter:

public class SinConverter : IValueConverter
{
    #region Implementation of IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            double angle = System.Convert.ToDouble(value);
            double angleRad = Math.PI * angle / 180;
            double radius = System.Convert.ToDouble(parameter);
            return radius * Math.Sin(angleRad);
        }
        catch
        {
            return Binding.DoNothing;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

public class CosConverter : IValueConverter
{
    #region Implementation of IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            double angle = System.Convert.ToDouble(value);
            double angleRad = Math.PI * angle / 180;
            double radius = System.Convert.ToDouble(parameter);
            return radius * Math.Cos(angleRad);
        }
        catch
        {
            return Binding.DoNothing;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

Теперь нам нужно свойство угла для анимации: поэтому мы определяем фиктивную RotateTransform в ресурсах, которая будет целью анимации.

Далее мы применяем TranslateTransform к «спутнику» и привязываем X и Y к углу, используя наши преобразователи.

В конце концов, нам просто нужно создать анимацию, которая будет анимировать угол.

Вот полный XAML:

<Window x:Class="WpfCS.Orbit"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfCS"
        Title="Orbit"
        Height="300" Width="300">
    <Window.Resources>
        <my:SinConverter x:Key="sinConverter" />
        <my:CosConverter x:Key="cosConverter" />
        <RotateTransform x:Key="rotate" Angle="0" />
    </Window.Resources>
    <Grid>
        <Rectangle Width="30" Height="30" Fill="Blue">
            <Rectangle.RenderTransform>
                <TranslateTransform X="{Binding Path=Angle,
                                                Source={StaticResource rotate},
                                                Converter={StaticResource cosConverter},
                                                ConverterParameter=100}"
                                    Y="{Binding Path=Angle,
                                                Source={StaticResource rotate},
                                                Converter={StaticResource sinConverter},
                                                ConverterParameter=60}"/>
            </Rectangle.RenderTransform>
        </Rectangle>
        <Ellipse Width="5" Height="5" Fill="White" Stroke="Black" StrokeThickness="1" />
    </Grid>
    <Window.Style>
        <Style TargetType="Window">
            <Style.Triggers>
                <EventTrigger RoutedEvent="Loaded">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.Target="{StaticResource rotate}"
                                         Storyboard.TargetProperty="Angle"
                                         From="0" To="360" Duration="0:0:5"
                                         RepeatBehavior="Forever" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Window.Style>
</Window>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...