Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从a";一小撮;情节串连板/动画?_C#_Wpf_Animation - Fatal编程技术网

C# 从a";一小撮;情节串连板/动画?

C# 从a";一小撮;情节串连板/动画?,c#,wpf,animation,C#,Wpf,Animation,简介: 所以我建立的是一个弹丸运动模拟器,在给定初始速度和角度的情况下,每次点击“开火”按钮,就会产生一个新的子弹,并通过MatrixAnimationUsingPath沿计算路径设置动画。路径只计算一次,并用于所有投射物 问题: 我遇到的问题是,在我遇到应用程序性能问题之前,可以设置动画的投射物的数量(例如:30)似乎相对较低,并且根据初始速度或角度的不同而变化很大。当问题发生时,“发射”按钮的响应速度会大大减慢,而且抛射物似乎在排队,并以突发方式发射,而不是在单击按钮时发射 我解决问题的尝试

简介:

所以我建立的是一个弹丸运动模拟器,在给定初始速度和角度的情况下,每次点击“开火”按钮,就会产生一个新的子弹,并通过MatrixAnimationUsingPath沿计算路径设置动画。路径只计算一次,并用于所有投射物

问题:

我遇到的问题是,在我遇到应用程序性能问题之前,可以设置动画的投射物的数量(例如:30)似乎相对较低,并且根据初始速度或角度的不同而变化很大。当问题发生时,“发射”按钮的响应速度会大大减慢,而且抛射物似乎在排队,并以突发方式发射,而不是在单击按钮时发射

我解决问题的尝试:

  • 最初,当我第一次编写它时,每次单击按钮时都会计算每个项目符号的路径,所以我起初认为这可能是问题所在。如果初始值相同,我重写它以重用相同的路径。这并没有解决问题
  • 然后我想也许我可以把制作子弹动画的责任交给另一条线。就在那时,在我的研究中,我了解了使用线程关联的困难,但还是尝试了一下。我给每个新线程一个要执行的方法,这就是其中的内容:
    this.Dispatcher.Invoke((操作)(()=>{/*用于创建和启动动画的代码*/}))它在创建子弹和设置子弹动画方面效果很好,但它并没有解决甚至改进主要问题。也许这不是正确的做法
  • 最近,我尝试降低帧速率,这很有帮助,但只是稍微降低了一点
问题:

还有什么其他的选择,或者我应该使用另一种方法来处理线程,或者它只是我正在使用的矩阵动画的性质,我应该考虑使用另一种类型的动画吗? 我注意到的一个可能的关联是,弹丸需要覆盖的初始速度或距离越大,将减少平滑动画子弹的数量,或相反地增加该数量(例如,速度越慢或覆盖的水平距离越小,则会增加数量)

我已经在我的笔记本电脑和高端桌面上运行了这个应用程序,并得到了类似的结果

下面我有一段主要的代码,负责创建一个新的项目符号,然后在没有多线程的情况下为它设置动画。我本来会在解释中加入截图,但我目前无法这样做

我提前感谢您的所有贡献

以下是一个指向压缩演示项目的下拉框链接以及屏幕截图:

公共部分类主窗口:窗口
{
弹丸;
项目运动项目;
私有void spawnAndFireBullet()
{
//创建新子弹:速度、初始角度、伤害
子弹=新射弹(100,45,0);
bullet.Template=资源[“BulletTemplate”]作为ControlTemplate;
canvas.Children.Add(项目符号);
//将子弹放在起始位置。
Canvas.SetLeft(bullet,50);
Canvas.SetTop(bullet,Canvas.ActualHeight-10);
项目移动动画项目(项目符号,主窗口);
}
}
公共类项目运动
{
情节提要路径动画情节提要;
使用路径投影的矩阵化;
矩阵变换;射影矩阵变换;
ProjectleMotion pMotion=新的ProjectleMotion();
公共虚空动画投射物(投射物投射物、窗口)
{
SetNameScope(窗口,newnamescope());
ProjectleMatrixTransform=新矩阵变换();
射弹.RenderTransform=射弹矩阵变换;
注册表名(“ProjectleTransform”,ProjectleMatrixTransform);
ProjectLeanimation=使用路径()的新矩阵animation;
ProjectLeanImation.PathGeometry=pMotion.GetProjectlePath(射弹);//获取射弹的路径。
ProjectLeanImation.Duration=TimeSpan.FromSeconds(pMotion.flightTime);
ProjectLeanImation.DoesRotateWithTangent=true;
Storyboard.SetTargetName(ProjectLeanImation,“ProjectletTransform”);
Storyboard.SetTargetProperty(ProjectLeanImation,新属性路径(MatrixTransform.MatrixProperty));
pathAnimationStoryboard=新故事板();
pathAnimationStoryboard.Children.Add(ProjectLeanImation);
pathAnimationStoryboard.Begin(窗口);
}
}
类投射运动
{
//轨迹变量。
公共双trajRange=0.0,trajHeight=0.0,trajTime=0.0;
私人双重力=9.81;//m/s^2
专用双速=0.0;//m/s
专用双角度=0.0;//以弧度为单位
专用双余弦、正割、正切;
私人双德尔泰,德尔泰;
私有双x_分量、y_分量;
私人双t_最大高度;
专用双启动,启动y,当前x,当前y;
私人双前向角度=0.0,前向速度=0.0;
private PathGeometry ProjectlePath,PreviousProjectlePath;//对象/投射的实际路径。
私有路径图pFigure;//ProjectlePath由pFigure组成。
专用多段线段多段线;//多段线由点组成。
私有点集合点;//点由路径中所有点的列表组成
/// 
///返回给定初始速度、初始角度和起点的投射物将采用的路径。
///以度为单位传递角度。
/// 
/// 
/// 
/// 
/// 
/// 
公共路径几何图形GetProjectlePath(UIElement投射、双级别、双ang、System.Windows.Point起始点)
{
//计算th
public partial class MainWindow : Window
{
    Projectile bullet;
    ProjectilePathMovement projMove;


    private void spawnAndFireBullet()
    {
        // Create new bullet with: Velocity, Initial Angle, Damage
        bullet = new Projectile(100, 45, 0);
        bullet.Template = Resources["BulletTemplate"] as ControlTemplate;

        canvas.Children.Add(bullet);

        // Position the bullet at it's starting location.
        Canvas.SetLeft(bullet, 50);
        Canvas.SetTop(bullet, canvas.ActualHeight - 10);

        projMove.animateProjectile(bullet, mainWindow);
    }
}



public class ProjectilePathMovement
{
    Storyboard pathAnimationStoryboard;
    MatrixAnimationUsingPath projectileAnimation;
    MatrixTransform projectileMatrixTransform;
    ProjectileMotion pMotion = new ProjectileMotion();

    public void animateProjectile(Projectile projectile, Window window)
    {
        NameScope.SetNameScope(window, new NameScope());

        projectileMatrixTransform = new MatrixTransform();
        projectile.RenderTransform = projectileMatrixTransform;

        window.RegisterName("ProjectileTransform", projectileMatrixTransform);

        projectileAnimation = new MatrixAnimationUsingPath();
        projectileAnimation.PathGeometry = pMotion.getProjectilePath(projectile); // Get the path of the projectile.
        projectileAnimation.Duration = TimeSpan.FromSeconds(pMotion.flightTime);

        projectileAnimation.DoesRotateWithTangent = true;

        Storyboard.SetTargetName(projectileAnimation, "ProjectileTransform");
        Storyboard.SetTargetProperty(projectileAnimation, new PropertyPath(MatrixTransform.MatrixProperty));

        pathAnimationStoryboard = new Storyboard();

        pathAnimationStoryboard.Children.Add(projectileAnimation);

        pathAnimationStoryboard.Begin(window);
    }
}

class ProjectileMotion
{
    // Trajectory variables.
    public double trajRange = 0.0, trajHeight = 0.0, trajTime = 0.0;

    private double gravity = 9.81; // m/s^2
    private double velocity = 0.0; // m/s
    private double angle = 0.0; // In radians
    private double cosine, secant, tangent;
    private double deltaX, deltaY;
    private double x_component, y_component;
    private double t_maxHeight;
    private double start_x, start_y, current_x, current_y;
    private double previousAngle = 0.0, previousVelocity = 0.0;

    private PathGeometry projectilePath, previousProjectilePath; // The actual path of the object/projectile.
    private PathFigure pFigure; // projectilePath is comprised of pFigure.
    private PolyLineSegment polyLine; // polyLine is comprised of points.
    private PointCollection points; // points is comprised of a list of all points in the path 


    /// <summary>
    /// Returns the path the projectile would take given its initial velocity, initial angle, and starting point.
    /// Pass the angle in Degrees.
    /// </summary>
    /// <param name="projectile"></param>
    /// <param name="vel"></param>
    /// <param name="ang"></param>
    /// <param name="startPoint"></param>
    /// <returns></returns>
    public PathGeometry getProjectilePath(UIElement projectile, double vel, double ang, System.Windows.Point startPoint)
    {
        // Calculate the necessary values.
        calculateValues(projectile, ang, vel);

        // Derive the object's/projectile's path.
        return deriveProjectilePath(startPoint);
    }

    public double getGravity()
    {
        return gravity;
    }

    private void calculateValues(UIElement projectile, double ang, double vel)
    {
        // Convert the angle from Degrees to Radians.
        angle = ang * (Math.PI / 180);

        velocity = vel;

        cosine = Math.Cos(angle);
        secant = 1 / cosine;
        tangent = Math.Tan(angle);

        deltaX = Math.Cos(angle);
        deltaY = Math.Sin(angle);

        // Get current coordinates.
        start_x = Canvas.GetLeft(projectile);
        start_y = Canvas.GetTop(projectile);
        current_y = start_y;
        current_x = start_x;

        // Calculate the horizontal and vertical components of initial velocity. 
        // Xvo = Vo * Cos(angle)
        // Yvo = Vo * Sin(angle)
        x_component = velocity * Math.Cos(angle);
        y_component = velocity * Math.Sin(angle);

        // Calculate time to reach max height.  t max = Vyo / 9.8
        t_maxHeight = y_component / gravity;

        // Calculate max height of projectile. h = Yo + Vyo·t - 0.5·g·t^2
        trajHeight = 0 + (y_component * t_maxHeight) - (.5 * gravity * t_maxHeight * t_maxHeight);

        //Calulate max range of projectile.
        trajRange = (2 * (velocity * velocity) * Math.Sin(angle) * Math.Cos(angle)) / gravity;

        // Calculate flight time.
        trajTime = 2 * t_maxHeight;
    }

    private PathGeometry deriveProjectilePath(System.Windows.Point pt)
    {
        projectilePath = new PathGeometry();
        pFigure = new PathFigure();

        start_x = pt.X;
        start_y = pt.Y;
        current_y = start_y;

        pFigure.StartPoint = pt;

        polyLine = new PolyLineSegment();

        points = new PointCollection();

        // Checks if the angle and velocity for this projectile is the same as last time.  If it is the same there is no need to recalculate the path of the projectile, just use the same one from before.
        if (previousAngle != angle && previousVelocity != velocity)
        {
            // Loop to obtain every point in the trajectory's path.
            for (current_x = start_x; current_x <= trajRange; current_x++)
            {
                current_y = start_y - current_x * tangent + ((gravity * current_x * current_x) / (2 * (velocity * velocity * cosine * cosine)));  //  Y = Yo + X*tan - ( (g*X^2) / 2(v*cos)^2 )      Trajectory Formula to find the 'y' value  at a given 'x' value.

                points.Add(new System.Windows.Point(current_x, current_y));
            }

            // If the last x-coordinate value exceeds the actual range of projectile set x = to actual range to 
            // obtain actual y-coordinate value for final trajectory point.
            if (current_x > trajRange)
            {
                current_x = trajRange;

                current_y = start_y - current_x * tangent + ((gravity * current_x * current_x) / (2 * (velocity * velocity * cosine * cosine)));  //  Y = Yo + X*tan - ( (g*X^2) / 2(v*cos)^2 )      Trajectory Formula to find the 'y' coord given an 'x' value.

                points.Add(new System.Windows.Point(current_x, current_y));
            }

            polyLine.Points = points;
            pFigure.Segments.Add(polyLine);
            projectilePath.Figures.Add(pFigure);
        }
        else
        {
            projectilePath = previousProjectilePath;
        }

        // Freeze the PathGeometry for performance benefits?
        projectilePath.Freeze();

        previousVelocity = velocity;
        previousAngle = angle;
        previousProjectilePath = projectilePath;

        return projectilePath;
    }
}
        Queue<FireBulletDelegate> bulletQueue = new Queue<FireBulletDelegate>();
        delegate void FireBulletDelegate();

        DispatcherTimer bulletQueueChecker;
        const int threshold = 100;

        private void fireButton_Click(object sender, RoutedEventArgs e)
        {
            if (bulletQueue.Count > threshold) return;

            FireBulletDelegate d = new FireBulletDelegate(spawnAndFireBullet);
            bulletQueue.Enqueue(d);

            if (bulletQueueChecker == null)
            {
                bulletQueueChecker = new DispatcherTimer(
                                TimeSpan.FromSeconds(0.2),
                                DispatcherPriority.Render,
                                (s1, e1) =>
                                {
                                    if (bulletQueue.Count > 0)
                                        (bulletQueue.Dequeue())();
                                    //spawnAndFireBullet();
                                },
                                fireButton.Dispatcher);
            }
            else if (!bulletQueueChecker.IsEnabled)
            {
                bulletQueueChecker.Start();
            }
        }