wpf 向量计算

xaml

    <Grid>

        <!--  坦克图片,RenderTransformOrigin 设置中心点为 .5 .5  -->
        <Rectangle
            x:Name="TankRectangle"
            Width="240" Height="120"
            RenderTransformOrigin=".5 .5">
            <Rectangle.Fill>
                <ImageBrush ImageSource="/Resource/Images/tank.png" />
            </Rectangle.Fill>
            <Rectangle.Effect>
                <DropShadowEffect BlurRadius="10" />
            </Rectangle.Effect>

            <Rectangle.LayoutTransform>
                <!--  设置旋转角度,在代码中即时计算  -->
                <RotateTransform x:Name="RotateTransform" Angle="0" />
            </Rectangle.LayoutTransform>
        </Rectangle>

    </Grid>

代码


    private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
    {
        try
        {
            var tank = this.TankRectangle;

            // 以坦克中点为中心 , 可以画下草图
            var tankPoint = tank.TranslatePoint(new Point(tank.ActualWidth / 2, tank.ActualHeight / 2), this);
            var mousePoint = e.GetPosition(this);

            // 因为我的坦克图片头指向 -100, 0 (以坦克中心为向量) 
            var a = new Vector(-100, 0);
            // 这是鼠标对应的向量(以坦克中心为向量)
            var b = new Vector(mousePoint.X - tankPoint.X, mousePoint.Y - tankPoint.Y);

            // 计算两个向量之间的夹角
            var angle = CalculateAngle(a, b);

            // 设置旋转角度
            this.RotateTransform.Angle = angle;

            Console.WriteLine(this.RotateTransform.Angle);
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
        }

    }

    // ai 给我的计算法
    private static double CalculateAngle(Vector a, Vector b)
    {
        // 计算点积和叉积
        double dotProduct = a.X * b.X + a.Y * b.Y;
        double crossProduct = a.X * b.Y - a.Y * b.X;

        // 计算向量模长
        double aMagnitude = a.Length;
        double bMagnitude = b.Length;

        if (aMagnitude == 0 || bMagnitude == 0)
            return 0; // 处理零向量

        // 计算夹角的余弦值并确保在有效范围
        double cosTheta = dotProduct / (aMagnitude * bMagnitude);
        cosTheta = Math.Clamp(cosTheta, -1.0, 1.0);

        // 转换为角度
        double angle = Math.Acos(cosTheta) * (180 / Math.PI);

        // 根据叉积调整到0-360度范围
        if (crossProduct < 0)
            angle = 360 - angle;

        return angle;
    }

发射子弹


    <Window.Resources>
        <ControlTemplate x:Key="BulletControlTemplate">
            <Border
                x:Name="BulletBorder"
                HorizontalAlignment="Center" VerticalAlignment="Center"
                RenderTransformOrigin=".5 .5">
                <Border.RenderTransform>
                    <TransformGroup>
                        <!--  X="-135" Y="8" 是坦克炮口位置  -->
                        <TranslateTransform x:Name="BulletTranslateTransform" X="-135" Y="8" />
                        <!--  跟随坦克旋转  -->
                        <RotateTransform x:Name="BulletRotateTransform" Angle="30" />
                    </TransformGroup>
                </Border.RenderTransform>

                <Rectangle
                    Width="30" Height="40"
                    HorizontalAlignment="Center" VerticalAlignment="Center"
                    RenderTransformOrigin=".5 .5">

                    <Rectangle.Fill>
                        <ImageBrush ImageSource="/Resource/Images/bulletII.png" />
                    </Rectangle.Fill>
                    <Rectangle.LayoutTransform>
                        <!--  调整子弹初始的方向  -->
                        <RotateTransform Angle="-90" />
                    </Rectangle.LayoutTransform>
                </Rectangle>

            </Border>
        </ControlTemplate>
    </Window.Resources>

    private void UIElement_OnKeyUp(object sender, KeyEventArgs e)
    {
        // 发射子弹
        if (e.Key != Key.Space || this.FindResource("BulletControlTemplate") is not ControlTemplate bulletTemplate)
        {
            return;
        }

        var control = new ContentControl
        {
            Template = bulletTemplate,
        };

        var rootGrid = this.RootGrid;

        rootGrid.Children.Add(control);

        // 应用一下模板,不然模板不会立即生效
        control.ApplyTemplate();

        if (control.Template.FindName("BulletRotateTransform", control) is not RotateTransform rotateTransform ||
            control.Template.FindName("BulletTranslateTransform", control) is not TranslateTransform translateTransform)
        {
            return;
        }

        // 子弹与坦克旋转角度相同
        rotateTransform.Angle = this.RotateTransform.Angle;

        var animation = new DoubleAnimation
        {
            To = -1500,
            Duration = TimeSpan.FromSeconds(1.5),
            EasingFunction = new ExponentialEase { Exponent = 3, EasingMode = EasingMode.EaseOut, },
        };

        // 动画完成后,回收子弹 
        animation.Completed += (_, _) => rootGrid.Children.Remove(control);

        translateTransform.BeginAnimation(TranslateTransform.XProperty, animation);
    }
上一篇
下一篇