代码
private void MoveCarWindow_OnLoaded(object sender, RoutedEventArgs e)
{
this.lastRenderingTime = TimeSpan.Zero;
// 订阅渲染事件, 在对象呈现到合成树之前即发生。
CompositionTarget.Rendering += this.CompositionTargetOnRendering;
}
private void CompositionTargetOnRendering(object? sender, EventArgs e)
{
if (e is RenderingEventArgs args)
{
var currentRenderingTime = args.RenderingTime;
var timeSpan = currentRenderingTime - this.lastRenderingTime;
this.lastRenderingTime = currentRenderingTime;
// 计算移动的向量
var vector = this.CalculateDirectionVector();
if (vector is { X: 0, Y: 0, } || double.IsNaN(vector.X) || double.IsNaN(vector.Y))
{
// 没有移动
return;
}
// 根据是否按 j 设置速度
double speed = Keyboard.IsKeyDown(Key.J) ? 400 : 200;
// 根据时间与速度计算出移动的距离
var moveVector = vector * (speed * timeSpan.TotalSeconds);
// 进行移动
this.MoveCar(this.CarRectangle, moveVector);
}
}
private Vector CalculateDirectionVector()
{
// 根据按下的按钮,计算出移动的向量
var vectorys = new List<Vector>();
if (Keyboard.IsKeyDown(Key.Up))
{
vectorys.Add(new Vector(0, 1));
}
if (Keyboard.IsKeyDown(Key.Down))
{
vectorys.Add(new Vector(0, -1));
}
if (Keyboard.IsKeyDown(Key.Left))
{
vectorys.Add(new Vector(-1, 0));
}
if (Keyboard.IsKeyDown(Key.Right))
{
vectorys.Add(new Vector(1, 0));
}
if (vectorys.Count == 0)
{
return new Vector(0, 0);
}
var sumVector = vectorys.Aggregate( new Vector(0, 0), (sum, it) => sum + it);
// 因为多个方向的向量累加,所以这里需要归一化,变长度为1
sumVector.Normalize();
return sumVector;
}
private void MoveCar(Rectangle car, Vector moveVector)
{
if (car.Parent is not FrameworkElement parent)
{
return;
}
var width = parent.ActualWidth;
var height = parent.ActualHeight;
var margin = this.CarRectangle.Margin;
// 因为 wpf 坐标与二维坐标系不同,需要做一下转换
margin.Left += moveVector.X;
margin.Top -= moveVector.Y;
// 限制只在窗口内移动
margin.Left = Math.Clamp(margin.Left, 0, width - car.ActualWidth);
margin.Top = Math.Clamp(margin.Top, 0, height - car.ActualHeight);
car.Margin = margin;
}