├── .gitignore ├── src ├── Box2DSharp.xkpkg.user ├── .gitignore ├── Ropes │ ├── StretchingModel.cs │ ├── BendingModel.cs │ ├── RopeDef.cs │ ├── RopeStretch.cs │ ├── RopeBend.cs │ └── RopeTuning.cs ├── Collision │ ├── Collider │ │ ├── ManifoldType.cs │ │ ├── ClipVertex.cs │ │ ├── RayCastInput.cs │ │ ├── RayCastOutput.cs │ │ ├── ContactID.cs │ │ ├── PointState.cs │ │ ├── ContactFeature.cs │ │ ├── ManifoldPoint.cs │ │ └── Manifold.cs │ ├── Shapes │ │ ├── ShapeType.cs │ │ ├── MassData.cs │ │ ├── Sweep.cs │ │ └── Shape.cs │ ├── ShapeCastOutput.cs │ ├── ShapeCastInput.cs │ ├── DistanceOutput.cs │ ├── SimplexVertex.cs │ ├── DistanceInput.cs │ └── SimplexCache.cs ├── Dynamics │ ├── Velocity.cs │ ├── Position.cs │ ├── Contacts │ │ ├── IContactFactory.cs │ │ ├── VelocityConstraintPoint.cs │ │ ├── ContactImpulse.cs │ │ ├── ContactSolverDef.cs │ │ ├── ContactEdge.cs │ │ ├── ContactPositionConstraint.cs │ │ ├── ContactVelocityConstraint.cs │ │ ├── CircleContact.cs │ │ ├── PolygonContact.cs │ │ ├── ChainAndPolygonContact.cs │ │ ├── EdgeAndCircleContact.cs │ │ ├── EdgeAndPolygonContact.cs │ │ ├── PolygonAndCircleContact.cs │ │ ├── ChainAndCircleContact.cs │ │ └── ContactPool.cs │ ├── Profile.cs │ ├── TimeStep.cs │ ├── IDestructionListener.cs │ ├── IContactFilter.cs │ ├── SolverData.cs │ ├── BodyFlags.cs │ ├── Joints │ │ ├── GearJointDef.cs │ │ ├── MouseJointDef.cs │ │ ├── MotorJointDef.cs │ │ ├── FrictionJointDef.cs │ │ ├── WeldJointDef.cs │ │ ├── DistanceJointDef.cs │ │ └── PulleyJointDef.cs │ ├── DefaultContactFilter.cs │ ├── Callbacks.cs │ └── IContactListener.cs ├── Box2DSharp.csproj.DotSettings ├── Common │ ├── DumpLogger.cs │ ├── DrawFlag.cs │ ├── Math │ │ └── EnumExtensions.cs │ ├── Drawer.cs │ ├── Transform.cs │ ├── Rotation.cs │ └── MathExtensions.cs └── Box2DSharp.csproj ├── test ├── ConsoleTest │ ├── .gitignore │ └── ConsoleTest.csproj ├── UnitTest │ ├── .gitignore │ ├── UnitTest.csproj │ ├── MathTest.cs │ └── WorldTest.cs ├── DeterministicTest │ ├── .gitignore │ ├── DeterministicTest.csproj │ └── Program.cs ├── Testbed.TestCases │ ├── .gitignore │ ├── Testbed.TestCases.csproj │ ├── Position.cs │ ├── Heavy1.cs │ ├── CircleStack.cs │ ├── AddPair.cs │ ├── Pyramid.cs │ ├── Restitution.cs │ ├── Chain.cs │ ├── HelloWorld.cs │ ├── ChainProblem.cs │ ├── DumpLoader.cs │ ├── DistanceJointTest.cs │ ├── Heavy2.cs │ ├── ConveyorBelt.cs │ ├── Mobile.cs │ └── PulleyJoint.cs ├── UnityTest │ ├── Assets │ │ ├── Game.cs.meta │ │ ├── Starter.cs.meta │ │ ├── UnityInput.cs.meta │ │ ├── ArrayExtensions.cs.meta │ │ ├── CustomFixedUpdate.cs.meta │ │ ├── Deterministic.cs.meta │ │ ├── TestSettingHelper.cs.meta │ │ ├── UnityTestSettings.cs.meta │ │ ├── DeterministicTester.cs.meta │ │ ├── TestInheritAttribute.cs.meta │ │ ├── Inspection │ │ │ ├── MouseInspector.cs.meta │ │ │ ├── Utils.cs.meta │ │ │ ├── UnityDraw.cs.meta │ │ │ ├── MouseInspector.cs │ │ │ └── Utils.cs │ │ ├── System.Buffers.dll │ │ ├── System.Memory.dll │ │ ├── System.Runtime.CompilerServices.Unsafe.dll │ │ ├── Scenes │ │ │ ├── Init.unity.meta │ │ │ ├── Test.unity.meta │ │ │ ├── Deterministic.unity.meta │ │ │ ├── InitSettings.lighting.meta │ │ │ ├── DeterministicSettings.lighting.meta │ │ │ ├── InitSettings.lighting │ │ │ └── DeterministicSettings.lighting │ │ ├── Scenes.meta │ │ ├── Tests.meta │ │ ├── Box2DSharp.meta │ │ ├── Inspection.meta │ │ ├── InputSystem.inputsettings.asset.meta │ │ ├── TestInheritAttribute.cs │ │ ├── DebugDraw.cs.meta │ │ ├── UnityLogger.cs.meta │ │ ├── Tests │ │ │ ├── RayCastRender.cs.meta │ │ │ ├── EdgeTestRender.cs.meta │ │ │ ├── RensorsTestRender.cs.meta │ │ │ ├── RopeTestRender.cs.meta │ │ │ ├── WreckingBallRender.cs.meta │ │ │ ├── CompoundShapesRender.cs.meta │ │ │ ├── DistanceJointTestRender.cs.meta │ │ │ ├── RevoluteJointTestRender.cs.meta │ │ │ ├── WheelJointTestRender.cs.meta │ │ │ ├── PrismaticJointTestRender.cs.meta │ │ │ ├── RensorsTestRender.cs │ │ │ ├── CompoundShapesRender.cs │ │ │ ├── EdgeTestRender.cs │ │ │ ├── WreckingBallRender.cs │ │ │ ├── RevoluteJointTestRender.cs │ │ │ ├── PrismaticJointTestRender.cs │ │ │ ├── WheelJointTestRender.cs │ │ │ ├── RayCastRender.cs │ │ │ └── DistanceJointTestRender.cs │ │ ├── UnityLogger.cs │ │ ├── UnityTestSettings.cs │ │ ├── ArrayExtensions.cs │ │ ├── Starter.cs │ │ ├── System.Buffers.dll.meta │ │ ├── System.Memory.dll.meta │ │ ├── System.Runtime.CompilerServices.Unsafe.dll.meta │ │ ├── InputSystem.inputsettings.asset │ │ ├── TestSettingHelper.cs │ │ ├── Deterministic.cs │ │ └── CustomFixedUpdate.cs │ ├── ProjectSettings │ │ ├── ProjectVersion.txt │ │ ├── ClusterInputManager.asset │ │ ├── NetworkManager.asset │ │ ├── XRSettings.asset │ │ ├── VersionControlSettings.asset │ │ ├── TimeManager.asset │ │ ├── VFXManager.asset │ │ ├── BurstAotSettings_Android.json │ │ ├── BurstAotSettings_StandaloneWindows.json │ │ ├── PresetManager.asset │ │ ├── AudioManager.asset │ │ ├── TagManager.asset │ │ ├── EditorBuildSettings.asset │ │ ├── UnityConnectSettings.asset │ │ ├── DynamicsManager.asset │ │ ├── PackageManagerSettings.asset │ │ ├── EditorSettings.asset │ │ ├── MemorySettings.asset │ │ ├── NavMeshAreas.asset │ │ ├── Physics2DSettings.asset │ │ └── GraphicsSettings.asset │ ├── Assembly-CSharp.csproj.DotSettings │ ├── UnityTest.sln │ ├── .gitignore │ └── Packages │ │ └── manifest.json ├── Testbed.Abstractions │ ├── .gitignore │ ├── MouseButton.cs │ ├── SizeCache.cs │ ├── Testbed.Abstractions.csproj │ ├── Extensions.cs │ ├── EnumExtensions.cs │ ├── InputAction.cs │ ├── IInput.cs │ ├── IDebugDrawer.cs │ ├── TestCaseAttribute.cs │ ├── KeyModifiers.cs │ ├── KeyInputEventArgs.cs │ ├── FpsCounter.cs │ ├── MouseInputEventArgs.cs │ ├── MathExtensions.cs │ ├── Global.cs │ └── KeyCodes.cs └── Testbed │ ├── .gitignore │ ├── TestInheritAttribute.cs │ ├── ColorExtensions.cs │ ├── EnumExtensions.cs │ ├── Testbed.csproj │ ├── Tests │ ├── CompoundShapesRender.cs │ ├── RensorsTestRender.cs │ ├── EdgeTestRender.cs │ ├── WreckingBallRender.cs │ ├── RevoluteJointTestRender.cs │ ├── WheelJointTestRender.cs │ ├── PrismaticJointTestRender.cs │ ├── RayCastRender.cs │ └── DistanceJointTestRender.cs │ ├── Program.cs │ ├── TestSettingHelper.cs │ └── Render │ └── RenderHelper.cs ├── CopyToUnityTestbed.bat ├── LICENSE-Box2D.txt ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vs/ 3 | *.DotSettings.user -------------------------------------------------------------------------------- /src/Box2DSharp.xkpkg.user: -------------------------------------------------------------------------------- 1 | !SettingsFile 2 | Settings: {} 3 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/ConsoleTest/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/UnitTest/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/DeterministicTest/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/Testbed.TestCases/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Game.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 143d54880e664cba8e885837f3c9e1d3 3 | timeCreated: 1542381903 -------------------------------------------------------------------------------- /test/UnityTest/Assets/Starter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52a69dd037a6472a8351f5f9423b2eb7 3 | timeCreated: 1609523284 -------------------------------------------------------------------------------- /test/Testbed.Abstractions/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/UnityInput.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7910dcfe71048cd87e085985c62371f 3 | timeCreated: 1607758298 -------------------------------------------------------------------------------- /test/UnityTest/Assets/ArrayExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed425140e76f4312b2ad1fdbee738a7f 3 | timeCreated: 1547395279 -------------------------------------------------------------------------------- /test/UnityTest/Assets/CustomFixedUpdate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a527d271f1fa451794e8d82a21cc2030 3 | timeCreated: 1609692882 -------------------------------------------------------------------------------- /test/UnityTest/Assets/Deterministic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7fa9b3656d424a33bd8b9955146566c1 3 | timeCreated: 1609508523 -------------------------------------------------------------------------------- /test/UnityTest/Assets/TestSettingHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7dcd27f1e91740e98b2ea02fca887277 3 | timeCreated: 1607764306 -------------------------------------------------------------------------------- /test/UnityTest/Assets/UnityTestSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69ab502e65f5441986a36885df4a0cea 3 | timeCreated: 1607786888 -------------------------------------------------------------------------------- /test/UnityTest/Assets/DeterministicTester.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c0c62ec2796f413fa5c79231787e51a7 3 | timeCreated: 1609508260 -------------------------------------------------------------------------------- /test/UnityTest/Assets/TestInheritAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a407bfe79b744bf9a831a6ccee1c5f40 3 | timeCreated: 1607748702 -------------------------------------------------------------------------------- /test/Testbed/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | 10 | settings.ini -------------------------------------------------------------------------------- /test/UnityTest/Assets/Inspection/MouseInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e74f060ec4274c01b2b11018d97e8ee1 3 | timeCreated: 1547565190 -------------------------------------------------------------------------------- /test/UnityTest/Assets/System.Buffers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp-deterministic/HEAD/test/UnityTest/Assets/System.Buffers.dll -------------------------------------------------------------------------------- /test/UnityTest/Assets/System.Memory.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp-deterministic/HEAD/test/UnityTest/Assets/System.Memory.dll -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2022.3.40f1c1 2 | m_EditorVersionWithRevision: 2022.3.40f1c1 (0bae6c114c78) 3 | -------------------------------------------------------------------------------- /src/Ropes/StretchingModel.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Ropes 2 | { 3 | public enum StretchingModel 4 | { 5 | PbdStretchingModel, 6 | 7 | XpbdStretchingModel 8 | }; 9 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/System.Runtime.CompilerServices.Unsafe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp-deterministic/HEAD/test/UnityTest/Assets/System.Runtime.CompilerServices.Unsafe.dll -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /src/Collision/Collider/ManifoldType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Collision.Collider 2 | { 3 | public enum ManifoldType 4 | { 5 | Circles, 6 | 7 | FaceA, 8 | 9 | FaceB 10 | } 11 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/MouseButton.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public enum MouseButton 4 | { 5 | Left = 0, 6 | 7 | Right = 1, 8 | 9 | Middle = 2 10 | } 11 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/Init.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79c7c302156531e4fa077558694321a5 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/Test.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cda990e2423bbf4892e6590ba056729 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 131a6b21c8605f84396be9f6751fb6e3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/Deterministic.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef2a0ebc31e23844b801eae538df4909 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d52a0991d05be24c96148e34889972a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Box2DSharp.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d7db7760f9ad70845b1ca71b09755a6a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Inspection.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9c49b21f81a982b4080ee2fc8902cbf5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/Testbed/TestInheritAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 6 | public class TestInheritAttribute : Attribute 7 | { } 8 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/SizeCache.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | public static class SizeCache 6 | { 7 | public static readonly int Size = Marshal.SizeOf(); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Dynamics/Velocity.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics 4 | { 5 | /// This is an internal structure. 6 | public struct Velocity 7 | { 8 | public FVector2 V; 9 | 10 | public FP W; 11 | } 12 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/InputSystem.inputsettings.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6aca77d95ee225648ac674145919689f 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/TestInheritAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Testbed.Unity 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 6 | public class TestInheritAttribute : Attribute 7 | { } 8 | } -------------------------------------------------------------------------------- /src/Dynamics/Position.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics 4 | { 5 | /// This is an internal structure. 6 | public struct Position 7 | { 8 | public FVector2 Center; 9 | 10 | public FP Angle; 11 | } 12 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/VersionControlSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!890905787 &1 4 | VersionControlSettings: 5 | m_ObjectHideFlags: 0 6 | m_Mode: Visible Meta Files 7 | m_CollabEditorSettings: 8 | inProgressEnabled: 1 9 | -------------------------------------------------------------------------------- /src/Collision/Shapes/ShapeType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Collision.Shapes 2 | { 3 | public enum ShapeType 4 | { 5 | Circle = 0, 6 | 7 | Edge = 1, 8 | 9 | Polygon = 2, 10 | 11 | Chain = 3, 12 | 13 | TypeCount = 4 14 | } 15 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/InitSettings.lighting.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d80d39faddaa5db4281e35ffc1400248 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 4890085278179872738 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Dynamics/Contacts/IContactFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Dynamics.Contacts 2 | { 3 | internal interface IContactFactory 4 | { 5 | Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB); 6 | 7 | void Destroy(Contact contact); 8 | } 9 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.1 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/DeterministicSettings.lighting.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d74142bca7e2bcc459f82aae74e55c71 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 4890085278179872738 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Collision/Collider/ClipVertex.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision.Collider 4 | { 5 | /// Used for computing contact manifolds. 6 | public struct ClipVertex 7 | { 8 | public FVector2 Vector; 9 | 10 | public ContactId Id; 11 | } 12 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/DebugDraw.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dff5cce8c46801248ac422a8cc44aae6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/UnityLogger.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b783310c671c58429d47a852d624778 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/Ropes/BendingModel.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Ropes 2 | { 3 | public enum BendingModel 4 | { 5 | SpringAngleBendingModel = 0, 6 | PbdAngleBendingModel, 7 | XpdAngleBendingModel, 8 | PbdDistanceBendingModel, 9 | PbdHeightBendingModel, 10 | PbdTriangleBendingModel 11 | }; 12 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Inspection/Utils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 704207448cecedb499a3e86a224ea556 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RayCastRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2e0ba7f6b9d9ed418511d8011eec456 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Inspection/UnityDraw.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0551b1aadef27346bed0a08a88a44ad 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/EdgeTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d52ba7766dcb2114e8150de21a80d2b0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RensorsTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c72653c74841ef4b8a0160263b1b45e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RopeTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 80f36883a3ba2624e9a2187d254bd999 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/WreckingBallRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7eb1a37761ecbe141a090a13ede7abdd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/Testbed.Abstractions/Testbed.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/CompoundShapesRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68c17be82e3be6b43982b2f9b8ff6ca4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/DistanceJointTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a320641aa8fc47d428f32e846e936164 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RevoluteJointTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e35e5a16e1942354595da336bc62b514 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/WheelJointTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8609bcdd182c00147be67b13281926ed 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/Testbed/ColorExtensions.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | using OpenTK.Mathematics; 3 | 4 | namespace Testbed 5 | { 6 | public static class ColorExtensions 7 | { 8 | public static Color4 ToColor4(in this Color color) 9 | { 10 | return new Color4(color.R, color.G, color.B, color.A); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/PrismaticJointTestRender.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0daff3d3ff8a46f478717be2d69bfb14 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/UnityLogger.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity 5 | { 6 | public class UnityLogger : IDumpLogger 7 | { 8 | /// 9 | public void Log(string message) 10 | { 11 | Debug.Log(message); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/Testbed.TestCases.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/UnityTestSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | using Testbed.Abstractions; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity 6 | { 7 | [DataContract] 8 | public class UnityTestSettings : TestSettings 9 | { 10 | [DataMember] 11 | public FullScreenMode FullScreenMode; 12 | } 13 | } -------------------------------------------------------------------------------- /src/Collision/ShapeCastOutput.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision 4 | { 5 | /// Output results for b2ShapeCast 6 | public struct ShapeCastOutput 7 | { 8 | public FVector2 Point; 9 | 10 | public FVector2 Normal; 11 | 12 | public FP Lambda; 13 | 14 | public int Iterations; 15 | } 16 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_RenderPipeSettingsPath: 10 | m_FixedTimeStep: 0.016666668 11 | m_MaxDeltaTime: 0.05 12 | -------------------------------------------------------------------------------- /src/Collision/Collider/RayCastInput.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision.Collider 4 | { 5 | /// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). 6 | public struct RayCastInput 7 | { 8 | public FVector2 P1; 9 | 10 | public FVector2 P2; 11 | 12 | public FP MaxFraction; 13 | } 14 | } -------------------------------------------------------------------------------- /src/Collision/Collider/RayCastOutput.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision.Collider 4 | { 5 | /// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 6 | /// come from b2RayCastInput. 7 | public struct RayCastOutput 8 | { 9 | public FVector2 Normal; 10 | 11 | public FP Fraction; 12 | } 13 | } -------------------------------------------------------------------------------- /src/Ropes/RopeDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Ropes 4 | { 5 | /// 6 | public struct RopeDef 7 | { 8 | public FVector2 Position; 9 | 10 | public FVector2[] Vertices; 11 | 12 | public int Count; 13 | 14 | public FP[] Masses; 15 | 16 | public FVector2 Gravity; 17 | 18 | public RopeTuning Tuning; 19 | }; 20 | } -------------------------------------------------------------------------------- /test/DeterministicTest/DeterministicTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | 10 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/Testbed.Abstractions/Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public static class Extensions 4 | { 5 | public static T[] Fill(this T[] array) 6 | where T : new() 7 | { 8 | for (var i = 0; i < array.Length; i++) 9 | { 10 | array[i] = new T(); 11 | } 12 | 13 | return array; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Ropes/RopeStretch.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Ropes 4 | { 5 | public struct RopeStretch 6 | { 7 | public int I1; 8 | 9 | public int I2; 10 | 11 | public FP InvMass1; 12 | 13 | public FP InvMass2; 14 | 15 | public FP L; 16 | 17 | public FP Lambda; 18 | 19 | public FP Spring; 20 | 21 | public FP Damper; 22 | }; 23 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | public static class EnumExtensions 6 | { 7 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 8 | public static bool HasSetFlag(this KeyModifiers flags, KeyModifiers flag) 9 | { 10 | return (flags & flag) != 0; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/InputAction.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public enum InputAction 4 | { 5 | /// The key or mouse button was released. 6 | Release, 7 | 8 | /// The key or mouse button was pressed. 9 | Press, 10 | 11 | /// The key was held down until it repeated. 12 | Repeat, 13 | } 14 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/BurstAotSettings_Android.json: -------------------------------------------------------------------------------- 1 | { 2 | "MonoBehaviour": { 3 | "m_Enabled": true, 4 | "m_EditorHideFlags": 0, 5 | "m_Name": "", 6 | "m_EditorClassIdentifier": "Unity.Burst.Editor:Unity.Burst.Editor:BurstPlatformAotSettings", 7 | "DisableOptimisations": false, 8 | "DisableSafetyChecks": true, 9 | "DisableBurstCompilation": false 10 | } 11 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/ArrayExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Testbed.Unity 2 | { 3 | public static class ArrayExtensions 4 | { 5 | public static T[] Fill(this T[] array) 6 | where T : new() 7 | { 8 | for (int i = 0; i < array.Length; i++) 9 | { 10 | array[i] = new T(); 11 | } 12 | 13 | return array; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Collision/ShapeCastInput.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision 4 | { 5 | /// Input parameters for b2ShapeCast 6 | public struct ShapeCastInput 7 | { 8 | public DistanceProxy ProxyA; 9 | 10 | public DistanceProxy ProxyB; 11 | 12 | public Transform TransformA; 13 | 14 | public Transform TransformB; 15 | 16 | public FVector2 TranslationB; 17 | } 18 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/IInput.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public interface IInput 4 | { 5 | bool IsKeyDown(KeyCodes key); 6 | 7 | bool IsKeyPressed(KeyCodes key); 8 | 9 | bool IsKeyUp(KeyCodes key); 10 | 11 | bool IsMouseDown(MouseButton button); 12 | 13 | bool IsMousePressed(MouseButton button); 14 | 15 | bool IsMouseUp(MouseButton button); 16 | } 17 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/BurstAotSettings_StandaloneWindows.json: -------------------------------------------------------------------------------- 1 | { 2 | "MonoBehaviour": { 3 | "m_Enabled": true, 4 | "m_EditorHideFlags": 0, 5 | "m_Name": "", 6 | "m_EditorClassIdentifier": "Unity.Burst.Editor:Unity.Burst.Editor:BurstPlatformAotSettings", 7 | "DisableOptimisations": false, 8 | "DisableSafetyChecks": true, 9 | "DisableBurstCompilation": false 10 | } 11 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | m_DefaultList: 7 | - type: 8 | m_NativeTypeID: 20 9 | m_ManagedTypePPtr: {fileID: 0} 10 | m_ManagedTypeFallback: 11 | defaultPresets: 12 | - m_Preset: {fileID: 2655988077585873504, guid: bfcfc320427f8224bbb7a96f3d3aebad, 13 | type: 2} 14 | -------------------------------------------------------------------------------- /test/Testbed/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using TKKeyModifiers = OpenTK.Windowing.GraphicsLibraryFramework.KeyModifiers; 3 | 4 | namespace Testbed; 5 | 6 | public static class EnumExtensions 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static bool HasSetFlag(this TKKeyModifiers flags, TKKeyModifiers flag) 10 | { 11 | return (flags & flag) != 0; 12 | } 13 | } -------------------------------------------------------------------------------- /src/Box2DSharp.csproj.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True -------------------------------------------------------------------------------- /src/Dynamics/Contacts/VelocityConstraintPoint.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Contacts 4 | { 5 | public struct VelocityConstraintPoint 6 | { 7 | public FP NormalImpulse; 8 | 9 | public FP NormalMass; 10 | 11 | public FVector2 Ra; 12 | 13 | public FVector2 Rb; 14 | 15 | public FP TangentImpulse; 16 | 17 | public FP TangentMass; 18 | 19 | public FP VelocityBias; 20 | } 21 | } -------------------------------------------------------------------------------- /src/Collision/DistanceOutput.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision 4 | { 5 | /// Output for b2Distance. 6 | public struct DistanceOutput 7 | { 8 | /// closest point on shapeA 9 | public FVector2 PointA; 10 | 11 | /// closest point on shapeB 12 | public FVector2 PointB; 13 | 14 | public FP Distance; 15 | 16 | /// number of GJK iterations used 17 | public int Iterations; 18 | } 19 | } -------------------------------------------------------------------------------- /test/UnityTest/Assembly-CSharp.csproj.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 1024 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_AmbisonicDecoderPlugin: 16 | m_DisableAudio: 0 17 | m_VirtualizeEffects: 1 18 | -------------------------------------------------------------------------------- /src/Collision/Collider/ContactID.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Box2DSharp.Collision.Collider 4 | { 5 | /// Contact ids to facilitate warm starting. 6 | [StructLayout(LayoutKind.Explicit, Size = 4)] 7 | public struct ContactId 8 | { 9 | [FieldOffset(0)] 10 | public ContactFeature ContactFeature; 11 | 12 | /// Used to quickly compare contact ids. 13 | [FieldOffset(0)] 14 | public uint Key; 15 | } 16 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/IDebugDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Box2DSharp.Collision; 3 | using Box2DSharp.Common; 4 | 5 | namespace Testbed.Abstractions 6 | { 7 | public interface IDebugDraw : IDraw 8 | { 9 | void DrawAABB(AABB aabb, Color color); 10 | 11 | void DrawString(float x, float y, string strings); 12 | 13 | void DrawString(int x, int y, string strings); 14 | 15 | void DrawString(Vector2 position, string strings); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Dynamics/Profile.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Dynamics 2 | { 3 | /// Profiling data. Times are in milliseconds. 4 | public struct Profile 5 | { 6 | public float Step; 7 | 8 | public float Collide; 9 | 10 | public float Solve; 11 | 12 | public float SolveInit; 13 | 14 | public float SolveVelocity; 15 | 16 | public float SolvePosition; 17 | 18 | public float Broadphase; 19 | 20 | public float SolveTOI; 21 | } 22 | } -------------------------------------------------------------------------------- /src/Collision/Collider/PointState.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Collision.Collider 2 | { 3 | /// This is used for determining the state of contact points. 4 | public enum PointState 5 | { 6 | /// point does not exist 7 | NullState, 8 | 9 | /// point was added in the update 10 | AddState, 11 | 12 | /// point persisted across the update 13 | PersistState, 14 | 15 | /// point was removed in the update 16 | RemoveState 17 | } 18 | } -------------------------------------------------------------------------------- /src/Collision/Shapes/MassData.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision.Shapes 4 | { 5 | public struct MassData 6 | { 7 | /// The mass of the shape, usually in kilograms. 8 | public FP Mass; 9 | 10 | /// The position of the shape's centroid relative to the shape's origin. 11 | public FVector2 Center; 12 | 13 | /// The rotational inertia of the shape about the local origin. 14 | public FP RotationInertia; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Dynamics/TimeStep.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics 4 | { 5 | /// This is an internal structure. 6 | public struct TimeStep 7 | { 8 | public FP Dt; // time step 9 | 10 | public FP InvDt; // inverse time step (0 if dt == 0). 11 | 12 | public FP DtRatio; // dt * inv_dt0 13 | 14 | public int VelocityIterations; 15 | 16 | public int PositionIterations; 17 | 18 | public bool WarmStarting; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Collision/SimplexVertex.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision 4 | { 5 | public struct SimplexVertex 6 | { 7 | public FVector2 Wa; // support point in proxyA 8 | 9 | public FVector2 Wb; // support point in proxyB 10 | 11 | public FVector2 W; // wB - wA 12 | 13 | public FP A; // barycentric coordinate for closest point 14 | 15 | public int IndexA; // wA index 16 | 17 | public int IndexB; // wB index 18 | } 19 | } -------------------------------------------------------------------------------- /test/DeterministicTest/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace DeterministicTest 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var tester = new DeterministicTester(); 11 | 12 | { 13 | var hash = tester.TestTumbler(3000, 400); 14 | Console.WriteLine(hash.Hash); 15 | File.WriteAllText("tumbler.txt", hash.Data); 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Collision/DistanceInput.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision 4 | { 5 | /// Input for b2Distance. 6 | /// You have to option to use the shape radii 7 | /// in the computation. Even 8 | public struct DistanceInput 9 | { 10 | public DistanceProxy ProxyA; 11 | 12 | public DistanceProxy ProxyB; 13 | 14 | public Transform TransformA; 15 | 16 | public Transform TransformB; 17 | 18 | public bool UseRadii; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Collision/SimplexCache.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision 4 | { 5 | /// Used to warm start b2Distance. 6 | /// Set count to zero on first call. 7 | public struct SimplexCache 8 | { 9 | /// length or area 10 | public FP Metric; 11 | 12 | public ushort Count; 13 | 14 | /// vertices on shape A 15 | public FixedArray3 IndexA; 16 | 17 | /// vertices on shape B 18 | public FixedArray3 IndexB; 19 | } 20 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/TestCaseAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 6 | public class TestCaseAttribute : Attribute 7 | { 8 | public TestCaseAttribute(string category, string name) 9 | { 10 | Category = category; 11 | Name = name; 12 | } 13 | 14 | public string Category { get; } 15 | 16 | public string Name { get; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Dynamics/IDestructionListener.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Dynamics.Joints; 2 | 3 | namespace Box2DSharp.Dynamics 4 | { 5 | public interface IDestructionListener 6 | { 7 | /// Called when any joint is about to be destroyed due 8 | /// to the destruction of one of its attached bodies. 9 | void SayGoodbye(Joint joint); 10 | 11 | /// Called when any fixture is about to be destroyed due 12 | /// to the destruction of its parent body. 13 | void SayGoodbye(Fixture fixture); 14 | } 15 | } -------------------------------------------------------------------------------- /CopyToUnityTestbed.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set rootPath=%cd% 3 | 4 | rmdir /s /q "%cd%\test\UnityTest\Assets\Box2DSharp" 5 | 6 | xcopy /s /y /q "%cd%\src" "%cd%\test\UnityTest\Assets\Box2DSharp\Box2DSharp\" 7 | xcopy /s /y /q "%cd%\test\Testbed.Abstractions" "%cd%\test\UnityTest\Assets\Box2DSharp\Testbed.Abstractions\" 8 | xcopy /s /y /q "%cd%\test\Testbed.TestCases" "%cd%\test\UnityTest\Assets\Box2DSharp\Testbed.TestCases\" 9 | 10 | cd "%cd%\test\UnityTest\Assets\Box2DSharp" 11 | for /d /r . %%d in (bin,obj) do @if exist "%%d" rd /s/q "%%d" 12 | cd %rootPath% 13 | -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ContactImpulse.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Contacts 4 | { 5 | /// Contact impulses for reporting. Impulses are used instead of forces because 6 | /// sub-step forces may approach infinity for rigid body collisions. These 7 | /// match up one-to-one with the contact points in b2Manifold. 8 | public struct ContactImpulse 9 | { 10 | public FixedArray2 NormalImpulses; 11 | 12 | public FixedArray2 TangentImpulses; 13 | 14 | public int Count; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Dynamics/IContactFilter.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Dynamics 2 | { 3 | /// Implement this class to provide collision filtering. In other words, you can implement 4 | /// this class if you want finer control over contact creation. 5 | public interface IContactFilter 6 | { 7 | /// Return true if contact calculations should be performed between these two shapes. 8 | /// @warning for performance reasons this is only called when the AABBs begin to overlap. 9 | bool ShouldCollide(Fixture fixtureA, Fixture fixtureB); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Dynamics/SolverData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Dynamics 4 | { 5 | /// Solver Data 6 | public ref struct SolverData 7 | { 8 | public readonly TimeStep Step; 9 | 10 | public readonly Position[] Positions; 11 | 12 | public readonly Velocity[] Velocities; 13 | 14 | public SolverData(in TimeStep step, Position[] positions, Velocity[] velocities) 15 | { 16 | Step = step; 17 | Positions = positions; 18 | Velocities = velocities; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Starter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.SceneManagement; 4 | using UnityEngine.UI; 5 | 6 | namespace Box2DSharp.Testbed.Unity 7 | { 8 | public class Starter : MonoBehaviour 9 | { 10 | public Button TestbedButton; 11 | 12 | public Button DeterministicButton; 13 | 14 | public void Start() 15 | { 16 | TestbedButton.onClick.AddListener(() => SceneManager.LoadScene("Test")); 17 | DeterministicButton.onClick.AddListener(() => SceneManager.LoadScene("Deterministic")); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Ropes/RopeBend.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Ropes 4 | { 5 | public struct RopeBend 6 | { 7 | public int i1; 8 | 9 | public int i2; 10 | 11 | public int i3; 12 | 13 | public FP invMass1; 14 | 15 | public FP invMass2; 16 | 17 | public FP invMass3; 18 | 19 | public FP invEffectiveMass; 20 | 21 | public FP lambda; 22 | 23 | public FP L1, L2; 24 | 25 | public FP alpha1; 26 | 27 | public FP alpha2; 28 | 29 | public FP spring; 30 | 31 | public FP damper; 32 | }; 33 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: 8 | - enabled: 1 9 | path: Assets/Scenes/Init.unity 10 | guid: 79c7c302156531e4fa077558694321a5 11 | - enabled: 1 12 | path: Assets/Scenes/Test.unity 13 | guid: 2cda990e2423bbf4892e6590ba056729 14 | - enabled: 1 15 | path: Assets/Scenes/Deterministic.unity 16 | guid: ef2a0ebc31e23844b801eae538df4909 17 | m_configObjects: 18 | com.unity.input.settings: {fileID: 11400000, guid: 6aca77d95ee225648ac674145919689f, 19 | type: 2} 20 | -------------------------------------------------------------------------------- /src/Common/DumpLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Common 4 | { 5 | public static class DumpLogger 6 | { 7 | public static IDumpLogger Instance { get; set; } = new InternalDumpLogger(); 8 | 9 | public static void Log(string message) 10 | { 11 | Instance.Log(message); 12 | } 13 | } 14 | 15 | public interface IDumpLogger 16 | { 17 | void Log(string message); 18 | } 19 | 20 | public class InternalDumpLogger : IDumpLogger 21 | { 22 | /// 23 | public void Log(string message) 24 | { 25 | Console.WriteLine(message); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Collision/Collider/ContactFeature.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Collision.Collider 2 | { 3 | /// The features that intersect to form the contact point 4 | /// This must be 4 bytes or less. 5 | public struct ContactFeature 6 | { 7 | public enum FeatureType: byte 8 | { 9 | Vertex = 0, 10 | 11 | Face = 1 12 | } 13 | 14 | /// Feature index on shapeA 15 | public byte IndexA; 16 | 17 | /// Feature index on shapeB 18 | public byte IndexB; 19 | 20 | /// The feature type on shapeA 21 | public byte TypeA; 22 | 23 | /// The feature type on shapeB 24 | public byte TypeB; 25 | } 26 | } -------------------------------------------------------------------------------- /test/Testbed/Testbed.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 12 6 | net8.0 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/ConsoleTest/ConsoleTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | true 6 | 12 7 | net8.0 8 | 9 | 10 | 11 | full 12 | 13 | 14 | 15 | true 16 | full 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/Testbed/Tests/CompoundShapesRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class CompoundShapesRender : CompoundShapes 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 15 | ImGui.Begin("Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.Button("Spawn")) 18 | { 19 | base.Spawn(); 20 | } 21 | 22 | ImGui.End(); 23 | base.OnRender(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/UnityTest/UnityTest.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Assembly-CSharp.csproj", "{5620fb03-1d25-2454-624c-ad3996b1095c}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {5620fb03-1d25-2454-624c-ad3996b1095c}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {5620fb03-1d25-2454-624c-ad3996b1095c}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | EndGlobalSection 14 | GlobalSection(SolutionProperties) = preSolution 15 | HideSolutionNode = FALSE 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /test/Testbed/Program.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Mathematics; 2 | using OpenTK.Windowing.Desktop; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | Global.Settings = TestSettingHelper.Load(); 12 | Global.Camera.Width = Global.Settings.WindowWidth; 13 | Global.Camera.Height = Global.Settings.WindowHeight; 14 | using (var game = new Game( 15 | new GameWindowSettings {RenderFrequency = 60, UpdateFrequency = 60}, 16 | new NativeWindowSettings {Size = new Vector2i(Global.Settings.WindowWidth, Global.Settings.WindowHeight)})) 17 | { 18 | game.Run(); 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ContactSolverDef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Dynamics.Contacts 4 | { 5 | public ref struct ContactSolverDef 6 | { 7 | public readonly TimeStep Step; 8 | 9 | public readonly int ContactCount; 10 | 11 | public readonly Contact[] Contacts; 12 | 13 | public readonly Position[] Positions; 14 | 15 | public readonly Velocity[] Velocities; 16 | 17 | public ContactSolverDef(in TimeStep step, int contactCount, Contact[] contacts, Position[] positions, Velocity[] velocities) 18 | { 19 | Step = step; 20 | Contacts = contacts; 21 | ContactCount = contactCount; 22 | Positions = positions; 23 | Velocities = velocities; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/KeyModifiers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | [Flags] 6 | public enum KeyModifiers 7 | { 8 | /// if one or more Shift keys were held down. 9 | Shift = 1 << 0, 10 | 11 | /// If one or more Control keys were held down. 12 | Ctrl = 1 << 1, 13 | 14 | /// If one or more Alt keys were held down. 15 | Alt = 1 << 2, 16 | 17 | /// If one or more Super keys were held down. 18 | Super = 1 << 3, 19 | 20 | /// If caps lock is enabled. 21 | CapsLock = 1 << 4, 22 | 23 | /// If num lock is enabled. 24 | NumLock = 1 << 5 25 | } 26 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RensorsTestRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Tests 5 | { 6 | [TestInherit] 7 | public class RensorsTestRender : Sensors 8 | { 9 | /// 10 | protected override void OnRender() 11 | { 12 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 13 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 60.0f)); 14 | // ImGui.Begin("Sensor Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 15 | // var force = (float)_force; 16 | // ImGui.SliderFloat("Force", ref force, 0.0f, 2000.0f, "%.0f"); 17 | // _force = force; 18 | // ImGui.End(); 19 | base.OnRender(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ContactEdge.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Box2DSharp.Common; 3 | 4 | namespace Box2DSharp.Dynamics.Contacts 5 | { 6 | /// A contact edge is used to connect bodies and contacts together 7 | /// in a contact graph where each body is a node and each contact 8 | /// is an edge. A contact edge belongs to a doubly linked list 9 | /// maintained in each attached body. Each contact has two contact 10 | /// nodes, one for each attached body. 11 | public class ContactEdge 12 | { 13 | /// provides quick access to the other body attached. 14 | public Body Other; 15 | 16 | /// the contact 17 | public Contact Contact; 18 | 19 | public readonly LinkedListNode Node = new LinkedListNode(default); 20 | } 21 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/System.Buffers.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39d42b83bc6ae044b9ed8e3869c31d98 3 | PluginImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | iconMap: {} 7 | executionOrder: {} 8 | defineConstraints: [] 9 | isPreloaded: 0 10 | isOverridable: 0 11 | isExplicitlyReferenced: 0 12 | validateReferences: 1 13 | platformData: 14 | - first: 15 | Any: 16 | second: 17 | enabled: 1 18 | settings: {} 19 | - first: 20 | Editor: Editor 21 | second: 22 | enabled: 0 23 | settings: 24 | DefaultValueInitialized: true 25 | - first: 26 | Windows Store Apps: WindowsStoreApps 27 | second: 28 | enabled: 0 29 | settings: 30 | CPU: AnyCPU 31 | userData: 32 | assetBundleName: 33 | assetBundleVariant: 34 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/System.Memory.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e078736bfc62344cab58e1413dac033 3 | PluginImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | iconMap: {} 7 | executionOrder: {} 8 | defineConstraints: [] 9 | isPreloaded: 0 10 | isOverridable: 0 11 | isExplicitlyReferenced: 0 12 | validateReferences: 1 13 | platformData: 14 | - first: 15 | Any: 16 | second: 17 | enabled: 1 18 | settings: {} 19 | - first: 20 | Editor: Editor 21 | second: 22 | enabled: 0 23 | settings: 24 | DefaultValueInitialized: true 25 | - first: 26 | Windows Store Apps: WindowsStoreApps 27 | second: 28 | enabled: 0 29 | settings: 30 | CPU: AnyCPU 31 | userData: 32 | assetBundleName: 33 | assetBundleVariant: 34 | -------------------------------------------------------------------------------- /test/Testbed.Abstractions/KeyInputEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public readonly struct KeyInputEventArgs 4 | { 5 | public readonly KeyCodes Key; 6 | 7 | public readonly KeyModifiers Modifiers; 8 | 9 | public readonly bool IsRepeat; 10 | 11 | public bool Alt => Modifiers.HasSetFlag(KeyModifiers.Alt); 12 | 13 | public bool Control => Modifiers.HasSetFlag(KeyModifiers.Ctrl); 14 | 15 | public bool Shift => Modifiers.HasSetFlag(KeyModifiers.Shift); 16 | 17 | public bool Command => Modifiers.HasSetFlag(KeyModifiers.Super); 18 | 19 | public KeyInputEventArgs(KeyCodes key, KeyModifiers modifiers, bool isRepeat) 20 | { 21 | Key = key; 22 | Modifiers = modifiers; 23 | IsRepeat = isRepeat; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/System.Runtime.CompilerServices.Unsafe.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d563cd1f317edb04489b1238a96056e5 3 | PluginImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | iconMap: {} 7 | executionOrder: {} 8 | defineConstraints: [] 9 | isPreloaded: 0 10 | isOverridable: 0 11 | isExplicitlyReferenced: 0 12 | validateReferences: 1 13 | platformData: 14 | - first: 15 | Any: 16 | second: 17 | enabled: 1 18 | settings: {} 19 | - first: 20 | Editor: Editor 21 | second: 22 | enabled: 0 23 | settings: 24 | DefaultValueInitialized: true 25 | - first: 26 | Windows Store Apps: WindowsStoreApps 27 | second: 28 | enabled: 0 29 | settings: 30 | CPU: AnyCPU 31 | userData: 32 | assetBundleName: 33 | assetBundleVariant: 34 | -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ContactPositionConstraint.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Collider; 2 | using Box2DSharp.Common; 3 | 4 | namespace Box2DSharp.Dynamics.Contacts 5 | { 6 | public struct ContactPositionConstraint 7 | { 8 | /// 9 | /// Size 10 | /// 11 | public FixedArray2 LocalPoints; 12 | 13 | public int IndexA; 14 | 15 | public int IndexB; 16 | 17 | public FP InvIa, InvIb; 18 | 19 | public FP InvMassA, InvMassB; 20 | 21 | public FVector2 LocalCenterA, LocalCenterB; 22 | 23 | public FVector2 LocalNormal; 24 | 25 | public FVector2 LocalPoint; 26 | 27 | public int PointCount; 28 | 29 | public FP RadiusA, RadiusB; 30 | 31 | public ManifoldType Type; 32 | } 33 | } -------------------------------------------------------------------------------- /test/Testbed/Tests/RensorsTestRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class RensorsTestRender : Sensors 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(200.0f, 60.0f)); 15 | ImGui.Begin("Sensor Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | var force = (float)_force; 18 | if (ImGui.SliderFloat("Force", ref force, 0.0f, 2000.0f, "%.0f")) 19 | { 20 | _force = force; 21 | } 22 | 23 | ImGui.End(); 24 | base.OnRender(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Dynamics/BodyFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Dynamics 4 | { 5 | [Flags] 6 | public enum BodyFlags 7 | { 8 | /// 9 | /// 孤岛 10 | /// 11 | Island = 1 << 0, 12 | 13 | /// 14 | /// 醒着的 15 | /// 16 | IsAwake = 1 << 1, 17 | 18 | /// 19 | /// 自动休眠 20 | /// 21 | AutoSleep = 1 << 2, 22 | 23 | /// 24 | /// 子弹 25 | /// 26 | IsBullet = 1 << 3, 27 | 28 | /// 29 | /// 30 | FixedRotation = 1 << 4, 31 | 32 | /// 33 | /// 活跃 34 | /// 35 | IsEnabled = 1 << 5, 36 | 37 | /// 38 | /// 碰撞时间 39 | /// 40 | Toi = 1 << 6 41 | } 42 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ContactVelocityConstraint.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Contacts 4 | { 5 | public struct ContactVelocityConstraint 6 | { 7 | /// 8 | /// Size 9 | /// 10 | public FixedArray2 Points; 11 | 12 | public int ContactIndex; 13 | 14 | public FP Friction; 15 | 16 | public int IndexA; 17 | 18 | public int IndexB; 19 | 20 | public FP InvIa, InvIb; 21 | 22 | public FP InvMassA, InvMassB; 23 | 24 | public Matrix2x2 K; 25 | 26 | public FVector2 Normal; 27 | 28 | public Matrix2x2 NormalMass; 29 | 30 | public int PointCount; 31 | 32 | public FP Restitution; 33 | 34 | public FP Threshold; 35 | 36 | public FP TangentSpeed; 37 | } 38 | } -------------------------------------------------------------------------------- /src/Common/DrawFlag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Common 4 | { 5 | [Flags] 6 | public enum DrawFlag 7 | { 8 | /// 9 | /// draw shapes 10 | /// 11 | DrawShape = 1 << 0, 12 | 13 | /// 14 | /// draw joint connections 15 | /// 16 | DrawJoint = 1 << 1, 17 | 18 | /// 19 | /// draw axis aligned bounding boxes 20 | /// 21 | DrawAABB = 1 << 2, 22 | 23 | /// 24 | /// draw broad-phase pairs 25 | /// 26 | DrawPair = 1 << 3, 27 | 28 | /// 29 | /// draw center of mass frame 30 | /// 31 | DrawCenterOfMass = 1 << 4, 32 | 33 | /// 34 | /// draw body contact point 35 | /// 36 | DrawContactPoint = 1 << 5 37 | } 38 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/InputSystem.inputsettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: c46f07b5ed07e4e92aa78254188d3d10, type: 3} 13 | m_Name: InputSystem.inputsettings 14 | m_EditorClassIdentifier: 15 | m_SupportedDevices: 16 | - Keyboard 17 | - Mouse 18 | - Touchscreen 19 | m_UpdateMode: 1 20 | m_CompensateForScreenOrientation: 1 21 | m_FilterNoiseOnCurrent: 0 22 | m_DefaultDeadzoneMin: 0.125 23 | m_DefaultDeadzoneMax: 0.925 24 | m_DefaultButtonPressPoint: 0.5 25 | m_DefaultTapTime: 0.2 26 | m_DefaultSlowTapTime: 0.5 27 | m_DefaultHoldTime: 0.4 28 | m_TapRadius: 5 29 | m_MultiTapDelayTime: 0.75 30 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/CompoundShapesRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace Box2DSharp.Testbed.Unity.Tests 6 | { 7 | [TestInherit] 8 | public class CompoundShapesRender : CompoundShapes 9 | { 10 | private GameObject CanvasObj; 11 | 12 | private Canvas Canvas; 13 | 14 | /// 15 | protected override void OnRender() 16 | { 17 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 18 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 19 | // ImGui.Begin("Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 20 | // 21 | // if (ImGui.Button("Spawn")) 22 | // { 23 | // Spawn(); 24 | // } 25 | // 26 | // ImGui.End(); 27 | base.OnRender(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Common/Math/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Box2DSharp.Dynamics; 3 | using Box2DSharp.Dynamics.Contacts; 4 | 5 | namespace Box2DSharp.Common 6 | { 7 | public static class EnumExtensions 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static bool HasSetFlag(this BodyFlags flags, BodyFlags flag) 11 | { 12 | return (flags & flag) != 0; 13 | } 14 | 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static bool HasSetFlag(this Contact.ContactFlag flags, Contact.ContactFlag flag) 17 | { 18 | return (flags & flag) != 0; 19 | } 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | public static bool HasSetFlag(this DrawFlag flags, DrawFlag flag) 23 | { 24 | return (flags & flag) != 0; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Inspection/MouseInspector.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.InputSystem; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Inspection 5 | { 6 | public class MouseInspector : MonoBehaviour 7 | { 8 | public Vector2 WorldMouse; 9 | 10 | public Vector2 ScreenMouse; 11 | 12 | public Vector2 ViewPortMouse; 13 | 14 | public Camera MainCamera; 15 | 16 | public bool HasMouse; 17 | 18 | private void Start() 19 | { 20 | MainCamera = Camera.main; 21 | HasMouse = Mouse.current != null; 22 | } 23 | 24 | private void Update() 25 | { 26 | if (HasMouse) 27 | { 28 | ScreenMouse = Mouse.current.position.ReadValue(); 29 | WorldMouse = MainCamera.ScreenToWorldPoint(ScreenMouse); 30 | ViewPortMouse = MainCamera.ScreenToViewportPoint(ScreenMouse); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Dynamics/Joints/GearJointDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Joints 4 | { 5 | /// 6 | /// Gear joint definition. This definition requires two existing 7 | /// revolute or prismatic joints (any combination will work). 8 | /// @warning bodyB on the input joints must both be dynamic 9 | /// 10 | public class GearJointDef : JointDef 11 | { 12 | /// The first revolute/prismatic joint attached to the gear joint. 13 | public Joint Joint1; 14 | 15 | /// The second revolute/prismatic joint attached to the gear joint. 16 | public Joint Joint2; 17 | 18 | /// The gear ratio. 19 | /// @see b2GearJoint for explanation. 20 | public FP Ratio; 21 | 22 | public GearJointDef() 23 | { 24 | JointType = JointType.GearJoint; 25 | Joint1 = null; 26 | Joint2 = null; 27 | Ratio = 1.0f; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/Testbed/Tests/EdgeTestRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class EdgeTestRender : EdgeTest 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 15 | ImGui.Begin("Custom Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.RadioButton("Boxes", Boxes == true)) 18 | { 19 | CreateBoxes(); 20 | Boxes = true; 21 | } 22 | 23 | if (ImGui.RadioButton("Circles", Boxes == false)) 24 | { 25 | CreateCircles(); 26 | Boxes = false; 27 | } 28 | 29 | ImGui.End(); 30 | base.OnRender(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/FpsCounter.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | public class FpsCounter 6 | { 7 | public float Ms = 0; 8 | 9 | public float Fps = 0; 10 | 11 | public int FrameCount = 0; 12 | 13 | private float _totalDiff = 0; 14 | 15 | private long _lastTimeDiff = 0; 16 | 17 | private long _lastTime = 0; 18 | 19 | private readonly Stopwatch _fpsTimer = Stopwatch.StartNew(); 20 | 21 | public void Count() 22 | { 23 | FrameCount++; 24 | var now = _fpsTimer.ElapsedMilliseconds; 25 | _lastTimeDiff = now - _lastTime; 26 | _totalDiff += _lastTimeDiff; 27 | _lastTime = now; 28 | 29 | if (_totalDiff > 1000) 30 | { 31 | Ms = _totalDiff / FrameCount; 32 | Fps = FrameCount / _totalDiff * 1000; 33 | _totalDiff = 0; 34 | FrameCount = 0; 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /test/Testbed.Abstractions/MouseInputEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public readonly struct MouseInputEventArgs 4 | { 5 | /// 6 | /// Initializes a new instance of the struct. 7 | /// 8 | /// The mouse button for the event. 9 | /// The action of the mouse button. 10 | /// The key modifiers held during the mouse button's action. 11 | public MouseInputEventArgs(MouseButton button, InputAction action, KeyModifiers modifiers) 12 | { 13 | Button = button; 14 | Action = action; 15 | Modifiers = modifiers; 16 | } 17 | 18 | public MouseButton Button { get; } 19 | 20 | public InputAction Action { get; } 21 | 22 | public KeyModifiers Modifiers { get; } 23 | 24 | public bool IsPressed => Action != InputAction.Release; 25 | } 26 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/MathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Box2DSharp.Common; 3 | 4 | namespace Testbed.Abstractions 5 | { 6 | public static class MathExtensions 7 | { 8 | public static void Set(ref this Vector2 vector2, float x, float y) 9 | { 10 | vector2.X = x; 11 | vector2.Y = y; 12 | } 13 | 14 | public static FVector2 ToFVector2(in this Vector2 vector2) 15 | { 16 | return new FVector2(vector2.X, vector2.Y); 17 | } 18 | 19 | public static Vector2 ToVector2(in this FVector2 vector2) 20 | { 21 | return new Vector2((float)vector2.X, (float)vector2.Y); 22 | } 23 | 24 | public static FVector3 ToFVector3(in this Vector3 vector3) 25 | { 26 | return new FVector3(vector3.X, vector3.Y, vector3.Z); 27 | } 28 | 29 | public static Vector3 ToVector3(in this FVector3 vector3) 30 | { 31 | return new Vector3((float)vector3.X, (float)vector3.Y, (float)vector3.Z); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/EdgeTestRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Tests 5 | { 6 | [TestInherit] 7 | public class EdgeTestRender : EdgeTest 8 | { 9 | /// 10 | protected override void OnRender() 11 | { 12 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 13 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 14 | // ImGui.Begin("Custom Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 15 | // 16 | // if (ImGui.RadioButton("Boxes", Boxes)) 17 | // { 18 | // CreateBoxes(); 19 | // Boxes = true; 20 | // } 21 | // 22 | // if (ImGui.RadioButton("Circles", Boxes == false)) 23 | // { 24 | // CreateCircles(); 25 | // Boxes = false; 26 | // } 27 | // 28 | // ImGui.End(); 29 | base.OnRender(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Dynamics/DefaultContactFilter.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp.Dynamics 2 | { 3 | /// Implement this class to provide collision filtering. In other words, you can implement 4 | /// this class if you want finer control over contact creation. 5 | public sealed class DefaultContactFilter : IContactFilter 6 | { 7 | /// Return true if contact calculations should be performed between these two shapes. 8 | /// @warning for performance reasons this is only called when the AABBs begin to overlap. 9 | public bool ShouldCollide(Fixture fixtureA, Fixture fixtureB) 10 | { 11 | var filterA = fixtureA.Filter; 12 | var filterB = fixtureB.Filter; 13 | 14 | if (filterA.GroupIndex == filterB.GroupIndex && filterA.GroupIndex != 0) 15 | { 16 | return filterA.GroupIndex > 0; 17 | } 18 | 19 | var collide = (filterA.MaskBits & filterB.CategoryBits) != 0 20 | && (filterA.CategoryBits & filterB.MaskBits) != 0; 21 | return collide; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/Position.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Extra", "Position Test")] 9 | public class Position : TestBase 10 | { 11 | /// 12 | public Position() 13 | { 14 | var gshape = new EdgeShape(); 15 | gshape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 16 | 17 | var ground = World.CreateBody(new BodyDef() {BodyType = BodyType.StaticBody, Position = new FVector2(0, -5)}) 18 | .CreateFixture(gshape, 1.0f); 19 | for (var i = 0; i < 100; i++) 20 | { 21 | var b1 = World.CreateBody( 22 | new BodyDef() {BodyType = BodyType.DynamicBody, Position = new FVector2(RandomFloat(0, 5), RandomFloat(0, 5))}); 23 | var shape = new CircleShape() {Radius = 1}; 24 | 25 | b1.CreateFixture(shape, 1.0f); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Common/Drawer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Common 4 | { 5 | public interface IDraw 6 | { 7 | DrawFlag Flags { get; set; } 8 | 9 | /// Draw a closed polygon provided in CCW order. 10 | void DrawPolygon(Span vertices, int vertexCount, in Color color); 11 | 12 | /// Draw a solid closed polygon provided in CCW order. 13 | void DrawSolidPolygon(Span vertices, int vertexCount, in Color color); 14 | 15 | /// Draw a circle. 16 | void DrawCircle(in FVector2 center, FP radius, in Color color); 17 | 18 | /// Draw a solid circle. 19 | void DrawSolidCircle(in FVector2 center, FP radius, in FVector2 axis, in Color color); 20 | 21 | /// Draw a line segment. 22 | void DrawSegment(in FVector2 p1, in FVector2 p2, in Color color); 23 | 24 | /// Draw a transform. Choose your own length scale. 25 | /// @param xf a transform. 26 | void DrawTransform(in Transform xf); 27 | 28 | /// Draw a point. 29 | void DrawPoint(in FVector2 p, FP size, in Color color); 30 | } 31 | } -------------------------------------------------------------------------------- /LICENSE-Box2D.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Erin Catto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Dynamics/Joints/MouseJointDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Joints 4 | { 5 | /// Mouse joint definition. This requires a world target point, 6 | /// tuning parameters, and the time step. 7 | public class MouseJointDef : JointDef 8 | { 9 | /// The damping ratio. 0 = no damping, 1 = critical damping. 10 | public FP Damping; 11 | 12 | /// The response speed. 13 | public FP Stiffness; 14 | 15 | /// The maximum constraint force that can be exerted 16 | /// to move the candidate body. Usually you will express 17 | /// as some multiple of the weight (multiplier * mass * gravity). 18 | public FP MaxForce; 19 | 20 | /// The initial world target point. This is assumed 21 | /// to coincide with the body anchor initially. 22 | public FVector2 Target; 23 | 24 | public MouseJointDef() 25 | { 26 | JointType = JointType.MouseJoint; 27 | Target.Set(0.0f, 0.0f); 28 | MaxForce = 0.0f; 29 | Stiffness = 5.0f; 30 | Damping = 0.7f; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /test/UnitTest/UnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | net6.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-present JunChao Liang(Zonciu Liang) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /test/Testbed/Tests/WreckingBallRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class WreckingBallRender : WreckingBall 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | base.OnRender(); 14 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 15 | ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 16 | ImGui.Begin("Wrecking Ball Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 17 | 18 | if (ImGui.Checkbox("Stabilize", ref _stabilize)) 19 | { 20 | if (_stabilize == true && _distanceJoint == null) 21 | { 22 | _distanceJoint = World.CreateJoint(_distanceJointDef); 23 | } 24 | else if (_stabilize == false && _distanceJoint != null) 25 | { 26 | World.DestroyJoint(_distanceJoint); 27 | _distanceJoint = null; 28 | } 29 | } 30 | 31 | ImGui.End(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Collision/Collider/ManifoldPoint.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision.Collider 4 | { 5 | /// A manifold point is a contact point belonging to a contact 6 | /// manifold. It holds details related to the geometry and dynamics 7 | /// of the contact points. 8 | /// The local point usage depends on the manifold type: 9 | /// -e_circles: the local center of circleB 10 | /// -e_faceA: the local center of cirlceB or the clip point of polygonB 11 | /// -e_faceB: the clip point of polygonA 12 | /// This structure is stored across time steps, so we keep it small. 13 | /// Note: the impulses are used for internal caching and may not 14 | /// provide reliable contact forces, especially for high speed collisions. 15 | public struct ManifoldPoint 16 | { 17 | /// usage depends on manifold type 18 | public FVector2 LocalPoint; 19 | 20 | /// the non-penetration impulse 21 | public FP NormalImpulse; 22 | 23 | /// /// the friction impulse 24 | public FP TangentImpulse; 25 | 26 | /// uniquely identifies a contact point between two shapes 27 | public ContactId Id; 28 | } 29 | } -------------------------------------------------------------------------------- /test/Testbed/TestSettingHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | using Testbed.Abstractions; 6 | 7 | namespace Testbed 8 | { 9 | public static class TestSettingHelper 10 | { 11 | public static void Save(TestSettings settings) 12 | { 13 | var json = JsonConvert.SerializeObject( 14 | settings, 15 | new JsonSerializerSettings 16 | { 17 | Formatting = Formatting.Indented, 18 | ContractResolver = new CamelCasePropertyNamesContractResolver() 19 | }); 20 | File.WriteAllText("settings.ini", json); 21 | } 22 | 23 | public static TestSettings Load() 24 | { 25 | try 26 | { 27 | var json = File.ReadAllText("settings.ini"); 28 | return JsonConvert.DeserializeObject(json); 29 | } 30 | catch (Exception) 31 | { 32 | // ignored error, retuen default setting 33 | return new TestSettings(); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/TestSettingHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity 6 | { 7 | public static class TestSettingHelper 8 | { 9 | private static string SettingFilePath = Path.Combine(Application.persistentDataPath, "settings.ini"); 10 | 11 | public static void Save(UnityTestSettings settings) 12 | { 13 | var json = JsonUtility.ToJson(settings, true); 14 | 15 | File.WriteAllText(SettingFilePath, json); 16 | } 17 | 18 | public static UnityTestSettings Load() 19 | { 20 | try 21 | { 22 | var json = File.ReadAllText(SettingFilePath); 23 | var settings = JsonUtility.FromJson(json); 24 | settings.Pause = false; 25 | settings.SingleStep = false; 26 | return settings; 27 | } 28 | catch (Exception e) 29 | { 30 | Debug.Log(e.Message); 31 | 32 | // ignored error, retuen default setting 33 | return new UnityTestSettings(); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/Testbed/Tests/RevoluteJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class RevoluteJointTestRender : RevoluteJointTest 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 15 | ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.Checkbox("Limit", ref EnableLimit)) 18 | { 19 | Joint1.EnableLimit(EnableLimit); 20 | } 21 | 22 | if (ImGui.Checkbox("Motor", ref EnableMotor)) 23 | { 24 | Joint1.EnableMotor(EnableMotor); 25 | } 26 | 27 | var speed = (float)MotorSpeed; 28 | if (ImGui.SliderFloat("Speed", ref speed, -20.0f, 20.0f, "%.0f")) 29 | { 30 | MotorSpeed = speed; 31 | Joint1.SetMotorSpeed(MotorSpeed); 32 | } 33 | 34 | ImGui.End(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/Heavy1.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Solver", "Heavy 1")] 9 | public class Heavy1 : TestBase 10 | { 11 | public Heavy1() 12 | { 13 | { 14 | var bd = new BodyDef(); 15 | var ground = World.CreateBody(bd); 16 | 17 | var shape = new EdgeShape(); 18 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 19 | ground.CreateFixture(shape, 0.0f); 20 | } 21 | { 22 | var bd = new BodyDef {BodyType = BodyType.DynamicBody, Position = new FVector2(0.0f, 0.5f)}; 23 | var body = World.CreateBody(bd); 24 | 25 | var shape = new CircleShape {Radius = 0.5f}; 26 | body.CreateFixture(shape, 10.0f); 27 | 28 | bd.Position = new FVector2(0.0f, 6.0f); 29 | body = World.CreateBody(bd); 30 | shape.Radius = 5.0f; 31 | body.CreateFixture(shape, 10.0f); 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 8 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_EnablePreviewPackages: 1 16 | m_EnablePackageDependencies: 0 17 | m_AdvancedSettingsExpanded: 1 18 | m_ScopedRegistriesSettingsExpanded: 1 19 | oneTimeWarningShown: 1 20 | m_Registries: 21 | - m_Id: main 22 | m_Name: 23 | m_Url: https://packages.unity.cn 24 | m_Scopes: [] 25 | m_IsDefault: 1 26 | m_Capabilities: 7 27 | m_UserSelectedRegistryName: 28 | m_UserAddingNewScopedRegistry: 0 29 | m_RegistryInfoDraft: 30 | m_ErrorMessage: 31 | m_Original: 32 | m_Id: 33 | m_Name: 34 | m_Url: 35 | m_Scopes: [] 36 | m_IsDefault: 0 37 | m_Capabilities: 0 38 | m_Modified: 0 39 | m_Name: 40 | m_Url: 41 | m_Scopes: 42 | - 43 | m_SelectedScopeIndex: 0 44 | -------------------------------------------------------------------------------- /test/Testbed/Tests/WheelJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class WheelJointTestRender : WheelJointTest 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 15 | ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.Checkbox("Limit", ref EnableLimit)) 18 | { 19 | Joint.EnableLimit(EnableLimit); 20 | } 21 | 22 | if (ImGui.Checkbox("Motor", ref EnableMotor)) 23 | { 24 | Joint.EnableMotor(EnableMotor); 25 | } 26 | 27 | var speed = (float)MotorSpeed; 28 | if (ImGui.SliderFloat("Speed", ref speed, -100.0f, 100.0f, "%.0f")) 29 | { 30 | MotorSpeed = speed; 31 | Joint.SetMotorSpeed(MotorSpeed); 32 | } 33 | 34 | ImGui.End(); 35 | base.OnRender(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Ropes/RopeTuning.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Ropes 4 | { 5 | /// 6 | public class RopeTuning 7 | { 8 | public RopeTuning() 9 | { 10 | StretchingModel = StretchingModel.PbdStretchingModel; 11 | BendingModel = BendingModel.PbdAngleBendingModel; 12 | Damping = 0.0f; 13 | StretchStiffness = 1.0f; 14 | StretchHertz = 1.0f; 15 | StretchDamping = 0.0f; 16 | BendStiffness = 0.5f; 17 | BendHertz = 1.0f; 18 | BendDamping = 0.0f; 19 | Isometric = false; 20 | FixedEffectiveMass = false; 21 | WarmStart = false; 22 | } 23 | 24 | public StretchingModel StretchingModel; 25 | 26 | public BendingModel BendingModel; 27 | 28 | public FP Damping; 29 | 30 | public FP StretchStiffness; 31 | 32 | public FP StretchHertz; 33 | 34 | public FP StretchDamping; 35 | 36 | public FP BendStiffness; 37 | 38 | public FP BendHertz; 39 | 40 | public FP BendDamping; 41 | 42 | public bool Isometric; 43 | 44 | public bool FixedEffectiveMass; 45 | 46 | public bool WarmStart; 47 | }; 48 | } -------------------------------------------------------------------------------- /test/Testbed/Tests/PrismaticJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class PrismaticJointTestRender : PrismaticJointTest 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 15 | ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.Checkbox("Limit", ref EnableLimit)) 18 | { 19 | Joint.EnableLimit(EnableLimit); 20 | } 21 | 22 | if (ImGui.Checkbox("Motor", ref EnableMotor)) 23 | { 24 | Joint.EnableMotor(EnableMotor); 25 | } 26 | 27 | var speed = (float)MotorSpeed; 28 | if (ImGui.SliderFloat("Speed", ref speed, -100.0f, 100.0f, "%.0f")) 29 | { 30 | MotorSpeed = speed; 31 | Joint.SetMotorSpeed(MotorSpeed); 32 | } 33 | 34 | ImGui.End(); 35 | base.OnRender(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/WreckingBallRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Tests 5 | { 6 | [TestInherit] 7 | public class WreckingBallRender : WreckingBall 8 | { 9 | /// 10 | protected override void OnRender() 11 | { 12 | base.OnRender(); 13 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 15 | // ImGui.Begin("Wrecking Ball Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | // 17 | // if (ImGui.Checkbox("Stabilize", ref _stabilize)) 18 | // { 19 | // if (_stabilize && _distanceJoint == null) 20 | // { 21 | // _distanceJoint = World.CreateJoint(_distanceJointDef); 22 | // } 23 | // else if (_stabilize == false && _distanceJoint != null) 24 | // { 25 | // World.DestroyJoint(_distanceJoint); 26 | // _distanceJoint = null; 27 | // } 28 | // } 29 | // 30 | // ImGui.End(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /test/UnitTest/MathTest.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Shouldly; 4 | using Xunit; 5 | 6 | namespace UnitTest 7 | { 8 | public class MathTest 9 | { 10 | [Fact(DisplayName = "sweep")] 11 | public void Sweep() 12 | { 13 | // From issue #447 14 | Sweep sweep = new Sweep(); 15 | sweep.LocalCenter.SetZero(); 16 | sweep.C0.Set(-2.0f, 4.0f); 17 | sweep.C.Set(3.0f, 8.0f); 18 | sweep.A0 = 0.5f; 19 | sweep.A = 5.0f; 20 | sweep.Alpha0 = 0.0f; 21 | 22 | Transform transform; 23 | 24 | sweep.GetTransform(out transform, 0.0f); 25 | transform.Position.X.ShouldBe(sweep.C0.X); 26 | transform.Position.Y.ShouldBe(sweep.C0.Y); 27 | transform.Rotation.Cos.ShouldBe(FP.Cos(sweep.A0)); 28 | transform.Rotation.Sin.ShouldBe(FP.Sin(sweep.A0)); 29 | 30 | sweep.GetTransform(out transform, 1.0f); 31 | transform.Position.X.ShouldBe(sweep.C.X); 32 | transform.Position.Y.ShouldBe(sweep.C.Y); 33 | transform.Rotation.Cos.ShouldBe(FP.Cos(sweep.A)); 34 | transform.Rotation.Sin.ShouldBe(FP.Sin(sweep.A)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RevoluteJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Tests 5 | { 6 | [TestInherit] 7 | public class RevoluteJointTestRender : RevoluteJointTest 8 | { 9 | /// 10 | protected override void OnRender() 11 | { 12 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 13 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 14 | // ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 15 | // 16 | // if (ImGui.Checkbox("Limit", ref EnableLimit)) 17 | // { 18 | // Joint1.EnableLimit(EnableLimit); 19 | // } 20 | // 21 | // if (ImGui.Checkbox("Motor", ref EnableMotor)) 22 | // { 23 | // Joint1.EnableMotor(EnableMotor); 24 | // } 25 | // var speed = (float)MotorSpeed; 26 | // if (ImGui.SliderFloat("Speed", ref speed, -20.0f, 20.0f, "%.0f")) 27 | // { 28 | // MotorSpeed = speed; 29 | // Joint1.SetMotorSpeed(MotorSpeed); 30 | // } 31 | // 32 | // ImGui.End(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 9 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 2 10 | m_DefaultBehaviorMode: 1 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 4 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref 20 | m_ProjectGenerationRootNamespace: Box2DSharp.Testbed.Unity 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 1 30 | m_AssetPipelineMode: 1 31 | m_CacheServerMode: 0 32 | m_CacheServerEndpoint: 33 | m_CacheServerNamespacePrefix: default 34 | m_CacheServerEnableDownload: 1 35 | m_CacheServerEnableUpload: 1 36 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/PrismaticJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | 3 | namespace Box2DSharp.Testbed.Unity.Tests 4 | { 5 | [TestInherit] 6 | public class PrismaticJointTestRender : PrismaticJointTest 7 | { 8 | /// 9 | protected override void OnRender() 10 | { 11 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 12 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 13 | // ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 14 | // 15 | // if (ImGui.Checkbox("Limit", ref EnableLimit)) 16 | // { 17 | // Joint.EnableLimit(EnableLimit); 18 | // } 19 | // 20 | // if (ImGui.Checkbox("Motor", ref EnableMotor)) 21 | // { 22 | // Joint.EnableMotor(EnableMotor); 23 | // } 24 | // 25 | // var speed = (float)MotorSpeed; 26 | // if (ImGui.SliderFloat("Speed", ref speed, -100.0f, 100.0f, "%.0f")) 27 | // { 28 | // MotorSpeed = speed; 29 | // Joint.SetMotorSpeed(MotorSpeed); 30 | // } 31 | // 32 | // ImGui.End(); 33 | base.OnRender(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/Global.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Testbed.Abstractions 7 | { 8 | public static class Global 9 | { 10 | public static IDebugDraw DebugDraw { get; set; } 11 | 12 | public static readonly Camera Camera = new Camera(); 13 | 14 | public static TestSettings Settings { get; set; } 15 | 16 | public static IInput Input { get; set; } 17 | 18 | public static List<(string Category, string Name, Type TestType)> Tests { get; private set; } 19 | 20 | public static void SetupTestCases(List testTypes) 21 | { 22 | var testBaseType = typeof(TestBase); 23 | Tests = testTypes 24 | .Where(e => testBaseType.IsAssignableFrom(e) && !e.IsAbstract) 25 | .Select( 26 | e => 27 | { 28 | var testCase = e.GetCustomAttribute() ?? throw new NullReferenceException(e.Name); 29 | return (testCase.Category, testCase.Name, e); 30 | }) 31 | .OrderBy(e => e.Category) 32 | .ThenBy(e => e.Name) 33 | .ToList(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/WheelJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Tests 5 | { 6 | [TestInherit] 7 | public class WheelJointTestRender : WheelJointTest 8 | { 9 | /// 10 | protected override void OnRender() 11 | { 12 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 13 | // ImGui.SetNextWindowSize(new Vector2(200.0f, 100.0f)); 14 | // ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 15 | // 16 | // if (ImGui.Checkbox("Limit", ref EnableLimit)) 17 | // { 18 | // Joint.EnableLimit(EnableLimit); 19 | // } 20 | // 21 | // if (ImGui.Checkbox("Motor", ref EnableMotor)) 22 | // { 23 | // Joint.EnableMotor(EnableMotor); 24 | // } 25 | // 26 | // var speed = (float)MotorSpeed; 27 | // if (ImGui.SliderFloat("Speed", ref speed, -100.0f, 100.0f, "%.0f")) 28 | // { 29 | // MotorSpeed = speed; 30 | // Joint.SetMotorSpeed(MotorSpeed); 31 | // } 32 | // 33 | // ImGui.End(); 34 | base.OnRender(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/MemorySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!387306366 &1 4 | MemorySettings: 5 | m_ObjectHideFlags: 0 6 | m_EditorMemorySettings: 7 | m_MainAllocatorBlockSize: -1 8 | m_ThreadAllocatorBlockSize: -1 9 | m_MainGfxBlockSize: -1 10 | m_ThreadGfxBlockSize: -1 11 | m_CacheBlockSize: -1 12 | m_TypetreeBlockSize: -1 13 | m_ProfilerBlockSize: -1 14 | m_ProfilerEditorBlockSize: -1 15 | m_BucketAllocatorGranularity: -1 16 | m_BucketAllocatorBucketsCount: -1 17 | m_BucketAllocatorBlockSize: -1 18 | m_BucketAllocatorBlockCount: -1 19 | m_ProfilerBucketAllocatorGranularity: -1 20 | m_ProfilerBucketAllocatorBucketsCount: -1 21 | m_ProfilerBucketAllocatorBlockSize: -1 22 | m_ProfilerBucketAllocatorBlockCount: -1 23 | m_TempAllocatorSizeMain: -1 24 | m_JobTempAllocatorBlockSize: -1 25 | m_BackgroundJobTempAllocatorBlockSize: -1 26 | m_JobTempAllocatorReducedBlockSize: -1 27 | m_TempAllocatorSizeGIBakingWorker: -1 28 | m_TempAllocatorSizeNavMeshWorker: -1 29 | m_TempAllocatorSizeAudioWorker: -1 30 | m_TempAllocatorSizeCloudWorker: -1 31 | m_TempAllocatorSizeGfx: -1 32 | m_TempAllocatorSizeJobWorker: -1 33 | m_TempAllocatorSizeBackgroundWorker: -1 34 | m_TempAllocatorSizePreloadManager: -1 35 | m_PlatformMemorySettings: {} 36 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Deterministic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using UnityEngine; 5 | using UnityEngine.SceneManagement; 6 | using UnityEngine.UI; 7 | 8 | namespace Box2DSharp.Testbed.Unity 9 | { 10 | public class Deterministic : MonoBehaviour 11 | { 12 | public Text HashText; 13 | 14 | public Button ExitButton; 15 | 16 | public string hash = "testing..."; 17 | 18 | private DeterministicTester _tester; 19 | 20 | public void Start() 21 | { 22 | ExitButton.onClick.AddListener(() => SceneManager.LoadScene("Init")); 23 | _tester = new DeterministicTester(); 24 | Task.Factory.StartNew( 25 | () => 26 | { 27 | var res = _tester.TestTumbler(3000, 400); 28 | hash = res.Hash; 29 | var path = Path.Combine(Application.persistentDataPath, "TestTumbler.txt"); 30 | if (File.Exists(path)) 31 | { 32 | File.Delete(path); 33 | } 34 | 35 | File.WriteAllText(path, res.Data); 36 | Debug.Log($"Data write to {path}"); 37 | }); 38 | } 39 | 40 | private void FixedUpdate() 41 | { 42 | HashText.text = $"{hash} {_tester.Step}/3000"; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Common/Transform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp.Common 4 | { 5 | public struct Transform : IFormattable 6 | { 7 | public FVector2 Position; 8 | 9 | public Rotation Rotation; 10 | 11 | /// Initialize using a position vector and a rotation. 12 | public Transform(in FVector2 position, in Rotation rotation) 13 | { 14 | Position = position; 15 | Rotation = rotation; 16 | } 17 | 18 | public Transform(in FVector2 position, FP angle) 19 | { 20 | Position = position; 21 | Rotation = new Rotation(angle); 22 | } 23 | 24 | /// Set this to the identity transform. 25 | public void SetIdentity() 26 | { 27 | Position = FVector2.Zero; 28 | Rotation.SetIdentity(); 29 | } 30 | 31 | /// Set this based on the position and angle. 32 | public void Set(in FVector2 position, FP angle) 33 | { 34 | Position = position; 35 | Rotation.Set(angle); 36 | } 37 | 38 | /// 39 | public string ToString(string format, IFormatProvider formatProvider) 40 | { 41 | return ToString(); 42 | } 43 | 44 | public new string ToString() 45 | { 46 | return $"({Position.X},{Position.Y}), Cos:{Rotation.Cos}, Sin:{Rotation.Sin})"; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/CircleStack.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Stacking", "Circles")] 9 | public class CircleStack : TestBase 10 | { 11 | private const int Count = 10; 12 | 13 | private readonly Body[] _bodies = new Body[Count]; 14 | 15 | public CircleStack() 16 | { 17 | { 18 | var bd = new BodyDef(); 19 | var ground = World.CreateBody(bd); 20 | 21 | var shape = new EdgeShape(); 22 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 23 | ground.CreateFixture(shape, 0.0f); 24 | } 25 | 26 | { 27 | var shape = new CircleShape {Radius = 1.0f}; 28 | 29 | for (var i = 0; i < Count; ++i) 30 | { 31 | var bd = new BodyDef 32 | { 33 | BodyType = BodyType.DynamicBody, Position = new FVector2(0.0f, 4.0f + 3.0f * i) 34 | }; 35 | 36 | _bodies[i] = World.CreateBody(bd); 37 | 38 | _bodies[i].CreateFixture(shape, 1.0f); 39 | 40 | _bodies[i].SetLinearVelocity(new FVector2(0.0f, -50.0f)); 41 | } 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Dynamics/Joints/MotorJointDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Joints 4 | { 5 | /// Motor joint definition. 6 | public class MotorJointDef : JointDef 7 | { 8 | /// The bodyB angle minus bodyA angle in radians. 9 | public FP AngularOffset; 10 | 11 | /// Position correction factor in the range [0,1]. 12 | public FP CorrectionFactor; 13 | 14 | /// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters. 15 | public FVector2 LinearOffset; 16 | 17 | /// The maximum motor force in N. 18 | public FP MaxForce; 19 | 20 | /// The maximum motor torque in N-m. 21 | public FP MaxTorque; 22 | 23 | public MotorJointDef() 24 | { 25 | JointType = JointType.MotorJoint; 26 | LinearOffset.SetZero(); 27 | AngularOffset = 0.0f; 28 | MaxForce = 1.0f; 29 | MaxTorque = 1.0f; 30 | CorrectionFactor = 0.3f; 31 | } 32 | 33 | /// Initialize the bodies and offsets using the current transforms. 34 | public void Initialize(Body bA, Body bB) 35 | { 36 | BodyA = bA; 37 | BodyB = bB; 38 | var xB = BodyB.GetPosition(); 39 | LinearOffset = BodyA.GetLocalPoint(xB); 40 | 41 | var angleA = BodyA.GetAngle(); 42 | var angleB = BodyB.GetAngle(); 43 | AngularOffset = angleB - angleA; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/KeyCodes.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public enum KeyCodes 4 | { 5 | D0, 6 | 7 | D1, 8 | 9 | D2, 10 | 11 | D3, 12 | 13 | D4, 14 | 15 | D5, 16 | 17 | D6, 18 | 19 | D7, 20 | 21 | D8, 22 | 23 | D9, 24 | 25 | Comma, 26 | 27 | Period, 28 | 29 | LeftCtrl, 30 | 31 | RightCtrl, 32 | 33 | LeftShift, 34 | 35 | RightShift, 36 | 37 | LeftAlt, 38 | 39 | RightAlt, 40 | 41 | A, 42 | 43 | B, 44 | 45 | C, 46 | 47 | D, 48 | 49 | E, 50 | 51 | F, 52 | 53 | G, 54 | 55 | H, 56 | 57 | I, 58 | 59 | J, 60 | 61 | K, 62 | 63 | L, 64 | 65 | M, 66 | 67 | N, 68 | 69 | O, 70 | 71 | P, 72 | 73 | Q, 74 | 75 | R, 76 | 77 | S, 78 | 79 | T, 80 | 81 | U, 82 | 83 | V, 84 | 85 | W, 86 | 87 | X, 88 | 89 | Y, 90 | 91 | Z, 92 | 93 | LeftArrow, 94 | 95 | RightArrow, 96 | 97 | UpArrow, 98 | 99 | DownArrow, 100 | 101 | LeftBracket, 102 | 103 | RightBracket, 104 | 105 | Home, 106 | 107 | Space, 108 | 109 | Tab, 110 | 111 | Escape 112 | } 113 | } -------------------------------------------------------------------------------- /src/Collision/Collider/Manifold.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Collision.Collider 4 | { 5 | /// A manifold for two touching convex shapes. 6 | /// Box2D supports multiple types of contact: 7 | /// - clip point versus plane with radius 8 | /// - point versus point with radius (circles) 9 | /// The local point usage depends on the manifold type: 10 | /// -e_circles: the local center of circleA 11 | /// -e_faceA: the center of faceA 12 | /// -e_faceB: the center of faceB 13 | /// Similarly the local normal usage: 14 | /// -e_circles: not used 15 | /// -e_faceA: the normal on polygonA 16 | /// -e_faceB: the normal on polygonB 17 | /// We store contacts in this way so that position correction can 18 | /// account for movement, which is critical for continuous physics. 19 | /// All contact scenarios must be expressed in one of these types. 20 | /// This structure is stored across time steps, so we keep it small. 21 | public struct Manifold 22 | { 23 | /// 24 | /// the points of contact, size Settings.MaxManifoldPoints 25 | /// 26 | public FixedArray2 Points; 27 | 28 | /// not use for Type::e_points 29 | public FVector2 LocalNormal; 30 | 31 | /// usage depends on manifold type 32 | public FVector2 LocalPoint; 33 | 34 | public ManifoldType Type; 35 | 36 | /// the number of manifold points 37 | public int PointCount; 38 | } 39 | } -------------------------------------------------------------------------------- /src/Common/Rotation.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Box2DSharp.Common 4 | { 5 | /// Rotation 6 | public struct Rotation 7 | { 8 | /// Sine and cosine 9 | public FP Sin; 10 | 11 | public FP Cos; 12 | 13 | public Rotation(FP sin, FP cos) 14 | { 15 | Sin = sin; 16 | Cos = cos; 17 | } 18 | 19 | /// Initialize from an angle in radians 20 | public Rotation(FP angle) 21 | { 22 | // TODO_ERIN optimize 23 | Sin = FP.Sin(angle); 24 | Cos = FP.Cos(angle); 25 | } 26 | 27 | /// Set using an angle in radians. 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public void Set(FP angle) 30 | { 31 | // TODO_ERIN optimize 32 | Sin = FP.Sin(angle); 33 | Cos = FP.Cos(angle); 34 | } 35 | 36 | /// Set to the identity rotation 37 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 | public void SetIdentity() 39 | { 40 | Sin = 0.0f; 41 | Cos = 1.0f; 42 | } 43 | 44 | /// Get the angle in radians 45 | public FP Angle => FP.Atan2(Sin, Cos); 46 | 47 | /// Get the x-axis 48 | public FVector2 GetXAxis() 49 | { 50 | return new FVector2(Cos, Sin); 51 | } 52 | 53 | /// Get the u-axis 54 | public FVector2 GetYAxis() 55 | { 56 | return new FVector2(-Sin, Cos); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/Common/MathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Box2DSharp.Common 4 | { 5 | public static class MathExtensions 6 | { 7 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 8 | public static void SetZero(ref this FVector2 vector2) 9 | { 10 | vector2.X = 0.0f; 11 | vector2.Y = 0.0f; 12 | } 13 | 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static void Set(ref this FVector2 vector2, FP x, FP y) 16 | { 17 | vector2.X = x; 18 | vector2.Y = y; 19 | } 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | public static void SetZero(ref this FVector3 vector3) 23 | { 24 | vector3.X = 0.0f; 25 | vector3.Y = 0.0f; 26 | vector3.Z = 0.0f; 27 | } 28 | 29 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | public static void Set(ref this FVector3 vector3, FP x, FP y, FP z) 31 | { 32 | vector3.X = x; 33 | vector3.Y = y; 34 | vector3.Z = z; 35 | } 36 | 37 | /// 38 | /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) 39 | /// 40 | /// 41 | /// 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static FVector2 Skew(ref this FVector2 vector2) 44 | { 45 | return new FVector2(-vector2.Y, vector2.X); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Dynamics/Callbacks.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Collider; 2 | using Box2DSharp.Common; 3 | 4 | namespace Box2DSharp.Dynamics 5 | { 6 | public interface IQueryCallback 7 | { 8 | bool QueryCallback(Fixture fixture); 9 | } 10 | 11 | public interface IRayCastCallback 12 | { 13 | /// Callback for ray casts. 14 | /// See b2World::RayCast 15 | /// Called for each fixture found in the query. You control how the ray cast 16 | /// proceeds by returning a float: 17 | /// return -1: ignore this fixture and continue 18 | /// return 0: terminate the ray cast 19 | /// return fraction: clip the ray to this point 20 | /// return 1: don't clip the ray and continue 21 | /// @param fixture the fixture hit by the ray 22 | /// @param point the point of initial intersection 23 | /// @param normal the normal vector at the point of intersection 24 | /// @return -1 to filter, 0 to terminate, fraction to clip the ray for 25 | /// closest hit, 1 to continue 26 | FP RayCastCallback(Fixture fixture, in FVector2 point, in FVector2 normal, FP fraction); 27 | } 28 | } 29 | 30 | namespace Box2DSharp.Dynamics.Internal 31 | { 32 | public interface ITreeQueryCallback 33 | { 34 | bool QueryCallback(int proxyId); 35 | } 36 | 37 | public interface ITreeRayCastCallback 38 | { 39 | FP RayCastCallback(in RayCastInput input, int proxyId); 40 | } 41 | 42 | public interface IAddPairCallback 43 | { 44 | void AddPairCallback(object proxyUserDataA, object proxyUserDataB); 45 | } 46 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/CircleContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | internal class CircleContact : Contact 11 | { 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 14 | { 15 | CollisionUtils.CollideCircles( 16 | ref manifold, 17 | (CircleShape)FixtureA.Shape, 18 | xfA, 19 | (CircleShape)FixtureB.Shape, 20 | xfB); 21 | } 22 | } 23 | 24 | internal class CircleContactFactory : IContactFactory 25 | { 26 | private readonly ContactPool _pool = new ContactPool(); 27 | 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 30 | { 31 | Debug.Assert(fixtureA.ShapeType == ShapeType.Circle); 32 | Debug.Assert(fixtureB.ShapeType == ShapeType.Circle); 33 | var contact = _pool.Get(); 34 | contact.Initialize(fixtureA, 0, fixtureB, 0); 35 | return contact; 36 | } 37 | 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public void Destroy(Contact contact) 40 | { 41 | _pool.Return((CircleContact)contact); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/PolygonContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | public class PolygonContact : Contact 11 | { 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 14 | { 15 | CollisionUtils.CollidePolygons( 16 | ref manifold, 17 | (PolygonShape)FixtureA.Shape, 18 | xfA, 19 | (PolygonShape)FixtureB.Shape, 20 | xfB); 21 | } 22 | } 23 | 24 | internal class PolygonContactFactory : IContactFactory 25 | { 26 | private readonly ContactPool _pool = new ContactPool(); 27 | 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 30 | { 31 | Debug.Assert(fixtureA.ShapeType == ShapeType.Polygon); 32 | Debug.Assert(fixtureB.ShapeType == ShapeType.Polygon); 33 | var contact = _pool.Get(); 34 | contact.Initialize(fixtureA, 0, fixtureB, 0); 35 | return contact; 36 | } 37 | 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public void Destroy(Contact contact) 40 | { 41 | _pool.Return((PolygonContact)contact); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/AddPair.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Benchmark", "Add Pair Stress Test")] 9 | public class AddPair : TestBase 10 | { 11 | public AddPair() 12 | { 13 | World.Gravity = new FVector2(0.0f, 0.0f); 14 | { 15 | var shape = new CircleShape(); 16 | shape.Position.SetZero(); 17 | shape.Radius = 0.1f; 18 | 19 | var minX = -6.0f; 20 | var maxX = 0.0f; 21 | var minY = 4.0f; 22 | var maxY = 6.0f; 23 | 24 | for (var i = 0; i < 400; ++i) 25 | { 26 | var bd = new BodyDef(); 27 | bd.BodyType = BodyType.DynamicBody; 28 | bd.Position = new FVector2(RandomFloat(minX, maxX), RandomFloat(minY, maxY)); 29 | var body = World.CreateBody(bd); 30 | body.CreateFixture(shape, 0.01f); 31 | } 32 | } 33 | 34 | { 35 | var shape = new PolygonShape(); 36 | shape.SetAsBox(1.5f, 1.5f); 37 | var bd = new BodyDef(); 38 | bd.BodyType = BodyType.DynamicBody; 39 | bd.Position.Set(-40.0f, 5.0f); 40 | bd.Bullet = true; 41 | var body = World.CreateBody(bd); 42 | body.CreateFixture(shape, 1.0f); 43 | body.SetLinearVelocity(new FVector2(10.0f, 0.0f)); 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ChainAndPolygonContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | public class ChainAndPolygonContact : Contact 11 | { 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 14 | { 15 | var chain = (ChainShape)FixtureA.Shape; 16 | 17 | chain.GetChildEdge(out var edge, ChildIndexA); 18 | CollisionUtils.CollideEdgeAndPolygon(ref manifold, edge, xfA, (PolygonShape)FixtureB.Shape, xfB); 19 | } 20 | } 21 | 22 | internal class ChainAndPolygonContactFactory : IContactFactory 23 | { 24 | private readonly ContactPool _pool = new ContactPool(); 25 | 26 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 27 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 28 | { 29 | Debug.Assert(fixtureA.ShapeType == ShapeType.Chain); 30 | Debug.Assert(fixtureB.ShapeType == ShapeType.Polygon); 31 | var contact = _pool.Get(); 32 | contact.Initialize(fixtureA, indexA, fixtureB, indexB); 33 | return contact; 34 | } 35 | 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public void Destroy(Contact contact) 38 | { 39 | _pool.Return((ChainAndPolygonContact)contact); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Dynamics/Joints/FrictionJointDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Joints 4 | { 5 | /// Friction joint definition. 6 | public class FrictionJointDef : JointDef 7 | { 8 | /// The local anchor point relative to bodyA's origin. 9 | public FVector2 LocalAnchorA; 10 | 11 | /// The local anchor point relative to bodyB's origin. 12 | public FVector2 LocalAnchorB; 13 | 14 | /// The maximum friction force in N. 15 | public FP MaxForce; 16 | 17 | /// The maximum friction torque in N-m. 18 | public FP MaxTorque; 19 | 20 | public FrictionJointDef() 21 | { 22 | JointType = JointType.FrictionJoint; 23 | LocalAnchorA.SetZero(); 24 | LocalAnchorB.SetZero(); 25 | MaxForce = 0.0f; 26 | MaxTorque = 0.0f; 27 | } 28 | 29 | // Point-to-point constraint 30 | // Cdot = v2 - v1 31 | // = v2 + cross(w2, r2) - v1 - cross(w1, r1) 32 | // J = [-I -r1_skew I r2_skew ] 33 | // Identity used: 34 | // w k % (rx i + ry j) = w * (-ry i + rx j) 35 | 36 | // Angle constraint 37 | // Cdot = w2 - w1 38 | // J = [0 0 -1 0 0 1] 39 | // K = invI1 + invI2 40 | /// Initialize the bodies, anchors, axis, and reference angle using the world 41 | /// anchor and world axis. 42 | public void Initialize(Body bA, Body bB, in FVector2 anchor) 43 | { 44 | BodyA = bA; 45 | BodyB = bB; 46 | LocalAnchorA = BodyA.GetLocalPoint(anchor); 47 | LocalAnchorB = BodyB.GetLocalPoint(anchor); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /test/UnityTest/.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Asset meta data should only be ignored when the corresponding asset is also ignored 18 | !/[Aa]ssets/**/*.meta 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.csproj 36 | *.unityproj 37 | *.sln 38 | *.suo 39 | *.tmp 40 | *.user 41 | *.userprefs 42 | *.pidb 43 | *.booproj 44 | *.svd 45 | *.pdb 46 | *.mdb 47 | *.opendb 48 | *.VC.db 49 | 50 | # Unity3D generated meta files 51 | *.pidb.meta 52 | *.pdb.meta 53 | *.mdb.meta 54 | 55 | # Unity3D generated file on crash reports 56 | sysinfo.txt 57 | 58 | # Builds 59 | *.apk 60 | *.aab 61 | *.unitypackage 62 | 63 | # Crashlytics generated file 64 | crashlytics-build.properties 65 | 66 | # Packed Addressables 67 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 68 | 69 | # Temporary auto-generated Android Assets 70 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 71 | /[Aa]ssets/[Ss]treamingAssets/aa/* 72 | 73 | # Custom 74 | /[Aa]ssets/Box2DSharp 75 | settings.ini 76 | imgui.ini -------------------------------------------------------------------------------- /src/Dynamics/Contacts/EdgeAndCircleContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | /// 11 | /// 边缘与圆接触 12 | /// 13 | public class EdgeAndCircleContact : Contact 14 | { 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 17 | { 18 | CollisionUtils.CollideEdgeAndCircle( 19 | ref manifold, 20 | (EdgeShape)FixtureA.Shape, 21 | xfA, 22 | (CircleShape)FixtureB.Shape, 23 | xfB); 24 | } 25 | } 26 | 27 | internal class EdgeAndCircleContactFactory : IContactFactory 28 | { 29 | private readonly ContactPool _pool = new ContactPool(); 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 33 | { 34 | Debug.Assert(fixtureA.ShapeType == ShapeType.Edge); 35 | Debug.Assert(fixtureB.ShapeType == ShapeType.Circle); 36 | var contact = _pool.Get(); 37 | contact.Initialize(fixtureA, 0, fixtureB, 0); 38 | return contact; 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public void Destroy(Contact contact) 43 | { 44 | _pool.Return((EdgeAndCircleContact)contact); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/Pyramid.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Stacking", "Pyramid")] 9 | public class Pyramid : TestBase 10 | { 11 | private const int Count = 20; 12 | 13 | public Pyramid() 14 | { 15 | { 16 | var bd = new BodyDef(); 17 | var ground = World.CreateBody(bd); 18 | 19 | var shape = new EdgeShape(); 20 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 21 | ground.CreateFixture(shape, 0.0f); 22 | } 23 | 24 | { 25 | var a = 0.5f; 26 | var shape = new PolygonShape(); 27 | shape.SetAsBox(a, a); 28 | 29 | var x = new FVector2(-7.0f, 0.75f); 30 | FVector2 y; 31 | var deltaX = new FVector2(0.5625f, 1.25f); 32 | var deltaY = new FVector2(1.125f, 0.0f); 33 | 34 | for (var i = 0; i < Count; ++i) 35 | { 36 | y = x; 37 | 38 | for (var j = i; j < Count; ++j) 39 | { 40 | var bd = new BodyDef(); 41 | bd.BodyType = BodyType.DynamicBody; 42 | bd.Position = y; 43 | var body = World.CreateBody(bd); 44 | body.CreateFixture(shape, 5.0f); 45 | 46 | y += deltaY; 47 | } 48 | 49 | x += deltaX; 50 | } 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/Restitution.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Forces", "Restitution")] 9 | public class Restitution : TestBase 10 | { 11 | public Restitution() 12 | { 13 | FP threshold = 10.0f; 14 | { 15 | var bd = new BodyDef(); 16 | var ground = World.CreateBody(bd); 17 | 18 | var shape = new EdgeShape(); 19 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 20 | 21 | FixtureDef fd = new FixtureDef(); 22 | fd.Shape = shape; 23 | fd.RestitutionThreshold = threshold; 24 | ground.CreateFixture(fd); 25 | } 26 | 27 | { 28 | var shape = new CircleShape(); 29 | shape.Radius = 1.0f; 30 | 31 | var fd = new FixtureDef(); 32 | fd.Shape = shape; 33 | fd.Density = 1.0f; 34 | 35 | FP[] restitution = {0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f}; 36 | 37 | for (var i = 0; i < 7; ++i) 38 | { 39 | var bd = new BodyDef(); 40 | bd.BodyType = BodyType.DynamicBody; 41 | bd.Position.Set(-10.0f + 3.0f * i, 20.0f); 42 | 43 | var body = World.CreateBody(bd); 44 | 45 | fd.Restitution = restitution[i]; 46 | fd.RestitutionThreshold = threshold; 47 | body.CreateFixture(fd); 48 | } 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /src/Dynamics/Contacts/EdgeAndPolygonContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | /// 11 | /// 边缘与多边形接触 12 | /// 13 | public class EdgeAndPolygonContact : Contact 14 | { 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 17 | { 18 | CollisionUtils.CollideEdgeAndPolygon( 19 | ref manifold, 20 | (EdgeShape)FixtureA.Shape, 21 | xfA, 22 | (PolygonShape)FixtureB.Shape, 23 | xfB); 24 | } 25 | } 26 | 27 | internal class EdgeAndPolygonContactFactory : IContactFactory 28 | { 29 | private readonly ContactPool _pool = new ContactPool(); 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 33 | { 34 | Debug.Assert(fixtureA.ShapeType == ShapeType.Edge); 35 | Debug.Assert(fixtureB.ShapeType == ShapeType.Polygon); 36 | var contact = _pool.Get(); 37 | contact.Initialize(fixtureA, 0, fixtureB, 0); 38 | return contact; 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public void Destroy(Contact contact) 43 | { 44 | _pool.Return((EdgeAndPolygonContact)contact); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/PolygonAndCircleContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | /// 11 | /// 多边形与圆接触 12 | /// 13 | public class PolygonAndCircleContact : Contact 14 | { 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 17 | { 18 | CollisionUtils.CollidePolygonAndCircle( 19 | ref manifold, 20 | (PolygonShape)FixtureA.Shape, 21 | xfA, 22 | (CircleShape)FixtureB.Shape, 23 | xfB); 24 | } 25 | } 26 | 27 | internal class PolygonAndCircleContactFactory : IContactFactory 28 | { 29 | private readonly ContactPool _pool = new ContactPool(); 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 33 | { 34 | Debug.Assert(fixtureA.ShapeType == ShapeType.Polygon); 35 | Debug.Assert(fixtureB.ShapeType == ShapeType.Circle); 36 | var contact = _pool.Get(); 37 | contact.Initialize(fixtureA, 0, fixtureB, 0); 38 | return contact; 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public void Destroy(Contact contact) 43 | { 44 | _pool.Return((PolygonAndCircleContact)contact); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ChainAndCircleContact.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using Box2DSharp.Collision; 4 | using Box2DSharp.Collision.Collider; 5 | using Box2DSharp.Collision.Shapes; 6 | using Box2DSharp.Common; 7 | 8 | namespace Box2DSharp.Dynamics.Contacts 9 | { 10 | public class ChainAndCircleContact : Contact 11 | { 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | internal override void Evaluate(ref Manifold manifold, in Transform xfA, Transform xfB) 14 | { 15 | var chain = (ChainShape)FixtureA.Shape; 16 | 17 | chain.GetChildEdge(out var edge, ChildIndexA); 18 | CollisionUtils.CollideEdgeAndCircle( 19 | ref manifold, 20 | edge, 21 | xfA, 22 | (CircleShape)FixtureB.Shape, 23 | xfB); 24 | } 25 | } 26 | 27 | internal class ChainAndCircleContactFactory : IContactFactory 28 | { 29 | private readonly ContactPool _pool = new ContactPool(); 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) 33 | { 34 | Debug.Assert(fixtureA.ShapeType == ShapeType.Chain); 35 | Debug.Assert(fixtureB.ShapeType == ShapeType.Circle); 36 | var contact = _pool.Get(); 37 | contact.Initialize(fixtureA, indexA, fixtureB, indexB); 38 | return contact; 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public void Destroy(Contact contact) 43 | { 44 | _pool.Return((ChainAndCircleContact)contact); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/Box2DSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 7.3 6 | Box2DSharp 7 | Box2DSharp 8 | 0.6 9 | Zonciu Liang 10 | Zonciu Studio 11 | https://github.com/Zonciu/Box2DSharp 12 | https://github.com/Zonciu/Box2DSharp 13 | Copyright © Zonciu Liang 2020 14 | A C# port of Box2D 15 | true 16 | Box2DSharp 17 | 2D;C#;Box2D;Physic 18 | LICENSE.txt 19 | false 20 | true 21 | 22 | 23 | 24 | 1701;1702;1591 25 | 26 | 27 | 28 | 1701;1702;1591 29 | 30 | 31 | 32 | 33 | True 34 | 35 | 36 | 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/Testbed.TestCases/Chain.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Box2DSharp.Dynamics.Joints; 5 | using Testbed.Abstractions; 6 | 7 | namespace Testbed.TestCases 8 | { 9 | [TestCase("Joints", "Chain")] 10 | public class Chain : TestBase 11 | { 12 | public Chain() 13 | { 14 | Body ground; 15 | { 16 | var bd = new BodyDef(); 17 | ground = World.CreateBody(bd); 18 | 19 | var shape = new EdgeShape(); 20 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 21 | ground.CreateFixture(shape, 0.0f); 22 | } 23 | 24 | { 25 | var shape = new PolygonShape(); 26 | shape.SetAsBox(0.6f, 0.125f); 27 | 28 | var fd = new FixtureDef 29 | { 30 | Shape = shape, 31 | Density = 20.0f, 32 | Friction = 0.2f 33 | }; 34 | 35 | var jd = new RevoluteJointDef {CollideConnected = false}; 36 | 37 | FP y = 25.0f; 38 | var prevBody = ground; 39 | for (var i = 0; i < 30; ++i) 40 | { 41 | var bd = new BodyDef {BodyType = BodyType.DynamicBody}; 42 | bd.Position.Set(0.5f + i, y); 43 | var body = World.CreateBody(bd); 44 | body.CreateFixture(fd); 45 | 46 | var anchor = new FVector2(i, y); 47 | jd.Initialize(prevBody, body, anchor); 48 | World.CreateJoint(jd); 49 | 50 | prevBody = body; 51 | } 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Dynamics/Contacts/ContactPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Threading; 4 | 5 | namespace Box2DSharp.Dynamics.Contacts 6 | { 7 | public class ContactPool 8 | where T : Contact, new() 9 | { 10 | private T[] _objects; 11 | 12 | private int _total; 13 | 14 | private int _capacity; 15 | 16 | private int _lock = Unlocked; 17 | 18 | private const int Locked = 1; 19 | 20 | private const int Unlocked = 0; 21 | 22 | public ContactPool(int capacity = 256) 23 | { 24 | _capacity = capacity; 25 | _objects = new T[_capacity]; 26 | } 27 | 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public T Get() 30 | { 31 | while (Interlocked.CompareExchange(ref _lock, Locked, Unlocked) == Locked) 32 | { } 33 | 34 | if (_total > 0) 35 | { 36 | --_total; 37 | var item = _objects[_total]; 38 | _objects[_total] = null; 39 | Interlocked.Exchange(ref _lock, Unlocked); 40 | return item; 41 | } 42 | 43 | Interlocked.Exchange(ref _lock, Unlocked); 44 | return new T(); 45 | } 46 | 47 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 48 | public void Return(T item) 49 | { 50 | while (Interlocked.CompareExchange(ref _lock, Locked, Unlocked) == Locked) 51 | { } 52 | 53 | item.Reset(); 54 | if (_total >= _capacity) 55 | { 56 | _capacity *= 2; 57 | Array.Resize(ref _objects, _capacity); 58 | } 59 | 60 | _objects[_total] = item; 61 | ++_total; 62 | 63 | Interlocked.Exchange(ref _lock, Unlocked); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /test/Testbed/Tests/RayCastRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using ImGuiNET; 3 | using Testbed.TestCases; 4 | 5 | namespace Testbed.Tests 6 | { 7 | [TestInherit] 8 | public class RayCastRender : RayCast 9 | { 10 | /// 11 | protected override void OnRender() 12 | { 13 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 14 | ImGui.SetNextWindowSize(new Vector2(210.0f, 285.0f)); 15 | ImGui.Begin("Ray-cast Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.Button("Shape 1")) 18 | { 19 | Create(0); 20 | } 21 | 22 | if (ImGui.Button("Shape 2")) 23 | { 24 | Create(1); 25 | } 26 | 27 | if (ImGui.Button("Shape 3")) 28 | { 29 | Create(2); 30 | } 31 | 32 | if (ImGui.Button("Shape 4")) 33 | { 34 | Create(3); 35 | } 36 | 37 | if (ImGui.Button("Shape 5")) 38 | { 39 | Create(4); 40 | } 41 | 42 | if (ImGui.Button("Shape 6")) 43 | { 44 | Create(5); 45 | } 46 | 47 | if (ImGui.Button("Destroy Shape")) 48 | { 49 | DestroyBody(); 50 | } 51 | 52 | var mode = (int)_mode; 53 | ImGui.RadioButton("Any", ref mode, (int)Mode.Any); 54 | ImGui.RadioButton("Closest", ref mode, (int)Mode.Closest); 55 | ImGui.RadioButton("Multiple", ref mode, (int)Mode.Multiple); 56 | _mode = (Mode)mode; 57 | var deg =(float) _degrees; 58 | ImGui.SliderFloat("Angle", ref deg, 0.0f, 360.0f, "%.0f"); 59 | _degrees = deg; 60 | ImGui.End(); 61 | base.OnRender(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /test/UnityTest/Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.ai.navigation": "1.1.5", 4 | "com.unity.collab-proxy": "2.4.3", 5 | "com.unity.ide.rider": "3.0.31", 6 | "com.unity.ide.visualstudio": "2.0.22", 7 | "com.unity.ide.vscode": "1.2.5", 8 | "com.unity.inputsystem": "1.7.0", 9 | "com.unity.test-framework": "1.1.33", 10 | "com.unity.textmeshpro": "3.0.6", 11 | "com.unity.timeline": "1.7.6", 12 | "com.unity.ugui": "1.0.0", 13 | "com.unity.modules.ai": "1.0.0", 14 | "com.unity.modules.androidjni": "1.0.0", 15 | "com.unity.modules.animation": "1.0.0", 16 | "com.unity.modules.assetbundle": "1.0.0", 17 | "com.unity.modules.audio": "1.0.0", 18 | "com.unity.modules.cloth": "1.0.0", 19 | "com.unity.modules.director": "1.0.0", 20 | "com.unity.modules.imageconversion": "1.0.0", 21 | "com.unity.modules.imgui": "1.0.0", 22 | "com.unity.modules.jsonserialize": "1.0.0", 23 | "com.unity.modules.particlesystem": "1.0.0", 24 | "com.unity.modules.physics": "1.0.0", 25 | "com.unity.modules.physics2d": "1.0.0", 26 | "com.unity.modules.screencapture": "1.0.0", 27 | "com.unity.modules.terrain": "1.0.0", 28 | "com.unity.modules.terrainphysics": "1.0.0", 29 | "com.unity.modules.tilemap": "1.0.0", 30 | "com.unity.modules.ui": "1.0.0", 31 | "com.unity.modules.uielements": "1.0.0", 32 | "com.unity.modules.umbra": "1.0.0", 33 | "com.unity.modules.unityanalytics": "1.0.0", 34 | "com.unity.modules.unitywebrequest": "1.0.0", 35 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 36 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 37 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 38 | "com.unity.modules.unitywebrequestwww": "1.0.0", 39 | "com.unity.modules.vehicles": "1.0.0", 40 | "com.unity.modules.video": "1.0.0", 41 | "com.unity.modules.vr": "1.0.0", 42 | "com.unity.modules.wind": "1.0.0", 43 | "com.unity.modules.xr": "1.0.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Dynamics/Joints/WeldJointDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Joints 4 | { 5 | /// Weld joint definition. You need to specify local anchor points 6 | /// where they are attached and the relative body angle. The position 7 | /// of the anchor points is important for computing the reaction torque. 8 | public class WeldJointDef : JointDef 9 | { 10 | /// The rotational stiffness in N*m 11 | /// Disable softness with a value of 0 12 | public FP Stiffness; 13 | 14 | /// The rotational damping in N*m*s 15 | public FP Damping; 16 | 17 | /// The local anchor point relative to bodyA's origin. 18 | public FVector2 LocalAnchorA; 19 | 20 | /// The local anchor point relative to bodyB's origin. 21 | public FVector2 LocalAnchorB; 22 | 23 | /// The bodyB angle minus bodyA angle in the reference state (radians). 24 | public FP ReferenceAngle; 25 | 26 | public WeldJointDef() 27 | { 28 | JointType = JointType.WeldJoint; 29 | LocalAnchorA.Set(0.0f, 0.0f); 30 | LocalAnchorB.Set(0.0f, 0.0f); 31 | ReferenceAngle = 0.0f; 32 | Stiffness = 0.0f; 33 | Damping = 0.0f; 34 | } 35 | 36 | /// 37 | /// Initialize the bodies, anchors, reference angle, stiffness, and damping. 38 | /// 39 | /// the first body connected by this joint 40 | /// the second body connected by this joint 41 | /// the point of connection in world coordinates 42 | public void Initialize(Body bA, Body bB, in FVector2 anchor) 43 | { 44 | BodyA = bA; 45 | BodyB = bB; 46 | LocalAnchorA = BodyA.GetLocalPoint(anchor); 47 | LocalAnchorB = BodyB.GetLocalPoint(anchor); 48 | ReferenceAngle = BodyB.GetAngle() - BodyA.GetAngle(); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/HelloWorld.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Examples", "HelloWorld")] 9 | public class HelloWorld : TestBase 10 | { 11 | private Body _body; 12 | 13 | public HelloWorld() 14 | { 15 | var groundBodyDef = new BodyDef {BodyType = BodyType.StaticBody}; 16 | groundBodyDef.Position.Set(0.0f, -10.0f); 17 | 18 | var groundBody = World.CreateBody(groundBodyDef); 19 | 20 | var groundBox = new PolygonShape(); 21 | groundBox.SetAsBox(1000.0f, 10.0f); 22 | 23 | groundBody.CreateFixture(groundBox, 0.0f); 24 | 25 | // Define the dynamic body. We set its position and call the body factory. 26 | var bodyDef = new BodyDef {BodyType = BodyType.DynamicBody}; 27 | 28 | bodyDef.Position.Set(0, 4f); 29 | 30 | var dynamicBox = new PolygonShape(); 31 | dynamicBox.SetAsBox(1f, 1f, FVector2.Zero, 45f); 32 | 33 | // Define the dynamic body fixture. 34 | var fixtureDef = new FixtureDef 35 | { 36 | Shape = dynamicBox, 37 | Density = 1.0f, 38 | Friction = 0.3f 39 | }; 40 | 41 | // Set the box density to be non-zero, so it will be dynamic. 42 | 43 | // Override the default friction. 44 | 45 | // Add the shape to the body. 46 | var body = World.CreateBody(bodyDef); 47 | body.CreateFixture(fixtureDef); 48 | 49 | _body = body; 50 | 51 | for (int i = 0; i < 100; i++) 52 | { 53 | bodyDef.Position = new FVector2(Random.Next(-50, 50), Random.Next(0, 500)); 54 | bodyDef.Angle = Random.Next(0, 360); 55 | World.CreateBody(bodyDef).CreateFixture(fixtureDef); 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/InitSettings.lighting: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!850595691 &4890085278179872738 4 | LightingSettings: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_Name: InitSettings 10 | serializedVersion: 3 11 | m_GIWorkflowMode: 0 12 | m_EnableBakedLightmaps: 0 13 | m_EnableRealtimeLightmaps: 0 14 | m_RealtimeEnvironmentLighting: 1 15 | m_BounceScale: 1 16 | m_AlbedoBoost: 1 17 | m_IndirectOutputScale: 1 18 | m_UsingShadowmask: 1 19 | m_BakeBackend: 1 20 | m_LightmapMaxSize: 1024 21 | m_BakeResolution: 40 22 | m_Padding: 2 23 | m_TextureCompression: 1 24 | m_AO: 0 25 | m_AOMaxDistance: 1 26 | m_CompAOExponent: 1 27 | m_CompAOExponentDirect: 0 28 | m_ExtractAO: 0 29 | m_MixedBakeMode: 2 30 | m_LightmapsBakeMode: 1 31 | m_FilterMode: 1 32 | m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} 33 | m_ExportTrainingData: 0 34 | m_TrainingDataDestination: TrainingData 35 | m_RealtimeResolution: 2 36 | m_ForceWhiteAlbedo: 0 37 | m_ForceUpdates: 0 38 | m_FinalGather: 0 39 | m_FinalGatherRayCount: 256 40 | m_FinalGatherFiltering: 1 41 | m_PVRCulling: 1 42 | m_PVRSampling: 1 43 | m_PVRDirectSampleCount: 32 44 | m_PVRSampleCount: 512 45 | m_PVREnvironmentSampleCount: 256 46 | m_PVREnvironmentReferencePointCount: 2048 47 | m_LightProbeSampleCountMultiplier: 4 48 | m_PVRBounces: 2 49 | m_PVRMinBounces: 2 50 | m_PVREnvironmentMIS: 1 51 | m_PVRFilteringMode: 1 52 | m_PVRDenoiserTypeDirect: 1 53 | m_PVRDenoiserTypeIndirect: 1 54 | m_PVRDenoiserTypeAO: 1 55 | m_PVRFilterTypeDirect: 0 56 | m_PVRFilterTypeIndirect: 0 57 | m_PVRFilterTypeAO: 0 58 | m_PVRFilteringGaussRadiusDirect: 1 59 | m_PVRFilteringGaussRadiusIndirect: 5 60 | m_PVRFilteringGaussRadiusAO: 2 61 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 62 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 63 | m_PVRFilteringAtrousPositionSigmaAO: 1 64 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Scenes/DeterministicSettings.lighting: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!850595691 &4890085278179872738 4 | LightingSettings: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_Name: DeterministicSettings 10 | serializedVersion: 3 11 | m_GIWorkflowMode: 0 12 | m_EnableBakedLightmaps: 0 13 | m_EnableRealtimeLightmaps: 0 14 | m_RealtimeEnvironmentLighting: 1 15 | m_BounceScale: 1 16 | m_AlbedoBoost: 1 17 | m_IndirectOutputScale: 1 18 | m_UsingShadowmask: 1 19 | m_BakeBackend: 1 20 | m_LightmapMaxSize: 1024 21 | m_BakeResolution: 40 22 | m_Padding: 2 23 | m_TextureCompression: 1 24 | m_AO: 0 25 | m_AOMaxDistance: 1 26 | m_CompAOExponent: 1 27 | m_CompAOExponentDirect: 0 28 | m_ExtractAO: 0 29 | m_MixedBakeMode: 2 30 | m_LightmapsBakeMode: 1 31 | m_FilterMode: 1 32 | m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} 33 | m_ExportTrainingData: 0 34 | m_TrainingDataDestination: TrainingData 35 | m_RealtimeResolution: 2 36 | m_ForceWhiteAlbedo: 0 37 | m_ForceUpdates: 0 38 | m_FinalGather: 0 39 | m_FinalGatherRayCount: 256 40 | m_FinalGatherFiltering: 1 41 | m_PVRCulling: 1 42 | m_PVRSampling: 1 43 | m_PVRDirectSampleCount: 32 44 | m_PVRSampleCount: 512 45 | m_PVREnvironmentSampleCount: 256 46 | m_PVREnvironmentReferencePointCount: 2048 47 | m_LightProbeSampleCountMultiplier: 4 48 | m_PVRBounces: 2 49 | m_PVRMinBounces: 2 50 | m_PVREnvironmentMIS: 1 51 | m_PVRFilteringMode: 1 52 | m_PVRDenoiserTypeDirect: 1 53 | m_PVRDenoiserTypeIndirect: 1 54 | m_PVRDenoiserTypeAO: 1 55 | m_PVRFilterTypeDirect: 0 56 | m_PVRFilterTypeIndirect: 0 57 | m_PVRFilterTypeAO: 0 58 | m_PVRFilteringGaussRadiusDirect: 1 59 | m_PVRFilteringGaussRadiusIndirect: 5 60 | m_PVRFilteringGaussRadiusAO: 2 61 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 62 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 63 | m_PVRFilteringAtrousPositionSigmaAO: 1 64 | -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/RayCastRender.cs: -------------------------------------------------------------------------------- 1 | using Testbed.TestCases; 2 | using UnityEngine; 3 | 4 | namespace Box2DSharp.Testbed.Unity.Tests 5 | { 6 | [TestInherit] 7 | public class RayCastRender : RayCast 8 | { 9 | /// 10 | protected override void OnRender() 11 | { 12 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 13 | // ImGui.SetNextWindowSize(new Vector2(210.0f, 285.0f)); 14 | // ImGui.Begin("Ray-cast Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 15 | // 16 | // if (ImGui.Button("Shape 1")) 17 | // { 18 | // Create(0); 19 | // } 20 | // 21 | // if (ImGui.Button("Shape 2")) 22 | // { 23 | // Create(1); 24 | // } 25 | // 26 | // if (ImGui.Button("Shape 3")) 27 | // { 28 | // Create(2); 29 | // } 30 | // 31 | // if (ImGui.Button("Shape 4")) 32 | // { 33 | // Create(3); 34 | // } 35 | // 36 | // if (ImGui.Button("Shape 5")) 37 | // { 38 | // Create(4); 39 | // } 40 | // 41 | // if (ImGui.Button("Shape 6")) 42 | // { 43 | // Create(5); 44 | // } 45 | // 46 | // if (ImGui.Button("Destroy Shape")) 47 | // { 48 | // DestroyBody(); 49 | // } 50 | // 51 | // var mode = (int)_mode; 52 | // ImGui.RadioButton("Any", ref mode, (int)Mode.Any); 53 | // ImGui.RadioButton("Closest", ref mode, (int)Mode.Closest); 54 | // ImGui.RadioButton("Multiple", ref mode, (int)Mode.Multiple); 55 | // _mode = (Mode)mode; 56 | // var deg = (float)_degrees; 57 | // ImGui.SliderFloat("Angle", ref deg, 0.0f, 360.0f, "%.0f"); 58 | // _degrees = deg; 59 | // ImGui.End(); 60 | base.OnRender(); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/ChainProblem.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Bugs", "Chain Problem")] 9 | public class ChainProblem : TestBase 10 | { 11 | public ChainProblem() 12 | { 13 | FVector2 g = new FVector2(0.0f, -10.0f); 14 | World.Gravity = g; 15 | var bodies = new Body[2]; 16 | { 17 | BodyDef bd = new BodyDef(); 18 | bd.BodyType = BodyType.StaticBody; 19 | bodies[0] = World.CreateBody(bd); 20 | 21 | { 22 | var v1 = new FVector2(0.0f, 1.0f); 23 | var v2 = new FVector2(0.0f, 0.0f); 24 | var v3 = new FVector2(4.0f, 0.0f); 25 | 26 | EdgeShape shape = new EdgeShape(); 27 | shape.SetTwoSided(v1, v2); 28 | bodies[0].CreateFixture(shape, 0.0f); 29 | 30 | shape.SetTwoSided(v2, v3); 31 | bodies[0].CreateFixture(shape, 0.0f); 32 | } 33 | } 34 | { 35 | BodyDef bd = new BodyDef(); 36 | bd.BodyType = BodyType.DynamicBody; 37 | 38 | //bd.position.Set(6.033980250358582e-01f, 3.028350114822388e+00f); 39 | bd.Position.Set(1.0f, 3.0f); 40 | bodies[1] = World.CreateBody(bd); 41 | 42 | { 43 | FixtureDef fd = new FixtureDef(); 44 | fd.Friction = 0.2f; 45 | fd.Density = 10.0f; 46 | PolygonShape shape = new PolygonShape(); 47 | var vs = new FVector2[8]; 48 | vs[0].Set(0.5f, -3.0f); 49 | vs[1].Set(0.5f, 3.0f); 50 | vs[2].Set(-0.5f, 3.0f); 51 | vs[3].Set(-0.5f, -3.0f); 52 | shape.Set(vs, 4); 53 | 54 | fd.Shape = shape; 55 | 56 | bodies[1].CreateFixture(fd); 57 | } 58 | } 59 | bodies = default; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /test/Testbed.TestCases/DumpLoader.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Testbed.Abstractions; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Bugs", "Dump Loader")] 9 | public class DumpLoader : TestBase 10 | { 11 | private readonly Body m_ball; 12 | 13 | public DumpLoader() 14 | { 15 | var chainShape = new ChainShape(); 16 | FVector2[] vertices = { new FVector2(-5, 0), new FVector2(5, 0), new FVector2(5, 5), new FVector2(4, 1), new FVector2(-4, 1), new FVector2(-5, 5) }; 17 | chainShape.CreateLoop(vertices, 6); 18 | 19 | var groundFixtureDef = new FixtureDef(); 20 | groundFixtureDef.Density = 0; 21 | groundFixtureDef.Shape = chainShape; 22 | 23 | var groundBodyDef = new BodyDef(); 24 | groundBodyDef.BodyType = BodyType.StaticBody; 25 | 26 | var groundBody = World.CreateBody(groundBodyDef); 27 | var groundBodyFixture = groundBody.CreateFixture(groundFixtureDef); 28 | 29 | var ballShape = new CircleShape(); 30 | ballShape.Radius = 1; 31 | 32 | var ballFixtureDef = new FixtureDef(); 33 | ballFixtureDef.Restitution = 0.75f; 34 | ballFixtureDef.Density = 1; 35 | ballFixtureDef.Shape = ballShape; 36 | 37 | var ballBodyDef = new BodyDef(); 38 | ballBodyDef.BodyType = BodyType.DynamicBody; 39 | ballBodyDef.Position = new FVector2(0, 10); 40 | 41 | // ballBodyDef.angularDamping = 0.2f; 42 | 43 | m_ball = World.CreateBody(ballBodyDef); 44 | var ballFixture = m_ball.CreateFixture(ballFixtureDef); 45 | m_ball.ApplyForceToCenter(new FVector2(-1000, -400), true); 46 | } 47 | 48 | /// 49 | protected override void PreStep() 50 | { 51 | var v = m_ball.LinearVelocity; 52 | var omega = m_ball.AngularVelocity; 53 | 54 | var massData = m_ball.GetMassData(); 55 | 56 | var ke = 0.5f * massData.Mass * FVector2.Dot(v, v) + 0.5f * massData.RotationInertia * omega * omega; 57 | 58 | DrawString($"kinetic energy = {ke}"); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /test/Testbed/Tests/DistanceJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics.Joints; 4 | using ImGuiNET; 5 | using Testbed.TestCases; 6 | 7 | namespace Testbed.Tests 8 | { 9 | [TestInherit] 10 | public class DistanceJointTestRender : DistanceJointTest 11 | { 12 | /// 13 | protected override void OnRender() 14 | { 15 | ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 16 | ImGui.SetNextWindowSize(new Vector2(260.0f, 150.0f)); 17 | ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 18 | float len = (float)m_length; 19 | if (ImGui.SliderFloat("Length", ref len, 0.0f, 20.0f, "%.0f")) 20 | { 21 | m_length = m_joint.SetLength(len); 22 | } 23 | 24 | float minlen = (float)m_minLength; 25 | if (ImGui.SliderFloat("Min Length", ref minlen, 0.0f, 20.0f, "%.0f")) 26 | { 27 | m_minLength = m_joint.SetMinLength(minlen); 28 | } 29 | 30 | float maxLen = (float)m_maxLength; 31 | if (ImGui.SliderFloat("Max Length", ref maxLen, 0.0f, 20.0f, "%.0f")) 32 | { 33 | m_maxLength = m_joint.SetMaxLength(maxLen); 34 | } 35 | 36 | float hz = (float)m_hertz; 37 | if (ImGui.SliderFloat("Hertz", ref hz, 0.0f, 10.0f, "%.1f")) 38 | { 39 | m_hertz = hz; 40 | JointUtils.LinearStiffness(out var stiffness, out var damping, m_hertz, m_dampingRatio, m_joint.BodyA, m_joint.BodyB); 41 | m_joint.Stiffness = stiffness; 42 | m_joint.Damping = damping; 43 | } 44 | 45 | float ratio = (float)m_dampingRatio; 46 | if (ImGui.SliderFloat("Damping Ratio", ref ratio, 0.0f, 2.0f, "%.1f")) 47 | { 48 | m_dampingRatio = ratio; 49 | JointUtils.LinearStiffness(out var stiffness, out var damping, m_hertz, m_dampingRatio, m_joint.BodyA, m_joint.BodyB); 50 | m_joint.Stiffness = stiffness; 51 | m_joint.Damping = damping; 52 | } 53 | 54 | ImGui.End(); 55 | base.OnRender(); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Dynamics/Joints/DistanceJointDef.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Common; 2 | 3 | namespace Box2DSharp.Dynamics.Joints 4 | { 5 | /// Distance joint definition. This requires defining an anchor point on both 6 | /// bodies and the non-zero distance of the distance joint. The definition uses 7 | /// local anchor points so that the initial configuration can violate the 8 | /// constraint slightly. This helps when saving and loading a game. 9 | public class DistanceJointDef : JointDef 10 | { 11 | /// Minimum length. Clamped to a stable minimum value. 12 | public FP MinLength; 13 | 14 | /// Maximum length. Must be greater than or equal to the minimum length. 15 | public FP MaxLength; 16 | 17 | /// The linear stiffness in N/m. 18 | public FP Stiffness; 19 | 20 | /// The linear damping in N*s/m. 21 | public FP Damping; 22 | 23 | /// The rest length of this joint. Clamped to a stable minimum value. 24 | public FP Length; 25 | 26 | /// The local anchor point relative to bodyA's origin. 27 | public FVector2 LocalAnchorA; 28 | 29 | /// The local anchor point relative to bodyB's origin. 30 | public FVector2 LocalAnchorB; 31 | 32 | public DistanceJointDef() 33 | { 34 | JointType = JointType.DistanceJoint; 35 | LocalAnchorA.Set(0.0f, 0.0f); 36 | LocalAnchorB.Set(0.0f, 0.0f); 37 | MinLength = 0.0f; 38 | MaxLength = Settings.MaxFloat; 39 | Length = 1.0f; 40 | Stiffness = 0.0f; 41 | Damping = 0.0f; 42 | } 43 | 44 | /// Initialize the bodies, anchors, and rest length using world space anchors. 45 | /// The minimum and maximum lengths are set to the rest length. 46 | public void Initialize( 47 | Body b1, 48 | Body b2, 49 | in FVector2 anchor1, 50 | in FVector2 anchor2) 51 | { 52 | BodyA = b1; 53 | BodyB = b2; 54 | LocalAnchorA = BodyA.GetLocalPoint(anchor1); 55 | LocalAnchorB = BodyB.GetLocalPoint(anchor2); 56 | var d = anchor2 - anchor1; 57 | Length = FP.Max(d.Length(), Settings.LinearSlop); 58 | MinLength = Length; 59 | MaxLength = Length; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/DistanceJointTest.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Box2DSharp.Dynamics.Joints; 5 | using Testbed.Abstractions; 6 | 7 | namespace Testbed.TestCases 8 | { 9 | [TestCase("Joints", "Distance Joint")] 10 | public class DistanceJointTest : TestBase 11 | { 12 | public DistanceJoint m_joint; 13 | 14 | public FP m_length; 15 | 16 | public FP m_minLength; 17 | 18 | public FP m_maxLength; 19 | 20 | public FP m_hertz; 21 | 22 | public FP m_dampingRatio; 23 | 24 | public DistanceJointTest() 25 | { 26 | Body ground = null; 27 | { 28 | BodyDef bd = new BodyDef(); 29 | ground = World.CreateBody(bd); 30 | 31 | EdgeShape shape = new EdgeShape(); 32 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 33 | ground.CreateFixture(shape, 0.0f); 34 | } 35 | { 36 | BodyDef bd = new BodyDef(); 37 | bd.BodyType = BodyType.DynamicBody; 38 | bd.AngularDamping = 0.1f; 39 | 40 | bd.Position.Set(0.0f, 5.0f); 41 | Body body = World.CreateBody(bd); 42 | 43 | PolygonShape shape = new PolygonShape(); 44 | shape.SetAsBox(0.5f, 0.5f); 45 | body.CreateFixture(shape, 5.0f); 46 | 47 | m_hertz = 1.0f; 48 | m_dampingRatio = 0.7f; 49 | 50 | DistanceJointDef jd = new DistanceJointDef(); 51 | jd.Initialize(ground, body, new FVector2(0.0f, 15.0f), bd.Position); 52 | jd.CollideConnected = true; 53 | m_length = jd.Length; 54 | m_minLength = m_length; 55 | m_maxLength = m_length; 56 | JointUtils.LinearStiffness(out jd.Stiffness, out jd.Damping, m_hertz, m_dampingRatio, jd.BodyA, jd.BodyB); 57 | m_joint = (DistanceJoint)World.CreateJoint(jd); 58 | } 59 | } 60 | 61 | /// 62 | protected override void OnRender() 63 | { 64 | DrawString("This demonstrates a soft distance joint."); 65 | DrawString("Press: (b) to delete a Body, (j) to delete a joint"); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/Heavy2.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Dynamics; 3 | using Testbed.Abstractions; 4 | using Box2DSharp.Common; 5 | 6 | namespace Testbed.TestCases 7 | { 8 | [TestCase("Solver", "Heavy 2")] 9 | public class Heavy2 : TestBase 10 | { 11 | private Body _heavy; 12 | 13 | public Heavy2() 14 | { 15 | { 16 | var bd = new BodyDef(); 17 | var ground = World.CreateBody(bd); 18 | 19 | var shape = new EdgeShape(); 20 | shape.SetTwoSided(new FVector2(-40.0f, 0.0f), new FVector2(40.0f, 0.0f)); 21 | ground.CreateFixture(shape, 0.0f); 22 | } 23 | { 24 | var bd = new BodyDef 25 | { 26 | BodyType = BodyType.DynamicBody, 27 | Position = new FVector2(0.0f, 2.5f) 28 | }; 29 | var body = World.CreateBody(bd); 30 | 31 | var shape = new CircleShape {Radius = 0.5f}; 32 | body.CreateFixture(shape, 10.0f); 33 | 34 | bd.Position = new FVector2(0.0f, 3.5f); 35 | body = World.CreateBody(bd); 36 | body.CreateFixture(shape, 10.0f); 37 | } 38 | _heavy = null; 39 | } 40 | 41 | void ToggleHeavy() 42 | { 43 | if (_heavy != null) 44 | { 45 | World.DestroyBody(_heavy); 46 | _heavy = null; 47 | } 48 | else 49 | { 50 | var bd = new BodyDef 51 | { 52 | BodyType = BodyType.DynamicBody, 53 | Position = new FVector2(0.0f, 9.0f) 54 | }; 55 | _heavy = World.CreateBody(bd); 56 | 57 | var shape = new CircleShape {Radius = 5.0f}; 58 | _heavy.CreateFixture(shape, 10.0f); 59 | } 60 | } 61 | 62 | /// 63 | public override void OnKeyDown(KeyInputEventArgs keyInput) 64 | { 65 | if (keyInput.Key == KeyCodes.H) 66 | { 67 | ToggleHeavy(); 68 | } 69 | } 70 | 71 | protected override void OnRender() 72 | { 73 | DrawString("Press H to place heavy body"); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/Dynamics/IContactListener.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Collider; 2 | using Box2DSharp.Dynamics.Contacts; 3 | 4 | namespace Box2DSharp.Dynamics 5 | { 6 | /// Implement this class to get contact information. You can use these results for 7 | /// things like sounds and game logic. You can also get contact results by 8 | /// traversing the contact lists after the time step. However, you might miss 9 | /// some contacts because continuous physics leads to sub-stepping. 10 | /// Additionally you may receive multiple callbacks for the same contact in a 11 | /// single time step. 12 | /// You should strive to make your callbacks efficient because there may be 13 | /// many callbacks per time step. 14 | /// @warning You cannot create/destroy Box2D entities inside these callbacks. 15 | public interface IContactListener 16 | { 17 | /// Called when two fixtures begin to touch. 18 | void BeginContact(Contact contact); 19 | 20 | /// Called when two fixtures cease to touch. 21 | void EndContact(Contact contact); 22 | 23 | /// This is called after a contact is updated. This allows you to inspect a 24 | /// contact before it goes to the solver. If you are careful, you can modify the 25 | /// contact manifold (e.g. disable contact). 26 | /// A copy of the old manifold is provided so that you can detect changes. 27 | /// Note: this is called only for awake bodies. 28 | /// Note: this is called even when the number of contact points is zero. 29 | /// Note: this is not called for sensors. 30 | /// Note: if you set the number of contact points to zero, you will not 31 | /// get an EndContact callback. However, you may get a BeginContact callback 32 | /// the next step. 33 | void PreSolve(Contact contact, in Manifold oldManifold); 34 | 35 | /// This lets you inspect a contact after the solver is finished. This is useful 36 | /// for inspecting impulses. 37 | /// Note: the contact manifold does not include time of impact impulses, which can be 38 | /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly 39 | /// in a separate data structure. 40 | /// Note: this is only called for contacts that are touching, solid, and awake. 41 | void PostSolve(Contact contact, in ContactImpulse impulse); 42 | } 43 | } -------------------------------------------------------------------------------- /src/Collision/Shapes/Sweep.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Box2DSharp.Common; 3 | 4 | namespace Box2DSharp.Collision.Shapes 5 | { 6 | /// This describes the motion of a body/shape for TOI computation. 7 | /// Shapes are defined with respect to the body origin, which may 8 | /// no coincide with the center of mass. However, to support dynamics 9 | /// we must interpolate the center of mass position. 10 | public struct Sweep 11 | { 12 | /// 13 | /// Get the interpolated transform at a specific time. 14 | /// @param beta is a factor in [0,1], where 0 indicates alpha0. 15 | /// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ 16 | /// 17 | /// 18 | /// 19 | public void GetTransform(out Transform xf, FP beta) 20 | { 21 | var position = (1.0f - beta) * C0 + beta * C; 22 | var angle = (1.0f - beta) * A0 + beta * A; 23 | xf = new Transform(position, angle); 24 | 25 | // Shift to origin 26 | xf.Position -= MathUtils.Mul(xf.Rotation, LocalCenter); 27 | } 28 | 29 | /// Advance the sweep forward, yielding a new initial state. 30 | /// @param alpha the new initial time. 31 | public void Advance(FP alpha) 32 | { 33 | Debug.Assert(Alpha0 < 1.0f); 34 | var beta = (alpha - Alpha0) / (1.0f - Alpha0); 35 | C0 += beta * (C - C0); 36 | A0 += beta * (A - A0); 37 | Alpha0 = alpha; 38 | } 39 | 40 | /// Normalize the angles. 41 | public void Normalize() 42 | { 43 | var d = FP.PiTimes2 * FP.Floor(A0 / FP.PiTimes2); 44 | A0 -= d; 45 | A -= d; 46 | } 47 | 48 | /// 49 | /// local center of mass position 50 | /// 51 | public FVector2 LocalCenter; 52 | 53 | /// 54 | /// center world positions 55 | /// 56 | public FVector2 C0, C; 57 | 58 | /// 59 | /// world angles 60 | /// 61 | public FP A0, A; 62 | 63 | /// Fraction of the current time step in the range [0,1] 64 | /// c0 and a0 are the positions at alpha0. 65 | public FP Alpha0; 66 | } 67 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/ConveyorBelt.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Collider; 2 | using Box2DSharp.Collision.Shapes; 3 | using Box2DSharp.Common; 4 | using Box2DSharp.Dynamics; 5 | using Box2DSharp.Dynamics.Contacts; 6 | using Testbed.Abstractions; 7 | 8 | namespace Testbed.TestCases 9 | { 10 | [TestCase("Examples", "Conveyor Belt")] 11 | public class ConveyorBelt : TestBase 12 | { 13 | private Fixture _platform; 14 | 15 | public ConveyorBelt() 16 | { 17 | // Ground 18 | { 19 | var bd = new BodyDef(); 20 | var ground = World.CreateBody(bd); 21 | 22 | var shape = new EdgeShape(); 23 | shape.SetTwoSided(new FVector2(-20.0f, 0.0f), new FVector2(20.0f, 0.0f)); 24 | ground.CreateFixture(shape, 0.0f); 25 | } 26 | 27 | // Platform 28 | { 29 | var bd = new BodyDef(); 30 | bd.Position.Set(-5.0f, 5.0f); 31 | var body = World.CreateBody(bd); 32 | 33 | var shape = new PolygonShape(); 34 | shape.SetAsBox(10.0f, 0.5f); 35 | 36 | var fd = new FixtureDef(); 37 | fd.Shape = shape; 38 | fd.Friction = 0.8f; 39 | _platform = body.CreateFixture(fd); 40 | } 41 | 42 | // Boxes 43 | for (var i = 0; i < 5; ++i) 44 | { 45 | var bd = new BodyDef(); 46 | bd.BodyType = BodyType.DynamicBody; 47 | bd.Position.Set(-10.0f + 2.0f * i, 7.0f); 48 | var body = World.CreateBody(bd); 49 | 50 | var shape = new PolygonShape(); 51 | shape.SetAsBox(0.5f, 0.5f); 52 | body.CreateFixture(shape, 20.0f); 53 | } 54 | } 55 | 56 | /// 57 | public override void PreSolve(Contact contact, in Manifold oldManifold) 58 | { 59 | base.PreSolve(contact, oldManifold); 60 | 61 | var fixtureA = contact.FixtureA; 62 | var fixtureB = contact.FixtureB; 63 | 64 | if (fixtureA == _platform) 65 | { 66 | contact.SetTangentSpeed(5.0f); 67 | } 68 | 69 | if (fixtureB == _platform) 70 | { 71 | contact.SetTangentSpeed(-5.0f); 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Box2DSharp deterministic version 2 | A C# port of [Box2D](https://github.com/erincatto/Box2D) 3 | 4 | Synchronized commits: 5 | ``` 6 | 9dc24a6fd4f32442c4bcf80791de47a0a7d25afb 7 | 2021/12/31 9:05:49 8 | ``` 9 | 10 | # Communicate 11 | 12 | [![Join the chat at Discord](https://img.shields.io/badge/Discord-Join%20chat-blue)](https://discord.gg/C244nr3) 13 | [![加入QQ群](https://img.shields.io/badge/QQ%20Group-加入QQ群-orange)](https://jq.qq.com/?_wv=1027&k=b2zyTWnZ) 14 | 15 | # Unity test 16 | Run `CopyToUnityTestbed.bat` to copy source code and test code to Unity project 17 | 18 | # Testbed 19 | Driven by [OpenTk](https://github.com/opentk/opentk) + [ImGui.NET](https://github.com/mellinoe/imgui.net) 20 | 21 | # Test cases 22 | 23 | ## Benchmark 24 | * [x] Add Pair Stress Test 25 | * [x] Tiles 26 | * [x] Tumbler 27 | 28 | ## Bugs 29 | * [x] Chain Problem 30 | * [x] Dump Loader 31 | * [x] Skier 32 | 33 | ## Collision 34 | * [x] Dynamic Tree 35 | * [x] Ray Cast 36 | * [x] Sensors 37 | * [x] Shape Cast 38 | * [x] Time of Impact 39 | 40 | ## Continuous 41 | * [x] Bullet Test 42 | * [x] Continuous Test 43 | 44 | ## Examples 45 | * [x] BodyTypes 46 | * [x] Breakable 47 | * [x] Car 48 | * [x] Character Collision 49 | * [x] Collision Filtering 50 | * [x] Collision Processing 51 | * [x] Compound Shapes 52 | * [x] Conveyor Belt 53 | * [x] Dominos 54 | * [x] HelloWorld 55 | * [x] Pinball 56 | * [x] Platformer 57 | * [x] Shape Editing 58 | * [x] Slider Crank 1 59 | * [x] Slider Crank 2 60 | * [x] Theo Jansen 61 | * [x] Web 62 | * [x] Wrecking Ball 63 | 64 | ## Extra 65 | * [x] Position Test 66 | 67 | ## Forces 68 | * [x] ApplyForce 69 | * [x] Friction 70 | * [x] Restitution 71 | 72 | ## Geometry 73 | * [x] Convex Hull 74 | * [x] Distance Test 75 | * [x] Edge Shapes 76 | * [x] Edge Test 77 | * [x] Polygon Collision 78 | * [x] Polygon Shapes 79 | 80 | ## Joints 81 | * [x] Bridge 82 | * [x] Cantilever 83 | * [x] Chain 84 | * [x] Distance Joint 85 | * [x] Gear 86 | * [x] Motor Joint 87 | * [x] Prismatic 88 | * [x] Pulley 89 | * [x] Revolute 90 | * [x] Wheel 91 | 92 | ## Rope 93 | * [x] Bending 94 | 95 | ## Solver 96 | * [x] Confined 97 | * [x] Heavy 1 98 | * [x] Heavy 2 99 | * [x] Mobile Balanced 100 | * [x] Mobile Unbalanced 101 | 102 | ## Stacking 103 | * [x] Boxes 104 | * [x] Circles 105 | * [x] Pyramid 106 | 107 | # License 108 | [MIT license](https://en.wikipedia.org/wiki/MIT_License). 109 | -------------------------------------------------------------------------------- /test/UnitTest/WorldTest.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Collider; 2 | using Box2DSharp.Collision.Shapes; 3 | using Box2DSharp.Common; 4 | using Box2DSharp.Dynamics; 5 | using Box2DSharp.Dynamics.Contacts; 6 | using Shouldly; 7 | using Xunit; 8 | 9 | namespace UnitTest 10 | { 11 | public class MyContactListener : IContactListener 12 | { 13 | public bool begin_contact = false; 14 | 15 | /// 16 | public void BeginContact(Contact contact) 17 | { 18 | begin_contact = true; 19 | } 20 | 21 | /// 22 | public void EndContact(Contact contact) 23 | { } 24 | 25 | /// 26 | public void PreSolve(Contact contact, in Manifold oldManifold) 27 | { } 28 | 29 | /// 30 | public void PostSolve(Contact contact, in ContactImpulse impulse) 31 | { } 32 | } 33 | 34 | public class WorldTest 35 | { 36 | [Fact(DisplayName = "begin contact")] 37 | public void BeginContact() 38 | { 39 | World world = new World(new FVector2(0.0f, -10.0f)); 40 | MyContactListener listener = new MyContactListener(); 41 | world.SetContactListener(listener); 42 | 43 | CircleShape circle = new CircleShape(); 44 | circle.Radius = 5; 45 | 46 | BodyDef bodyDef = new BodyDef(); 47 | bodyDef.BodyType = BodyType.DynamicBody; 48 | 49 | var bodyA = world.CreateBody(bodyDef); 50 | var bodyB = world.CreateBody(bodyDef); 51 | bodyA.CreateFixture(circle, 0.0f); 52 | bodyB.CreateFixture(circle, 0.0f); 53 | 54 | bodyA.SetTransform(new FVector2(0f, 0f), 0f); 55 | bodyB.SetTransform(new FVector2(100f, 0f), 0f); 56 | 57 | const float timeStep = 1f / 60f; 58 | const int velocityIterations = 6; 59 | const int positionIterations = 2; 60 | 61 | world.Step(timeStep, velocityIterations, positionIterations); 62 | 63 | world.ContactManager.ContactList.ShouldBeEmpty(); 64 | listener.begin_contact.ShouldBeFalse(); 65 | 66 | bodyB.SetTransform(new FVector2(1f, 0f), 0f); 67 | 68 | world.Step(timeStep, velocityIterations, positionIterations); 69 | 70 | world.ContactManager.ContactList.ShouldNotBeEmpty(); 71 | listener.begin_contact.ShouldBeTrue(); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/Collision/Shapes/Shape.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Collider; 2 | using Box2DSharp.Common; 3 | 4 | namespace Box2DSharp.Collision.Shapes 5 | { 6 | /// This holds the mass data computed for a shape. 7 | /// A shape is used for collision detection. You can create a shape however you like. 8 | /// Shapes used for simulation in b2World are created automatically when a b2Fixture 9 | /// is created. Shapes may encapsulate a one or more child shapes. 10 | public abstract class Shape 11 | { 12 | /// Radius of a shape. For polygonal shapes this must be b2_polygonRadius. There is no support for 13 | /// making rounded polygons. 14 | public FP Radius { get; internal set; } 15 | 16 | public ShapeType ShapeType { get; internal set; } 17 | 18 | /// Clone the concrete shape using the provided allocator. 19 | public abstract Shape Clone(); 20 | 21 | /// Get the number of child primitives. 22 | public abstract int GetChildCount(); 23 | 24 | /// Test a point for containment in this shape. This only works for convex shapes. 25 | /// @param xf the shape world transform. 26 | /// @param p a point in world coordinates. 27 | public abstract bool TestPoint(in Transform transform, in FVector2 point); 28 | 29 | /// Cast a ray against a child shape. 30 | /// @param output the ray-cast results. 31 | /// @param input the ray-cast input parameters. 32 | /// @param transform the transform to be applied to the shape. 33 | /// @param childIndex the child shape index 34 | public abstract bool RayCast( 35 | out RayCastOutput output, 36 | in RayCastInput input, 37 | in Transform transform, 38 | int childIndex); 39 | 40 | /// Given a transform, compute the associated axis aligned bounding box for a child shape. 41 | /// @param aabb returns the axis aligned box. 42 | /// @param xf the world transform of the shape. 43 | /// @param childIndex the child shape 44 | public abstract void ComputeAABB(out AABB aabb, in Transform xf, int childIndex); 45 | 46 | /// Compute the mass properties of this shape using its dimensions and density. 47 | /// The inertia tensor is computed about the local origin. 48 | /// @param massData returns the mass data for this shape. 49 | /// @param density the density in kilograms per meter squared. 50 | public abstract void ComputeMass(out MassData massData, FP density); 51 | } 52 | } -------------------------------------------------------------------------------- /src/Dynamics/Joints/PulleyJointDef.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Box2DSharp.Common; 3 | 4 | namespace Box2DSharp.Dynamics.Joints 5 | { 6 | /// Pulley joint definition. This requires two ground anchors, 7 | /// two dynamic body anchor points, and a pulley ratio. 8 | public class PulleyJointDef : JointDef 9 | { 10 | /// The first ground anchor in world coordinates. This point never moves. 11 | public FVector2 GroundAnchorA; 12 | 13 | /// The second ground anchor in world coordinates. This point never moves. 14 | public FVector2 GroundAnchorB; 15 | 16 | /// The a reference length for the segment attached to bodyA. 17 | public FP LengthA; 18 | 19 | /// The a reference length for the segment attached to bodyB. 20 | public FP LengthB; 21 | 22 | /// The local anchor point relative to bodyA's origin. 23 | public FVector2 LocalAnchorA; 24 | 25 | /// The local anchor point relative to bodyB's origin. 26 | public FVector2 LocalAnchorB; 27 | 28 | /// The pulley ratio, used to simulate a block-and-tackle. 29 | public FP Ratio; 30 | 31 | public PulleyJointDef() 32 | { 33 | JointType = JointType.PulleyJoint; 34 | 35 | GroundAnchorA.Set(-1.0f, 1.0f); 36 | 37 | GroundAnchorB.Set(1.0f, 1.0f); 38 | 39 | LocalAnchorA.Set(-1.0f, 0.0f); 40 | 41 | LocalAnchorB.Set(1.0f, 0.0f); 42 | 43 | LengthA = 0.0f; 44 | 45 | LengthB = 0.0f; 46 | 47 | Ratio = 1.0f; 48 | 49 | CollideConnected = true; 50 | } 51 | 52 | /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. 53 | public void Initialize( 54 | Body bA, 55 | Body bB, 56 | in FVector2 groundA, 57 | in FVector2 groundB, 58 | in FVector2 anchorA, 59 | in FVector2 anchorB, 60 | FP r) 61 | { 62 | BodyA = bA; 63 | BodyB = bB; 64 | GroundAnchorA = groundA; 65 | GroundAnchorB = groundB; 66 | LocalAnchorA = BodyA.GetLocalPoint(anchorA); 67 | LocalAnchorB = BodyB.GetLocalPoint(anchorB); 68 | var dA = anchorA - groundA; 69 | LengthA = dA.Length(); 70 | var dB = anchorB - groundB; 71 | LengthB = dB.Length(); 72 | Ratio = r; 73 | Debug.Assert(Ratio > Settings.Epsilon); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /test/Testbed/Render/RenderHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using OpenTK.Graphics.OpenGL4; 4 | 5 | namespace Testbed.Render 6 | { 7 | public static class RenderHelper 8 | { 9 | public static void CheckGLError() 10 | { 11 | var errCode = GL.GetError(); 12 | if (errCode == ErrorCode.NoError) 13 | { 14 | return; 15 | } 16 | 17 | Console.WriteLine($"OpenGL error = {errCode}"); 18 | Debug.Assert(false); 19 | } 20 | 21 | public static void PrintLog(int obj) 22 | { 23 | string log = null; 24 | if (GL.IsShader(obj)) 25 | { 26 | GL.GetShaderInfoLog(obj, out log); 27 | } 28 | else if (GL.IsProgram(obj)) 29 | { 30 | GL.GetProgramInfoLog(obj, out log); 31 | } 32 | 33 | Console.WriteLine(!string.IsNullOrWhiteSpace(log) ? log : "printlog: Not a shader or a program"); 34 | } 35 | 36 | public static int CreateShaderFromString(string source, ShaderType type) 37 | { 38 | var res = GL.CreateShader(type); 39 | 40 | GL.ShaderSource(res, source); 41 | GL.CompileShader(res); 42 | var error = GL.GetShaderInfoLog(res); 43 | if (!string.IsNullOrWhiteSpace(error)) 44 | { 45 | Console.WriteLine($"Error compiling shader {res} of type {type}: {error}"); 46 | PrintLog(res); 47 | GL.DeleteShader(res); 48 | return 0; 49 | } 50 | 51 | return res; 52 | } 53 | 54 | // 55 | public static int CreateShaderProgram(string vs, string fs) 56 | { 57 | var vsId = CreateShaderFromString(vs, ShaderType.VertexShader); 58 | var fsId = CreateShaderFromString(fs, ShaderType.FragmentShader); 59 | Debug.Assert(vsId != 0 && fsId != 0); 60 | 61 | var programId = GL.CreateProgram(); 62 | GL.AttachShader(programId, vsId); 63 | GL.AttachShader(programId, fsId); 64 | GL.BindFragDataLocation(programId, 0, "color"); 65 | GL.LinkProgram(programId); 66 | 67 | GL.DeleteShader(vsId); 68 | GL.DeleteShader(fsId); 69 | 70 | GL.GetProgram(programId, GetProgramParameterName.LinkStatus, out var status); 71 | Debug.Assert(status != (int)All.False); 72 | 73 | return programId; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/CustomFixedUpdate.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Box2DSharp.Testbed.Unity 4 | { 5 | public class CustomFixedUpdate 6 | { 7 | public delegate void OnFixedUpdateCallback(float aDeltaTime); 8 | 9 | private float m_FixedTimeStep; 10 | 11 | private float m_Timer = 0; 12 | 13 | private OnFixedUpdateCallback m_Callback; 14 | 15 | public float MaxAllowedTimeStep { get; set; } = 0f; 16 | 17 | public float DeltaTime 18 | { 19 | get => m_FixedTimeStep; 20 | set => m_FixedTimeStep = Mathf.Max(value, 0.000001f); // max rate: 1000000 21 | } 22 | 23 | public float UpdateRate 24 | { 25 | get => 1.0f / DeltaTime; 26 | set => DeltaTime = 1.0f / value; 27 | } 28 | 29 | public CustomFixedUpdate(float aTimeStep, OnFixedUpdateCallback aCallback, float aMaxAllowedTimestep = 0f) 30 | { 31 | if (aTimeStep <= 0f) 32 | { 33 | throw new System.ArgumentException("TimeStep needs to be greater than 0"); 34 | } 35 | 36 | m_Callback = aCallback ?? throw new System.ArgumentException("CustomFixedUpdate needs a valid callback"); 37 | DeltaTime = aTimeStep; 38 | MaxAllowedTimeStep = aMaxAllowedTimestep; 39 | } 40 | 41 | public CustomFixedUpdate(OnFixedUpdateCallback aCallback) 42 | : this(0.01f, aCallback, 0f) 43 | { } 44 | 45 | public CustomFixedUpdate(OnFixedUpdateCallback aCallback, float aFPS, float aMaxAllowedTimestep = 0f) 46 | : this(1f / aFPS, aCallback, aMaxAllowedTimestep) 47 | { } 48 | 49 | public void Update(float aDeltaTime) 50 | { 51 | m_Timer -= aDeltaTime; 52 | if (MaxAllowedTimeStep > 0) 53 | { 54 | var timeout = Time.realtimeSinceStartup + MaxAllowedTimeStep; 55 | while (m_Timer < 0f && Time.realtimeSinceStartup < timeout) 56 | { 57 | m_Callback(m_FixedTimeStep); 58 | m_Timer += m_FixedTimeStep; 59 | } 60 | } 61 | else 62 | { 63 | while (m_Timer < 0f) 64 | { 65 | m_Callback(m_FixedTimeStep); 66 | m_Timer += m_FixedTimeStep; 67 | } 68 | } 69 | } 70 | 71 | public void Update() 72 | { 73 | Update(Time.deltaTime); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /test/UnityTest/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 13 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 16003, guid: 0000000000000000f000000000000000, type: 0} 39 | m_PreloadedShaders: [] 40 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 41 | type: 0} 42 | m_CustomRenderPipeline: {fileID: 0} 43 | m_TransparencySortMode: 0 44 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 45 | m_DefaultRenderingPath: 1 46 | m_DefaultMobileRenderingPath: 1 47 | m_TierSettings: [] 48 | m_LightmapStripping: 0 49 | m_FogStripping: 0 50 | m_InstancingStripping: 0 51 | m_LightmapKeepPlain: 1 52 | m_LightmapKeepDirCombined: 1 53 | m_LightmapKeepDynamicPlain: 1 54 | m_LightmapKeepDynamicDirCombined: 1 55 | m_LightmapKeepShadowMask: 1 56 | m_LightmapKeepSubtractive: 1 57 | m_FogKeepLinear: 1 58 | m_FogKeepExp: 1 59 | m_FogKeepExp2: 1 60 | m_AlbedoSwatchInfos: [] 61 | m_LightsUseLinearIntensity: 0 62 | m_LightsUseColorTemperature: 0 63 | m_LogWhenShaderIsCompiled: 0 64 | m_AllowEnlightenSupportForUpgradedProject: 1 65 | -------------------------------------------------------------------------------- /test/Testbed.TestCases/Mobile.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Box2DSharp.Dynamics.Joints; 5 | using Testbed.Abstractions; 6 | 7 | namespace Testbed.TestCases 8 | { 9 | [TestCase("Solver", "Mobile Unbalanced")] 10 | public class Mobile : TestBase 11 | { 12 | private const int Depth = 4; 13 | 14 | public Mobile() 15 | { 16 | Body ground; 17 | 18 | // Create ground body. 19 | { 20 | var bodyDef = new BodyDef(); 21 | bodyDef.Position.Set(0.0f, 20.0f); 22 | ground = World.CreateBody(bodyDef); 23 | } 24 | 25 | var a = 0.5f; 26 | var h = new FVector2(0.0f, a); 27 | 28 | var root = AddNode(ground, FVector2.Zero, 0, 3.0f, a); 29 | 30 | var jointDef = new RevoluteJointDef(); 31 | jointDef.BodyA = ground; 32 | jointDef.BodyB = root; 33 | jointDef.LocalAnchorA.SetZero(); 34 | jointDef.LocalAnchorB = h; 35 | World.CreateJoint(jointDef); 36 | } 37 | 38 | private Body AddNode(Body parent, FVector2 localAnchor, int depth, FP offset, FP a) 39 | { 40 | var density = 20.0f; 41 | var h = new FVector2(0.0f, a); 42 | 43 | var p = parent.GetPosition() + localAnchor - h; 44 | 45 | var bodyDef = new BodyDef(); 46 | bodyDef.BodyType = BodyType.DynamicBody; 47 | bodyDef.Position = p; 48 | var body = World.CreateBody(bodyDef); 49 | 50 | var shape = new PolygonShape(); 51 | shape.SetAsBox(0.25f * a, a); 52 | body.CreateFixture(shape, density); 53 | 54 | if (depth == Depth) 55 | { 56 | return body; 57 | } 58 | 59 | var a1 = new FVector2(offset, -a); 60 | var a2 = new FVector2(-offset, -a); 61 | var body1 = AddNode(body, a1, depth + 1, 0.5f * offset, a); 62 | var body2 = AddNode(body, a2, depth + 1, 0.5f * offset, a); 63 | 64 | var jointDef = new RevoluteJointDef(); 65 | jointDef.BodyA = body; 66 | jointDef.LocalAnchorB = h; 67 | 68 | jointDef.LocalAnchorA = a1; 69 | jointDef.BodyB = body1; 70 | World.CreateJoint(jointDef); 71 | 72 | jointDef.LocalAnchorA = a2; 73 | jointDef.BodyB = body2; 74 | World.CreateJoint(jointDef); 75 | 76 | return body; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Tests/DistanceJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Dynamics.Joints; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.Tests 6 | { 7 | [TestInherit] 8 | public class DistanceJointTestRender : DistanceJointTest 9 | { 10 | /// 11 | public DistanceJointTestRender() 12 | { 13 | 14 | } 15 | 16 | /// 17 | protected override void OnRender() 18 | { 19 | // ImGui.SetNextWindowPos(new Vector2(10.0f, 100.0f)); 20 | // ImGui.SetNextWindowSize(new Vector2(260.0f, 150.0f)); 21 | // ImGui.Begin("Joint Controls", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 22 | // 23 | // float len = (float)m_length; 24 | // if (ImGui.SliderFloat("Length", ref len, 0.0f, 20.0f, "%.0f")) 25 | // { 26 | // m_length = m_joint.SetLength(len); 27 | // } 28 | // 29 | // float minlen = (float)m_minLength; 30 | // if (ImGui.SliderFloat("Min Length", ref minlen, 0.0f, 20.0f, "%.0f")) 31 | // { 32 | // m_minLength = m_joint.SetMinLength(minlen); 33 | // } 34 | // 35 | // float maxLen = (float)m_maxLength; 36 | // if (ImGui.SliderFloat("Max Length", ref maxLen, 0.0f, 20.0f, "%.0f")) 37 | // { 38 | // m_maxLength = m_joint.SetMaxLength(maxLen); 39 | // } 40 | // 41 | // float hz = (float)m_hertz; 42 | // if (ImGui.SliderFloat("Hertz", ref hz, 0.0f, 10.0f, "%.1f")) 43 | // { 44 | // m_hertz = hz; 45 | // JointUtils.LinearStiffness(out var stiffness, out var damping, m_hertz, m_dampingRatio, m_joint.BodyA, m_joint.BodyB); 46 | // m_joint.Stiffness = stiffness; 47 | // m_joint.Damping = damping; 48 | // } 49 | // 50 | // float ratio = (float)m_dampingRatio; 51 | // if (ImGui.SliderFloat("Damping Ratio", ref ratio, 0.0f, 2.0f, "%.1f")) 52 | // { 53 | // m_dampingRatio = ratio; 54 | // JointUtils.LinearStiffness(out var stiffness, out var damping, m_hertz, m_dampingRatio, m_joint.BodyA, m_joint.BodyB); 55 | // m_joint.Stiffness = stiffness; 56 | // m_joint.Damping = damping; 57 | // } 58 | // 59 | // ImGui.End(); 60 | base.OnRender(); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /test/UnityTest/Assets/Inspection/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Box2DSharp.Common; 3 | using UnityEngine; 4 | using Color = UnityEngine.Color; 5 | using SVector2 = System.Numerics.Vector2; 6 | using SVector3 = System.Numerics.Vector3; 7 | using UVector2 = UnityEngine.Vector2; 8 | using UVector3 = UnityEngine.Vector3; 9 | 10 | namespace Box2DSharp.Testbed.Unity.Inspection 11 | { 12 | public static class Utils 13 | { 14 | #region From FVector 15 | 16 | public static UVector2 ToUVector2(this FVector2 vector2) 17 | { 18 | return new UVector2(vector2.X.AsFloat, vector2.Y.AsFloat); 19 | } 20 | 21 | #endregion 22 | 23 | #region From System Vector 24 | 25 | public static UVector2 ToUVector2(in this SVector2 vector2) 26 | { 27 | return new UVector2(vector2.X, vector2.Y); 28 | } 29 | 30 | #endregion 31 | 32 | #region From Unity Vector 33 | 34 | public static UVector3 ToUVector3(in this UVector2 vector2) 35 | { 36 | return new UVector3(vector2.x, vector2.y, 0); 37 | } 38 | 39 | public static FVector2 ToFVector2(in this UVector3 vector3) 40 | { 41 | return new FVector2(vector3.x, vector3.y); 42 | } 43 | 44 | #endregion 45 | 46 | public static Color ToUnityColor(this Box2DSharp.Common.Color color) 47 | { 48 | return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); 49 | } 50 | } 51 | 52 | [AttributeUsage(AttributeTargets.Field, Inherited = true)] 53 | public class ShowOnlyAttribute : PropertyAttribute 54 | { } 55 | 56 | [AttributeUsage(AttributeTargets.Field, Inherited = true)] 57 | public class ShowVectorAttribute : PropertyAttribute 58 | { } 59 | #if UNITY_EDITOR 60 | [UnityEditor.CustomPropertyDrawer(typeof(ShowOnlyAttribute))] 61 | public class ShowOnlyAttributeDrawer : UnityEditor.PropertyDrawer 62 | { 63 | public override void OnGUI(Rect rect, UnityEditor.SerializedProperty prop, GUIContent label) 64 | { 65 | bool wasEnabled = GUI.enabled; 66 | GUI.enabled = false; 67 | UnityEditor.EditorGUI.PropertyField(rect, prop); 68 | GUI.enabled = wasEnabled; 69 | } 70 | } 71 | 72 | [UnityEditor.CustomPropertyDrawer(typeof(ShowVectorAttribute))] 73 | public class ShowVectorAttributeDrawer : UnityEditor.PropertyDrawer 74 | { 75 | public override void OnGUI(Rect rect, UnityEditor.SerializedProperty prop, GUIContent label) 76 | { 77 | UnityEditor.EditorGUI.PropertyField(rect, prop); 78 | } 79 | } 80 | #endif 81 | } -------------------------------------------------------------------------------- /test/Testbed.TestCases/PulleyJoint.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp.Collision.Shapes; 2 | using Box2DSharp.Common; 3 | using Box2DSharp.Dynamics; 4 | using Box2DSharp.Dynamics.Joints; 5 | using Testbed.Abstractions; 6 | 7 | namespace Testbed.TestCases 8 | { 9 | [TestCase("Joints", "Pulley")] 10 | public class PulleyJoint : TestBase 11 | { 12 | private Box2DSharp.Dynamics.Joints.PulleyJoint _joint1; 13 | 14 | public PulleyJoint() 15 | { 16 | var y = 16.0f; 17 | var L = 12.0f; 18 | var a = 1.0f; 19 | var b = 2.0f; 20 | 21 | Body ground; 22 | { 23 | var bd = new BodyDef(); 24 | ground = World.CreateBody(bd); 25 | 26 | var circle = new CircleShape(); 27 | circle.Radius = 2.0f; 28 | 29 | circle.Position.Set(-10.0f, y + b + L); 30 | ground.CreateFixture(circle, 0.0f); 31 | 32 | circle.Position.Set(10.0f, y + b + L); 33 | ground.CreateFixture(circle, 0.0f); 34 | } 35 | 36 | { 37 | var shape = new PolygonShape(); 38 | shape.SetAsBox(a, b); 39 | 40 | var bd = new BodyDef(); 41 | bd.BodyType = BodyType.DynamicBody; 42 | 43 | //bd.fixedRotation = true; 44 | bd.Position.Set(-10.0f, y); 45 | var body1 = World.CreateBody(bd); 46 | body1.CreateFixture(shape, 5.0f); 47 | 48 | bd.Position.Set(10.0f, y); 49 | var body2 = World.CreateBody(bd); 50 | body2.CreateFixture(shape, 5.0f); 51 | 52 | var pulleyDef = new PulleyJointDef(); 53 | var anchor1 = new FVector2(-10.0f, y + b); 54 | var anchor2 = new FVector2(10.0f, y + b); 55 | var groundAnchor1 = new FVector2(-10.0f, y + b + L); 56 | var groundAnchor2 = new FVector2(10.0f, y + b + L); 57 | pulleyDef.Initialize( 58 | body1, 59 | body2, 60 | groundAnchor1, 61 | groundAnchor2, 62 | anchor1, 63 | anchor2, 64 | 1.5f); 65 | 66 | _joint1 = (Box2DSharp.Dynamics.Joints.PulleyJoint)World.CreateJoint(pulleyDef); 67 | } 68 | } 69 | 70 | /// 71 | protected override void OnRender() 72 | { 73 | var ratio = _joint1.GetRatio(); 74 | var L = _joint1.GetCurrentLengthA() + ratio * _joint1.GetCurrentLengthB(); 75 | DrawString($"L1 + {ratio:F2} * L2 = {L:F2}"); 76 | } 77 | } 78 | } --------------------------------------------------------------------------------