codingben / box2d-netstandard Goto Github PK
View Code? Open in Web Editor NEWC# port of Box2D - Erin Catto's 2D Physics Engine
Home Page: https://box2d.org
License: MIT License
C# port of Box2D - Erin Catto's 2D Physics Engine
Home Page: https://box2d.org
License: MIT License
Difficult to describe, but polygons sometimes pass through edges that are not straight.
I'm having an issue with the ContactListener.
I added a simple ContactListener to the RubeGoldbergWorld in the samples, and I'm having trouble identifying the two Fixture objects involved in the Contact, and their parent Body objects.
I turned this line:
world = RubeGoldbergWorld.CreateWorld(out Body[] bodies, out Joint[] joints);
into these two lines:
world = RubeGoldbergWorld.CreateWorld(out Body[] bodies, out Joint[] joints);
world.SetContactListener(new TestContactListener());
And I added the following class:
public class TestContactListener : ContactListener
{
public override void BeginContact(in Contact contact)
{
Fixture fixtureA = contact.GetFixtureA();
Fixture fixtureB = contact.GetFixtureB();
Body bodyA = fixtureA.GetBody();
Body bodyB = fixtureB.GetBody();
if (bodyA == null || bodyB == null)
{
File.AppendAllText(@"C:\Users\username\Desktop\nothing.txt", "just making sure this function does something so it is not optimized out");
}
}
public override void EndContact(in Contact contact)
{
}
public override void PostSolve(in Contact contact, in ContactImpulse impulse)
{
}
public override void PreSolve(in Contact contact, in Manifold oldManifold)
{
}
}
Setting a breakpoint on the if
statement and inspecting the objects above it indicates problems:
All four of the functions in the ContactListener behave the same way. What am I doing wrong?
I'm trying to use a FrictionJointDef, but when I try to create one, I get:
System.Runtime.CompilerServices.SwitchExpressionException: 'Non-exhaustive switch expression failed to match its input.
Unmatched value was Box2D.NetStandard.Dynamics.Joints.Friction.FrictionJointDef.'
at Box2D.NetStandard.Dynamics.Joints.Joint.Create(JointDef def)
at Box2D.NetStandard.Dynamics.World.World.CreateJoint(JointDef def)
...
In source code, it doesn't look like that joint def is in the switch statement. Being that FrictionJoint and FrictionJointDef do exist, I'm wondering if this was just missed (or incomplete)?
Using Box2D.NetStandard 2.4.2-alpha
I am using 2.4.5-alpha.
I created a PolygonShape, and it appears to behave as expected (collisions, rotations, etc).
I then created a CircleShape in the same way as the polygon, but it does not detect collisions properly, and at times just spins off and fly's around out of control. Is CircleShape working? If so then I must be misunderstanding something in the shape's creation. I will paste some code here, but it's kind of messy since I'm trying different things to figure this out.
Thanks for any help!
Working (colliding etc):
public RectangleBody(float x, float y, float w, float h, World world, BodyType type)
{
this.w = w;
this.h = h;
this.aliveBuffer = w + h;
this.position = new Vector2(x, y);
BodyDef bodyDef = new BodyDef();
bodyDef.position = Box2DHelper.CoordPixelsToWorld(x, y);
bodyDef.type = type;
if (type == BodyType.Dynamic)
{
bodyDef.angularVelocity = (float)Random(-10, 10);
bodyDef.linearVelocity = new Vector2((float)Random(-5, 5), (float)Random(10));
}
body = world.CreateBody(bodyDef);
PolygonShape shape = new PolygonShape();
float scalarW = Box2DHelper.ScalarPixelsToWorld(w / 2);
float scalarH = Box2DHelper.ScalarPixelsToWorld(h / 2);
shape.SetAsBox(scalarW, scalarH);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
float rngDensity = (float)Random(5, 15);
this.density = (int)rngDensity;
fixtureDef.density = rngDensity;
fixtureDef.friction = 1f;
fixtureDef.restitution = 0.15f;
body.CreateFixture(fixtureDef);
}
Not working (no collisions, etc):
public CircleBody(float x, float y, float r, World world, BodyType type)
{
this.r = r;
this.aliveBuffer = r * 2;
this.position = new Vector2(x, y);
Vector2 worldPos = Box2DHelper.CoordPixelsToWorld(position);
BodyDef bodyDef = new BodyDef();
bodyDef.position = worldPos;
bodyDef.type = type;
if (type == BodyType.Dynamic)
{
//bodyDef.angularVelocity = (float)Random(-10, 10);
bodyDef.linearVelocity = new Vector2((float)Random(-5, 5), (float)Random(10));
}
body = world.CreateBody(bodyDef);
CircleShape shape = new CircleShape();
float scalarR = Box2DHelper.ScalarPixelsToWorld(r);
shape.Set(worldPos, scalarR);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
float rngDensity = (float)Random(5, 15);
this.density = (int)rngDensity;
fixtureDef.density = 10000;
fixtureDef.friction = 0.3f;
fixtureDef.restitution = 0.1f;
body.CreateFixture(fixtureDef);
}
Don't know why yet, other polygon collisions seem to work. There also may be a quirk around the polygons against edges - need to devise another world for that.
I'm not sure if I'm missing something, but I can't seem to set the radius of a CircleShape. There isn't a 'Radius' property as is shown in the example, there isn't a way for it to use a CircleDef object.
CircleShape shape = new CircleShape();
shape.Radius //not a thing
There should be a 'shape.Radius' property like in the example
I believe I found a bug with Body.DestroyFixture
. Body
tracks fixtures using a linked list. When calling Body.DestroyFixture
, and the fixture to be destroyed is the first fixture in the linked list, m_fixtureList isn't updated, and continues to point to the fixture getting destroyed. This results in Body.m_fixtureList pointing to a single, broken fixture (where both m_body and m_next are null), and all other fixtures are lost (no longer in Body's linked list).
I believe the fix should be simple enough. If the fixture to be destroyed is the first in the linked list, update m_fixtureList to point to that fixture's m_next.
This bug also exists in the C++ implementation, and currently have a thread for it on discord: https://discord.com/channels/460295137705197568/460295137705197570/927374070515900416. Just wanted to track it here as well, as I'm currently halted on my project due to this.
Properties of a Manifold are all set to "internal". Manifold.cs
Additionally, Contact.GetWorldManifold
Contact.cs
This means while using the nuget package, I have no access to contact manifolds in a ContactListener
Create a new project using the nuget package and try to access oldManifold.points
Manifolds are accessible
Evident in RubeGoldberg test world: after the ball hits the ragdoll, the ball gradually sinks lower as it swings.
I fixed these and somehow the files went walkabout.
In summary, in some places structs are expected, and that's fine in the C++ code because they're accessed by reference. In C#, when an item is picked from an array and it's a value type (e.g. a struct), what you get is a copy. The upshot is that mutating the object mutates the copy that you got, and not the item in the array. As a consequence, I had to use classes for several types. And a knock-on effect is that they then must be explicitly instantiated with the new keyword.
I'm thinking how to implement my own box2d renderer.
DebugDraw is fine but its really made for debug purposes only.
Callbacks in DebugDraw do not provide anything to link to my objects. I cant select texture, fox example.
To render PolygonShape myself I must get its current vertices coordinates.
C++ box2d engine holds them inside b2PolygonShape.m_vertices.
C# interface do not provide any methods to access vertices
This isn't actually an issue, I'm just looking for guidance.
Suppose I have a rectangle (representing a brick) and a circle (representing a slow-ish bullet) and if the bullet hits the brick with enough speed I want to turn the brick from one object into two or three objects along fracture lines that seem intuitive.
Do you think it would work for me to modify the ContactManager.Collide()
method in such a way that it does two passes... The first pass could replace the bottom part of the function that looks like
// Here we destroy contacts that cease to overlap in the broad-phase.
if (overlap == false)
{
Contact cNuke = c;
c = cNuke.GetNext();
Destroy(cNuke);
continue;
}
// The contact persists.
c.Update(m_contactListener);
c = c.GetNext();
with something like
if (overlap == true)
{
...break brick into pieces if conditions are met...
}
and then the second pass would be exactly the code that's in the ContactManager.Collide()
method normally?
Or would this not work? Maybe I would need to rewind positions after the first pass? Possibly by capturing the world state at the beginning of the first pass and resetting it to that (except for the broken brick) before doing the second pass?
When applying a Prismatic Joint, the localAxisA is normalized. This causes {NaN, NaN}
when the joint is new Vector2(0,0)
See
Create a new prismatic joint where the localAxisA
is new Vector2(0,0)
You can work around the issue by using Reflection to update the private values:
var jdef = new PrismaticJointDef();
jdef.bodyA = body1;
jdef.bodyB = body2;
jdef.collideConnected = false;
jdef.localAxisA = new Vector2(0, 0);
var pJoint = world.CreateJoint(jdef);
var propX = pJoint.GetType().GetField("m_localXAxisA", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var propY = pJoint.GetType().GetField("m_localYAxisA", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
propX.SetValue(pJoint, new Vector2(0, 0));
propY.SetValue(pJoint, new Vector2(0, 0));
Something similar to:
In Version 1.0.3 of the project, the Filter.MaskBits
and Filter.CategoryBits
seem to be ignored.
I have created a really simple scene where I have a square and a static floor. I have set the filter data up like below which I expect would allow the square to not collide with the floor as the mask and category bits for each are different.
FilterData cubeFilter = new() { CategoryBits = 0b0001, MaskBits = 0b0010 };
FilterData floorFilter = new() { CategoryBits = 0b0100, MaskBits = 0b1000 };
However, the square and the floor still collide and do not pass through each other.
I created the project as a .NET 5 console application.
NuGets
Install-Package Box2D.NetStandard -Version 1.0.3
Install-Package Box2D.Window -Version 1.0.3
Code
using Box2D.Window;
using Box2DX.Collision;
using Box2DX.Common;
using Box2DX.Dynamics;
using System.Threading;
namespace Box2dMcve
{
internal static class Program
{
private static void Main()
{
AABB aabb = new();
aabb.LowerBound.Set(-20, -10);
aabb.UpperBound.Set(20, 110);
World world = new(aabb, new Vec2(0.0f, -9.81f), false);
BodyDef cubeDefinition = new();
cubeDefinition.Position.Set(0, 70);
PolygonDef cubeFixture = new();
cubeFixture.SetAsBox(5, 5);
cubeFixture.Friction = 0;
cubeFixture.Restitution = 0;
cubeFixture.Density = 1;
FilterData cubeFilter = new() { CategoryBits = 0b0001, MaskBits = 0b0010 };
cubeFixture.Filter = cubeFilter;
Body basicCube = world.CreateBody(cubeDefinition);
basicCube.CreateFixture(cubeFixture);
basicCube.SetMassFromShapes();
BodyDef floorDefinition = new();
floorDefinition.Position.Set(0, 20);
PolygonDef floorFixture = new();
floorFixture.SetAsBox(20, 5);
floorFixture.Friction = 0;
floorFixture.Restitution = 0;
FilterData floorFilter = new() { CategoryBits = 0b0100, MaskBits = 0b1000 };
floorFixture.Filter = floorFilter;
Body floor = world.CreateBody(floorDefinition);
floor.CreateFixture(floorFixture);
floor.SetStatic();
Thread windowThread = new(() =>
{
SimulationWindow game = new("Physics Simulation", 800, 600);
game.UpdateFrame += (_, _) => { world.Step(0.02f, 8, 3); };
game.SetView(new CameraView());
DrawPhysics physicsDrawer = new(game);
physicsDrawer.AppendFlags(DebugDraw.DrawFlags.Aabb);
physicsDrawer.AppendFlags(DebugDraw.DrawFlags.Shape);
world.SetDebugDraw(physicsDrawer);
game.VSync = OpenTK.VSyncMode.Adaptive;
game.Run(60, 0);
});
windowThread.Start();
}
}
}
Hi, i was wondering if somebody has an example on how to use Raycast. The implementation showed in the docs does not quite work for me
The following methods in DebugDraw are obsolete but without new Vector2 based version:
[Obsolete("Look out for new calls using Vector2")]
public abstract void DrawPolygon(in Vec2[] vertices, int vertexCount, in Color color);
[Obsolete("Look out for new calls using Vector2")]
public abstract void DrawSolidPolygon(in Vec2[] vertices, int vertexCount, in Color color);
[Obsolete("Look out for new calls using Vector2")]
public abstract void DrawCircle(in Vec2 center, float radius, in Color color);
[Obsolete("Look out for new calls using Vector2")]
public abstract void DrawSolidCircle(in Vec2 center, float radius, in Vec2 axis, in Color color);
[Obsolete("Look out for new calls using Vector2")]
public abstract void DrawSegment(in Vec2 p1, in Vec2 p2, in Color color);
### How To Reproduce
Implement inherited class and compiler spits out warnings
### Expected Behavior
The abstract DebugDraw class should provide non obsolete method versions:
[Obsolete("Look out for new calls using Vector2")]
public abstract void DrawPolygon(in Vec2[] vertices, int vertexCount, in Color color);
public abstract void DrawPolygon(in Vector2[] vertices, int vertexCount, in Color color);
It was left out as a "to-do-later" job. Debug Draw changed significantly between Box2DX (2008) and today (2020!! 12 years on!!)
test code
var b = world.CreateBody(new BodyDef { Position = new Vec2(0, 0), MassData = new MassData { Mass = 0 } });
var s = new PolygonDef();
s.SetAsBox(10, 10, Vec2.Zero, 30 * 0.01745f);
b.CreateFixture(s);
need the convert angle to radian, current i test meet expectation, i am correct?
not found need radian in SetAsBox params comment
thank
Hello! just wanted to know if anyone is going work on/add the ChainShape soon or not.
because I really want it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.