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);
}