FrameBasedAnimation.axaml代码

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Height="396" Width="463.2"
        x:Class="AvaloniaUI.FrameBasedAnimation"
        Title="FrameBasedAnimation">
    <Grid Margin="3" RowDefinitions="auto,*">
        <StackPanel Orientation="Horizontal">
            <Button Margin="3" Padding="3" Click="cmdStart_Clicked">Start</Button>
            <Button Margin="3" Padding="3" Click="cmdStop_Clicked">Stop</Button>
        </StackPanel>
        <Canvas Name="canvas" Grid.Row="1" Margin="3"></Canvas>
    </Grid>
</Window>

FrameBasedAnimation.axaml.cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Shares.Avalonia;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AvaloniaUI;
public class EllipseInfo
{
    public Ellipse Ellipse { get; set; }
    public double VelocityY { get; set; }
    public bool HasStopped { get; set; }  // 当前是否停止
    public int BouncesRemaining { get; set; }  // 剩余弹跳次数
    public double MaxBounceSpeed { get; set; } // 最大反弹初速度

    public EllipseInfo(Ellipse ellipse, double velocityY, int bounces, double bounceSpeed)
    {
        Ellipse = ellipse;
        VelocityY = velocityY;
        HasStopped = false;
        BouncesRemaining = bounces;
        MaxBounceSpeed = bounceSpeed;
    }
}
public partial class FrameBasedAnimation : Window
{
    private readonly AnimationPlayer player = new AnimationPlayer();
    private readonly List<EllipseInfo> ellipses = new();
    private readonly Random rand = new Random();

    private double accelerationY = 0.1;
    private int minStartingSpeed = 1;
    private int maxStartingSpeed = 50;
    private double speedRatio = 0.1;
    private int minEllipses = 20;
    private int maxEllipses = 100;
    private int ellipseRadius = 10;

    public FrameBasedAnimation()
    {
        InitializeComponent();

        player.Duration = 8;       // 整个动画总时间(秒),自动清屏
        player.At(0)
           .PlayGlobal(progress =>
           {
               if (ellipses.Count == 0)
               {
                   player.Stop();
                   return;
               }

               double bottomLimit = canvas.Bounds.Height - ellipseRadius * 2 - 10;

               foreach (var info in ellipses)
               {
                   double top = Canvas.GetTop(info.Ellipse);

                   // 弹跳逻辑
                   if (info.HasStopped)
                   {
                       if (info.BouncesRemaining > 0 && top >= bottomLimit)
                       {
                           // 随机弹起
                           info.VelocityY = -rand.NextDouble() * info.MaxBounceSpeed;
                           info.BouncesRemaining--;
                           info.HasStopped = false; // 重新开始运动
                       }
                       else
                       {
                           Canvas.SetTop(info.Ellipse, bottomLimit);
                           info.VelocityY = 0;
                           continue;
                       }
                   }

                   double newTop = top + info.VelocityY;
                   info.VelocityY += accelerationY;

                   if (newTop >= bottomLimit)
                   {
                       Canvas.SetTop(info.Ellipse, bottomLimit);
                       info.HasStopped = true;
                   }
                   else
                   {
                       Canvas.SetTop(info.Ellipse, newTop);
                   }
               }
           });
        player.AnimationCompleted += () =>
        {
            ellipses.Clear();
            canvas.Children.Clear();
        };
    }

    private void cmdStart_Clicked(object? sender, RoutedEventArgs e)
    {
        ellipses.Clear();
        canvas.Children.Clear();

        int halfCanvasWidth = (int)canvas.Bounds.Width / 2;
        int ellipseCount = rand.Next(minEllipses, maxEllipses + 1);

        for (int i = 0; i < ellipseCount; i++)
        {
            var ellipse = new Ellipse
            {
                Fill = Brushes.LimeGreen,
                Width = ellipseRadius,
                Height = ellipseRadius
            };
            Canvas.SetLeft(ellipse, halfCanvasWidth + rand.Next(-halfCanvasWidth, halfCanvasWidth));
            Canvas.SetTop(ellipse, 0);
            canvas.Children.Add(ellipse);

            var info = new EllipseInfo(
                ellipse,
                speedRatio * rand.Next(minStartingSpeed, maxStartingSpeed),
                rand.Next(0, 3), // 随机弹跳次数 0~2
                rand.Next(1,4) //随机反弹速度1~3
            );
            ellipses.Add(info);
        }

        player.Start();
    }

    private void cmdStop_Clicked(object? sender, RoutedEventArgs e)
    {
        player.Stop();
        ellipses.Clear();
        canvas.Children.Clear();
    }
}

运行效果

image

 

posted on 2025-10-18 09:23  dalgleish  阅读(1)  评论(0)    收藏  举报