我正在使用Farseer Physics 引擎和 WPF。
现在,我设法使用以下代码创建了一个带有落球的窗口:
XAML:
<Window x:Class="test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" MouseDown="Window_MouseDown_1">
<Canvas
HorizontalAlignment="Center"
VerticalAlignment="Center"
x:Name="root"
RenderTransform="1 0 0 -1 0 0">
</Canvas>
</Window>
后面的代码:
using FarseerPhysics;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace test
{
public partial class MainWindow : Window
{
World world;
public MainWindow()
{
InitializeComponent();
world = new World(new Vector2(0, -9.81f));
var polygon = new Polygon() { Fill = Brushes.Gray };
foreach (var pt in border)
polygon.Points.Add(pt);
root.Children.Add(polygon);
var vertices = new Vertices();
foreach (var pt in border)
vertices.Add(ConvertUnits.ToSimUnits(pt.X, pt.Y));
var body = BodyFactory.CreateChainShape(world, vertices);
body.BodyType = BodyType.Static;
body.CollisionCategories = Category.All;
body.CollidesWith = Category.All;
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
Point[] border = new[]
{
new Point(200, -200),
new Point(200, 200),
new Point(-200, 200),
new Point(-200, -200),
new Point(200, -200)
};
Dictionary<Body, UIElement> balls = new Dictionary<Body, UIElement>();
void CompositionTarget_Rendering(object sender, EventArgs e)
{
world.Step(1/60f);
foreach (var ball in balls.Keys)
display(ball);
}
void display(Body ball)
{
var element = balls[ball];
Canvas.SetLeft(element, ConvertUnits.ToDisplayUnits(ball.Position.X));
Canvas.SetTop(element, ConvertUnits.ToDisplayUnits(ball.Position.Y));
}
private void Window_MouseDown_1(object sender, MouseButtonEventArgs e)
{
var w = 20f;
var point = e.GetPosition(root);
var ball = BodyFactory.CreateCircle(world, ConvertUnits.ToSimUnits(w), 1);
ball.BodyType = BodyType.Dynamic;
ball.Position = ConvertUnits.ToSimUnits(new Vector2((float)point.X, (float)point.Y));
ball.CollisionCategories = Category.All;
ball.CollidesWith = Category.All;
ball.Restitution = .5f;
var c = new Canvas();
var ellipse = new Ellipse() { Width = w, Height = w, Fill = Brushes.Yellow };
c.Children.Add(ellipse);
Canvas.SetLeft(ellipse, -w / 2);
Canvas.SetTop(ellipse, -w / 2);
Canvas.SetZIndex(c, 10);
root.Children.Add(c);
balls.Add(ball, c);
display(ball);
}
}
}
如下图所示,结果不是我所期望的:所有球加在一起和世界边界之间有一个偏移量。
- 我尽力使用
ConvertUnits
助手正确处理 Farseer 世界单位和显示单位。 - 我还读过一些关于包围所有身体以避免连续碰撞的“皮肤”,但我没想到它会那么大。
- 我注意到 UIElement 的 X/Y 值是 UIElement 的上/左角这一事实。
有什么特别的我忘记了吗?
我知道我可以通过玩椭圆的显示半径来作弊,但我更愿意了解我在处理世界单位和显示单位的方式上做错了什么。