├── .github └── FUNDING.yml ├── .gitignore ├── Box2DSharp.sln ├── LICENSE-Box2D.txt ├── LICENSE.txt ├── README.md ├── src ├── .gitignore ├── Body │ ├── Body.cs │ ├── BodyDef.cs │ ├── BodyEvents.cs │ ├── BodyMoveEvent.cs │ ├── BodySim.cs │ ├── BodyState.cs │ └── BodyType.cs ├── Box2DSharp.csproj ├── Box2DSharp.csproj.DotSettings ├── Box2DSharp.xkpkg.user ├── Collision │ ├── AABB.cs │ ├── Distance │ │ ├── DistanceCache.cs │ │ ├── DistanceInput.cs │ │ ├── DistanceOutput.cs │ │ ├── DistanceProxy.cs │ │ ├── SegmentDistanceResult.cs │ │ ├── ShapeCastPairInput.cs │ │ ├── Simplex.cs │ │ ├── SimplexVertex.cs │ │ ├── Sweep.cs │ │ ├── TOIInput.cs │ │ ├── TOIOutput.cs │ │ └── TOIState.cs │ ├── DynamicTree.cs │ ├── Geometry │ │ ├── BroadPhase.cs │ │ ├── Capsule.cs │ │ ├── CastOutput.cs │ │ ├── ChainDef.cs │ │ ├── ChainSegment.cs │ │ ├── ChainShape.cs │ │ ├── Circle.cs │ │ ├── DistanceFunc.cs │ │ ├── Filter.cs │ │ ├── Geometry.cs │ │ ├── Hull.cs │ │ ├── HullFunc.cs │ │ ├── MassData.cs │ │ ├── Polygon.cs │ │ ├── RayCastInput.cs │ │ ├── Segment.cs │ │ ├── Shape.cs │ │ ├── ShapeCastInput.cs │ │ ├── ShapeDef.cs │ │ ├── ShapeExtent.cs │ │ ├── ShapeType.cs │ │ └── UnionShape.cs │ ├── Manifold.cs │ ├── ManifoldFcn.cs │ ├── ManifoldFunc.cs │ ├── ManifoldPoint.cs │ └── RayResult.cs ├── Common │ ├── Array │ │ ├── BodySimArray.cs │ │ ├── BodyStateArray.cs │ │ ├── ContactArray.cs │ │ ├── IslandArray.cs │ │ └── JointArray.cs │ ├── ArrayHelper.cs │ ├── B2Array.cs │ ├── B2HashSet.cs │ ├── BitSet.cs │ ├── BitTool.cs │ ├── BodyId.cs │ ├── ChainId.cs │ ├── Core.cs │ ├── EnumExtensions.cs │ ├── FixedArray │ │ ├── FixedArray3.cs │ │ ├── FixedArray8.cs │ │ └── IFixedArray.cs │ ├── Guard.cs │ ├── HashTool.cs │ ├── IdPool.cs │ ├── InterlockedHelper.cs │ ├── JointId.cs │ ├── Pool │ │ ├── B2ArrayPool.cs │ │ └── B2ObjectPool.cs │ ├── ShapeId.cs │ ├── StopwatchHelper.cs │ ├── WorkerStack.cs │ └── WorldId.cs ├── Contact │ ├── ConstraintGraph.cs │ ├── Contact.cs │ ├── ContactBeginTouchEvent.cs │ ├── ContactData.cs │ ├── ContactEdge.cs │ ├── ContactEndTouchEvent.cs │ ├── ContactEvents.cs │ ├── ContactFlags.cs │ ├── ContactHitEvent.cs │ ├── ContactRegister.cs │ ├── ContactSim.cs │ ├── ContactSimFlags.cs │ ├── ContactSolver.cs │ └── GraphColor.cs ├── Debug │ ├── B2HexColor.cs │ ├── Counters.cs │ ├── DebugDrawBase.cs │ └── Profile.cs ├── Joints │ ├── DistanceJoint.cs │ ├── DistanceJointDef.cs │ ├── DistanceJointFunc.cs │ ├── Joint.cs │ ├── JointEdge.cs │ ├── JointSim.cs │ ├── JointType.cs │ ├── JointUnion.cs │ ├── MotorJoint.cs │ ├── MotorJointDef.cs │ ├── MotorJointFunc.cs │ ├── MouseJoint.cs │ ├── MouseJointDef.cs │ ├── MouseJointFunc.cs │ ├── PrismaticJoint.cs │ ├── PrismaticJointDef.cs │ ├── PrismaticJointFunc.cs │ ├── RevoluteJoint.cs │ ├── RevoluteJointDef.cs │ ├── RevoluteJointFunc.cs │ ├── WeldJoint.cs │ ├── WeldJointDef.cs │ ├── WeldJointFunc.cs │ ├── WheelJoint.cs │ ├── WheelJointDef.cs │ └── WheelJointFunc.cs ├── Math │ ├── B2Math.cs │ ├── Mat22.cs │ ├── Rot.cs │ ├── Transform.cs │ └── Vec2.cs ├── Sensor │ ├── SensorBeginTouchEvent.cs │ ├── SensorEndTouchEvent.cs │ └── SensorEvents.cs ├── Solver │ ├── Island.cs │ ├── Softness.cs │ ├── Solver.cs │ ├── SolverBlock.cs │ ├── SolverBlockType.cs │ ├── SolverSet.cs │ ├── SolverSetType.cs │ ├── SolverStage.cs │ ├── SolverStageType.cs │ ├── StepContext.cs │ ├── TaskContext.cs │ └── WorkerContext.cs ├── Types │ ├── CastResultFcn.cs │ ├── CustomFilterFcn.cs │ ├── DynamicTreeCallbackFcn.cs │ ├── EnqueueTaskCallback.cs │ ├── FinishTaskCallback.cs │ ├── OverlapResultFcn.cs │ ├── PreSolveFcn.cs │ ├── QueryFilter.cs │ └── TaskCallback.cs ├── Version.cs ├── World.cs └── WorldDef.cs └── test ├── ConsoleTest ├── .gitignore ├── Base │ ├── Car.cs │ ├── Donut.cs │ └── Human.cs ├── ConsoleTest.csproj ├── Program.cs └── TestCases │ ├── LargePyramid.cs │ ├── LargeWorld.cs │ └── ManyTumbler.cs ├── Testbed.Abstractions ├── .gitignore ├── B2Random.cs ├── Camera.cs ├── EnumExtensions.cs ├── Extensions.cs ├── Global.cs ├── IDraw.cs ├── IInput.cs ├── InputAction.cs ├── KeyCodes.cs ├── KeyInputEventArgs.cs ├── KeyModifiers.cs ├── MouseButton.cs ├── MouseInputEventArgs.cs ├── MouseMoveEventArgs.cs ├── SampleAttribute.cs ├── SampleBase.cs ├── SizeCache.cs ├── TestSettings.cs └── Testbed.Abstractions.csproj ├── Testbed.Samples ├── .gitignore ├── Benchmark │ ├── Barrel.cs │ ├── Compound.cs │ ├── CreateDestroy.cs │ ├── JointGrid.cs │ ├── Kinematic.cs │ ├── LargePyramid.cs │ ├── ManyPyramids.cs │ ├── ManyTumbler.cs │ ├── Sleep.cs │ ├── Smash.cs │ └── Tumbler.cs ├── Bodies │ ├── BadBody.cs │ ├── BodyTypeSample.cs │ ├── Character.cs │ ├── Sleep.cs │ └── Weeble.cs ├── Car.cs ├── Collision │ ├── DynamicTreeSample.cs │ ├── ManifoldSample.cs │ ├── OverlapWorld.cs │ ├── RayCast.cs │ ├── RayCastWorld.cs │ ├── ShapeCast.cs │ ├── ShapeDistance.cs │ ├── SmoothManifold.cs │ └── TimeOfImpact.cs ├── Continuous │ ├── BounceHouse.cs │ ├── FastChain.cs │ ├── GhostCollision.cs │ ├── Pinball.cs │ ├── SkinnyBox.cs │ └── SpeculativeFallback.cs ├── Determinism │ └── FallingHinges.cs ├── Donut.cs ├── Doohickey.cs ├── Events │ ├── BodyMove.cs │ ├── ContactEvent.cs │ ├── Platformer.cs │ └── SensorEvent.cs ├── GeometrySample │ └── ConvexHull.cs ├── Human.cs ├── Joints │ ├── BallAndChain.cs │ ├── BreakableJoint.cs │ ├── Bridge.cs │ ├── Cantilever.cs │ ├── DistanceJointSample.cs │ ├── DoohickeyFarm.cs │ ├── Driving.cs │ ├── FixedRotation.cs │ ├── MotorJointSample.cs │ ├── PrismaticJointSample.cs │ ├── Ragdoll.cs │ ├── RevoluteJointSample.cs │ ├── ScissorLift.cs │ ├── SoftBody.cs │ ├── UserConstraint.cs │ └── WheelJointSample.cs ├── Robustness │ ├── HighMassRatio1.cs │ ├── HighMassRatio2.cs │ └── OverlapRecovery.cs ├── Shapes │ ├── ChainLink.cs │ ├── ChainShape.cs │ ├── CircleStack.cs │ ├── CompoundShapes.cs │ ├── CustomFilter.cs │ ├── Friction.cs │ ├── ModifyGeometry.cs │ ├── OffsetShapes.cs │ ├── Restitution.cs │ ├── RoundedShapes.cs │ └── ShapeFilter.cs ├── Stacking │ ├── Arch.cs │ ├── CardHouse.cs │ ├── Cliff.cs │ ├── Confined.cs │ ├── DoubleDomino.cs │ ├── SingleBox.cs │ ├── TiltedStack.cs │ └── VerticalStack.cs ├── Testbed.Samples.csproj ├── Truck.cs └── WorldSample │ └── LargeWorld.cs ├── Testbed.Unity ├── .gitignore ├── Assets │ ├── ArrayExtensions.cs │ ├── ArrayExtensions.cs.meta │ ├── Box2DSharp.meta │ ├── DebugDraw.cs │ ├── DebugDraw.cs.meta │ ├── FixedUpdate.cs │ ├── FixedUpdate.cs.meta │ ├── FpsCounter.cs │ ├── FpsCounter.cs.meta │ ├── GUIController.cs │ ├── GUIController.cs.meta │ ├── Game.cs │ ├── Game.cs.meta │ ├── InputSystem.inputsettings.asset │ ├── InputSystem.inputsettings.asset.meta │ ├── Inspection.meta │ ├── Inspection │ │ ├── MouseInspector.cs │ │ ├── MouseInspector.cs.meta │ │ ├── UnityDraw.cs │ │ ├── UnityDraw.cs.meta │ │ ├── Utils.cs │ │ └── Utils.cs.meta │ ├── Scenes.meta │ ├── Scenes │ │ ├── Test.unity │ │ └── Test.unity.meta │ ├── System.Buffers.dll │ ├── System.Buffers.dll.meta │ ├── System.Memory.dll │ ├── System.Memory.dll.meta │ ├── System.Runtime.CompilerServices.Unsafe.dll │ ├── System.Runtime.CompilerServices.Unsafe.dll.meta │ ├── TestInheritAttribute.cs │ ├── TestInheritAttribute.cs.meta │ ├── TestSettingHelper.cs │ ├── TestSettingHelper.cs.meta │ ├── Tests.meta │ ├── Tests │ │ ├── CompoundShapesRender.cs │ │ ├── CompoundShapesRender.cs.meta │ │ ├── DistanceJointTestRender.cs │ │ ├── DistanceJointTestRender.cs.meta │ │ ├── EdgeTestRender.cs │ │ ├── EdgeTestRender.cs.meta │ │ ├── PrismaticJointTestRender.cs │ │ ├── PrismaticJointTestRender.cs.meta │ │ ├── RayCastRender.cs │ │ ├── RayCastRender.cs.meta │ │ ├── RensorsTestRender.cs │ │ ├── RensorsTestRender.cs.meta │ │ ├── RevoluteJointTestRender.cs │ │ ├── RevoluteJointTestRender.cs.meta │ │ ├── RopeTestRender.cs │ │ ├── RopeTestRender.cs.meta │ │ ├── WheelJointTestRender.cs │ │ ├── WheelJointTestRender.cs.meta │ │ ├── WreckingBallRender.cs │ │ └── WreckingBallRender.cs.meta │ ├── UnityInput.cs │ ├── UnityInput.cs.meta │ ├── UnityLogger.cs │ ├── UnityLogger.cs.meta │ ├── UnityTestSettings.cs │ ├── UnityTestSettings.cs.meta │ ├── UniversalRenderPipelineGlobalSettings.asset │ └── UniversalRenderPipelineGlobalSettings.asset.meta ├── CopyBox2DSharp.bat ├── Packages │ ├── manifest.json │ └── packages-lock.json └── ProjectSettings │ ├── AudioManager.asset │ ├── BurstAotSettings_Android.json │ ├── BurstAotSettings_StandaloneWindows.json │ ├── ClusterInputManager.asset │ ├── CommonBurstAotSettings.json │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── MemorySettings.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── PackageManagerSettings.asset │ ├── Physics2DSettings.asset │ ├── PresetManager.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── SceneTemplateSettings.json │ ├── ShaderGraphSettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityConnectSettings.asset │ ├── VFXManager.asset │ ├── VersionControlSettings.asset │ └── XRSettings.asset ├── Testbed ├── .gitignore ├── ColorExtensions.cs ├── Game.cs ├── Gui │ ├── ImGuiController.cs │ ├── Shader.cs │ ├── Texture.cs │ └── Util.cs ├── Input.cs ├── MouseButtonExtensions.cs ├── Program.cs ├── Render │ ├── DebugDraw.cs │ ├── GLBackground.cs │ ├── GLCircles.cs │ ├── GLDraw.cs │ ├── GLLines.cs │ ├── GLPoints.cs │ ├── GLPolygons.cs │ ├── GLRenderTriangles.cs │ ├── GLSolidCapsules.cs │ ├── GLSolidCircles.cs │ ├── RenderHelper.cs │ └── data │ │ ├── background.fs │ │ ├── background.vs │ │ ├── circle.fs │ │ ├── circle.vs │ │ ├── droid_sans.ttf │ │ ├── solid_capsule.fs │ │ ├── solid_capsule.vs │ │ ├── solid_circle.fs │ │ ├── solid_circle.vs │ │ ├── solid_polygon.fs │ │ └── solid_polygon.vs ├── TestInheritAttribute.cs ├── TestSamples │ ├── Benchmark │ │ ├── Barrel.cs │ │ ├── JointGrid.cs │ │ ├── ManyPyramids.cs │ │ ├── ManyTumbler.cs │ │ └── Tumbler.cs │ ├── Bodies │ │ ├── BodyTypeSample.cs │ │ ├── Sleep.cs │ │ └── Weeble.cs │ ├── Collision │ │ ├── DynamicTreeSample.cs │ │ ├── ManifoldSample.cs │ │ ├── OverlapWorld.cs │ │ ├── RayCast.cs │ │ ├── RayCastWorld.cs │ │ ├── ShapeDistance.cs │ │ └── SmoothManifold.cs │ ├── Continuous │ │ ├── BounceHouse.cs │ │ ├── FastChain.cs │ │ ├── GhostCollision.cs │ │ └── SkinnyBox.cs │ ├── Events │ │ ├── BodyMove.cs │ │ ├── ContactEvent.cs │ │ ├── Platformer.cs │ │ └── SensorEvent.cs │ ├── Joints │ │ ├── BallAndChain.cs │ │ ├── BreakableJoint.cs │ │ ├── Bridge.cs │ │ ├── Cantilever.cs │ │ ├── DistanceJointSample.cs │ │ ├── Driving.cs │ │ ├── FixedRotation.cs │ │ ├── MotorJointSample.cs │ │ ├── PrismaticJointSample.cs │ │ ├── Ragdoll.cs │ │ ├── RevoluteJointSample.cs │ │ ├── ScissorLift.cs │ │ └── WheelJointSample.cs │ ├── Robustness │ │ └── OverlapRecovery.cs │ ├── Shapes │ │ ├── ChainShape.cs │ │ ├── CompoundShapes.cs │ │ ├── ModifyGeometry.cs │ │ ├── Restitution.cs │ │ └── ShapeFilter.cs │ ├── Stacking │ │ ├── Cliff.cs │ │ └── VerticalStack.cs │ └── WorldSample │ │ └── LargeWorld.cs ├── TestSettingHelper.cs ├── Testbed.csproj ├── Tests │ ├── CompoundShapesRender.cs │ ├── DistanceJointTestRender.cs │ ├── EdgeTestRender.cs │ ├── PrismaticJointTestRender.cs │ ├── RayCastRender.cs │ ├── RensorsTestRender.cs │ ├── RevoluteJointTestRender.cs │ ├── RopeTestRender.cs │ ├── WheelJointTestRender.cs │ └── WreckingBallRender.cs └── VectorExtensions.cs └── UnitTest ├── .gitignore ├── BitSetTest.cs ├── CollisionTest.cs ├── DistanceTest.cs ├── MathTest.cs ├── ShapeTest.cs ├── TableTest.cs ├── UnitTest.csproj └── WorldTest.cs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Box2DSharp # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: ['https://mobilecodec.alipay.com/show.htm?code=a6x08011xatoeca5cga6f32&picSize=M'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vs/ 3 | *.DotSettings.user -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Box2DSharp 2 | A C# port of [Box2D](https://github.com/erincatto/Box2D) 3 | 4 | Synchronized commits: 5 | ``` 6 | d323a0e7cebb8bdcd63ebc600107b577225c521f 7 | 2024/9/1 6:18:51 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 | # Testbed 16 | Driven by [OpenTk](https://github.com/opentk/opentk) + [ImGui.NET](https://github.com/mellinoe/imgui.net) 17 | 18 | # License 19 | [MIT license](https://en.wikipedia.org/wiki/MIT_License). 20 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /src/Body/BodyEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// Body events are buffered in the Box2D world and are available 6 | /// as event arrays after the time step is complete. 7 | /// Note: this data becomes invalid if bodies are destroyed 8 | public struct BodyEvents 9 | { 10 | /// Array of move events 11 | public Memory MoveEvents; 12 | 13 | /// Number of move events 14 | public int MoveCount; 15 | 16 | public BodyEvents(Memory moveEvents, int moveCount) 17 | { 18 | MoveEvents = moveEvents; 19 | MoveCount = moveCount; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Body/BodyMoveEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// Body move events triggered when a body moves. 4 | /// Triggered when a body moves due to simulation. Not reported for bodies moved by the user. 5 | /// This also has a flag to indicate that the body went to sleep so the application can also 6 | /// sleep that actor/entity/object associated with the body. 7 | /// On the other hand if the flag does not indicate the body went to sleep then the application 8 | /// can treat the actor/entity/object associated with the body as awake. 9 | /// This is an efficient way for an application to update game object transforms rather than 10 | /// calling functions such as b2Body_GetTransform() because this data is delivered as a contiguous array 11 | /// and it is only populated with bodies that have moved. 12 | /// @note If sleeping is disabled all dynamic and kinematic bodies will trigger move events. 13 | public struct BodyMoveEvent 14 | { 15 | public Transform Transform; 16 | 17 | public BodyId BodyId; 18 | 19 | public object? UserData; 20 | 21 | public bool FellAsleep; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Body/BodyType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// The body simulation type. 4 | /// Each body is one of these three types. The type determines how the body behaves in the simulation. 5 | /// @ingroup body 6 | public enum BodyType 7 | { 8 | /// zero mass, zero velocity, may be manually moved 9 | StaticBody = 0, 10 | 11 | /// zero mass, velocity set by user, moved by solver 12 | KinematicBody = 1, 13 | 14 | /// positive mass, velocity determined by forces, moved by solver 15 | DynamicBody = 2, 16 | 17 | /// number of body types 18 | BodyTypeCount, 19 | } 20 | } -------------------------------------------------------------------------------- /src/Box2DSharp.xkpkg.user: -------------------------------------------------------------------------------- 1 | !SettingsFile 2 | Settings: {} 3 | -------------------------------------------------------------------------------- /src/Collision/Distance/DistanceCache.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Used to warm start b2Distance. Set count to zero on first call or 5 | /// 6 | /// use zero initialization. 7 | public struct DistanceCache 8 | { 9 | /// 10 | /// The number of stored simplex points 11 | /// 12 | public ushort Count; 13 | 14 | /// 15 | /// The cached simplex indices on shape A 16 | /// 17 | public FixedArray3 IndexA; 18 | 19 | /// 20 | /// The cached simplex indices on shape B 21 | /// 22 | public FixedArray3 IndexB; 23 | } 24 | } -------------------------------------------------------------------------------- /src/Collision/Distance/DistanceInput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Input for b2ShapeDistance 5 | /// 6 | public struct DistanceInput 7 | { 8 | /// 9 | /// The proxy for shape A 10 | /// 11 | public DistanceProxy ProxyA; 12 | 13 | /// 14 | /// The proxy for shape B 15 | /// 16 | public DistanceProxy ProxyB; 17 | 18 | /// 19 | /// The world transform for shape A 20 | /// 21 | public Transform TransformA; 22 | 23 | /// 24 | /// The world transform for shape B 25 | /// 26 | public Transform TransformB; 27 | 28 | /// 29 | /// Should the proxy radius be considered? 30 | /// 31 | public bool UseRadii; 32 | } 33 | } -------------------------------------------------------------------------------- /src/Collision/Distance/DistanceOutput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Output for b2ShapeDistance 5 | /// 6 | public struct DistanceOutput 7 | { 8 | public Vec2 PointA; 9 | 10 | /// Closest point on shapeA 11 | public Vec2 PointB; 12 | 13 | /// Closest point on shapeB 14 | public float Distance; 15 | 16 | /// The final distance, zero if overlapped 17 | public int Iterations; 18 | 19 | /// Number of GJK iterations used 20 | public int SimplexCount; // The number of simplexes stored in the simplex array 21 | } 22 | } -------------------------------------------------------------------------------- /src/Collision/Distance/DistanceProxy.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A distance proxy is used by the GJK algorithm. It encapsulates any shape. 5 | /// 6 | public struct DistanceProxy 7 | { 8 | /// 9 | /// The point cloud 10 | /// 11 | public FixedArray8 Points; 12 | 13 | /// 14 | /// The number of points 15 | /// 16 | public int Count; 17 | 18 | /// 19 | /// The external radius of the point cloud 20 | /// 21 | public float Radius; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Collision/Distance/SegmentDistanceResult.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Result of computing the distance between two line segments 5 | /// 6 | public struct SegmentDistanceResult 7 | { 8 | /// 9 | /// The closest point on the first segment 10 | /// 11 | public Vec2 Closest1; 12 | 13 | /// 14 | /// The closest point on the second segment 15 | /// 16 | public Vec2 Closest2; 17 | 18 | /// 19 | /// The barycentric coordinate on the first segment 20 | /// 21 | public float Fraction1; 22 | 23 | /// 24 | /// The barycentric coordinate on the second segment 25 | /// 26 | public float Fraction2; 27 | 28 | /// 29 | /// The squared distance between the closest points 30 | /// 31 | public float DistanceSquared; 32 | } 33 | } -------------------------------------------------------------------------------- /src/Collision/Distance/ShapeCastPairInput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Input parameters for b2ShapeCast 5 | /// 6 | public struct ShapeCastPairInput 7 | { 8 | public DistanceProxy ProxyA; 9 | 10 | /// The proxy for shape A 11 | public DistanceProxy ProxyB; 12 | 13 | /// The proxy for shape B 14 | public Transform TransformA; 15 | 16 | /// The world transform for shape A 17 | public Transform TransformB; 18 | 19 | /// The world transform for shape B 20 | public Vec2 TranslationB; 21 | 22 | /// The translation of shape B 23 | public float MaxFraction; // The fraction of the translation to consider, typically 1 24 | } 25 | } -------------------------------------------------------------------------------- /src/Collision/Distance/Simplex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Box2DSharp 6 | { 7 | /// 8 | /// Simplex from the GJK algorithm 9 | /// 10 | public struct Simplex 11 | { 12 | public SimplexVertex V1; 13 | 14 | public SimplexVertex V2; 15 | 16 | public SimplexVertex V3; 17 | 18 | /// 19 | /// V1,V2,V3 vertices span 20 | /// 21 | public Span Vertices 22 | { 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | get => MemoryMarshal.CreateSpan(ref V1, 3); 25 | } 26 | 27 | /// 28 | /// number of valid vertices 29 | /// 30 | public int Count; 31 | } 32 | } -------------------------------------------------------------------------------- /src/Collision/Distance/SimplexVertex.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Simplex vertex for debugging the GJK algorithm 5 | /// 6 | public struct SimplexVertex 7 | { 8 | public Vec2 WA; 9 | 10 | /// support point in proxyA 11 | public Vec2 WB; 12 | 13 | /// support point in proxyB 14 | public Vec2 W; 15 | 16 | /// wB - wA 17 | public float A; 18 | 19 | /// barycentric coordinate for closest point 20 | public int IndexA; 21 | 22 | /// wA index 23 | public int IndexB; // wB index 24 | } 25 | } -------------------------------------------------------------------------------- /src/Collision/Distance/Sweep.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin, 5 | /// which may not coincide with the center of mass. However, to support dynamics we must interpolate the center of mass 6 | /// position. 7 | /// 8 | public struct Sweep 9 | { 10 | public Vec2 LocalCenter; 11 | 12 | /// Local center of mass position 13 | public Vec2 C1; 14 | 15 | /// Starting center of mass world position 16 | public Vec2 C2; 17 | 18 | /// Ending center of mass world position 19 | public Rot Q1; 20 | 21 | /// Starting world rotation 22 | public Rot Q2; // Ending world rotation 23 | 24 | public Sweep(Vec2 localCenter, Vec2 c1, Vec2 c2, Rot q1, Rot q2) 25 | { 26 | LocalCenter = localCenter; 27 | C1 = c1; 28 | C2 = c2; 29 | Q1 = q1; 30 | Q2 = q2; 31 | } 32 | 33 | public static implicit operator Sweep((Vec2 localCenter, Vec2 c1, Vec2 c2, Rot q1, Rot q2) tuple) 34 | { 35 | return new Sweep(tuple.localCenter, tuple.c1, tuple.c2, tuple.q1, tuple.q2); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Collision/Distance/TOIInput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Input parameters for b2TimeOfImpact 5 | /// 6 | public struct TOIInput 7 | { 8 | public DistanceProxy ProxyA; 9 | 10 | /// The proxy for shape A 11 | public DistanceProxy ProxyB; 12 | 13 | /// The proxy for shape B 14 | public Sweep SweepA; 15 | 16 | /// The movement of shape A 17 | public Sweep SweepB; 18 | 19 | /// The movement of shape B 20 | public float TMax; // Defines the sweep interval [0, tMax] 21 | } 22 | } -------------------------------------------------------------------------------- /src/Collision/Distance/TOIOutput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Output parameters for b2TimeOfImpact. 5 | /// 6 | public struct TOIOutput 7 | { 8 | public TOIState State; 9 | 10 | /// The type of result 11 | public float T; // The time of the collision 12 | } 13 | } -------------------------------------------------------------------------------- /src/Collision/Distance/TOIState.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Describes the TOI output 5 | /// 6 | public enum TOIState 7 | { 8 | Unknown, 9 | 10 | Failed, 11 | 12 | Overlapped, 13 | 14 | Hit, 15 | 16 | Separated 17 | } 18 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/Capsule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Box2DSharp 6 | { 7 | /// 8 | /// A solid capsule can be viewed as two semicircles connected by a rectangle.(20 bytes) 9 | /// 10 | public struct Capsule 11 | { 12 | /// 13 | /// Local center of the first semicircle 14 | /// 15 | public Vec2 Center1; 16 | 17 | /// 18 | /// Local center of the second semicircle 19 | /// 20 | public Vec2 Center2; 21 | 22 | /// 23 | /// The radius of the semicircles 24 | /// 25 | public float Radius; 26 | 27 | public Span Points 28 | { 29 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | get => MemoryMarshal.CreateSpan(ref Center1, 2); 31 | } 32 | 33 | public Capsule(Vec2 center1, Vec2 center2, float radius) 34 | { 35 | Center1 = center1; 36 | Center2 = center2; 37 | Radius = radius; 38 | } 39 | 40 | public static implicit operator Capsule((Vec2 center1, Vec2 center2, float radius) tuple) 41 | { 42 | return new Capsule(tuple.center1, tuple.center2, tuple.radius); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/CastOutput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Low level ray-cast or shape-cast output data 5 | /// 6 | public struct CastOutput 7 | { 8 | /// 9 | /// The surface normal at the hit point 10 | /// 11 | public Vec2 Normal; 12 | 13 | /// 14 | /// The surface hit point 15 | /// 16 | public Vec2 Point; 17 | 18 | /// 19 | /// The fraction of the input translation at collision 20 | /// 21 | public float Fraction; 22 | 23 | /// 24 | /// The number of iterations used 25 | /// 26 | public int Iterations; 27 | 28 | /// 29 | /// Did the cast hit? 30 | /// 31 | public bool Hit; 32 | } 33 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/ChainSegment.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A line segment with one-sided collision(36 bytes). Only collides on the right side. 5 | /// Several of these are generated for a chain shape. 6 | /// ghost1 -> point1 -> point2 -> ghost2 7 | /// 8 | public struct ChainSegment 9 | { 10 | /// 11 | /// The tail ghost vertex 12 | /// 13 | public Vec2 Ghost1; 14 | 15 | /// 16 | /// The line segment 17 | /// 18 | public Segment Segment; 19 | 20 | /// 21 | /// The head ghost vertex 22 | /// 23 | public Vec2 Ghost2; 24 | 25 | /// 26 | /// The owning chain shape index (internal usage only) 27 | /// 28 | public int ChainId; 29 | 30 | public ChainSegment(Vec2 ghost1, Segment segment, Vec2 ghost2, int chainId) 31 | { 32 | Ghost1 = ghost1; 33 | Segment = segment; 34 | Ghost2 = ghost2; 35 | ChainId = chainId; 36 | } 37 | 38 | public static implicit operator ChainSegment((Vec2 Ghost1, Segment Segment, Vec2 Ghost2, int ChainId) tuple) 39 | { 40 | return new ChainSegment(tuple.Ghost1, tuple.Segment, tuple.Ghost2, tuple.ChainId); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/ChainShape.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public struct ChainShape 4 | { 5 | public int Id; 6 | 7 | public int BodyId; 8 | 9 | public int NextChainId; 10 | 11 | public int[] ShapeIndices; 12 | 13 | public int Count; 14 | 15 | public ushort Revision; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/Circle.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A solid circle (12 bytes) 5 | /// 6 | public struct Circle 7 | { 8 | /// 9 | /// The local center 10 | /// 11 | public Vec2 Center; 12 | 13 | /// 14 | /// The radius 15 | /// 16 | public float Radius; 17 | 18 | public Circle(Vec2 center, float radius) 19 | { 20 | Center = center; 21 | Radius = radius; 22 | } 23 | 24 | public static implicit operator Circle((Vec2 Center, float Radius) tuple) 25 | { 26 | return new Circle(tuple.Center, tuple.Radius); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/Hull.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A convex hull. Used to create convex polygons. 5 | /// @warning Do not modify these values directly, instead use b2ComputeHull() 6 | /// 7 | public struct Hull 8 | { 9 | /// The final points of the hull 10 | public FixedArray8 Points; 11 | 12 | /// The number of points 13 | public int Count; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/MassData.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// This holds the mass data computed for a shape. 5 | /// 6 | public struct MassData 7 | { 8 | /// 9 | /// The mass of the shape, usually in kilograms. 10 | /// 11 | public float Mass; 12 | 13 | /// 14 | /// The position of the shape's centroid relative to the shape's origin. 15 | /// 16 | public Vec2 Center; 17 | 18 | /// 19 | /// The rotational inertia of the shape about the local origin. 20 | /// 21 | public float RotationalInertia; 22 | 23 | public MassData(float mass, Vec2 center, float rotationalInertia) 24 | { 25 | Mass = mass; 26 | Center = center; 27 | RotationalInertia = rotationalInertia; 28 | } 29 | 30 | public static implicit operator MassData((float mass, Vec2 center, float rotationalInertia) tuple) 31 | { 32 | return new MassData(tuple.mass, tuple.center, tuple.rotationalInertia); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/Polygon.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A solid convex polygon (144 bytes). It is assumed that the interior of the polygon is to 5 | /// the left of each edge. 6 | /// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. 7 | /// In most cases you should not need many vertices for a convex polygon. 8 | /// @warning DO NOT fill this out manually, instead use a helper function like 9 | /// b2MakePolygon or b2MakeBox. 10 | /// 11 | public struct Polygon 12 | { 13 | /// 14 | /// The polygon vertices 15 | /// 16 | public FixedArray8 Vertices; 17 | 18 | /// 19 | /// The outward normal vectors of the polygon sides 20 | /// 21 | public FixedArray8 Normals; 22 | 23 | /// 24 | /// The centroid of the polygon 25 | /// 26 | public Vec2 Centroid; 27 | 28 | /// 29 | /// The external radius for rounded polygons 30 | /// 31 | public float Radius; 32 | 33 | /// 34 | /// The number of polygon vertices 35 | /// 36 | public int Count; 37 | } 38 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/RayCastInput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Low level ray-cast input data 5 | /// 6 | public struct RayCastInput 7 | { 8 | /// 9 | /// Start point of the ray cast 10 | /// 11 | public Vec2 Origin; 12 | 13 | /// 14 | /// Translation of the ray cast 15 | /// 16 | public Vec2 Translation; 17 | 18 | /// 19 | /// The maximum fraction of the translation to consider, typically 1 20 | /// 21 | public float MaxFraction; 22 | 23 | public RayCastInput(Vec2 origin, Vec2 translation, float maxFraction) 24 | { 25 | Origin = origin; 26 | Translation = translation; 27 | MaxFraction = maxFraction; 28 | } 29 | 30 | public static implicit operator RayCastInput((Vec2 origin, Vec2 translation, float maxFraction) tuple) 31 | { 32 | return new RayCastInput(tuple.origin, tuple.translation, tuple.maxFraction); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/Segment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Box2DSharp 6 | { 7 | /// 8 | /// A line segment with two-sided collision.(16 bytes) 9 | /// 10 | public struct Segment 11 | { 12 | /// 13 | /// The first point 14 | /// 15 | public Vec2 Point1; 16 | 17 | /// 18 | /// The second point 19 | /// 20 | public Vec2 Point2; 21 | 22 | public Span Points 23 | { 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | get => MemoryMarshal.CreateSpan(ref Point1, 2); 26 | } 27 | 28 | public Segment(Vec2 point1, Vec2 point2) 29 | { 30 | Point1 = point1; 31 | Point2 = point2; 32 | } 33 | 34 | public static implicit operator Segment((Vec2 point1, Vec2 point2) tuple) 35 | { 36 | return new Segment(tuple.point1, tuple.point2); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/ShapeCastInput.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Low level shape cast input in generic form. This allows casting an arbitrary point 5 | /// cloud wrap with a radius. For example, a circle is a single point with a non-zero radius. 6 | /// A capsule is two points with a non-zero radius. A box is four points with a zero radius. 7 | /// 8 | public struct ShapeCastInput 9 | { 10 | /// 11 | /// A point cloud to cast 12 | /// 13 | public FixedArray8 Points; 14 | 15 | /// 16 | /// The number of points 17 | /// 18 | public int Count; 19 | 20 | /// 21 | /// The radius around the point cloud 22 | /// 23 | public float Radius; 24 | 25 | /// 26 | /// The translation of the shape cast 27 | /// 28 | public Vec2 Translation; 29 | 30 | /// 31 | /// The maximum fraction of the translation to consider, typically 1 32 | /// 33 | public float MaxFraction; 34 | } 35 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/ShapeExtent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public struct ShapeExtent 4 | { 5 | public float MinExtent; 6 | 7 | public float MaxExtent; 8 | } 9 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/ShapeType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// Shape type 4 | /// 形状类型 5 | /// @ingroup shape 6 | public enum ShapeType 7 | { 8 | /// A circle with an offset 9 | CircleShape, 10 | 11 | /// A capsule is an extruded circle 12 | CapsuleShape, 13 | 14 | /// A line segment 15 | SegmentShape, 16 | 17 | /// A convex polygon 18 | PolygonShape, 19 | 20 | /// A line segment owned by a chain shape 21 | ChainSegmentShape, 22 | 23 | /// The number of shape types 24 | ShapeTypeCount 25 | } 26 | } -------------------------------------------------------------------------------- /src/Collision/Geometry/UnionShape.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Box2DSharp 4 | { 5 | [StructLayout(LayoutKind.Explicit)] 6 | public struct UnionShape 7 | { 8 | [FieldOffset(0)] 9 | public Capsule Capsule; 10 | 11 | [FieldOffset(0)] 12 | public Circle Circle; 13 | 14 | [FieldOffset(0)] 15 | public Polygon Polygon; 16 | 17 | [FieldOffset(0)] 18 | public Segment Segment; 19 | 20 | [FieldOffset(0)] 21 | public ChainSegment ChainSegment; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Collision/Manifold.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Box2DSharp 6 | { 7 | /// 8 | /// A contact manifold describes the contact points between colliding shapes 9 | /// 接触流形,描述相碰形状之间的接触点 10 | /// 11 | public struct Manifold 12 | { 13 | /// 14 | /// The manifold points, up to two are possible in 2D 15 | /// 流形点,2D中最多2个 16 | /// 17 | public ManifoldPoint Point1; 18 | 19 | /// 20 | /// The manifold points, up to two are possible in 2D 21 | /// 流形点,2D中最多2个 22 | /// 23 | public ManifoldPoint Point2; 24 | 25 | /// 26 | /// The unit normal vector in world space, points from shape A to bodyB 27 | /// 世界空间中的单位法向量,从形状A指向刚体B 28 | /// 29 | public Vec2 Normal; 30 | 31 | /// 32 | /// The number of contacts points, will be 0, 1, or 2 33 | /// 接触点数量,有效值0、1、2 34 | /// 35 | public int PointCount; 36 | 37 | public Span Points 38 | { 39 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 40 | get => MemoryMarshal.CreateSpan(ref Point1, 2); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Collision/ManifoldFcn.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public delegate Manifold ManifoldFcn(in Shape shapeA, in Transform xfA, in Shape shapeB, in Transform xfB, ref DistanceCache cache); 4 | } -------------------------------------------------------------------------------- /src/Collision/RayResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// Result from b2World_RayCastClosest 7 | /// 8 | public class RayResult : IDisposable 9 | { 10 | public ShapeId ShapeId; 11 | 12 | public Vec2 Point; 13 | 14 | public Vec2 Normal; 15 | 16 | public float Fraction; 17 | 18 | public bool Hit; 19 | 20 | private bool _disposed; 21 | 22 | public void Dispose() 23 | { 24 | if (_disposed) 25 | { 26 | return; 27 | } 28 | 29 | B2ObjectPool.Shared.Return(this); 30 | _disposed = true; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Common/Array/BodySimArray.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp 4 | { 5 | public class BodySimArray : B2Array 6 | { 7 | public BodySimArray() 8 | { } 9 | 10 | public BodySimArray(int capacity) 11 | : base(capacity) 12 | { } 13 | 14 | public BodySim AddBodySim() 15 | { 16 | EnsureCapacity(); 17 | 18 | if (Data[Count] == null!) 19 | { 20 | Data[Count] = new(); 21 | } 22 | 23 | var element = Data[Count]; 24 | Count += 1; 25 | return element; 26 | } 27 | 28 | // Returns the index of the element moved into the empty slot (or B2_NULL_INDEX) 29 | public int RemoveBodySim(int index) 30 | { 31 | Debug.Assert(0 <= index && index < Count); 32 | if (index < Count - 1) 33 | { 34 | // 把最后一个有效对象和待删除对象交换位置,然后重置待删除对象的状态 35 | var removed = Count - 1; 36 | (Data[index], Data[removed]) = (Data[removed], Data[index]); 37 | Data[removed].Reset(); 38 | Count -= 1; 39 | return removed; 40 | } 41 | 42 | Count -= 1; 43 | return Core.NullIndex; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/Common/Array/BodyStateArray.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp 4 | { 5 | public class BodyStateArray : B2Array 6 | { 7 | public ref BodyState AddBodyState() 8 | { 9 | EnsureCapacity(); 10 | 11 | ref var element = ref Data[Count]; 12 | element.Reset(); 13 | Count += 1; 14 | return ref element; 15 | } 16 | 17 | public BodyStateArray() 18 | { } 19 | 20 | public BodyStateArray(int capacity) 21 | : base(capacity) 22 | { } 23 | 24 | public int RemoveBodyState(int index) 25 | { 26 | Debug.Assert(0 <= index && index < Count); 27 | if (index < Count - 1) 28 | { 29 | // 把最后一个有效对象和待删除对象交换位置,然后重置待删除对象的状态 30 | var removed = Count - 1; 31 | (Data[index], Data[removed]) = (Data[removed], Data[index]); 32 | Data[removed].Reset(); 33 | Count -= 1; 34 | return removed; 35 | } 36 | 37 | Count -= 1; 38 | return Core.NullIndex; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/Common/Array/ContactArray.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp 4 | { 5 | public class ContactArray : B2Array 6 | { 7 | public ContactArray() 8 | { } 9 | 10 | public ContactArray(int capacity) 11 | : base(capacity) 12 | { } 13 | 14 | public override string ToString() 15 | { 16 | return $"{Count}/{Capacity}"; 17 | } 18 | 19 | public ContactSim AddContact() 20 | { 21 | EnsureCapacity(); 22 | if (Data[Count] == null!) 23 | { 24 | Data[Count] = new(); 25 | } 26 | 27 | // 申请时返回尾部第一个元素 28 | var element = Data[Count]; 29 | Count += 1; 30 | return element; 31 | } 32 | 33 | public int RemoveContact(int index) 34 | { 35 | Debug.Assert(0 <= index && index < Count); 36 | if (index < Count - 1) 37 | { 38 | // 把最后一个有效对象和待删除对象交换位置,然后重置待删除对象的状态 39 | var removed = Count - 1; 40 | (Data[index], Data[removed]) = (Data[removed], Data[index]); 41 | Data[removed].Reset(); 42 | Count -= 1; 43 | return removed; 44 | } 45 | 46 | Count -= 1; 47 | return Core.NullIndex; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/Common/Array/IslandArray.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp 4 | { 5 | public class IslandArray : B2Array 6 | { 7 | public IslandArray() 8 | { } 9 | 10 | public IslandArray(int capacity) 11 | : base(capacity) 12 | { } 13 | 14 | public IslandSim AddIsland() 15 | { 16 | EnsureCapacity(); 17 | if (Data[Count] == null!) 18 | { 19 | Data[Count] = new(); 20 | } 21 | 22 | IslandSim element = Data[Count]; 23 | 24 | element.IslandId = Core.NullIndex; 25 | Count += 1; 26 | return element; 27 | } 28 | 29 | public int RemoveIsland(int index) 30 | { 31 | Debug.Assert(0 <= index && index < Count); 32 | if (index < Count - 1) 33 | { 34 | // 把最后一个有效对象和待删除对象交换位置,然后重置待删除对象的状态 35 | var removed = Count - 1; 36 | (Data[index], Data[removed]) = (Data[removed], Data[index]); 37 | Data[removed].Reset(); 38 | Count -= 1; 39 | return removed; 40 | } 41 | 42 | Count -= 1; 43 | return Core.NullIndex; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/Common/Array/JointArray.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp 4 | { 5 | public class JointArray : B2Array 6 | { 7 | public JointArray() 8 | { } 9 | 10 | public JointArray(int capacity) 11 | : base(capacity) 12 | { } 13 | 14 | public JointSim AddJoint() 15 | { 16 | EnsureCapacity(); 17 | if (Data[Count] == null!) 18 | { 19 | Data[Count] = new(); 20 | } 21 | 22 | var element = Data[Count]; 23 | 24 | Count += 1; 25 | return element; 26 | } 27 | 28 | public int RemoveJoint(int index) 29 | { 30 | Debug.Assert(0 <= index && index < Count); 31 | if (index < Count - 1) 32 | { 33 | // 把最后一个有效对象和待删除对象交换位置,然后重置待删除对象的状态,并返回交换后的空位的索引 34 | var removed = Count - 1; 35 | (Data[index], Data[removed]) = (Data[removed], Data[index]); 36 | Data[removed].Reset(); 37 | Count -= 1; 38 | return removed; 39 | } 40 | 41 | Count -= 1; 42 | return Core.NullIndex; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Common/ArrayHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | public static class ArrayHelper 6 | { 7 | public static void FillFromPool(T[] array, int start, int length) 8 | where T : class, new() 9 | { 10 | var span = array.AsSpan(start, length); 11 | for (var i = 0; i < span.Length; i++) 12 | { 13 | span[i] = B2ObjectPool.Shared.Get(); 14 | } 15 | } 16 | 17 | public static void ReturnToPool(T[] array, int start, int length) 18 | where T : class, new() 19 | { 20 | var span = array.AsSpan(start, length); 21 | foreach (var t in span) 22 | { 23 | B2ObjectPool.Shared.Return(t); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Common/ChainId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// Chain id references a chain instances. This should be treated as an opaque handle. 7 | /// 8 | public struct ChainId : IEquatable 9 | { 10 | public int Index1; 11 | 12 | public ushort World0; 13 | 14 | public ushort Revision; 15 | 16 | public static ChainId NullId = new(); 17 | 18 | public bool IsNull => Index1 == 0; 19 | 20 | public bool IsNotNull => Index1 != 0; 21 | 22 | public ChainId(int index1, ushort world0, ushort revision) 23 | { 24 | Index1 = index1; 25 | World0 = world0; 26 | Revision = revision; 27 | } 28 | 29 | public bool Equals(ChainId other) 30 | { 31 | return Index1 == other.Index1 32 | && World0 == other.World0 33 | && Revision == other.Revision; 34 | } 35 | 36 | public override bool Equals(object? obj) 37 | { 38 | return obj is ChainId other && Equals(other); 39 | } 40 | 41 | public override int GetHashCode() 42 | { 43 | return HashCode.Combine(Index1, World0, Revision); 44 | } 45 | 46 | public static bool operator ==(ChainId left, ChainId right) 47 | { 48 | return left.Equals(right); 49 | } 50 | 51 | public static bool operator !=(ChainId left, ChainId right) 52 | { 53 | return !(left == right); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Common/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// 7 | /// 8 | public static class EnumExtensions 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public static bool IsSet(this ContactSimFlags self, ContactSimFlags flag) => (self & flag) == flag; 12 | 13 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 14 | public static bool IsSet(this ContactFlags self, ContactFlags flag) => (self & flag) == flag; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Common/FixedArray/FixedArray3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Box2DSharp 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct FixedArray3 : IFixedArray 9 | where T : unmanaged 10 | { 11 | public T V0; 12 | 13 | public T V1; 14 | 15 | public T V2; 16 | 17 | public int Length => 3; 18 | 19 | public FixedArray3(T v0, T v1, T v2) 20 | { 21 | V0 = v0; 22 | V1 = v1; 23 | V2 = v2; 24 | } 25 | 26 | public static implicit operator Span(FixedArray3 v) 27 | { 28 | return v.Span; 29 | } 30 | 31 | public static implicit operator ReadOnlySpan(FixedArray3 v) 32 | { 33 | return v.Span; 34 | } 35 | 36 | public Span Span 37 | { 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | get => MemoryMarshal.CreateSpan(ref V0, Length); 40 | } 41 | 42 | public ref T this[int index] 43 | { 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | get => ref MemoryMarshal.CreateSpan(ref V0, Length)[index]; 46 | } 47 | 48 | public override string ToString() 49 | { 50 | return $"({V0},{V1},{V2})"; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/Common/FixedArray/IFixedArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | public interface IFixedArray 6 | where T : unmanaged 7 | { 8 | public int Length { get; } 9 | 10 | public Span Span { get; } 11 | 12 | public ref T this[int index] { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Common/Guard.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp 4 | { 5 | public static class Guard 6 | { 7 | public static void CheckIndex(this B2Array a, int index) 8 | { 9 | Debug.Assert(0 <= index && index < a.Count); 10 | } 11 | 12 | public static void CheckId(this B2Array array, int id) 13 | { 14 | Debug.Assert(0 <= id && id < array.Count && array[id].Id == id); 15 | } 16 | 17 | public static void CheckId(this B2Array array, int id) 18 | { 19 | Debug.Assert(0 <= id && id < array.Count && array[id].Id == id); 20 | } 21 | 22 | public static void CheckId(this B2Array array, int id) 23 | { 24 | Debug.Assert(0 <= id && id < array.Count && array[id].Id == id); 25 | } 26 | 27 | public static void CheckIdAndRevision(this B2Array array, int id, int rev) 28 | { 29 | Debug.Assert(0 <= id && id < array.Count && array[id].Id == id && array[id].Revision == rev); 30 | } 31 | 32 | public static void CheckIdAndRevision(this B2Array array, int id, int rev) 33 | { 34 | Debug.Assert(0 <= id && id < array.Count && array[id].Id == id && array[id].Revision == rev); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/Common/HashTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | public static class HashTool 6 | { 7 | public const uint HashInit = 5381; 8 | 9 | public static uint Hash(uint hash, ReadOnlySpan data) 10 | { 11 | var result = hash; 12 | foreach (var t in data) 13 | { 14 | result = (result << 5) + result + t; 15 | } 16 | 17 | return result; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Common/InterlockedHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Threading; 3 | 4 | namespace Box2DSharp 5 | { 6 | public static class InterlockedHelper 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint Exchange(ref uint location1, uint value) => 10 | (uint)Interlocked.Exchange(ref Unsafe.As(ref location1), (int)value); 11 | 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | public static uint CompareExchange(ref uint location1, uint value, uint comparand) => 14 | (uint)Interlocked.CompareExchange(ref Unsafe.As(ref location1), (int)value, (int)comparand); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Common/JointId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// Joint id references a joint instance. This should be treated as an opaque handle. 7 | /// 8 | public struct JointId : IEquatable 9 | { 10 | public int Index1; 11 | 12 | public ushort World0; 13 | 14 | public ushort Revision; 15 | 16 | public static JointId NullId = new(); 17 | 18 | public bool IsNull => Index1 == 0; 19 | 20 | public bool IsNotNull => Index1 != 0; 21 | 22 | public JointId(int index1, ushort world0, ushort revision) 23 | { 24 | Index1 = index1; 25 | World0 = world0; 26 | Revision = revision; 27 | } 28 | 29 | public bool Equals(JointId other) 30 | { 31 | return Index1 == other.Index1 32 | && World0 == other.World0 33 | && Revision == other.Revision; 34 | } 35 | 36 | public override bool Equals(object? obj) 37 | { 38 | return obj is JointId other && Equals(other); 39 | } 40 | 41 | public override int GetHashCode() 42 | { 43 | return HashCode.Combine(Index1, World0, Revision); 44 | } 45 | 46 | public static bool operator ==(JointId left, JointId right) 47 | { 48 | return left.Equals(right); 49 | } 50 | 51 | public static bool operator !=(JointId left, JointId right) 52 | { 53 | return !(left == right); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Common/StopwatchHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Box2DSharp 5 | { 6 | public static class StopwatchHelper 7 | { 8 | private const long TicksPerMillisecond = 10000; 9 | 10 | private const long TicksPerSecond = TicksPerMillisecond * 1000; 11 | 12 | // performance-counter frequency, in counts per ticks. 13 | // This can speed up conversion from high frequency performance-counter 14 | // to ticks. 15 | private static readonly double _tickFrequency = (double)TicksPerSecond / Stopwatch.Frequency; 16 | 17 | public static TimeSpan GetElapsedTime(long startingTimestamp) => 18 | GetElapsedTime(startingTimestamp, Stopwatch.GetTimestamp()); 19 | 20 | public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) => 21 | new TimeSpan((long)((endingTimestamp - startingTimestamp) * _tickFrequency)); 22 | } 23 | } -------------------------------------------------------------------------------- /src/Common/WorldId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// World id references a world instance. This should be treated as an opaque handle. 7 | /// 8 | public struct WorldId : IEquatable 9 | { 10 | public ushort Index1; 11 | 12 | public ushort Revision; 13 | 14 | public static WorldId NullId = new(); 15 | 16 | public bool IsNull => Index1 == 0; 17 | 18 | public bool IsNotNull => Index1 != 0; 19 | 20 | public WorldId(ushort index1, ushort revision) 21 | { 22 | Index1 = index1; 23 | Revision = revision; 24 | } 25 | 26 | public bool Equals(WorldId other) 27 | { 28 | return Index1 == other.Index1 && Revision == other.Revision; 29 | } 30 | 31 | public override bool Equals(object? obj) 32 | { 33 | return obj is WorldId other && Equals(other); 34 | } 35 | 36 | public override int GetHashCode() 37 | { 38 | return HashCode.Combine(Index1, Revision); 39 | } 40 | 41 | public static bool operator ==(WorldId left, WorldId right) 42 | { 43 | return left.Equals(right); 44 | } 45 | 46 | public static bool operator !=(WorldId left, WorldId right) 47 | { 48 | return !(left == right); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/Contact/ContactBeginTouchEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A begin touch event is generated when two shapes begin touching. 5 | /// 6 | public struct ContactBeginTouchEvent 7 | { 8 | /// Id of the first shape 9 | public ShapeId ShapeIdA; 10 | 11 | /// Id of the second shape 12 | public ShapeId ShapeIdB; 13 | 14 | public ContactBeginTouchEvent(ShapeId shapeIdA, ShapeId shapeIdB) 15 | { 16 | ShapeIdA = shapeIdA; 17 | ShapeIdB = shapeIdB; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Contact/ContactData.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// The contact data for two shapes. By convention the manifold normal points 4 | /// from shape A to shape B. 5 | /// @see b2Shape_GetContactData() and b2Body_GetContactData() 6 | public struct ContactData 7 | { 8 | public ShapeId ShapeIdA; 9 | 10 | public ShapeId ShapeIdB; 11 | 12 | public Manifold Manifold; 13 | 14 | public ContactData(ShapeId shapeIdA, ShapeId shapeIdB, Manifold manifold) 15 | { 16 | ShapeIdA = shapeIdA; 17 | ShapeIdB = shapeIdB; 18 | Manifold = manifold; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Contact/ContactEdge.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A contact edge is used to connect bodies and contacts together 5 | /// in a contact graph where each body is a node and each contact 6 | /// is an edge. A contact edge belongs to a doubly linked list 7 | /// maintained in each attached body. Each contact has two contact 8 | /// edges, one for each attached body. 9 | /// 在接触图中,每个刚体是一个节点,每个接触点是一条边,接触边用于将刚体和接触点关联在一起。接触边属于每个关联刚体中的双链表。每个接触都有两条接触边,接触点关联的两个刚体各一条。 10 | /// 11 | public struct ContactEdge 12 | { 13 | /// 14 | /// 刚体Id 15 | /// 16 | public int BodyId; 17 | 18 | /// 19 | /// 20 | /// 21 | public int PrevKey; 22 | 23 | /// 24 | /// 25 | /// 26 | public int NextKey; 27 | } 28 | } -------------------------------------------------------------------------------- /src/Contact/ContactEndTouchEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// An end touch event is generated when two shapes stop touching. 5 | /// 6 | public struct ContactEndTouchEvent 7 | { 8 | /// Id of the first shape 9 | public ShapeId ShapeIdA; 10 | 11 | /// Id of the second shape 12 | public ShapeId ShapeIdB; 13 | 14 | public ContactEndTouchEvent(ShapeId shapeIdA, ShapeId shapeIdB) 15 | { 16 | ShapeIdA = shapeIdA; 17 | ShapeIdB = shapeIdB; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Contact/ContactEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// Contact events are buffered in the Box2D world and are available 6 | /// as event arrays after the time step is complete. 7 | /// Note: these may become invalid if bodies and/or shapes are destroyed 8 | public struct ContactEvents 9 | { 10 | /// Array of begin touch events 11 | public Memory BeginEvents; 12 | 13 | /// Array of end touch events 14 | public Memory EndEvents; 15 | 16 | /// Array of hit events 17 | public Memory HitEvents; 18 | 19 | /// Number of begin touch events 20 | public int BeginCount; 21 | 22 | /// Number of end touch events 23 | public int EndCount; 24 | 25 | /// Number of hit events 26 | public int HitCount; 27 | 28 | public ContactEvents(Memory beginEvents, Memory endEvents, Memory hitEvents, int beginCount, int endCount, int hitCount) 29 | { 30 | BeginEvents = beginEvents; 31 | EndEvents = endEvents; 32 | HitEvents = hitEvents; 33 | BeginCount = beginCount; 34 | EndCount = endCount; 35 | HitCount = hitCount; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Contact/ContactHitEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A hit touch event is generated when two shapes collide with a speed faster than the hit speed threshold. 5 | /// 当两个形状碰撞的速度快于碰撞速度阈值时,就会产生碰撞触碰事件 6 | /// 7 | public struct ContactHitEvent 8 | { 9 | /// Id of the first shape 10 | public ShapeId ShapeIdA; 11 | 12 | /// Id of the second shape 13 | public ShapeId ShapeIdB; 14 | 15 | /// Point where the shapes hit 16 | public Vec2 Point; 17 | 18 | /// Normal vector pointing from shape A to shape B 19 | public Vec2 Normal; 20 | 21 | /// The speed the shapes are approaching. Always positive. Typically in meters per second. 22 | public float ApproachSpeed; 23 | 24 | public ContactHitEvent(ShapeId shapeIdA, ShapeId shapeIdB, Vec2 point, Vec2 normal, float approachSpeed) 25 | { 26 | ShapeIdA = shapeIdA; 27 | ShapeIdB = shapeIdB; 28 | Point = point; 29 | Normal = normal; 30 | ApproachSpeed = approachSpeed; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Contact/ContactRegister.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class ContactRegister 4 | { 5 | public ManifoldFcn Fcn; 6 | 7 | public bool Primary; 8 | 9 | public static readonly ContactRegister[,] Registers = new ContactRegister[(int)ShapeType.ShapeTypeCount, (int)ShapeType.ShapeTypeCount]; 10 | 11 | public static bool Initialized = false; 12 | 13 | public ContactRegister(ManifoldFcn fcn, bool primary) 14 | { 15 | Fcn = fcn; 16 | Primary = primary; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Contact/ContactSimFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// Shifted to be distinct from b2ContactFlags 7 | /// 8 | [Flags] 9 | public enum ContactSimFlags 10 | { 11 | /// 12 | /// Set when the shapes are touching, including sensors 13 | /// 14 | TouchingFlag = 0x00010000, 15 | 16 | /// 17 | /// This contact no longer has overlapping AABBs 18 | /// 19 | Disjoint = 0x00020000, 20 | 21 | /// 22 | /// This contact started touching 23 | /// 24 | StartedTouching = 0x00040000, 25 | 26 | /// 27 | /// This contact stopped touching 28 | /// 29 | StoppedTouching = 0x00080000, 30 | 31 | /// 32 | /// This contact has a hit event 33 | /// 34 | EnableHitEvent = 0x00100000, 35 | 36 | /// 37 | /// This contact wants pre-solve events 38 | /// 39 | EnablePreSolveEvents = 0x00200000, 40 | }; 41 | } -------------------------------------------------------------------------------- /src/Contact/GraphColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// This holds constraints that cannot fit the graph color limit. This happens when a single dynamic body 7 | /// is touching many other bodies. 8 | /// 9 | public class GraphColor 10 | { 11 | /// 12 | /// This bitset is indexed by bodyId so this is over-sized to encompass static bodies 13 | /// however I never traverse these bits or use the bit count for anything 14 | /// This bitset is unused on the overflow color. 15 | /// 16 | public BitSet BodySet; 17 | 18 | /// 19 | /// cache friendly arrays 20 | /// 21 | public ContactArray Contacts; 22 | 23 | public JointArray Joints; 24 | 25 | public Memory SimdConstraints; 26 | 27 | public Memory OverflowConstraints; 28 | 29 | // transient 30 | 31 | public GraphColor() 32 | { 33 | Contacts = new(); 34 | Joints = new(); 35 | BodySet = null!; 36 | } 37 | 38 | public GraphColor(int bodyCapacity) 39 | { 40 | Contacts = new(); 41 | Joints = new(); 42 | BodySet = new(bodyCapacity); 43 | BodySet.SetBitCountAndClear(bodyCapacity); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/Debug/Counters.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Counters that give details of the simulation size. 5 | /// 6 | public class Counters 7 | { 8 | public int StaticBodyCount; 9 | 10 | public int BodyCount; 11 | 12 | public int ShapeCount; 13 | 14 | public int ContactCount; 15 | 16 | public int JointCount; 17 | 18 | public int IslandCount; 19 | 20 | public int StackUsed; 21 | 22 | public int StaticTreeHeight; 23 | 24 | public int TreeHeight; 25 | 26 | public int ByteCount; 27 | 28 | public int TaskCount; 29 | 30 | public int[] ColorCounts = new int[Core.GraphColorCount]; // [12] 31 | } 32 | } -------------------------------------------------------------------------------- /src/Debug/Profile.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Profiling data. Times are in milliseconds. 5 | /// 6 | public class Profile 7 | { 8 | public float Step; 9 | 10 | public float Pairs; 11 | 12 | public float Collide; 13 | 14 | public float Solve; 15 | 16 | public float BuildIslands; 17 | 18 | public float SolveConstraints; 19 | 20 | public float PrepareTasks; 21 | 22 | public float SolverTasks; 23 | 24 | public float PrepareConstraints; 25 | 26 | public float IntegrateVelocities; 27 | 28 | public float WarmStart; 29 | 30 | public float SolveVelocities; 31 | 32 | public float IntegratePositions; 33 | 34 | public float RelaxVelocities; 35 | 36 | public float ApplyRestitution; 37 | 38 | public float StoreImpulses; 39 | 40 | public float FinalizeBodies; 41 | 42 | public float SplitIslands; 43 | 44 | public float SleepIslands; 45 | 46 | public float HitEvents; 47 | 48 | public float Broadphase; 49 | 50 | public float Continuous; 51 | } 52 | } -------------------------------------------------------------------------------- /src/Joints/DistanceJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class DistanceJoint 4 | { 5 | public float Length; 6 | 7 | public float Hertz; 8 | 9 | public float DampingRatio; 10 | 11 | public float MinLength; 12 | 13 | public float MaxLength; 14 | 15 | public float MaxMotorForce; 16 | 17 | public float MotorSpeed; 18 | 19 | public float Impulse; 20 | 21 | public float LowerImpulse; 22 | 23 | public float UpperImpulse; 24 | 25 | public float MotorImpulse; 26 | 27 | public int IndexA; 28 | 29 | public int IndexB; 30 | 31 | public Vec2 AnchorA; 32 | 33 | public Vec2 AnchorB; 34 | 35 | public Vec2 DeltaCenter; 36 | 37 | public Softness DistanceSoftness; 38 | 39 | public float AxialMass; 40 | 41 | public bool EnableSpring; 42 | 43 | public bool EnableLimit; 44 | 45 | public bool EnableMotor; 46 | } 47 | } -------------------------------------------------------------------------------- /src/Joints/JointEdge.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// A joint edge is used to connect bodies and joints together 4 | /// in a joint graph where each body is a node and each joint 5 | /// is an edge. A joint edge belongs to a doubly linked list 6 | /// maintained in each attached body. Each joint has two joint 7 | /// nodes, one for each attached body. 8 | public struct JointEdge 9 | { 10 | public int BodyId; 11 | 12 | public int PrevKey; 13 | 14 | public int NextKey; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Joints/JointType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// Joint type enumeration 4 | /// 5 | /// This is useful because all joint types use b2JointId and sometimes you 6 | /// want to get the type of a joint. 7 | /// @ingroup joint 8 | public enum JointType 9 | { 10 | DistanceJoint, 11 | 12 | MotorJoint, 13 | 14 | MouseJoint, 15 | 16 | PrismaticJoint, 17 | 18 | RevoluteJoint, 19 | 20 | WeldJoint, 21 | 22 | WheelJoint 23 | } 24 | } -------------------------------------------------------------------------------- /src/Joints/JointUnion.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Box2DSharp 4 | { 5 | [StructLayout(LayoutKind.Explicit)] 6 | public struct JointUnion 7 | { 8 | [FieldOffset(0)] 9 | public DistanceJoint DistanceJoint; 10 | 11 | [FieldOffset(0)] 12 | public MotorJoint MotorJoint; 13 | 14 | [FieldOffset(0)] 15 | public MouseJoint MouseJoint; 16 | 17 | [FieldOffset(0)] 18 | public RevoluteJoint RevoluteJoint; 19 | 20 | [FieldOffset(0)] 21 | public PrismaticJoint PrismaticJoint; 22 | 23 | [FieldOffset(0)] 24 | public WeldJoint WeldJoint; 25 | 26 | [FieldOffset(0)] 27 | public WheelJoint WheelJoint; 28 | } 29 | } -------------------------------------------------------------------------------- /src/Joints/MotorJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class MotorJoint 4 | { 5 | public Vec2 LinearOffset; 6 | 7 | public float AngularOffset; 8 | 9 | public Vec2 LinearImpulse; 10 | 11 | public float AngularImpulse; 12 | 13 | public float MaxForce; 14 | 15 | public float MaxTorque; 16 | 17 | public float CorrectionFactor; 18 | 19 | public int IndexA; 20 | 21 | public int IndexB; 22 | 23 | public Vec2 AnchorA; 24 | 25 | public Vec2 AnchorB; 26 | 27 | public Vec2 DeltaCenter; 28 | 29 | public float DeltaAngle; 30 | 31 | public Mat22 LinearMass; 32 | 33 | public float AngularMass; 34 | } 35 | } -------------------------------------------------------------------------------- /src/Joints/MouseJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class MouseJoint 4 | { 5 | public Vec2 TargetA; 6 | 7 | public float Hertz; 8 | 9 | public float DampingRatio; 10 | 11 | public float MaxForce; 12 | 13 | public Vec2 LinearImpulse; 14 | 15 | public float AngularImpulse; 16 | 17 | public Softness LinearSoftness; 18 | 19 | public Softness AngularSoftness; 20 | 21 | public int IndexB; 22 | 23 | public Vec2 AnchorB; 24 | 25 | public Vec2 DeltaCenter; 26 | 27 | public Mat22 LinearMass; 28 | } 29 | } -------------------------------------------------------------------------------- /src/Joints/PrismaticJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class PrismaticJoint 4 | { 5 | public Vec2 LocalAxisA; 6 | 7 | public Vec2 Impulse; 8 | 9 | public float SpringImpulse; 10 | 11 | public float MotorImpulse; 12 | 13 | public float LowerImpulse; 14 | 15 | public float UpperImpulse; 16 | 17 | public float Hertz; 18 | 19 | public float DampingRatio; 20 | 21 | public float MaxMotorForce; 22 | 23 | public float MotorSpeed; 24 | 25 | public float ReferenceAngle; 26 | 27 | public float LowerTranslation; 28 | 29 | public float UpperTranslation; 30 | 31 | public int IndexA; 32 | 33 | public int IndexB; 34 | 35 | public Vec2 AnchorA; 36 | 37 | public Vec2 AnchorB; 38 | 39 | public Vec2 AxisA; 40 | 41 | public Vec2 DeltaCenter; 42 | 43 | public float DeltaAngle; 44 | 45 | public float AxialMass; 46 | 47 | public Softness SpringSoftness; 48 | 49 | public bool EnableSpring; 50 | 51 | public bool EnableLimit; 52 | 53 | public bool EnableMotor; 54 | } 55 | } -------------------------------------------------------------------------------- /src/Joints/RevoluteJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class RevoluteJoint 4 | { 5 | public Vec2 LinearImpulse; 6 | 7 | public float SpringImpulse; 8 | 9 | public float MotorImpulse; 10 | 11 | public float LowerImpulse; 12 | 13 | public float UpperImpulse; 14 | 15 | public float Hertz; 16 | 17 | public float DampingRatio; 18 | 19 | public float MaxMotorTorque; 20 | 21 | public float MotorSpeed; 22 | 23 | public float ReferenceAngle; 24 | 25 | public float LowerAngle; 26 | 27 | public float UpperAngle; 28 | 29 | public int IndexA; 30 | 31 | public int IndexB; 32 | 33 | public Vec2 AnchorA; 34 | 35 | public Vec2 AnchorB; 36 | 37 | public Vec2 DeltaCenter; 38 | 39 | public float DeltaAngle; 40 | 41 | public float AxialMass; 42 | 43 | public Softness SpringSoftness; 44 | 45 | public bool EnableSpring; 46 | 47 | public bool EnableMotor; 48 | 49 | public bool EnableLimit; 50 | } 51 | } -------------------------------------------------------------------------------- /src/Joints/WeldJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class WeldJoint 4 | { 5 | public float ReferenceAngle; 6 | 7 | public float LinearHertz; 8 | 9 | public float LinearDampingRatio; 10 | 11 | public float AngularHertz; 12 | 13 | public float AngularDampingRatio; 14 | 15 | public Softness LinearSoftness; 16 | 17 | public Softness AngularSoftness; 18 | 19 | public Vec2 LinearImpulse; 20 | 21 | public float AngularImpulse; 22 | 23 | public int IndexA; 24 | 25 | public int IndexB; 26 | 27 | public Vec2 AnchorA; 28 | 29 | public Vec2 AnchorB; 30 | 31 | public Vec2 DeltaCenter; 32 | 33 | public float DeltaAngle; 34 | 35 | public float AxialMass; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Joints/WheelJoint.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class WheelJoint 4 | { 5 | public Vec2 LocalAxisA; 6 | 7 | public float PerpImpulse; 8 | 9 | public float MotorImpulse; 10 | 11 | public float SpringImpulse; 12 | 13 | public float LowerImpulse; 14 | 15 | public float UpperImpulse; 16 | 17 | public float MaxMotorTorque; 18 | 19 | public float MotorSpeed; 20 | 21 | public float LowerTranslation; 22 | 23 | public float UpperTranslation; 24 | 25 | public float Hertz; 26 | 27 | public float DampingRatio; 28 | 29 | public int IndexA; 30 | 31 | public int IndexB; 32 | 33 | public Vec2 AnchorA; 34 | 35 | public Vec2 AnchorB; 36 | 37 | public Vec2 AxisA; 38 | 39 | public Vec2 DeltaCenter; 40 | 41 | public float PerpMass; 42 | 43 | public float MotorMass; 44 | 45 | public float AxialMass; 46 | 47 | public Softness SpringSoftness; 48 | 49 | public bool EnableSpring; 50 | 51 | public bool EnableMotor; 52 | 53 | public bool EnableLimit; 54 | } 55 | } -------------------------------------------------------------------------------- /src/Math/Mat22.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// A 2-by-2 Matrix (16 bytes) 5 | /// 6 | public struct Mat22 7 | { 8 | /// 9 | /// columns 10 | /// 11 | public Vec2 Cx; 12 | 13 | /// 14 | /// columns 15 | /// 16 | public Vec2 Cy; 17 | 18 | public Mat22(Vec2 cx, Vec2 cy) 19 | { 20 | Cx = cx; 21 | Cy = cy; 22 | } 23 | 24 | public static Mat22 Zero = new(new(0, 0), new(0, 0)); 25 | } 26 | } -------------------------------------------------------------------------------- /src/Math/Transform.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// 6 | /// A 2D rigid transform (16 bytes) 7 | /// 位移描述,含坐标和角度(弧度制) 8 | /// 9 | [StructLayout(LayoutKind.Explicit, Size = 16)] 10 | public struct Transform 11 | { 12 | [FieldOffset(0)] 13 | public Vec2 P; 14 | 15 | [FieldOffset(8)] 16 | public Rot Q; 17 | 18 | public Transform(Vec2 p, Rot q) 19 | { 20 | P = p; 21 | Q = q; 22 | } 23 | 24 | public static implicit operator Transform((Vec2 p, Rot q) tuple) 25 | { 26 | return new Transform(tuple.p, tuple.q); 27 | } 28 | 29 | public static readonly Transform Identity = new(new(0, 0), new(1, 0)); 30 | 31 | public override string ToString() 32 | { 33 | return $"{P}({Q})"; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Sensor/SensorBeginTouchEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /** 4 | * @defgroup events Events 5 | * World event types. 6 | * 7 | * Events are used to collect events that occur during the world time step. These events 8 | * are then available to query after the time step is complete. This is preferable to callbacks 9 | * because Box2D uses multithreaded simulation. 10 | * 11 | * Also when events occur in the simulation step it may be problematic to modify the world, which is 12 | * often what applications want to do when events occur. 13 | * 14 | * With event arrays, you can scan the events in a loop and modify the world. However, you need to be careful 15 | * that some event data may become invalid. There are several samples that show how to do this safely. 16 | * 17 | * @{ 18 | */ 19 | /// A begin touch event is generated when a shape starts to overlap a sensor shape. 20 | public struct SensorBeginTouchEvent 21 | { 22 | /// The id of the sensor shape 23 | public ShapeId SensorShapeId; 24 | 25 | /// The id of the dynamic shape that began touching the sensor shape 26 | public ShapeId VisitorShapeId; 27 | 28 | public SensorBeginTouchEvent(ShapeId sensorShapeId, ShapeId visitorShapeId) 29 | { 30 | SensorShapeId = sensorShapeId; 31 | VisitorShapeId = visitorShapeId; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Sensor/SensorEndTouchEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// An end touch event is generated when a shape stops overlapping a sensor shape. 4 | public struct SensorEndTouchEvent 5 | { 6 | /// The id of the sensor shape 7 | public ShapeId SensorShapeId; 8 | 9 | /// The id of the dynamic shape that stopped touching the sensor shape 10 | public ShapeId VisitorShapeId; 11 | 12 | public SensorEndTouchEvent(ShapeId sensorShapeId, ShapeId visitorShapeId) 13 | { 14 | SensorShapeId = sensorShapeId; 15 | VisitorShapeId = visitorShapeId; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Sensor/SensorEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Box2DSharp 4 | { 5 | /// Sensor events are buffered in the Box2D world and are available 6 | /// as begin/end overlap event arrays after the time step is complete. 7 | /// Note: these may become invalid if bodies and/or shapes are destroyed 8 | public struct SensorEvents 9 | { 10 | /// Array of sensor begin touch events 11 | public Memory BeginEvents; 12 | 13 | /// Array of sensor end touch events 14 | public Memory EndEvents; 15 | 16 | /// The number of begin touch events 17 | public int BeginCount; 18 | 19 | /// The number of end touch events 20 | public int EndCount; 21 | 22 | public SensorEvents(Memory beginEvents, Memory endEvents, int beginCount, int endCount) 23 | { 24 | BeginEvents = beginEvents; 25 | EndEvents = endEvents; 26 | BeginCount = beginCount; 27 | EndCount = endCount; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Solver/Softness.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// 柔软? 5 | /// 6 | public struct Softness 7 | { 8 | /// 9 | /// 偏差率 10 | /// 11 | public float BiasRate; 12 | 13 | /// 14 | /// 质量比例 15 | /// 16 | public float MassScale; 17 | 18 | /// 19 | /// 冲量比例 20 | /// 21 | public float ImpulseScale; 22 | 23 | public Softness(float biasRate, float massScale, float impulseScale) 24 | { 25 | BiasRate = biasRate; 26 | MassScale = massScale; 27 | ImpulseScale = impulseScale; 28 | } 29 | 30 | public static Softness MakeSoft(float hertz, float zeta, float h) 31 | { 32 | if (hertz == 0.0f) 33 | { 34 | return new Softness(0.0f, 1.0f, 0.0f); 35 | } 36 | 37 | float omega = 2.0f * B2Math.Pi * hertz; 38 | float a1 = 2.0f * zeta + h * omega; 39 | float a2 = h * omega * a1; 40 | float a3 = 1.0f / (1.0f + a2); 41 | return new Softness(omega / a1, a2 * a3, a3); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Solver/SolverBlock.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Each block of work has a sync index that gets incremented when a worker claims the block. This ensures only a single worker 5 | /// claims a block, yet lets work be distributed dynamically across multiple workers (work stealing). This also reduces contention 6 | /// on a single block index atomic. For non-iterative stages the sync index is simply set to one. For iterative stages (solver 7 | /// iteration) the same block of work is executed once per iteration and the atomic sync index is shared across iterations, so it 8 | /// increases monotonically. 9 | /// 10 | public class SolverBlock 11 | { 12 | public int StartIndex; 13 | 14 | public short Count; 15 | 16 | public short BlockType; // b2SolverBlockType 17 | 18 | /// 19 | /// Atomic index, todo consider false sharing of this atomic 20 | /// 21 | public int SyncIndex; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Solver/SolverBlockType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// 解算区块类型 5 | /// 6 | public enum SolverBlockType 7 | { 8 | /// 9 | /// 刚体区块 10 | /// 11 | BodyBlock, 12 | 13 | /// 14 | /// 关节区块 15 | /// 16 | JointBlock, 17 | 18 | /// 19 | /// 接触点区块 20 | /// 21 | ContactBlock, 22 | 23 | /// 24 | /// 图关节区块 25 | /// 26 | GraphJointBlock, 27 | 28 | /// 29 | /// 图接触点区块 30 | /// 31 | GraphContactBlock 32 | } 33 | } -------------------------------------------------------------------------------- /src/Solver/SolverSetType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public static class SolverSetType 4 | { 5 | public const int StaticSet = 0; 6 | 7 | public const int DisabledSet = 1; 8 | 9 | public const int AwakeSet = 2; 10 | 11 | public const int FirstSleepingSet = 3; 12 | } 13 | } -------------------------------------------------------------------------------- /src/Solver/SolverStage.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Each stage must be completed before going to the next stage. 5 | /// Non-iterative stages use a stage instance once while iterative stages re-use the same instance each iteration. 6 | /// 7 | public class SolverStage 8 | { 9 | public SolverStageType Type; 10 | 11 | public SolverBlock[] Blocks = null!; 12 | 13 | public int BlockCount; 14 | 15 | public int ColorIndex; 16 | 17 | /// 18 | /// Atomic, todo consider false sharing of this atomic 19 | /// 20 | public int CompletionCount; 21 | } 22 | } -------------------------------------------------------------------------------- /src/Solver/SolverStageType.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// 解算步骤 5 | /// 6 | public enum SolverStageType 7 | { 8 | /// 9 | /// 准备关节 10 | /// 11 | PrepareJoints, 12 | 13 | /// 14 | /// 准备接触点 15 | /// 16 | PrepareContacts, 17 | 18 | /// 19 | /// 速度积分 20 | /// 21 | IntegrateVelocities, 22 | 23 | /// 24 | /// 热启动 25 | /// 26 | WarmStart, 27 | 28 | /// 29 | /// 解算 30 | /// 31 | Solve, 32 | 33 | /// 34 | /// 位置积分 35 | /// 36 | IntegratePositions, 37 | 38 | /// 39 | /// 松弛 40 | /// 41 | Relax, 42 | 43 | /// 44 | /// 弹性计算 45 | /// 46 | Restitution, 47 | 48 | /// 49 | /// 储存冲量 50 | /// 51 | StoreImpulses 52 | } 53 | } -------------------------------------------------------------------------------- /src/Solver/TaskContext.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public class TaskContext 4 | { 5 | // These bits align with the b2ConstraintGraph::contactBlocks and signal a change in contact status 6 | public BitSet ContactStateBitSet = new(1024); 7 | 8 | // Used to track bodies with shapes that have enlarged AABBs. This avoids having a bit array 9 | // that is very large when there are many static shapes. 10 | public BitSet EnlargedSimBitSet = new(256); 11 | 12 | // Used to put islands to sleep 13 | public BitSet AwakeIslandBitSet = new(256); 14 | 15 | // Per worker split island candidate 16 | public float SplitSleepTime; 17 | 18 | public int SplitIslandId; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Solver/WorkerContext.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// 工人上下文 5 | /// 6 | public struct WorkerContext 7 | { 8 | /// 9 | /// 所属步进上下文 10 | /// 11 | public StepContext Context; 12 | 13 | /// 14 | /// 工人索引 15 | /// 16 | public int WorkerIndex; 17 | } 18 | } -------------------------------------------------------------------------------- /src/Types/CastResultFcn.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// Prototype callback for ray casts. 4 | /// Called for each shape found in the query. You control how the ray cast 5 | /// proceeds by returning a float: 6 | /// return -1: ignore this shape and continue 7 | /// return 0: terminate the ray cast 8 | /// return fraction: clip the ray to this point 9 | /// return 1: don't clip the ray and continue 10 | /// @param shapeId the shape hit by the ray 11 | /// @param point the point of initial intersection 12 | /// @param normal the normal vector at the point of intersection 13 | /// @param fraction the fraction along the ray at the point of intersection 14 | /// @param context the user context 15 | /// @return -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue 16 | /// @see b2World_CastRay 17 | /// @ingroup world 18 | public delegate float CastResultFcn(ShapeId shapeId, Vec2 point, Vec2 normal, float fraction, object context); 19 | } -------------------------------------------------------------------------------- /src/Types/CustomFilterFcn.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /**@}*/ 4 | /// Prototype for a contact filter callback. 5 | /// This is called when a contact pair is considered for collision. This allows you to 6 | /// perform custom logic to prevent collision between shapes. This is only called if 7 | /// one of the two shapes has custom filtering enabled. @see b2ShapeDef. 8 | /// Notes: 9 | /// - this function must be thread-safe 10 | /// - this is only called if one of the two shapes has enabled custom filtering 11 | /// - this is called only for awake dynamic bodies 12 | /// Return false if you want to disable the collision 13 | /// @warning Do not attempt to modify the world inside this callback 14 | /// @ingroup world 15 | public delegate bool CustomFilterFcn(ShapeId shapeIdA, ShapeId shapeIdB, object context); 16 | } -------------------------------------------------------------------------------- /src/Types/DynamicTreeCallbackFcn.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | public delegate bool TreeQueryCallbackFcn(int proxyId, int userData, object context); 4 | 5 | public delegate float TreeRayCastCallbackFcn(ref RayCastInput input, int proxyId, int userData, object context); 6 | 7 | public delegate float TreeShapeCastCallbackFcn(ref ShapeCastInput input, int proxyId, int userData, object context); 8 | } -------------------------------------------------------------------------------- /src/Types/FinishTaskCallback.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Finishes a user task object that wraps a Box2D task. 5 | /// 任务完成回调 6 | /// 7 | public delegate void FinishTaskCallback(object userTask, object userContext); 8 | } -------------------------------------------------------------------------------- /src/Types/OverlapResultFcn.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// Prototype callback for overlap queries. 4 | /// Called for each shape found in the query. 5 | /// @see b2World_QueryAABB 6 | /// @return false to terminate the query. 7 | /// @ingroup world 8 | public delegate bool OverlapResultFcn(ShapeId shapeId, object context); 9 | } -------------------------------------------------------------------------------- /src/Types/PreSolveFcn.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// Prototype for a pre-solve callback. 4 | /// This is called after a contact is updated. This allows you to inspect a 5 | /// contact before it goes to the solver. If you are careful, you can modify the 6 | /// contact manifold (e.g. modify the normal). 7 | /// Notes: 8 | /// - this function must be thread-safe 9 | /// - this is only called if the shape has enabled pre-solve events 10 | /// - this is called only for awake dynamic bodies 11 | /// - this is not called for sensors 12 | /// - the supplied manifold has impulse values from the previous step 13 | /// Return false if you want to disable the contact this step 14 | /// @warning Do not attempt to modify the world inside this callback 15 | /// @ingroup world 16 | public delegate bool PreSolveFcn(ShapeId shapeIdA, ShapeId shapeIdB, ref Manifold manifold, object context); 17 | } -------------------------------------------------------------------------------- /src/Types/QueryFilter.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// The query filter is used to filter collisions between queries and shapes. For example, 4 | /// you may want a ray-cast representing a projectile to hit players and the static environment 5 | /// but not debris. 6 | /// @ingroup shape 7 | public struct QueryFilter 8 | { 9 | /// The collision category bits of this query. Normally you would just set one bit. 10 | public ulong CategoryBits; 11 | 12 | /// The collision mask bits. This states the shape categories that this 13 | /// query would accept for collision. 14 | public ulong MaskBits; 15 | 16 | public QueryFilter(ulong categoryBits, ulong maskBits) 17 | { 18 | CategoryBits = categoryBits; 19 | MaskBits = maskBits; 20 | } 21 | 22 | /// Use this to initialize your query filter 23 | /// @ingroup shape 24 | public static QueryFilter DefaultQueryFilter() 25 | { 26 | QueryFilter filter = new(0x0001UL, ulong.MaxValue); 27 | return filter; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Types/TaskCallback.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Task interface 5 | /// This is prototype for a Box2D task. Your task system is expected to invoke the Box2D task with these arguments. 6 | /// The task spans a range of the parallel-for: [startIndex, endIndex) 7 | /// The worker index must correctly identify each worker in the user thread pool, expected in [0, workerCount). 8 | /// A worker must only exist on only one thread at a time and is analogous to the thread index. 9 | /// The task context is the context pointer sent from Box2D when it is enqueued. 10 | /// The startIndex and endIndex are expected in the range [0, itemCount) where itemCount is the argument to b2EnqueueTaskCallback 11 | /// below. Box2D expects startIndex < endIndex and will execute a loop like this: 12 | /// 13 | /// 任务回调接口 14 | /// 这是 Box2D 任务的原型。您的任务系统应使用这些参数调用 Box2D 任务。 15 | /// 并行任务的范围为:[startIndex, endIndex) 16 | /// Worker 索引必须正确标识用户线程池中的每个 Worker,预计为 [0, workerCount]。 17 | /// Worker 每次只能存在于一个线程中,类似于线程索引。 18 | /// 任务上下文是 Box2D 在排队时发送的上下文指针。 19 | /// startIndex 和 endIndex 的范围是 [0,itemCount],其中 itemCount 是下面 EnqueueTaskCallback 的参数。 20 | /// Box2D 预计 startIndex < endIndex 将执行这样一个循环: 21 | /// 22 | /// @code{.c} 23 | /// for (int i = startIndex; i < endIndex; ++i) 24 | /// { 25 | /// DoWork(); 26 | /// } 27 | /// @endcode 28 | /// 29 | public delegate void TaskCallback(int startIndex, int endIndex, int workerIndex, object taskContext); 30 | } -------------------------------------------------------------------------------- /src/Version.cs: -------------------------------------------------------------------------------- 1 | namespace Box2DSharp 2 | { 3 | /// 4 | /// Version numbering scheme. 5 | /// See https://semver.org/ 6 | /// 7 | public struct Version 8 | { 9 | /// Significant changes 10 | public int Major; 11 | 12 | /// Incremental changes 13 | public int Minor; 14 | 15 | /// Bug fixes 16 | public int Revision; 17 | 18 | public Version(int major, int minor, int revision) 19 | { 20 | Major = major; 21 | Minor = minor; 22 | Revision = revision; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /test/ConsoleTest/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/ConsoleTest/ConsoleTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | true 6 | 13 7 | net8.0 8 | 9 | 10 | 11 | full 12 | 13 | 14 | 15 | true 16 | full 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/ConsoleTest/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ConsoleTest.TestCases; 3 | 4 | namespace ConsoleTest 5 | { 6 | static class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var steps = args.Length > 0 ? int.Parse(args[0]) : 100; 11 | using var test = new ManyTumbler(); 12 | for (int i = 0; i < steps; i++) 13 | { 14 | test.Step(); 15 | Console.WriteLine(i); 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /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/Testbed.Abstractions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Abstractions 2 | { 3 | public static class EnumExtensions 4 | { 5 | public static bool IsSet(this KeyModifiers self, KeyModifiers flag) => (self & flag) == flag; 6 | } 7 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 IDraw Draw { get; set; } 11 | 12 | public static readonly Camera Camera = new Camera(); 13 | 14 | public static Settings Settings { get; set; } 15 | 16 | public static IInput Input { get; set; } 17 | 18 | public static List<(string Category, string Name, Type SampleType)> Samples { get; private set; } 19 | 20 | public static void SetupSamples(List testTypes) 21 | { 22 | var testBaseType = typeof(SampleBase); 23 | Samples = testTypes 24 | .Where(e => testBaseType.IsAssignableFrom(e) && !e.IsAbstract) 25 | .Select( 26 | e => 27 | { 28 | var sample = e.GetCustomAttribute() ?? throw new NullReferenceException(e.Name); 29 | return (sample.Category, sample.Name, e); 30 | }) 31 | .OrderBy(e => e.Category) 32 | .ThenBy(e => e.Name) 33 | .ToList(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/IDraw.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Box2DSharp; 3 | 4 | namespace Testbed.Abstractions 5 | { 6 | public interface IDraw : IDisposable 7 | { 8 | DebugDrawBase DebugDraw { get; } 9 | 10 | void DrawPolygon(ReadOnlySpan vertices, int vertexCount, B2HexColor color); 11 | 12 | void DrawSolidPolygon(Transform transform, ReadOnlySpan vertices, int vertexCount, float radius, B2HexColor color); 13 | 14 | void DrawCircle(Vec2 center, float radius, B2HexColor color); 15 | 16 | void DrawSolidCircle(Transform transform, Vec2 center, float radius, B2HexColor color); 17 | 18 | void DrawCapsule(Vec2 p1, Vec2 p2, float radius, B2HexColor color); 19 | 20 | void DrawSolidCapsule(Vec2 p1, Vec2 p2, float radius, B2HexColor color); 21 | 22 | void DrawSegment(Vec2 p1, Vec2 p2, B2HexColor color); 23 | 24 | void DrawTransform(Transform transform); 25 | 26 | void DrawPoint(Vec2 p, float size, B2HexColor color); 27 | 28 | void DrawString(int x, int y, string str); 29 | 30 | void DrawString(Vec2 p, string str); 31 | 32 | void DrawAABB(AABB aabb, B2HexColor color); 33 | 34 | void Flush(); 35 | 36 | void DrawBackground(); 37 | } 38 | } -------------------------------------------------------------------------------- /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 IsMouseClicked(MouseButton button); 14 | 15 | bool IsMouseUp(MouseButton button); 16 | } 17 | } -------------------------------------------------------------------------------- /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/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 | LeftControl, 30 | 31 | RightControl, 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 | Space 94 | } 95 | } -------------------------------------------------------------------------------- /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.IsSet(KeyModifiers.Alt); 12 | 13 | public bool Control => Modifiers.IsSet(KeyModifiers.Control); 14 | 15 | public bool Shift => Modifiers.IsSet(KeyModifiers.Shift); 16 | 17 | public bool Command => Modifiers.IsSet(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/Testbed.Abstractions/KeyModifiers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | [Flags] 6 | public enum KeyModifiers 7 | { 8 | None = 0, 9 | 10 | /// if one or more Shift keys were held down. 11 | Shift = 1 << 0, 12 | 13 | /// If one or more Control keys were held down. 14 | Control = 1 << 1, 15 | 16 | /// If one or more Alt keys were held down. 17 | Alt = 1 << 2, 18 | 19 | /// If one or more Super keys were held down. 20 | Super = 1 << 3, 21 | 22 | /// If caps lock is enabled. 23 | CapsLock = 1 << 4, 24 | 25 | /// If num lock is enabled. 26 | NumLock = 1 << 5 27 | } 28 | } -------------------------------------------------------------------------------- /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/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/MouseMoveEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace Testbed.Abstractions; 4 | 5 | public readonly struct MouseMoveEventArgs(Vector2 position, Vector2 delta) 6 | { 7 | public MouseMoveEventArgs(float x, float y, float deltaX, float deltaY) 8 | : this(new Vector2(x, y), new Vector2(deltaX, deltaY)) 9 | { } 10 | 11 | /// 12 | /// Gets the new X position produced by this event. 13 | /// This position is relative to the top-left corner of the contents of the window. 14 | /// 15 | public float X => this.Position.X; 16 | 17 | /// 18 | /// Gets the new Y position produced by this event. 19 | /// This position is relative to the top-left corner of the contents of the window. 20 | /// 21 | public float Y => this.Position.Y; 22 | 23 | /// 24 | /// Gets the new position produced by this event. 25 | /// This position is relative to the top-left corner of the contents of the window. 26 | /// 27 | public Vector2 Position { get; } = position; 28 | 29 | /// Gets the change in X position since the last event. 30 | public float DeltaX => this.Delta.X; 31 | 32 | /// Gets the change in Y position since the last event. 33 | public float DeltaY => this.Delta.Y; 34 | 35 | /// Gets the change in position since the last event. 36 | public Vector2 Delta { get; } = delta; 37 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/SampleAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed.Abstractions 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 6 | public class SampleAttribute : Attribute 7 | { 8 | public SampleAttribute(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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /test/Testbed.Abstractions/Testbed.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 12 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/Testbed.Samples/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/Testbed.Samples/Benchmark/Kinematic.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.Samples.Benchmark; 5 | 6 | [Sample("Benchmark", "Kinematic")] 7 | public class Kinematic : SampleBase 8 | { 9 | public Kinematic(Settings settings) 10 | : base(settings) 11 | { 12 | if (settings.Restart == false) 13 | { 14 | Global.Camera.Center = (0.0f, 0.0f); 15 | Global.Camera.Zoom = 150.0f; 16 | } 17 | 18 | float grid = 1.0f; 19 | 20 | int span = Core.B2Debug ? 20 : 100; 21 | 22 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 23 | bodyDef.Type = BodyType.KinematicBody; 24 | bodyDef.AngularVelocity = 1.0f; 25 | 26 | // defer mass properties to avoid n-squared mass computations 27 | bodyDef.AutomaticMass = false; 28 | 29 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 30 | shapeDef.Filter.CategoryBits = 1; 31 | shapeDef.Filter.MaskBits = 2; 32 | 33 | BodyId bodyId = Body.CreateBody(WorldId, bodyDef); 34 | 35 | for (int i = -span; i < span; ++i) 36 | { 37 | float y = i * grid; 38 | for (int j = -span; j < span; ++j) 39 | { 40 | float x = j * grid; 41 | Polygon square = Geometry.MakeOffsetBox(0.5f * grid, 0.5f * grid, (x, y), Rot.Identity); 42 | Shape.CreatePolygonShape(bodyId, shapeDef, square); 43 | } 44 | } 45 | 46 | // All shapes have been added so I can efficiently compute the mass properties. 47 | Body.ApplyMassFromShapes(bodyId); 48 | } 49 | } -------------------------------------------------------------------------------- /test/Testbed.Samples/Joints/DoohickeyFarm.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.Samples.Joints; 5 | 6 | [Sample("Joints", "Doohickey Farm")] 7 | public class DoohickeyFarm : SampleBase 8 | { 9 | public DoohickeyFarm(Settings settings) 10 | : base(settings) 11 | { 12 | if (settings.Restart == false) 13 | { 14 | Global.Camera.Center = (0.0f, 5.0f); 15 | Global.Camera.Zoom = 25.0f * 0.35f; 16 | } 17 | 18 | { 19 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 20 | BodyId groundId = Body.CreateBody(WorldId, bodyDef); 21 | 22 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 23 | Segment segment = ((-20.0f, 0.0f), (20.0f, 0.0f)); 24 | Shape.CreateSegmentShape(groundId, shapeDef, segment); 25 | 26 | Polygon box = Geometry.MakeOffsetBox(1.0f, 1.0f, (0.0f, 1.0f), Rot.Identity); 27 | Shape.CreatePolygonShape(groundId, shapeDef, box); 28 | } 29 | 30 | float y = 4.0f; 31 | for (int i = 0; i < 4; ++i) 32 | { 33 | Doohickey doohickey = new(); 34 | doohickey.Spawn(WorldId, (0.0f, y), 0.5f); 35 | y += 2.0f; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /test/Testbed.Samples/Joints/Ragdoll.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.Samples.Joints; 5 | 6 | [Sample("Joints", "Ragdoll")] 7 | public class Ragdoll : SampleBase 8 | { 9 | public Ragdoll(Settings settings) 10 | : base(settings) 11 | { 12 | if (settings.Restart == false) 13 | { 14 | Global.Camera.Center = (0.0f, 3.0f); 15 | Global.Camera.Zoom = 25.0f * 0.15f; 16 | } 17 | 18 | { 19 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 20 | BodyId groundId = Body.CreateBody(WorldId, bodyDef); 21 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 22 | Segment segment = ((-20.0f, 0.0f), (20.0f, 0.0f)); 23 | Shape.CreateSegmentShape(groundId, shapeDef, segment); 24 | } 25 | 26 | m_jointFrictionTorque = 0.05f; 27 | m_jointHertz = 0.0f; 28 | m_jointDampingRatio = 0.5f; 29 | 30 | m_human.Spawn( 31 | WorldId, 32 | (0.0f, 5.0f), 33 | 1.0f, 34 | m_jointFrictionTorque, 35 | m_jointHertz, 36 | m_jointDampingRatio, 37 | 1, 38 | null, 39 | true); 40 | m_human.ApplyRandomAngularImpulse(10.0f); 41 | } 42 | 43 | protected Human m_human = new(); 44 | 45 | protected float m_jointFrictionTorque; 46 | 47 | protected float m_jointHertz; 48 | 49 | protected float m_jointDampingRatio; 50 | } -------------------------------------------------------------------------------- /test/Testbed.Samples/Joints/SoftBody.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.Samples.Joints; 5 | 6 | [Sample("Joints", "Soft Body")] 7 | public class SoftBody : SampleBase 8 | { 9 | public SoftBody(Settings settings) 10 | : base(settings) 11 | { 12 | if (settings.Restart == false) 13 | { 14 | Global.Camera.Center = (0.0f, 5.0f); 15 | Global.Camera.Zoom = 25.0f * 0.25f; 16 | } 17 | 18 | { 19 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 20 | BodyId groundId = Body.CreateBody(WorldId, bodyDef); 21 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 22 | Segment segment = ((-20.0f, 0.0f), (20.0f, 0.0f)); 23 | Shape.CreateSegmentShape(groundId, shapeDef, segment); 24 | } 25 | 26 | m_donut.Spawn(WorldId, (0.0f, 10.0f), 2.0f, 0, null); 27 | } 28 | 29 | protected Donut m_donut = new(); 30 | } -------------------------------------------------------------------------------- /test/Testbed.Samples/Shapes/CircleStack.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.Samples.Shapes; 5 | 6 | [Sample("Stacking", "Circle Stack")] 7 | public class CircleStack : SampleBase 8 | { 9 | public CircleStack(Settings settings) 10 | : base(settings) 11 | { 12 | if (settings.Restart == false) 13 | { 14 | Global.Camera.Center = (0.0f, 2.0f); 15 | Global.Camera.Zoom = 3.0f; 16 | } 17 | 18 | { 19 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 20 | BodyId groundId = Body.CreateBody(WorldId, bodyDef); 21 | 22 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 23 | Segment segment = ((-10.0f, 0.0f), (10.0f, 0.0f)); 24 | Shape.CreateSegmentShape(groundId, shapeDef, segment); 25 | } 26 | 27 | World.SetGravity(WorldId, (0.0f, -20.0f)); 28 | World.SetContactTuning(WorldId, 0.25f * 360.0f, 10.0f, 3.0f); 29 | { 30 | Circle circle = new(); 31 | circle.Radius = 0.5f; 32 | 33 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 34 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 35 | bodyDef.Type = BodyType.DynamicBody; 36 | 37 | float y = 0.5f; 38 | 39 | for (int i = 0; i < 8; ++i) 40 | { 41 | bodyDef.Position.Y = y; 42 | 43 | BodyId bodyId = Body.CreateBody(WorldId, bodyDef); 44 | Shape.CreateCircleShape(bodyId, shapeDef, circle); 45 | 46 | y += 1.0f; 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /test/Testbed.Samples/Stacking/SingleBox.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.Samples.Stacking; 5 | 6 | [Sample("Stacking", "SingleBox")] 7 | public class SingleBox : SampleBase 8 | { 9 | public SingleBox(Settings settings) 10 | : base(settings) 11 | { 12 | float extent = 1.0f; 13 | 14 | BodyDef bodyDef = BodyDef.DefaultBodyDef(); 15 | BodyId groundId = Body.CreateBody(WorldId, bodyDef); 16 | 17 | float groundWidth = 66.0f * extent; 18 | ShapeDef shapeDef = ShapeDef.DefaultShapeDef(); 19 | shapeDef.Friction = 0.5f; 20 | 21 | Segment segment = new(new(-0.5f * 2.0f * groundWidth, 0.0f), new(0.5f * 2.0f * groundWidth, 0.0f)); 22 | Shape.CreateSegmentShape(groundId, shapeDef, segment); 23 | bodyDef.Type = BodyType.DynamicBody; 24 | { 25 | Polygon box = Geometry.MakeBox(extent, extent); 26 | bodyDef.Position = new(0.0f, 4.0f); 27 | BodyId bodyId = Body.CreateBody(WorldId, bodyDef); 28 | Shape.CreatePolygonShape(bodyId, shapeDef, box); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/Testbed.Samples/Testbed.Samples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 13 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/ArrayExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed425140e76f4312b2ad1fdbee738a7f 3 | timeCreated: 1547395279 -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/Box2DSharp.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d7db7760f9ad70845b1ca71b09755a6a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/Assets/FixedUpdate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f0d87a7eecf1b794e81407a1660e4136 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.Unity/Assets/FpsCounter.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Box2DSharp.Testbed.Unity 4 | { 5 | public class FpsCounter 6 | { 7 | public float Ms = 0; 8 | 9 | public float Fps = 0; 10 | 11 | public int FrameCount; 12 | 13 | private long _lastTimeDiff = 0; 14 | 15 | private long _lastTime = 0; 16 | 17 | private readonly Stopwatch _fpsTimer = Stopwatch.StartNew(); 18 | 19 | private float _msSum = 0; 20 | 21 | private int _fpsCount = 0; 22 | 23 | private const int FpsSumMax = 10; 24 | 25 | public void SetFps() 26 | { 27 | FrameCount++; 28 | var now = _fpsTimer.ElapsedMilliseconds; 29 | _lastTimeDiff = now - _lastTime; 30 | _lastTime = now; 31 | 32 | if (_fpsCount != FpsSumMax) 33 | { 34 | _msSum += _lastTimeDiff; 35 | _fpsCount++; 36 | } 37 | 38 | if (_fpsCount == FpsSumMax) 39 | { 40 | Ms = _msSum / FpsSumMax; 41 | Fps = FpsSumMax / (_msSum / 1000f); 42 | _msSum = 0; 43 | _fpsCount = 0; 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/FpsCounter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1dc0bae7884e4699b63ab5db7af47ae6 3 | timeCreated: 1556021032 -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/GUIController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6bb46d75722b48de84051820c4aba07c 3 | timeCreated: 1607766607 -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/Game.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 143d54880e664cba8e885837f3c9e1d3 3 | timeCreated: 1542381903 -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | m_UpdateMode: 1 19 | m_CompensateForScreenOrientation: 1 20 | m_FilterNoiseOnCurrent: 0 21 | m_DefaultDeadzoneMin: 0.125 22 | m_DefaultDeadzoneMax: 0.925 23 | m_DefaultButtonPressPoint: 0.5 24 | m_DefaultTapTime: 0.2 25 | m_DefaultSlowTapTime: 0.5 26 | m_DefaultHoldTime: 0.4 27 | m_TapRadius: 5 28 | m_MultiTapDelayTime: 0.75 29 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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.Unity/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 | private void Start() 17 | { 18 | MainCamera = Camera.main; 19 | } 20 | 21 | private void Update() 22 | { 23 | ScreenMouse = Mouse.current.position.ReadValue(); 24 | WorldMouse = MainCamera.ScreenToWorldPoint(ScreenMouse); 25 | ViewPortMouse = MainCamera.ScreenToViewportPoint(ScreenMouse); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/Inspection/MouseInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e74f060ec4274c01b2b11018d97e8ee1 3 | timeCreated: 1547565190 -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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/Testbed.Unity/Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: defa990f0023d3342a8d910d28e91f51 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/Scenes/Test.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66423098b77c3cd4fbb36f238ef87547 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/System.Buffers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp/6bd0dd8fd14fb811cbc4f0ffa8b256a67f5f1e72/test/Testbed.Unity/Assets/System.Buffers.dll -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/Assets/System.Memory.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp/6bd0dd8fd14fb811cbc4f0ffa8b256a67f5f1e72/test/Testbed.Unity/Assets/System.Memory.dll -------------------------------------------------------------------------------- /test/Testbed.Unity/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.Unity/Assets/System.Runtime.CompilerServices.Unsafe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp/6bd0dd8fd14fb811cbc4f0ffa8b256a67f5f1e72/test/Testbed.Unity/Assets/System.Runtime.CompilerServices.Unsafe.dll -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/System.Runtime.CompilerServices.Unsafe.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20394b20baf041b4aa7e52d89cccacf4 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.Unity/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 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/TestInheritAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a407bfe79b744bf9a831a6ccee1c5f40 3 | timeCreated: 1607748702 -------------------------------------------------------------------------------- /test/Testbed.Unity/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.Unity/Assets/TestSettingHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7dcd27f1e91740e98b2ea02fca887277 3 | timeCreated: 1607764306 -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d52a0991d05be24c96148e34889972a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/Tests/CompoundShapesRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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 | Spawn(); 20 | } 21 | 22 | ImGui.End(); 23 | base.OnRender(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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/Testbed.Unity/Assets/Tests/EdgeTestRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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)) 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.Unity/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/Testbed.Unity/Assets/Tests/PrismaticJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, -100.0f, 100.0f, "%.0f")) 28 | { 29 | Joint.SetMotorSpeed(MotorSpeed); 30 | } 31 | 32 | ImGui.End(); 33 | base.OnRender(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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/Testbed.Unity/Assets/Tests/RensorsTestRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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 | ImGui.SliderFloat("Force", ref _force, 0.0f, 2000.0f, "%.0f"); 18 | 19 | ImGui.End(); 20 | base.OnRender(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/Assets/Tests/RevoluteJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, -20.0f, 20.0f, "%.0f")) 28 | { 29 | Joint1.SetMotorSpeed(MotorSpeed); 30 | } 31 | 32 | ImGui.End(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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/Testbed.Unity/Assets/Tests/WheelJointTestRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, -100.0f, 100.0f, "%.0f")) 28 | { 29 | Joint.SetMotorSpeed(MotorSpeed); 30 | } 31 | 32 | ImGui.End(); 33 | base.OnRender(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/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.Unity/Assets/Tests/WreckingBallRender.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.TestCases; 3 | using UnityEngine; 4 | 5 | namespace Box2DSharp.Testbed.Unity.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 && _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 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/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.Unity/Assets/UnityInput.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7910dcfe71048cd87e085985c62371f 3 | timeCreated: 1607758298 -------------------------------------------------------------------------------- /test/Testbed.Unity/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.Unity/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 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | } -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/UnityTestSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69ab502e65f5441986a36885df4a0cea 3 | timeCreated: 1607786888 -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/UniversalRenderPipelineGlobalSettings.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: 2ec995e51a6e251468d2a3fd8a686257, type: 3} 13 | m_Name: UniversalRenderPipelineGlobalSettings 14 | m_EditorClassIdentifier: 15 | k_AssetVersion: 3 16 | m_RenderingLayerNames: 17 | - Default 18 | m_ValidRenderingLayers: 1 19 | lightLayerName0: 20 | lightLayerName1: 21 | lightLayerName2: 22 | lightLayerName3: 23 | lightLayerName4: 24 | lightLayerName5: 25 | lightLayerName6: 26 | lightLayerName7: 27 | m_StripDebugVariants: 1 28 | m_StripUnusedPostProcessingVariants: 0 29 | m_StripUnusedVariants: 1 30 | m_StripUnusedLODCrossFadeVariants: 1 31 | m_StripScreenCoordOverrideVariants: 1 32 | supportRuntimeDebugDisplay: 0 33 | m_ShaderVariantLogLevel: 0 34 | m_ExportShaderVariants: 1 35 | -------------------------------------------------------------------------------- /test/Testbed.Unity/Assets/UniversalRenderPipelineGlobalSettings.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e105c0aa3bf3ac4c8f5ed95a0fb65ad 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /test/Testbed.Unity/CopyBox2DSharp.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set rootPath=%cd% 3 | 4 | rmdir /s /q "%cd%\Assets\Box2DSharp" 5 | 6 | xcopy /s /y /q "%cd%\..\..\src" "%cd%\Assets\Box2DSharp\Box2DSharp\" 7 | xcopy /s /y /q "%cd%\..\Testbed.Abstractions" "%cd%\Assets\Box2DSharp\Testbed.Abstractions\" 8 | xcopy /s /y /q "%cd%\..\Testbed.TestCases" "%cd%\Assets\Box2DSharp\Testbed.TestCases\" 9 | 10 | cd "%cd%\Assets\Box2DSharp" 11 | for /d /r . %%d in (bin,obj) do @if exist "%%d" rd /s/q "%%d" 12 | cd %rootPath% 13 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 0 20 | -------------------------------------------------------------------------------- /test/Testbed.Unity/ProjectSettings/BurstAotSettings_Android.json: -------------------------------------------------------------------------------- 1 | { 2 | "MonoBehaviour": { 3 | "Version": 4, 4 | "EnableBurstCompilation": true, 5 | "EnableOptimisations": true, 6 | "EnableSafetyChecks": false, 7 | "EnableDebugInAllBuilds": false, 8 | "DebugDataKind": 1, 9 | "EnableArmv9SecurityFeatures": false, 10 | "CpuMinTargetX32": 0, 11 | "CpuMaxTargetX32": 0, 12 | "CpuMinTargetX64": 0, 13 | "CpuMaxTargetX64": 0, 14 | "CpuTargetsArm64": 512, 15 | "OptimizeFor": 0 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Testbed.Unity/ProjectSettings/BurstAotSettings_StandaloneWindows.json: -------------------------------------------------------------------------------- 1 | { 2 | "MonoBehaviour": { 3 | "Version": 4, 4 | "EnableBurstCompilation": true, 5 | "EnableOptimisations": true, 6 | "EnableSafetyChecks": false, 7 | "EnableDebugInAllBuilds": false, 8 | "DebugDataKind": 1, 9 | "EnableArmv9SecurityFeatures": false, 10 | "CpuMinTargetX32": 0, 11 | "CpuMaxTargetX32": 0, 12 | "CpuMinTargetX64": 0, 13 | "CpuMaxTargetX64": 0, 14 | "CpuTargetsX32": 6, 15 | "CpuTargetsX64": 72, 16 | "OptimizeFor": 0 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | -------------------------------------------------------------------------------- /test/Testbed.Unity/ProjectSettings/CommonBurstAotSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "MonoBehaviour": { 3 | "Version": 4, 4 | "DisabledWarnings": "" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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: 13 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_DefaultMaxDepenetrationVelocity: 10 11 | m_SleepThreshold: 0.005 12 | m_DefaultContactOffset: 0.01 13 | m_DefaultSolverIterations: 6 14 | m_DefaultSolverVelocityIterations: 1 15 | m_QueriesHitBackfaces: 0 16 | m_QueriesHitTriggers: 1 17 | m_EnableAdaptiveForce: 0 18 | m_ClothInterCollisionDistance: 0.1 19 | m_ClothInterCollisionStiffness: 0.2 20 | m_ContactsGeneration: 1 21 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 22 | m_AutoSimulation: 1 23 | m_AutoSyncTransforms: 0 24 | m_ReuseCollisionCallbacks: 1 25 | m_ClothInterCollisionSettingsToggle: 0 26 | m_ClothGravity: {x: 0, y: -9.81, z: 0} 27 | m_ContactPairsMode: 0 28 | m_BroadphaseType: 0 29 | m_WorldBounds: 30 | m_Center: {x: 0, y: 0, z: 0} 31 | m_Extent: {x: 250, y: 250, z: 250} 32 | m_WorldSubdivisions: 8 33 | m_FrictionType: 0 34 | m_EnableEnhancedDeterminism: 0 35 | m_EnableUnifiedHeightmaps: 1 36 | m_SolverType: 0 37 | m_DefaultMaxAngularSpeed: 50 38 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Test.unity 10 | guid: 66423098b77c3cd4fbb36f238ef87547 11 | m_configObjects: {} 12 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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: 11 7 | m_SerializationMode: 2 8 | m_LineEndingsForNewScripts: 0 9 | m_DefaultBehaviorMode: 1 10 | m_PrefabRegularEnvironment: {fileID: 0} 11 | m_PrefabUIEnvironment: {fileID: 0} 12 | m_SpritePackerMode: 5 13 | m_SpritePackerPaddingPower: 1 14 | m_EtcTextureCompressorBehavior: 1 15 | m_EtcTextureFastCompressor: 1 16 | m_EtcTextureNormalCompressor: 2 17 | m_EtcTextureBestCompressor: 4 18 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp 19 | m_ProjectGenerationRootNamespace: 20 | m_EnableTextureStreamingInEditMode: 1 21 | m_EnableTextureStreamingInPlayMode: 1 22 | m_AsyncShaderCompilation: 1 23 | m_CachingShaderPreprocessor: 1 24 | m_PrefabModeAllowAutoSave: 1 25 | m_EnterPlayModeOptionsEnabled: 0 26 | m_EnterPlayModeOptions: 3 27 | m_GameObjectNamingDigits: 1 28 | m_GameObjectNamingScheme: 0 29 | m_AssetNamingUsesSpace: 1 30 | m_UseLegacyProbeSampleCount: 0 31 | m_SerializeInlineMappingsOnOneLine: 1 32 | m_DisableCookiesInLightmapper: 1 33 | m_AssetPipelineMode: 1 34 | m_CacheServerMode: 0 35 | m_CacheServerEndpoint: 36 | m_CacheServerNamespacePrefix: default 37 | m_CacheServerEnableDownload: 1 38 | m_CacheServerEnableUpload: 1 39 | m_CacheServerEnableAuth: 0 40 | m_CacheServerEnableTls: 0 41 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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/Testbed.Unity/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_EnablePreReleasePackages: 0 16 | m_AdvancedSettingsExpanded: 1 17 | m_ScopedRegistriesSettingsExpanded: 1 18 | m_SeeAllPackageVersions: 0 19 | m_DismissPreviewPackagesInUse: 0 20 | oneTimeWarningShown: 0 21 | m_Registries: 22 | - m_Id: main 23 | m_Name: 24 | m_Url: https://packages.unity.cn 25 | m_Scopes: [] 26 | m_IsDefault: 1 27 | m_Capabilities: 7 28 | m_ConfigSource: 0 29 | m_UserSelectedRegistryName: 30 | m_UserAddingNewScopedRegistry: 0 31 | m_RegistryInfoDraft: 32 | m_Modified: 0 33 | m_ErrorMessage: 34 | m_UserModificationsInstanceId: -842 35 | m_OriginalInstanceId: -844 36 | m_LoadAssets: 0 37 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | serializedVersion: 2 7 | m_DefaultPresets: {} 8 | -------------------------------------------------------------------------------- /test/Testbed.Unity/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2022.3.20f1c1 2 | m_EditorVersionWithRevision: 2022.3.20f1c1 (82a5dab7aa2a) 3 | -------------------------------------------------------------------------------- /test/Testbed.Unity/ProjectSettings/ShaderGraphSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 53 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: de02f9e1d18f588468e474319d09a723, type: 3} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | shaderVariantLimit: 128 16 | customInterpolatorErrorThreshold: 32 17 | customInterpolatorWarningThreshold: 16 18 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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/Testbed.Unity/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.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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: 1 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_DashboardUrl: https://dashboard.unity3d.com 13 | m_CNEventUrl: https://cdp.cloud.unity.cn/v1/events 14 | m_CNConfigUrl: https://cdp.cloud.unity.cn/config 15 | m_TestInitMode: 0 16 | CrashReportingSettings: 17 | m_EventUrl: https://perf-events.cloud.unity.cn 18 | m_Enabled: 0 19 | m_LogBufferSize: 10 20 | m_CaptureEditorExceptions: 1 21 | UnityPurchasingSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | UnityAnalyticsSettings: 25 | m_Enabled: 1 26 | m_TestMode: 0 27 | m_InitializeOnStartup: 1 28 | m_PackageRequiringCoreStatsPresent: 0 29 | UnityAdsSettings: 30 | m_Enabled: 0 31 | m_InitializeOnStartup: 1 32 | m_TestMode: 0 33 | m_IosGameId: 34 | m_AndroidGameId: 35 | m_GameIds: {} 36 | m_GameId: 37 | PerformanceReportingSettings: 38 | m_Enabled: 0 39 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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_StripUpdateShader: {fileID: 0} 10 | m_RenderPipeSettingsPath: 11 | m_FixedTimeStep: 0.016666668 12 | m_MaxDeltaTime: 0.05 13 | m_CompiledVersion: 0 14 | m_RuntimeVersion: 0 15 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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 | -------------------------------------------------------------------------------- /test/Testbed.Unity/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/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | *.ini -------------------------------------------------------------------------------- /test/Testbed/ColorExtensions.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using OpenTK.Mathematics; 3 | 4 | namespace Testbed 5 | { 6 | public static class ColorExtensions 7 | { 8 | public static Color4 ToColor4(this B2HexColor color) 9 | { 10 | var val = (int)color; 11 | var r = (byte)((val >> 16) & 0xFF); 12 | var g = (byte)((val >> 8) & 0xFF); 13 | var b = (byte)(val & 0xFF); 14 | return new Color4(r, g, b, 255); 15 | } 16 | 17 | public static Color4 ToColor4(this B2HexColor color, float alpha) 18 | { 19 | var val = (int)color; 20 | var r = (byte)((val >> 16) & 0xFF); 21 | var g = (byte)((val >> 8) & 0xFF); 22 | var b = (byte)(val & 0xFF); 23 | return new Color4(r, g, b, (byte)(255 * alpha)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/Testbed/MouseButtonExtensions.cs: -------------------------------------------------------------------------------- 1 | using Testbed.Abstractions; 2 | 3 | namespace Testbed; 4 | 5 | public static class MouseButtonExtensions 6 | { 7 | public static Testbed.Abstractions.MouseButton Convert(this OpenTK.Windowing.GraphicsLibraryFramework.MouseButton mouseButton) 8 | { 9 | return (Testbed.Abstractions.MouseButton)mouseButton; 10 | } 11 | 12 | public static Testbed.Abstractions.MouseInputEventArgs Convert(this OpenTK.Windowing.Common.MouseButtonEventArgs e) 13 | { 14 | return new MouseInputEventArgs((MouseButton)e.Button, (InputAction)e.Action, (KeyModifiers)e.Modifiers); 15 | } 16 | } 17 | 18 | public static class KeyboardExtensions 19 | { 20 | public static Testbed.Abstractions.KeyModifiers Convert(this OpenTK.Windowing.GraphicsLibraryFramework.KeyModifiers keyModifiers) 21 | { 22 | return (KeyModifiers)keyModifiers; 23 | } 24 | } -------------------------------------------------------------------------------- /test/Testbed/Render/data/background.fs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | 4 | #version 330 5 | 6 | out vec4 FragColor; 7 | 8 | uniform float time; 9 | uniform vec2 resolution; 10 | uniform vec3 baseColor; 11 | 12 | // A simple pseudo-random function 13 | float random(vec2 st) 14 | { 15 | return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123); 16 | } 17 | 18 | void main() 19 | { 20 | vec2 uv = gl_FragCoord.xy / resolution.xy; 21 | 22 | // Create some noise 23 | float noise = random(uv + time * 0.1); 24 | 25 | // Adjust these values to control the intensity and color of the grain 26 | float grainIntensity = 0.03; 27 | 28 | // Mix the base color with the noise 29 | vec3 color = baseColor + vec3(noise * grainIntensity); 30 | 31 | FragColor = vec4(color, 1.0); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /test/Testbed/Render/data/background.vs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | #version 330 4 | 5 | layout(location = 0) in vec2 v_position; 6 | 7 | void main(void) 8 | { 9 | gl_Position = vec4(v_position, 0.0f, 1.0f); 10 | } 11 | -------------------------------------------------------------------------------- /test/Testbed/Render/data/circle.fs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | 4 | #version 330 5 | 6 | in vec2 f_position; 7 | in vec4 f_color; 8 | in float f_thickness; 9 | 10 | out vec4 fragColor; 11 | 12 | void main() 13 | { 14 | // radius in unit quad 15 | float radius = 1.0; 16 | 17 | // distance to circle 18 | vec2 w = f_position; 19 | float dw = length(w); 20 | float d = abs(dw - radius); 21 | 22 | fragColor = vec4(f_color.rgb, smoothstep(f_thickness, 0.0, d)); 23 | } 24 | -------------------------------------------------------------------------------- /test/Testbed/Render/data/circle.vs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | 4 | #version 330 5 | 6 | uniform mat4 projectionMatrix; 7 | uniform float pixelScale; 8 | 9 | layout(location = 0) in vec2 v_localPosition; 10 | layout(location = 1) in vec2 v_instancePosition; 11 | layout(location = 2) in float v_instanceRadius; 12 | layout(location = 3) in vec4 v_instanceColor; 13 | 14 | out vec2 f_position; 15 | out vec4 f_color; 16 | out float f_thickness; 17 | 18 | void main() 19 | { 20 | f_position = v_localPosition; 21 | f_color = v_instanceColor; 22 | float radius = v_instanceRadius; 23 | 24 | // resolution.y = pixelScale * radius 25 | f_thickness = 3.0f / (pixelScale * radius); 26 | 27 | vec2 p = vec2(radius * v_localPosition.x, radius * v_localPosition.y) + v_instancePosition; 28 | gl_Position = projectionMatrix * vec4(p, 0.0f, 1.0f); 29 | } 30 | -------------------------------------------------------------------------------- /test/Testbed/Render/data/droid_sans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zonciu/Box2DSharp/6bd0dd8fd14fb811cbc4f0ffa8b256a67f5f1e72/test/Testbed/Render/data/droid_sans.ttf -------------------------------------------------------------------------------- /test/Testbed/Render/data/solid_capsule.vs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | 4 | #version 330 5 | 6 | uniform mat4 projectionMatrix; 7 | uniform float pixelScale; 8 | 9 | layout(location=0) in vec2 v_localPosition; 10 | layout(location=1) in vec4 v_instanceTransform; 11 | layout(location=2) in float v_instanceRadius; 12 | layout(location=3) in float v_instanceLength; 13 | layout(location=4) in vec4 v_instanceColor; 14 | 15 | out vec2 f_position; 16 | out vec4 f_color; 17 | out float f_length; 18 | out float f_thickness; 19 | 20 | void main() 21 | { 22 | f_position = v_localPosition; 23 | f_color = v_instanceColor; 24 | 25 | float radius = v_instanceRadius; 26 | float length = v_instanceLength; 27 | 28 | // scale quad large enough to hold capsule 29 | float scale = radius + 0.5 * length; 30 | 31 | // quad range of [-1, 1] implies normalize radius and length 32 | f_length = length / scale; 33 | 34 | // resolution.y = pixelScale * scale 35 | f_thickness = 3.0f / (pixelScale * scale); 36 | 37 | float x = v_instanceTransform.x; 38 | float y = v_instanceTransform.y; 39 | float c = v_instanceTransform.z; 40 | float s = v_instanceTransform.w; 41 | vec2 p = vec2(scale * v_localPosition.x, scale * v_localPosition.y); 42 | p = vec2((c * p.x - s * p.y) + x, (s * p.x + c * p.y) + y); 43 | gl_Position = projectionMatrix * vec4(p, 0.0, 1.0); 44 | } 45 | -------------------------------------------------------------------------------- /test/Testbed/Render/data/solid_circle.fs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | 4 | #version 330 5 | 6 | in vec2 f_position; 7 | in vec4 f_color; 8 | in float f_thickness; 9 | 10 | out vec4 fragColor; 11 | 12 | // https://en.wikipedia.org/wiki/Alpha_compositing 13 | vec4 blend_colors(vec4 front, vec4 back) 14 | { 15 | vec3 cSrc = front.rgb; 16 | float alphaSrc = front.a; 17 | vec3 cDst = back.rgb; 18 | float alphaDst = back.a; 19 | 20 | vec3 cOut = cSrc * alphaSrc + cDst * alphaDst * (1.0 - alphaSrc); 21 | float alphaOut = alphaSrc + alphaDst * (1.0 - alphaSrc); 22 | cOut = cOut / alphaOut; 23 | 24 | return vec4(cOut, alphaOut); 25 | } 26 | 27 | void main() 28 | { 29 | // radius in unit quad 30 | float radius = 1.0; 31 | 32 | // distance to axis line segment 33 | vec2 e = vec2(radius, 0); 34 | vec2 w = f_position; 35 | float we = dot(w, e); 36 | vec2 b = w - e * clamp(we / dot(e, e), 0.0, 1.0); 37 | float da = length(b); 38 | 39 | // distance to circle 40 | float dw = length(w); 41 | float dc = abs(dw - radius); 42 | 43 | // union of circle and axis 44 | float d = min(da, dc); 45 | 46 | vec4 borderColor = f_color; 47 | vec4 fillColor = 0.6f * borderColor; 48 | 49 | // roll the fill alpha down at the border 50 | vec4 back = vec4(fillColor.rgb, fillColor.a * smoothstep(radius + f_thickness, radius, dw)); 51 | 52 | // roll the border alpha down from 1 to 0 across the border thickness 53 | vec4 front = vec4(borderColor.rgb, smoothstep(f_thickness, 0.0f, d)); 54 | 55 | fragColor = blend_colors(front, back); 56 | } 57 | -------------------------------------------------------------------------------- /test/Testbed/Render/data/solid_circle.vs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Erin Catto 2 | // SPDX-License-Identifier: MIT 3 | 4 | #version 330 5 | 6 | uniform mat4 projectionMatrix; 7 | uniform float pixelScale; 8 | 9 | layout(location = 0) in vec2 v_localPosition; 10 | layout(location = 1) in vec4 v_instanceTransform; 11 | layout(location = 2) in float v_instanceRadius; 12 | layout(location = 3) in vec4 v_instanceColor; 13 | 14 | out vec2 f_position; 15 | out vec4 f_color; 16 | out float f_thickness; 17 | 18 | void main() 19 | { 20 | f_position = v_localPosition; 21 | f_color = v_instanceColor; 22 | float radius = v_instanceRadius; 23 | 24 | // resolution.y = pixelScale * radius 25 | f_thickness = 3.0f / (pixelScale * radius); 26 | 27 | float x = v_instanceTransform.x; 28 | float y = v_instanceTransform.y; 29 | float c = v_instanceTransform.z; 30 | float s = v_instanceTransform.w; 31 | vec2 p = vec2(radius * v_localPosition.x, radius * v_localPosition.y); 32 | p = vec2((c * p.x - s * p.y) + x, (s * p.x + c * p.y) + y); 33 | gl_Position = projectionMatrix * vec4(p, 0.0f, 1.0f); 34 | } 35 | -------------------------------------------------------------------------------- /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/Testbed/TestSamples/Benchmark/Barrel.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Benchmark; 5 | 6 | [TestInherit] 7 | public class Barrel(Settings settings) : Samples.Benchmark.Barrel(settings) 8 | { 9 | private static readonly string[] _shapeTypes = ["Circle", "Capsule", "Mix", "Compound", "Human"]; 10 | 11 | public override void UpdateUI() 12 | { 13 | float height = 80.0f; 14 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 15 | ImGui.SetNextWindowSize(new(220.0f, height)); 16 | ImGui.Begin("Benchmark: Barrel", ImGuiWindowFlags.NoResize); 17 | 18 | bool changed = false; 19 | 20 | int shapeType = (int)ShapeType; 21 | changed = changed || ImGui.Combo("Shape", ref shapeType, _shapeTypes, _shapeTypes.Length); 22 | ShapeType = (TestShapeType)shapeType; 23 | 24 | changed = changed || ImGui.Button("Reset Scene"); 25 | 26 | if (changed) 27 | { 28 | CreateScene(); 29 | } 30 | 31 | ImGui.End(); 32 | base.UpdateUI(); 33 | } 34 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Benchmark/JointGrid.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Benchmark; 6 | 7 | [TestInherit] 8 | public class JointGrid(Settings settings) : Samples.Benchmark.JointGrid(settings) 9 | { 10 | public override void UpdateUI() 11 | { 12 | float height = 60.0f; 13 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 14 | ImGui.SetNextWindowSize(new(240.0f, height)); 15 | ImGui.Begin("Benchmark: Joint Grid", ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.SliderFloat("gravity", ref Gravity, 0.0f, 20.0f, "%.1f")) 18 | { 19 | World.SetGravity(WorldId, (0.0f, -Gravity)); 20 | } 21 | 22 | ImGui.End(); 23 | 24 | base.UpdateUI(); 25 | } 26 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Benchmark/ManyPyramids.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Benchmark; 5 | 6 | [TestInherit] 7 | public class ManyPyramids(Settings settings) : Samples.Benchmark.ManyPyramids(settings) 8 | { 9 | public override void UpdateUI() 10 | { 11 | float height = 160.0f; 12 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 13 | ImGui.SetNextWindowSize(new(200.0f, height)); 14 | ImGui.Begin("Benchmark: Many Pyramids", ImGuiWindowFlags.NoResize); 15 | ImGui.PushItemWidth(100.0f); 16 | 17 | bool changed = false; 18 | changed = changed || ImGui.SliderInt("Row Count", ref RowCount, 1, 32); 19 | changed = changed || ImGui.SliderInt("Column Count", ref ColumnCount, 1, 32); 20 | changed = changed || ImGui.SliderInt("Base Count", ref BaseCount, 1, 30); 21 | 22 | changed = changed || ImGui.SliderFloat("Round", ref Round, 0.0f, 0.4f, "%.1f"); 23 | changed = changed || ImGui.Button("Reset Scene"); 24 | 25 | if (changed) 26 | { 27 | CreateScene(); 28 | } 29 | 30 | ImGui.PopItemWidth(); 31 | ImGui.End(); 32 | base.UpdateUI(); 33 | } 34 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Benchmark/ManyTumbler.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Benchmark; 6 | 7 | [TestInherit] 8 | public class ManyTumbler(Settings settings) : Samples.Benchmark.ManyTumbler(settings) 9 | { 10 | public override void UpdateUI() 11 | { 12 | float height = 110.0f; 13 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 14 | ImGui.SetNextWindowSize(new(200.0f, height)); 15 | ImGui.Begin("Benchmark: Many Tumblers", ImGuiWindowFlags.NoResize); 16 | ImGui.PushItemWidth(100.0f); 17 | 18 | bool changed = false; 19 | changed = changed || ImGui.SliderInt("Row Count", ref RowCount, 1, 32); 20 | changed = changed || ImGui.SliderInt("Column Count", ref ColumnCount, 1, 32); 21 | 22 | if (changed) 23 | { 24 | CreateScene(); 25 | } 26 | 27 | if (ImGui.SliderFloat("Speed", ref AngularSpeed, 0.0f, 100.0f, "%.f")) 28 | { 29 | for (int i = 0; i < TumblerCount; ++i) 30 | { 31 | Body.SetAngularVelocity(TumblerIds[i], (B2Math.Pi / 180.0f) * AngularSpeed); 32 | Body.SetAwake(TumblerIds[i], true); 33 | } 34 | } 35 | 36 | ImGui.PopItemWidth(); 37 | ImGui.End(); 38 | base.UpdateUI(); 39 | } 40 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Benchmark/Tumbler.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Benchmark; 6 | 7 | [TestInherit] 8 | public class Tumbler(Settings settings) : Samples.Benchmark.Tumbler(settings) 9 | { 10 | public override void UpdateUI() 11 | { 12 | float height = 60.0f; 13 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 14 | ImGui.SetNextWindowSize(new(200.0f, height)); 15 | ImGui.Begin("Benchmark: Tumbler", ImGuiWindowFlags.NoResize); 16 | ImGui.PushItemWidth(120.0f); 17 | 18 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, 0.0f, 100.0f, "%.f")) 19 | { 20 | RevoluteJointFunc.SetMotorSpeed(JointId, B2Math.Pi / 180.0f * MotorSpeed); 21 | 22 | if (MotorSpeed > 0.0f) 23 | { 24 | Joint.WakeBodies(JointId); 25 | } 26 | } 27 | 28 | ImGui.PopItemWidth(); 29 | ImGui.End(); 30 | base.UpdateUI(); 31 | } 32 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Bodies/Sleep.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Bodies; 6 | 7 | [TestInherit] 8 | public class Sleep : Samples.Bodies.Sleep 9 | { 10 | public Sleep(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 100.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | ImGui.Begin("Sleep", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 20 | 21 | ImGui.PushItemWidth(120.0f); 22 | 23 | ImGui.Text("Pendulum Tuning"); 24 | 25 | float sleepVelocity = Body.GetSleepThreshold(PendulumId); 26 | if (ImGui.SliderFloat("sleep velocity", ref sleepVelocity, 0.0f, 1.0f, "%.2f")) 27 | { 28 | Body.SetSleepThreshold(PendulumId, sleepVelocity); 29 | Body.SetAwake(PendulumId, true); 30 | } 31 | 32 | float angularDamping = Body.GetAngularDamping(PendulumId); 33 | if (ImGui.SliderFloat("angular damping", ref angularDamping, 0.0f, 2.0f, "%.2f")) 34 | { 35 | Body.SetAngularDamping(PendulumId, angularDamping); 36 | } 37 | 38 | ImGui.PopItemWidth(); 39 | 40 | ImGui.End(); 41 | } 42 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Bodies/Weeble.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Bodies; 6 | 7 | [TestInherit] 8 | public class Weeble : Samples.Bodies.Weeble 9 | { 10 | public Weeble(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 120.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(200.0f, height)); 19 | ImGui.Begin("Weeble", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 20 | if (ImGui.Button("Teleport")) 21 | { 22 | Body.SetTransform(WeebleId, (0.0f, 5.0f), B2Math.MakeRot(0.95f * B2Math.Pi)); 23 | } 24 | 25 | if (ImGui.Button("Explode")) 26 | { 27 | World.Explode(WorldId, ExplosionPosition, ExplosionRadius, ExplosionMagnitude); 28 | } 29 | 30 | ImGui.PushItemWidth(100.0f); 31 | 32 | ImGui.SliderFloat("Magnitude", ref ExplosionMagnitude, -100.0f, 100.0f, "%.1f"); 33 | 34 | ImGui.PopItemWidth(); 35 | ImGui.End(); 36 | } 37 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Collision/RayCast.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Collision; 6 | 7 | [TestInherit] 8 | public class RayCast : Samples.Collision.RayCast 9 | { 10 | public RayCast(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 230.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(200.0f, height)); 19 | 20 | ImGui.Begin("Ray-cast", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 21 | 22 | ImGui.PushItemWidth(100.0f); 23 | 24 | ImGui.SliderFloat("x offset", ref Transform.P.X, -2.0f, 2.0f, "%.2f"); 25 | ImGui.SliderFloat("y offset", ref Transform.P.Y, -2.0f, 2.0f, "%.2f"); 26 | 27 | if (ImGui.SliderFloat("angle", ref Angle, -B2Math.Pi, B2Math.Pi, "%.2f")) 28 | { 29 | Transform.Q = B2Math.MakeRot(Angle); 30 | } 31 | 32 | ImGui.Checkbox("show fraction", ref ShowFraction); 33 | 34 | if (ImGui.Button("Reset")) 35 | { 36 | Transform = Transform.Identity; 37 | Angle = 0.0f; 38 | } 39 | 40 | ImGui.Separator(); 41 | 42 | ImGui.Text("mouse btn 1: ray cast"); 43 | ImGui.Text("mouse btn 1 + shift: translate"); 44 | ImGui.Text("mouse btn 1 + ctrl: rotate"); 45 | 46 | ImGui.PopItemWidth(); 47 | 48 | ImGui.End(); 49 | } 50 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Continuous/BounceHouse.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Continuous; 6 | 7 | [TestInherit] 8 | public class BounceHouse : Samples.Continuous.BounceHouse 9 | { 10 | public BounceHouse(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | private readonly string[] _shapeTypes = ["Circle", "Capsule", "Box"]; 15 | 16 | public override void UpdateUI() 17 | { 18 | base.UpdateUI(); 19 | 20 | float height = 100.0f; 21 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 22 | ImGui.SetNextWindowSize(new(240.0f, height)); 23 | 24 | ImGui.Begin("Bounce House", ImGuiWindowFlags.NoResize); 25 | 26 | if (ImGui.Combo("Shape", ref m_shapeType, _shapeTypes, _shapeTypes.Length)) 27 | { 28 | Launch(); 29 | } 30 | 31 | if (ImGui.Checkbox("hit events", ref m_enableHitEvents)) 32 | { 33 | Body.EnableHitEvents(m_bodyId, m_enableHitEvents); 34 | } 35 | 36 | ImGui.End(); 37 | } 38 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Continuous/FastChain.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Continuous; 5 | 6 | [TestInherit] 7 | public class FastChain : Samples.Continuous.FastChain 8 | { 9 | public FastChain(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | base.UpdateUI(); 16 | 17 | float height = 70.0f; 18 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 19 | ImGui.SetNextWindowSize(new(240.0f, height)); 20 | 21 | ImGui.Begin("Fast Chain", ImGuiWindowFlags.NoResize); 22 | 23 | if (ImGui.Button("Launch")) 24 | { 25 | Launch(); 26 | } 27 | 28 | ImGui.End(); 29 | } 30 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Continuous/SkinnyBox.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Continuous; 5 | 6 | [TestInherit] 7 | public class SkinnyBox : Samples.Continuous.SkinnyBox 8 | { 9 | public SkinnyBox(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | base.UpdateUI(); 16 | 17 | float height = 110.0f; 18 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 19 | ImGui.SetNextWindowSize(new(140.0f, height)); 20 | 21 | ImGui.Begin("Skinny Box", ImGuiWindowFlags.NoResize); 22 | 23 | ImGui.Checkbox("Capsule", ref m_capsule); 24 | 25 | if (ImGui.Button("Launch")) 26 | { 27 | Launch(); 28 | } 29 | 30 | ImGui.Checkbox("Auto Test", ref m_autoTest); 31 | 32 | ImGui.End(); 33 | } 34 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Events/BodyMove.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Events; 6 | 7 | [TestInherit] 8 | public class BodyMove : Samples.Events.BodyMove 9 | { 10 | public BodyMove(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | base.UpdateUI(); 17 | float height = 100.0f; 18 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 19 | ImGui.SetNextWindowSize(new(240.0f, height)); 20 | 21 | ImGui.Begin("Body Move", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 22 | 23 | if (ImGui.Button("Explode")) 24 | { 25 | World.Explode(WorldId, ExplosionPosition, ExplosionRadius, ExplosionMagnitude); 26 | } 27 | 28 | ImGui.SliderFloat("Magnitude", ref ExplosionMagnitude, -8.0f, 8.0f, "%.1f"); 29 | 30 | ImGui.End(); 31 | } 32 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Events/ContactEvent.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Events; 5 | 6 | [TestInherit] 7 | public class ContactEvent : Samples.Events.ContactEvent 8 | { 9 | public ContactEvent(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | base.UpdateUI(); 16 | float height = 60.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Contact Event", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 21 | 22 | ImGui.SliderFloat("force", ref m_force, 100.0f, 500.0f, "%.1f"); 23 | 24 | ImGui.End(); 25 | 26 | DrawString("move using WASD"); 27 | } 28 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Events/Platformer.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Events; 5 | 6 | [TestInherit] 7 | public class Platformer : Samples.Events.Platformer 8 | { 9 | public Platformer(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | base.UpdateUI(); 16 | float height = 100.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Platformer", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 21 | 22 | ImGui.SliderFloat("force", ref m_force, 0.0f, 50.0f, "%.1f"); 23 | ImGui.SliderFloat("impulse", ref m_impulse, 0.0f, 50.0f, "%.1f"); 24 | 25 | ImGui.End(); 26 | 27 | DrawString("Movement: A/D/Space"); 28 | 29 | DrawString($"Can jump = {_canJump}"); 30 | } 31 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Events/SensorEvent.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Events; 5 | 6 | [TestInherit] 7 | public class SensorEvent : Samples.Events.SensorEvent 8 | { 9 | public SensorEvent(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | base.UpdateUI(); 16 | float height = 90.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(140.0f, height)); 19 | 20 | ImGui.Begin("Sensor Event", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); 21 | 22 | if (ImGui.RadioButton("donut", Type == Donut)) 23 | { 24 | Clear(); 25 | Type = Donut; 26 | } 27 | 28 | if (ImGui.RadioButton("human", Type == Human)) 29 | { 30 | Clear(); 31 | Type = Human; 32 | } 33 | 34 | ImGui.End(); 35 | } 36 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/BallAndChain.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Joints; 6 | 7 | [TestInherit] 8 | public class BallAndChain : Samples.Joints.BallAndChain 9 | { 10 | public BallAndChain(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 60.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Ball and Chain", ImGuiWindowFlags.NoResize); 21 | 22 | bool updateFriction = ImGui.SliderFloat("Joint Friction", ref m_frictionTorque, 0.0f, 1000.0f, "%2.F"); 23 | if (updateFriction) 24 | { 25 | for (int i = 0; i <= e_count; ++i) 26 | { 27 | RevoluteJointFunc.SetMaxMotorTorque(m_jointIds[i], m_frictionTorque); 28 | } 29 | } 30 | 31 | ImGui.End(); 32 | } 33 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/BreakableJoint.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Joints; 6 | 7 | [TestInherit] 8 | public class BreakableJoint : Samples.Joints.BreakableJoint 9 | { 10 | public BreakableJoint(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 100.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Breakable Joint", ImGuiWindowFlags.NoResize); 21 | 22 | ImGui.SliderFloat("break force", ref m_breakForce, 0.0f, 10000.0f, "%.1f"); 23 | 24 | Vec2 gravity = World.GetGravity(WorldId); 25 | if (ImGui.SliderFloat("gravity", ref gravity.Y, -50.0f, 50.0f, "%.1f")) 26 | { 27 | World.SetGravity(WorldId, gravity); 28 | } 29 | 30 | ImGui.End(); 31 | } 32 | }; -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/Bridge.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Joints; 6 | 7 | [TestInherit] 8 | public class Bridge : Samples.Joints.Bridge 9 | { 10 | public Bridge(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 80.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Bridge", ImGuiWindowFlags.NoResize); 21 | 22 | // Slider takes half the window 23 | ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.5f); 24 | bool updateFriction = ImGui.SliderFloat("Joint Friction", ref m_frictionTorque, 0.0f, 1000.0f, "%2.F"); 25 | if (updateFriction) 26 | { 27 | for (int i = 0; i <= e_count; ++i) 28 | { 29 | RevoluteJointFunc.SetMaxMotorTorque(m_jointIds[i], m_frictionTorque); 30 | } 31 | } 32 | 33 | if (ImGui.SliderFloat("Gravity scale", ref m_gravityScale, -1.0f, 1.0f, "%.1f")) 34 | { 35 | for (int i = 0; i < e_count; ++i) 36 | { 37 | Body.SetGravityScale(m_bodyIds[i], m_gravityScale); 38 | } 39 | } 40 | 41 | ImGui.End(); 42 | } 43 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/Driving.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Joints; 5 | 6 | [TestInherit] 7 | public class Driving : Samples.Joints.Driving 8 | { 9 | public Driving(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | float height = 140.0f; 16 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 17 | ImGui.SetNextWindowSize(new(200.0f, height)); 18 | 19 | ImGui.Begin("Driving", ImGuiWindowFlags.NoResize); 20 | 21 | ImGui.PushItemWidth(100.0f); 22 | if (ImGui.SliderFloat("Spring Hertz", ref m_hertz, 0.0f, 20.0f, "%.0f")) 23 | { 24 | m_car.SetHertz(m_hertz); 25 | } 26 | 27 | if (ImGui.SliderFloat("Damping Ratio", ref m_dampingRatio, 0.0f, 10.0f, "%.1f")) 28 | { 29 | m_car.SetDampingRadio(m_dampingRatio); 30 | } 31 | 32 | if (ImGui.SliderFloat("Speed", ref m_speed, 0.0f, 50.0f, "%.0f")) 33 | { 34 | m_car.SetSpeed(m_throttle * m_speed); 35 | } 36 | 37 | if (ImGui.SliderFloat("Torque", ref m_torque, 0.0f, 5.0f, "%.1f")) 38 | { 39 | m_car.SetTorque(m_torque); 40 | } 41 | 42 | ImGui.PopItemWidth(); 43 | 44 | ImGui.End(); 45 | } 46 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/FixedRotation.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Joints; 6 | 7 | [TestInherit] 8 | public class FixedRotation : Samples.Joints.FixedRotation 9 | { 10 | public FixedRotation(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 60.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(180.0f, height)); 19 | 20 | ImGui.Begin("Fixed Rotation", ImGuiWindowFlags.NoResize); 21 | 22 | if (ImGui.Checkbox("Fixed Rotation", ref m_fixedRotation)) 23 | { 24 | for (int i = 0; i < e_count; ++i) 25 | { 26 | Body.SetFixedRotation(m_bodyIds[i], m_fixedRotation); 27 | } 28 | } 29 | 30 | ImGui.End(); 31 | } 32 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/MotorJointSample.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Joints; 6 | 7 | /// This test shows how to use a motor joint. A motor joint 8 | /// can be used to animate a dynamic body. With finite motor forces 9 | /// the body can be blocked by collision with other bodies. 10 | /// By setting the correction factor to zero, the motor joint acts 11 | /// like top-down dry friction. 12 | [TestInherit] 13 | public class MotorJointSample : Samples.Joints.MotorJointSample 14 | { 15 | public MotorJointSample(Settings settings) 16 | : base(settings) 17 | { } 18 | 19 | public override void UpdateUI() 20 | { 21 | float height = 140.0f; 22 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 23 | ImGui.SetNextWindowSize(new(240.0f, height)); 24 | 25 | ImGui.Begin("Motor Joint", ImGuiWindowFlags.NoResize); 26 | 27 | if (ImGui.Checkbox("Go", ref m_go)) 28 | { } 29 | 30 | if (ImGui.SliderFloat("Max Force", ref m_maxForce, 0.0f, 1000.0f, "%.0f")) 31 | { 32 | MotorJointFunc.SetMaxForce(m_jointId, m_maxForce); 33 | } 34 | 35 | if (ImGui.SliderFloat("Max Torque", ref m_maxTorque, 0.0f, 1000.0f, "%.0f")) 36 | { 37 | MotorJointFunc.SetMaxTorque(m_jointId, m_maxTorque); 38 | } 39 | 40 | if (ImGui.SliderFloat("Correction", ref m_correctionFactor, 0.0f, 1.0f, "%.1f")) 41 | { 42 | MotorJointFunc.SetCorrectionFactor(m_jointId, m_correctionFactor); 43 | } 44 | 45 | ImGui.End(); 46 | } 47 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/Ragdoll.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Joints; 5 | 6 | [TestInherit] 7 | public class Ragdoll : Samples.Joints.Ragdoll 8 | { 9 | public Ragdoll(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | float height = 140.0f; 16 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 17 | ImGui.SetNextWindowSize(new(180.0f, height)); 18 | 19 | ImGui.Begin("Ragdoll", ImGuiWindowFlags.NoResize); 20 | ImGui.PushItemWidth(100.0f); 21 | 22 | if (ImGui.SliderFloat("Friction", ref m_jointFrictionTorque, 0.0f, 1.0f, "%3.2f")) 23 | { 24 | m_human.SetJointFrictionTorque(m_jointFrictionTorque); 25 | } 26 | 27 | if (ImGui.SliderFloat("Hertz", ref m_jointHertz, 0.0f, 10.0f, "%3.1f")) 28 | { 29 | m_human.SetJointSpringHertz(m_jointHertz); 30 | } 31 | 32 | if (ImGui.SliderFloat("Damping", ref m_jointDampingRatio, 0.0f, 4.0f, "%3.1f")) 33 | { 34 | m_human.SetJointDampingRatio(m_jointDampingRatio); 35 | } 36 | 37 | ImGui.PopItemWidth(); 38 | ImGui.End(); 39 | } 40 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Joints/ScissorLift.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Joints; 6 | 7 | [TestInherit] 8 | public class ScissorLift : Samples.Joints.ScissorLift 9 | { 10 | public ScissorLift(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 140.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Scissor Lift", ImGuiWindowFlags.NoResize); 21 | 22 | if (ImGui.Checkbox("Motor", ref m_enableMotor)) 23 | { 24 | DistanceJointFunc.EnableMotor(m_liftJointId, m_enableMotor); 25 | Joint.WakeBodies(m_liftJointId); 26 | } 27 | 28 | if (ImGui.SliderFloat("Max Force", ref m_motorForce, 0.0f, 3000.0f, "%.0f")) 29 | { 30 | DistanceJointFunc.SetMaxMotorForce(m_liftJointId, m_motorForce); 31 | Joint.WakeBodies(m_liftJointId); 32 | } 33 | 34 | if (ImGui.SliderFloat("Speed", ref m_motorSpeed, -0.3f, 0.3f, "%.2f")) 35 | { 36 | DistanceJointFunc.SetMotorSpeed(m_liftJointId, m_motorSpeed); 37 | Joint.WakeBodies(m_liftJointId); 38 | } 39 | 40 | ImGui.End(); 41 | } 42 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Shapes/ChainShape.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using ImGuiNET; 3 | using Testbed.Abstractions; 4 | 5 | namespace Testbed.TestSamples.Shapes; 6 | 7 | [TestInherit] 8 | public class ChainShape : Samples.Shapes.ChainShape 9 | { 10 | public ChainShape(Settings settings) 11 | : base(settings) 12 | { } 13 | 14 | public override void UpdateUI() 15 | { 16 | float height = 135.0f; 17 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 18 | ImGui.SetNextWindowSize(new(240.0f, height)); 19 | 20 | ImGui.Begin("Chain Shape", ImGuiWindowFlags.NoResize); 21 | 22 | string[] shapeTypes = ["Circle", "Capsule", "Box"]; 23 | 24 | if (ImGui.Combo("Shape", ref ShapeType, shapeTypes, shapeTypes.Length)) 25 | { 26 | Launch(); 27 | } 28 | 29 | if (ImGui.SliderFloat("Friction", ref Friction, 0.0f, 1.0f, "%.2f")) 30 | { 31 | Shape.SetFriction(ShapeId, Friction); 32 | Shape.SetFriction(ChainId, Friction); 33 | } 34 | 35 | if (ImGui.SliderFloat("Restitution", ref Restitution, 0.0f, 2.0f, "%.1f")) 36 | { 37 | Shape.SetRestitution(ShapeId, Restitution); 38 | } 39 | 40 | if (ImGui.Button("Launch")) 41 | { 42 | Launch(); 43 | } 44 | 45 | ImGui.End(); 46 | } 47 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Shapes/CompoundShapes.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Shapes; 5 | 6 | [TestInherit] 7 | public class CompoundShapes : Samples.Shapes.CompoundShapes 8 | { 9 | public CompoundShapes(Settings settings) 10 | : base(settings) 11 | { } 12 | 13 | public override void UpdateUI() 14 | { 15 | float height = 100.0f; 16 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 17 | ImGui.SetNextWindowSize(new(180.0f, height)); 18 | 19 | ImGui.Begin("Compound Shapes", ImGuiWindowFlags.NoResize); 20 | 21 | if (ImGui.Button("Intrude")) 22 | { 23 | Spawn(); 24 | } 25 | 26 | ImGui.Checkbox("Body AABBs", ref DrawBodyAABBs); 27 | 28 | ImGui.End(); 29 | } 30 | }; -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Shapes/Restitution.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Shapes; 5 | 6 | [TestInherit] 7 | public class Restitution(Settings settings) : Samples.Shapes.Restitution(settings) 8 | { 9 | public override void UpdateUI() 10 | { 11 | float height = 100.0f; 12 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 13 | ImGui.SetNextWindowSize(new(240.0f, height)); 14 | 15 | ImGui.Begin("Restitution", ImGuiWindowFlags.NoResize); 16 | 17 | bool changed = false; 18 | string[] shapeTypes = ["Circle", "Box"]; 19 | 20 | changed = changed || ImGui.Combo("Shape", ref ShapeType, shapeTypes, shapeTypes.Length); 21 | 22 | changed = changed || ImGui.Button("Reset"); 23 | 24 | if (changed) 25 | { 26 | CreateBodies(); 27 | } 28 | 29 | ImGui.End(); 30 | } 31 | } -------------------------------------------------------------------------------- /test/Testbed/TestSamples/Stacking/Cliff.cs: -------------------------------------------------------------------------------- 1 | using ImGuiNET; 2 | using Testbed.Abstractions; 3 | 4 | namespace Testbed.TestSamples.Stacking; 5 | 6 | [TestInherit] 7 | public class Cliff(Settings settings) : Samples.Stacking.Cliff(settings) 8 | { 9 | public override void UpdateUI() 10 | { 11 | float height = 60.0f; 12 | ImGui.SetNextWindowPos(new(10.0f, Global.Camera.Height - height - 50.0f), ImGuiCond.Once); 13 | ImGui.SetNextWindowSize(new(160.0f, height)); 14 | 15 | ImGui.Begin("Cliff", ImGuiWindowFlags.NoResize); 16 | 17 | if (ImGui.Button("Flip")) 18 | { 19 | Flip = !Flip; 20 | CreateBodies(); 21 | } 22 | 23 | ImGui.End(); 24 | } 25 | } -------------------------------------------------------------------------------- /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(Settings 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 Settings Load() 24 | { 25 | try 26 | { 27 | var json = File.ReadAllText("settings.ini"); 28 | return JsonConvert.DeserializeObject(json) ?? new(); 29 | } 30 | catch (Exception) 31 | { 32 | // ignored error, retuen default setting 33 | return new Settings(); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/Testbed/Testbed.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 12 6 | net8.0 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Always 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /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/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/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 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, -100.0f, 100.0f, "%.0f")) 28 | { 29 | Joint.SetMotorSpeed(MotorSpeed); 30 | } 31 | 32 | ImGui.End(); 33 | base.OnRender(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /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 | ImGui.SliderFloat("Force", ref _force, 0.0f, 2000.0f, "%.0f"); 18 | 19 | ImGui.End(); 20 | base.OnRender(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /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 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, -20.0f, 20.0f, "%.0f")) 28 | { 29 | Joint1.SetMotorSpeed(MotorSpeed); 30 | } 31 | 32 | ImGui.End(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /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 | if (ImGui.SliderFloat("Speed", ref MotorSpeed, -100.0f, 100.0f, "%.0f")) 28 | { 29 | Joint.SetMotorSpeed(MotorSpeed); 30 | } 31 | 32 | ImGui.End(); 33 | base.OnRender(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /test/Testbed/VectorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Box2DSharp; 3 | 4 | namespace Testbed; 5 | 6 | public static class VectorExtensions 7 | { 8 | public static Vector2 ToVector2(this Vec2 vector) 9 | { 10 | return new Vector2(vector.X, vector.Y); 11 | } 12 | 13 | public static Vector2 ToVector2(this OpenTK.Mathematics.Vector2 vector) 14 | { 15 | return new Vector2(vector.X, vector.Y); 16 | } 17 | 18 | public static void Set(ref this Vector2 vector, float x, float y) 19 | { 20 | vector.X = x; 21 | vector.Y = y; 22 | } 23 | } -------------------------------------------------------------------------------- /test/UnitTest/.gitignore: -------------------------------------------------------------------------------- 1 | [bB]in/ 2 | [oO]bj/ 3 | /.vs 4 | .idea/ 5 | .DS_Store 6 | .vs/ 7 | 8 | *.DotSettings.user 9 | -------------------------------------------------------------------------------- /test/UnitTest/BitSetTest.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using FluentAssertions; 3 | using Xunit; 4 | 5 | namespace UnitTest; 6 | 7 | public class BitSetTest 8 | { 9 | private const int Count = 169; 10 | 11 | [Fact] 12 | public int BitSet() 13 | { 14 | BitSet bitSet = new BitSet(Count); 15 | bitSet.SetBitCountAndClear(Count); 16 | 17 | bool[] values = new bool[Count]; 18 | 19 | var i1 = 0; 20 | var i2 = 1; 21 | bitSet.SetBit(i1); 22 | values[i1] = true; 23 | 24 | while (i2 < Count) 25 | { 26 | bitSet.SetBit(i2); 27 | 28 | values[i2] = true; 29 | var next = i1 + i2; 30 | i1 = i2; 31 | i2 = next; 32 | } 33 | 34 | for (var i = 0; i < Count; ++i) 35 | { 36 | bool value = bitSet.GetBit(i); 37 | value.Should().Be(values[i]); 38 | } 39 | 40 | bitSet.Dispose(); 41 | 42 | return 0; 43 | } 44 | } -------------------------------------------------------------------------------- /test/UnitTest/CollisionTest.cs: -------------------------------------------------------------------------------- 1 | using Box2DSharp; 2 | using FluentAssertions; 3 | using Xunit; 4 | 5 | namespace UnitTest; 6 | 7 | public class CollisionTest 8 | { 9 | [Fact] 10 | public int AABBTest() 11 | { 12 | AABB a = new(); 13 | a.LowerBound = (-1.0f, -1.0f); 14 | a.UpperBound = (-2.0f, -2.0f); 15 | 16 | a.IsValid.Should().BeFalse(); 17 | 18 | a.UpperBound = (1.0f, 1.0f); 19 | a.IsValid.Should().BeTrue(); 20 | 21 | AABB b = ((2.0f, 2.0f), (4.0f, 4.0f)); 22 | AABB.Overlaps(a, b).Should().BeFalse(); 23 | AABB.Contains(a, b).Should().BeFalse(); 24 | 25 | Vec2 p1 = (-2.0f, 0.0f); 26 | Vec2 p2 = (2.0f, 0.0f); 27 | 28 | CastOutput output = a.RayCast(p1, p2); 29 | output.Hit.Should().BeTrue(); 30 | output.Fraction.Should().BeInRange(0.1f, 0.9f); 31 | 32 | return 0; 33 | } 34 | } -------------------------------------------------------------------------------- /test/UnitTest/UnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | net8.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 | --------------------------------------------------------------------------------