Смещение между сталкивающимися объектами в Farseer Physics
Я играю с движком 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);
}
}
}
Как показано на рисунке ниже, результат не тот, который я ожидаю: между всеми шарами и границами мира есть смещение.
- Я изо всех сил старался правильно обрабатывать юниты мира Farseer и отображать юниты, используя
ConvertUnits
помощник. - Я также читал кое-что о "коже", которая охватывает все тела, чтобы избежать непрерывных столкновений, но я не ожидал, что она будет такой большой.
- Я позаботился о том, чтобы значение X/Y элемента UIElement находилось в верхнем / левом углу элемента UIElement.
Есть что-то особенное, что я забыл?
Я знаю, что мог бы обмануть, играя с радиусом отображения Эллипса, но я бы предпочел понять, что я делаю неправильно, когда я обращаюсь с мировыми единицами и единицами отображения.
1 ответ
Решение
Хорошо, я нашел это. Проблема была проста:
- Элемент Ellipse WPF использует ширину и высоту, чтобы определить размер объекта, то есть диаметр
- CreateCircle использует Radius
Таким образом, правильное назначение для тела шара:
var ball = BodyFactory.CreateCircle(world, ConvertUnits.ToSimUnits(w / 2), 1);