zoukankan      html  css  js  c++  java
  • win10 uwp 萤火虫效果

    本文在Nukepayload2指导下,使用他的思想用C#写出来。

    本文告诉大家,如何使用 win2d 做出萤火虫效果。

    安装 win2d

    安装win2d的方法请使用 Nuget 下载的方法,参见:win10 uwp win2d

    下面先让大家看一下效果图再告诉大家如何做

    创建界面

    界面只需要很简单两句代码,第一句代码是命名引用,第二句代码就是添加 win2d

        xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
    
            <canvas:CanvasAnimatedControl x:Name="canvas" ClearColor="Black" Update="Canvas_OnUpdate" Draw="Canvas_Draw"></canvas:CanvasAnimatedControl>
    

    这里为何使用 CanvasAnimatedControl 而不是使用 CanvasControl ?因为需要进行更新,CanvasAnimatedControl提供了一些事件,这些事件可以用来做动画。

    后台的方法

    Canvas_OnUpdate就写更新所有萤火虫的代码,在Canvas_Draw就写画出萤火虫的代码。

    萤火虫

    于是开始创建萤火虫的代码,在创建之前,需要一个随机的类,这个类用于控制萤火虫的呼吸和移动,都是随机的。

    在指定的范围之内,随机取一个点,这个点作为目的的点。于是当前的值就开始移动向目的的点,移动的过程存在速度。

    从这里可以知道,这个类需要下面这些属性

            public double Value { get; set; }
            public double To { get; set; }
            public double Dalue { get; set; }
    
            public double Ma { get; set; }
    
            public double Mi { get; set; }
    
            /// <summary>
            /// 加速度
            /// </summary>
            public double Po { get; set; }

    其中 Dalue 就是速度,从 Value 到 To 的速度,这个速度在随时可以被修改。

    下面是这个类全部代码

        class Ran
        {
            public Ran(double value, double ma, double mi)
            {
                Value = value;
                Ma = ma;
                Mi = mi;
                To = ran.NextDouble() * (Ma - Mi) + Mi;
            }
    
            public double Value { get; set; }
            public double To { get; set; }
            public double Dalue { get; set; }
    
            public double Ma { get; set; }
    
            public double Mi { get; set; }
    
            public bool EasingFunction { get; set; }
    
            /// <summary>
            /// 加速度
            /// </summary>
            public double Po { get; set; }
    
            public void Time(TimeSpan time)
            {
    
                if (Math.Abs(Dalue) < 0.000001)
                {
                    if (Math.Abs(Po) < 0.0001)
                    {
                        Dalue = Math.Abs(Value - To) / ran.Next(10, 300);
                    }
                    else
                    {
                        Dalue = Po;
                    }
                }
                //减数
                if (EasingFunction && Math.Abs(Value - To) < Dalue*10/*如果接近*/)
                {
                    Dalue /= 2;
                    if (Math.Abs(Dalue) < 1)
                    {
                        Dalue = 1;
                    }
                }
                int n = 1;
                if (Value > To)
                {
                    n = n * -1;
                }
                Value += n * Dalue * time.TotalSeconds * 2;
                if (n > 0 && Value >= To)
                {
                    Value = To;
                    To = ran.NextDouble() * (Ma - Mi) + Mi;
                    Dalue = 0;
                }
                if (n < 0 && Value <= To)
                {
                    Value = To;
                    To = ran.NextDouble() * (Ma - Mi) + Mi;
                    Dalue = 0;
                }
            }
    
    
            private static Random ran = new Random();
        }
    

    下面就是主要的类FireflyParticle包含了位置和颜色,不同透明度,当然不透明度可以做呼吸效果,于是这些值都需要做随机移动

        class FireflyParticle
        {
            public FireflyParticle(Rect bound)
            {
                Point = new Point(ran.Next((int) bound.Width), ran.Next((int) bound.Height));
                _x = new Ran(Point.X, bound.Width, 0)
                {
                    EasingFunction = true,
                };
                _y = new Ran(Point.Y, bound.Height, 0)
                {
                    EasingFunction = true,
                };
                _radius = new Ran(ran.Next(2, 5), 5, 2)
                {
                    Po = 0.71
                };
                Bound = bound;
            }
    
            public FireflyParticle()
            {
            }
    
            public void Time(TimeSpan time)
            {
                _radius.Time(time);
                _opColor.Time(time);
                _x.Time(time);
                _y.Time(time);
    
                Radius = _radius.Value;
                OpColor = _opColor.Value;
                Point = new Point(_x.Value, _y.Value);
            }
    
            public Point Point { get; set; }
    
            public Rect Bound
            {
                get { return _bound; }
                set
                {
                    _bound = value;
                    _x.Ma = value.Width;
                    _y.Ma = value.Height;
                }
            }
    
            public double Radius { get; set; } = 10;
            public Color CenterColor { get; set; } = Color.FromArgb(255, 252, 203, 89);
            public double OpColor { set; get; } = 1;
            private static Random ran = new Random();
    
            private Ran _radius;
            private Ran _opColor = new Ran(1, 1, 0.001);
    
            private Ran _x;
            private Ran _y;
            private Rect _bound;
        }
    

    看到这,是不是觉得参数存在 time 无法理解?这里的使用 time 是为了在性能比较差的电脑得到效果和性能比较好的一样,虽然中途有一些没有显示的,但是计算结果相同,不会出现性能差的电脑,动画速度和性能好的电脑不一样。

    动画

    下面就是更新所有的值,创建属性FireflyParticle用于放所有的类,因为很简单,我就不解释。

            private List<FireflyParticle> FireflyParticle { set; get; } = new List<FireflyParticle>();
    
            private void BpyaxxjwkQwknemobzPage_Loaded(object sender, RoutedEventArgs e)
            {
                if (!FireflyParticle.Any())
                {
                    Rect bound = new Rect(0, 0, canvas.ActualWidth, canvas.ActualHeight);
                    for (int i = 0; i < 100; i++)
                    {
                        FireflyParticle.Add(new FireflyParticle(bound));
                    }
                }
            }
    
             private void Canvas_OnUpdate(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs args)
            {
                foreach (var temp in FireflyParticle)
                {
                    temp.Time(args.Timing.ElapsedTime);
                }
            }
    

    把所有的值都进行变化,就是在做动画,但是移动距离不能太长,移动的算法在上面的随机类写的,算法很简单,也不是关键,于是在这里就不说了。

    核心代码

    这里的核心就是画出来,如何在 win2d 画出一个点,把这个点高斯模糊。不知道大家知道 PhotoShop ,这里用到了图层,需要自己心中知道是什么东西。现在的图片一般都是很多个图片合成,于是可以把一个点作为一个图层,到时候把这些点合并就是上面给大家看到的图。

    如何在 win2d 使用图层,主要的类是CanvasCommandList用它就可以做出图层,最好使用DrawImage把他弄出来。

          private void Canvas_Draw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
            {
                using (var session = args.DrawingSession)
                {
                     using (var cl = new CanvasCommandList(session))
                     using (var ds = cl.CreateDrawingSession())
                     {
                        //这里就是图层
                        // session.DrawImage(cl); 把 图层画出来
    
                     }
                }
            }

    如何对图层做模糊?在win2d有很多效果,先尝试把点画出来,效果图:

    需要知道所有的效果都是可以直接画出来,我用的方法很简单,就直接写代码

       class GlowEffectGraph : IDisposable
        {
            private MorphologyEffect morphology;
            public GlowEffectGraph()
            {
                Blur.BlurAmount = 10;
                Blur.BorderMode = EffectBorderMode.Soft;
    
                morphology = new MorphologyEffect()
                {
                    Mode = MorphologyEffectMode.Dilate,
                    Width = 10,
                    Height = 10,
                };
    
                Blur.Source = morphology;
    
            }
    
            public GaussianBlurEffect Blur { get; set; } = new GaussianBlurEffect();
    
            public void Dispose()
            {
                Blur.Dispose();
                morphology.Dispose();
            }
    
            public void Setup(ICanvasImage canvas, double amount = 10)
            {
                morphology.Source = canvas;
                amount = Math.Min(amount / 2, 100);
                morphology.Width = (int) Math.Truncate(Math.Floor(amount));
                morphology.Height = (int) Math.Truncate(Math.Floor(amount));
                Blur.BlurAmount = (float) amount;
            }
        }

    如何要把图层画出来,那么修改Canvas_Draw的代码

         private void Canvas_Draw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
            {
                using (var session = args.DrawingSession)
                {
                    foreach (var temp in FireflyParticle)
                    {
                        using (var cl = new CanvasCommandList(session))
                        using (var ds = cl.CreateDrawingSession())
                        {
                            var c = temp.CenterColor;
                            c.A = (byte) (temp.OpColor * 255);
                            ds.FillCircle((float) temp.Point.X, (float) temp.Point.Y, (float) temp.Radius, c);
                            using (var glow = new GlowEffectGraph())
                            {
                                glow.Setup(cl, temp.Radius);
                                session.DrawImage(glow.Blur);
                            }
                        }
                    }
                }
            }

    这个效果我放在 商业游戏 可以玩一下,代码开源https://github.com/lindexi/UWP/tree/master/uwp/src/VarietyHiggstGushed

    参见:使用win2d实现萤火虫粒子效果 - Nukepayload2 - 博客园

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

  • 相关阅读:
    分布式缓存
    分布式事务
    数据库系列-分库分表
    消息队列系列-简介
    JAVA系列-引用
    生产环境CPU占用过高分析
    技术书单(部分)
    GitHub的强大搜索功能简介
    VS2019 community版本下载Extension太慢解决方案
    Python2同时输出中文和变量时中文乱码
  • 原文地址:https://www.cnblogs.com/lindexi/p/12087311.html
Copyright © 2011-2022 走看看