我正在玩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);
}
}
}
如下图所示,结果不符合我的预期:所有球和世界边界之间存在偏移。
ConvertUnits
帮助程序正确处理Farseer世界单位和显示单位。有什么特别的事我忘记了吗?
我知道我可以通过玩椭圆的显示半径来作弊,但我更愿意理解我在处理世界单位和显示单位时所犯的错误。
答案 0 :(得分:1)
好的,我找到了。问题很简单:
所以球体的正确分配是:
var ball = BodyFactory.CreateCircle(world, ConvertUnits.ToSimUnits(w / 2), 1);