Farseer Physics中碰撞对象之间的偏移

时间:2013-03-28 22:07:59

标签: c# wpf collision-detection offset farseer

我正在玩Farseer Physics engine和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);
        }
    }
}

如下图所示,结果不符合我的预期:所有球和世界边界之间存在偏移

Test

  • 我尽力使用ConvertUnits帮助程序正确处理Farseer世界单位和显示单位。
  • 我还读到了一些关于“皮肤”的东西,它围绕着所有的身体,以避免连续的碰撞,但我没想到它会那么大。
  • 我注意到UIElement的X / Y值是UIElement的左上角。

有什么特别的事我忘记了吗?

我知道我可以通过玩椭圆的显示半径来作弊,但我更愿意理解我在处理世界单位和显示单位时所犯的错误。

1 个答案:

答案 0 :(得分:1)

好的,我找到了。问题很简单:

  • Ellipse WPF元素使用 Width Height 来定义对象大小,即 Diameter
  • CreateCircle使用 Radius

所以球体的正确分配是:

var ball = BodyFactory.CreateCircle(world, ConvertUnits.ToSimUnits(w / 2), 1);