WPF手敲一套状态机系统用于动画(像游戏开发引擎里的那种)

目录

前言:

Ⅰ效果演示:

(1)为100×100的控件加载动画(控件名为GD)

(2)MVVM模式下,通过预先设置的条件关系,让控件自动加载动画效果

(3)生命周期支持

Ⅱ实现原理:

1.反射

2.★ 线性插值

3.图形变换矩阵

Ⅲ详细内容请参阅:


前言:

WPF的storyboard、visualstate是强劲的动画工具,但个人觉得XAML写起来不舒服,特别是动画效果特别复杂时,光是看着前端代码界面就晕了,加上最近有在学习Unity,觉得Unity的Animator实现动画很轻松,于是就产生了手写一个状态机的想法,截至文章发布,类库已经更新到了1.5.2版本,可以在详细内容中通过链接访问github或nuget查看文档

Ⅰ效果演示:

(1)为100×100的控件加载动画(控件名为GD)

        private RotateTransform rotateTransform = new RotateTransform(-280, 50, 50);
        private TranslateTransform translateTransform = new TranslateTransform(-100, -50);
        private ScaleTransform scaleTransform = new ScaleTransform(2, 2, 50, 50);

        private void GD_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            GD.StateMachineTransfer()
                .Add(x => x.RenderTransform, rotateTransform, translateTransform, scaleTransform)
                .Add(x => x.Opacity, 0.2)
                .Add(x => x.CornerRadius,new CornerRadius(15))
                .Set((x) =>
                {
                    x.Duration = 0.4;
                    x.Completed = () =>
                    {
                        Notification.Message("过渡完成 √");
                    };
                })
                .Start();
        }

这个示例中,让GD同时实现了旋转、平移、缩放、透明度、边框圆滑度的渐变动画,持续时间为0.4秒,动画结束时弹出一个模态窗口提示动画完成。

可以试着用WPF原生方法写一下这段动画,然后对比使用这个类库,类库需求的代码量是会少很多,且结构会很清晰;原生方法性能更为强劲、稳定;

还有至关重要的一点,状态机支持对【任何类型】的【任何类型受支持的属性的值】进行渐变,而不局限于控件,它还提供了一个接口,允许任何【自定义的类型】作为【属性】参与到状态机渐变中。

(2)MVVM模式下,通过预先设置的条件关系,让控件自动加载动画效果

- 鼠标进入控件时,令其背景透明度过渡为0.2
- 鼠标离开控件时,令其背景透明度过渡为0

    <UserControl.DataContext>
        <local:MButtonViewModel x:Name="ViewModel"/>
    </UserControl.DataContext>
    public partial class MButton : UserControl
    {
        public MButton()
        {
            InitializeComponent();
            this.StateMachineLoading(ViewModel);
        }
    }
 public class MButtonViewModel : ViewModelBase<MButtonViewModel, MButtonModel>
    {
        public MButtonViewModel() { }

        public static State Start = State.FromObject(new MButtonViewModel())
            .SetName("defualt")
            .SetProperty(x => x.HoverBackgroundOpacity, 0)
            .ToState();
        public static State MouseIn = State.FromObject(new MButtonViewModel())
            .SetName("mouseInside")
            .SetProperty(x => x.HoverBackgroundOpacity, 0.2)
            .ToState();

        public StateVector<MButtonViewModel> ConditionA { get; set; } = StateVector<MButtonViewModel>.Create()
            .AddCondition(x => x.IsMouseInside, MouseIn, (x) => { x.Duration = 0.2; })
            .AddCondition(x => !x.IsMouseInside, Start, (x) => { x.Duration = 0.2; });

        public override bool IsMouseInside
        {
            get => base.IsMouseInside;
            set
            {
                base.IsMouseInside = value;
  
                OnConditionsChecked();
                //鼠标进出控件时修改IsMouseInside
                //IsMouseInside被修改时检查是否满足条件,若满足,则切换State
            }
        }
    }

 这里使得控件的背景板的透明度绑定为ViewModel内定义的HoverBackgroundOpacity属性, 随后你便可以设置两个State记录控件ViewModel在鼠标悬停和非悬停下的状态值,接着用一个StateVector定义【在ViewModel满足何种条件时,自动过渡至哪个Sate】的对照关系,于是该控件已经可以自动加载悬停/非悬停动画了!这就和Unity的Animator有些使用方式上的相似了。

(3)生命周期支持

依旧是像Unity那样,在状态机运行渐变效果时,你可通过设置如下委托丰富过程中的行为

Ⅱ实现原理:

1.反射

实现不需要已知起始值,只需要知道最终值,就可以从当前状态渐变至最终状态

2.★ 线性插值

对任何类型的指定属性做出平滑的修改, 那么视觉上的确是一个丝滑的动画

3.图形变换矩阵

Transform变换本质是从一个矩阵渐变至另一个矩阵

Ⅲ详细内容请参阅:

github

nuget

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值