├── .DS_Store ├── .gitignore ├── Box2DNet.sln ├── LICENSE ├── README.md ├── deps └── cimgui │ ├── linux-x64 │ └── cimgui.so │ ├── osx-x64 │ └── cimgui.dylib │ ├── win-x64 │ └── cimgui.dll │ └── win-x86 │ └── cimgui.dll ├── doc └── install-vulkan.md ├── examples ├── .DS_Store ├── HelloWorld │ ├── .DS_Store │ ├── HelloWorld.csproj │ └── Program.cs └── Testbed │ ├── Framework │ ├── ContactState.cs │ ├── DebugViewBase.cs │ ├── DebugViewXNA.cs │ ├── GameSettings.cs │ ├── KeyboardManager.cs │ ├── PrimitiveBatch.cs │ ├── Rand.cs │ ├── Settings.cs │ ├── Test.cs │ ├── TestEntries.cs │ └── TestEntry.cs │ ├── Game1.cs │ ├── Program.cs │ ├── Shaders │ ├── GLSL │ │ ├── imgui-frag.glsl │ │ └── imgui-vertex.glsl │ ├── HLSL │ │ ├── imgui-frag.hlsl │ │ ├── imgui-frag.hlsl.bytes │ │ ├── imgui-vertex.hlsl │ │ └── imgui-vertex.hlsl.bytes │ ├── Metal │ │ ├── imgui-frag.metal │ │ ├── imgui-frag.metallib │ │ ├── imgui-vertex.metal │ │ └── imgui-vertex.metallib │ └── SPIR-V │ │ ├── generate-spirv.bat │ │ ├── imgui-frag.glsl │ │ ├── imgui-frag.spv │ │ ├── imgui-vertex.glsl │ │ └── imgui-vertex.spv │ ├── Testbed.csproj │ └── Tests │ ├── Bridge.cs │ ├── Car.cs │ └── SimpleTest.cs └── src ├── .DS_Store └── Box2DNet ├── .DS_Store ├── Box2DNet.csproj ├── Box2DXDebug.cs ├── Collision ├── BroadPhase.cs ├── Collision.CollideCircle.cs ├── Collision.CollideEdge.cs ├── Collision.CollidePoly.cs ├── Collision.Distance.cs ├── Collision.TimeOfImpact.cs ├── Collision.cs ├── PairManager.cs └── Shapes │ ├── CircleShape.cs │ ├── EdgeShape.cs │ ├── PolygonShape.cs │ └── Shape.cs ├── Common ├── Mar33.cs ├── Mat22.cs ├── Math.cs ├── Settings.cs ├── Sweep.cs ├── Transform.cs ├── Utils.cs ├── Vec2.cs ├── Vec3.cs └── XForm.cs └── Dynamics ├── Body.cs ├── ContactManager.cs ├── Contacts ├── CircleContact.cs ├── Contact.cs ├── ContactSolver.cs ├── EdgeAndCircleContact.cs ├── NullContact.cs ├── PolyAndCircleContact.cs ├── PolyAndEdgeContact.cs └── PolyContact.cs ├── Controllers ├── BuoyancyController.cs ├── ConstantAccelController.cs ├── ConstantForceController.cs ├── Controller.cs ├── GravityController.cs └── TensorDampingController.cs ├── Fixture.cs ├── Island.cs ├── Joints ├── DistanceJoint.cs ├── GearJoint.cs ├── Joint.cs ├── LineJoint.cs ├── MouseJoint.cs ├── PrismaticJoint.cs ├── PulleyJoint.cs └── RevoluteJoint.cs ├── World.cs └── WorldCallbacks.cs /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | .DS_Store 255 | -------------------------------------------------------------------------------- /Box2DNet.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04EF37E0-B0CD-4A85-ACAA-53B7C0E8B5C5}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Box2DNet", "src\Box2DNet\Box2DNet.csproj", "{C20791D0-F341-44A8-B6C1-50049A29B158}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{BB66E02A-0B91-4D4C-80F6-D0686B124992}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld", "examples\HelloWorld\HelloWorld.csproj", "{DD567358-C46A-4354-B7E9-7479EF9B6236}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestBed", "examples\TestBed\TestBed.csproj", "{46D4436A-8750-4F01-8790-4028AF2D1127}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|Any CPU = Release|Any CPU 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Debug|x64.ActiveCfg = Debug|Any CPU 32 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Debug|x64.Build.0 = Debug|Any CPU 33 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Debug|x86.ActiveCfg = Debug|Any CPU 34 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Debug|x86.Build.0 = Debug|Any CPU 35 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Release|x64.ActiveCfg = Release|Any CPU 38 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Release|x64.Build.0 = Release|Any CPU 39 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Release|x86.ActiveCfg = Release|Any CPU 40 | {C20791D0-F341-44A8-B6C1-50049A29B158}.Release|x86.Build.0 = Release|Any CPU 41 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Debug|x64.ActiveCfg = Debug|Any CPU 44 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Debug|x64.Build.0 = Debug|Any CPU 45 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Debug|x86.ActiveCfg = Debug|Any CPU 46 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Debug|x86.Build.0 = Debug|Any CPU 47 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Release|x64.ActiveCfg = Release|Any CPU 50 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Release|x64.Build.0 = Release|Any CPU 51 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Release|x86.ActiveCfg = Release|Any CPU 52 | {DD567358-C46A-4354-B7E9-7479EF9B6236}.Release|x86.Build.0 = Release|Any CPU 53 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Debug|x64.ActiveCfg = Debug|Any CPU 56 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Debug|x64.Build.0 = Debug|Any CPU 57 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Debug|x86.ActiveCfg = Debug|Any CPU 58 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Debug|x86.Build.0 = Debug|Any CPU 59 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Release|x64.ActiveCfg = Release|Any CPU 62 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Release|x64.Build.0 = Release|Any CPU 63 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Release|x86.ActiveCfg = Release|Any CPU 64 | {46D4436A-8750-4F01-8790-4028AF2D1127}.Release|x86.Build.0 = Release|Any CPU 65 | EndGlobalSection 66 | GlobalSection(NestedProjects) = preSolution 67 | {C20791D0-F341-44A8-B6C1-50049A29B158} = {04EF37E0-B0CD-4A85-ACAA-53B7C0E8B5C5} 68 | {DD567358-C46A-4354-B7E9-7479EF9B6236} = {BB66E02A-0B91-4D4C-80F6-D0686B124992} 69 | {46D4436A-8750-4F01-8790-4028AF2D1127} = {BB66E02A-0B91-4D4C-80F6-D0686B124992} 70 | EndGlobalSection 71 | EndGlobal 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 zhu yu 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Box2DNet 2 | Fork from http://code.google.com/p/box2dx/ 3 | 4 | Box2DNet is a C# port of Box2D - Erin Catto's 2D Physics Engine. You can find original C++ version on www.box2d.org 5 | -------------------------------------------------------------------------------- /deps/cimgui/linux-x64/cimgui.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/deps/cimgui/linux-x64/cimgui.so -------------------------------------------------------------------------------- /deps/cimgui/osx-x64/cimgui.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/deps/cimgui/osx-x64/cimgui.dylib -------------------------------------------------------------------------------- /deps/cimgui/win-x64/cimgui.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/deps/cimgui/win-x64/cimgui.dll -------------------------------------------------------------------------------- /deps/cimgui/win-x86/cimgui.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/deps/cimgui/win-x86/cimgui.dll -------------------------------------------------------------------------------- /doc/install-vulkan.md: -------------------------------------------------------------------------------- 1 | 1. Download [vulkansdk-macos-1.0.xx.0.tar.gz](https://vulkan.lunarg.com/sdk/home#sdk/downloadConfirm/latest/mac/vulkan-sdk.tar.gz) 2 | 2. `tar -xzf vulkan-sdk.tar.gz` 3 | 3. set environment variables(in `~/.profile` file): 4 | ```bash 5 | export VK_SDK=~/vulkansdk-macos-1.1.85.0/macOS 6 | export PATH=$VK_SDK/bin:$PATH 7 | export DYLD_LIBRARY_PATH=$VK_SDK/lib:$DYLD_LIBRARY_PATH 8 | export VK_LAYER_PATH=$VK_SDK/etc/vulkan/explicit_layers.d 9 | export VK_ICD_FILENAMES=$VK_SDK/etc/vulkan/icd.d/MoltenVK_icd.json 10 | ``` -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/.DS_Store -------------------------------------------------------------------------------- /examples/HelloWorld/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/HelloWorld/.DS_Store -------------------------------------------------------------------------------- /examples/HelloWorld/HelloWorld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Exe 9 | netcoreapp2.1 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/HelloWorld/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using Box2DNet.Dynamics; 4 | using Box2DNet.Dynamics; 5 | using Box2DNet.Collision; 6 | using Box2DNet.Common; 7 | 8 | namespace HelloWorld 9 | { 10 | class Program 11 | { 12 | // This is a simple example of building and running a simulation 13 | // using Box2DNet. Here we create a large ground box and a small dynamic 14 | // box. 15 | static void Main(string[] args) 16 | { 17 | // Define the size of the world. Simulation will still work 18 | // if bodies reach the end of the world, but it will be slower. 19 | AABB worldAABB = new AABB 20 | { 21 | UpperBound = new Vector2(100, 100), 22 | LowerBound = new Vector2(-100, -100) 23 | }; 24 | 25 | // Define the gravity vector. 26 | Vector2 gravity = new Vector2(0.0f, -10.0f); 27 | 28 | // Do we want to let bodies sleep? 29 | bool doSleep = true; 30 | 31 | // Construct a world object, which will hold and simulate the rigid bodies. 32 | World world = new World(worldAABB, gravity, doSleep); 33 | 34 | // Define the ground body. 35 | BodyDef groundBodyDef = new BodyDef(); 36 | groundBodyDef.Position = new Vector2(0.0f, -10.0f); 37 | 38 | // Call the body factory which creates the ground box shape. 39 | // The body is also added to the world. 40 | Body groundBody = world.CreateBody(groundBodyDef); 41 | 42 | // Define the ground box shape. 43 | PolygonDef groundShapeDef = new PolygonDef(); 44 | 45 | // The extents are the half-widths of the box. 46 | groundShapeDef.SetAsBox(50.0f, 10.0f); 47 | 48 | // Add the ground shape to the ground body. 49 | groundBody.CreateFixture(groundShapeDef); 50 | 51 | // Define the dynamic body. We set its position and call the body factory. 52 | BodyDef bodyDef = new BodyDef(); 53 | bodyDef.Position = new Vector2(0.0f, 4.0f); 54 | Body body = world.CreateBody(bodyDef); 55 | 56 | // Define another box shape for our dynamic body. 57 | PolygonDef shapeDef = new PolygonDef(); 58 | shapeDef.SetAsBox(1.0f, 1.0f); 59 | 60 | // Set the box density to be non-zero, so it will be dynamic. 61 | shapeDef.Density = 1.0f; 62 | 63 | // Override the default friction. 64 | shapeDef.Friction = 0.3f; 65 | 66 | // Add the shape to the body. 67 | body.CreateFixture(shapeDef); 68 | 69 | // Now tell the dynamic body to compute it's mass properties base 70 | // on its shape. 71 | body.SetMassFromShapes(); 72 | 73 | // Prepare for simulation. Typically we use a time step of 1/60 of a 74 | // second (60Hz) and 10 iterations. This provides a high quality simulation 75 | // in most game scenarios. 76 | float timeStep = 1.0f / 60.0f; 77 | int velocityIterations = 8; 78 | int positionIterations = 1; 79 | 80 | // This is our little game loop. 81 | for (int i = 0; i < 100; ++i) 82 | { 83 | // Instruct the world to perform a single step of simulation. It is 84 | // generally best to keep the time step and iterations fixed. 85 | world.Step(timeStep, velocityIterations, positionIterations); 86 | 87 | // Now print the position and angle of the body. 88 | Vector2 position = body.GetPosition(); 89 | float angle = body.GetAngle(); 90 | 91 | Console.WriteLine("Step: {3} - X: {0}, Y: {1}, Angle: {2}", new object[] { position.X.ToString(), position.Y.ToString(), angle.ToString(), i.ToString() }); 92 | } 93 | 94 | // When the world destructor is called, all bodies and joints are freed. This can 95 | // create orphaned pointers, so be careful about your world management. 96 | Console.ReadLine(); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/ContactState.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Framework 2 | { 3 | public enum ContactState 4 | { 5 | ContactAdded, 6 | ContactPersisted, 7 | ContactRemoved 8 | } 9 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/DebugViewBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using Box2DNet.Common; 4 | using Box2DNet.Dynamics; 5 | 6 | namespace Testbed.Framework 7 | { 8 | [Flags] 9 | public enum DebugViewFlags 10 | { 11 | /// 12 | /// Draw shapes. 13 | /// 14 | Shape = (1 << 0), 15 | 16 | /// 17 | /// Draw joint connections. 18 | /// 19 | Joint = (1 << 1), 20 | 21 | /// 22 | /// Draw axis aligned bounding boxes. 23 | /// 24 | AABB = (1 << 2), 25 | 26 | /// 27 | /// Draw broad-phase pairs. 28 | /// 29 | //Pair = (1 << 3), 30 | 31 | /// 32 | /// Draw center of mass frame. 33 | /// 34 | CenterOfMass = (1 << 4), 35 | 36 | /// 37 | /// Draw useful debug data such as timings and number of bodies, joints, contacts and more. 38 | /// 39 | DebugPanel = (1 << 5), 40 | 41 | /// 42 | /// Draw contact points between colliding bodies. 43 | /// 44 | ContactPoints = (1 << 6), 45 | 46 | /// 47 | /// Draw contact normals. Need ContactPoints to be enabled first. 48 | /// 49 | ContactNormals = (1 << 7), 50 | 51 | /// 52 | /// Draws the vertices of polygons. 53 | /// 54 | PolygonPoints = (1 << 8), 55 | 56 | /// 57 | /// Draws the performance graph. 58 | /// 59 | PerformanceGraph = (1 << 9), 60 | 61 | /// 62 | /// Draws controllers. 63 | /// 64 | Controllers = (1 << 10) 65 | } 66 | 67 | /// Implement and register this class with a World to provide debug drawing of physics 68 | /// entities in your game. 69 | public abstract class DebugViewBase 70 | { 71 | protected DebugViewBase(World world) 72 | { 73 | World = world; 74 | } 75 | 76 | protected World World { get; private set; } 77 | 78 | /// 79 | /// Gets or sets the debug view flags. 80 | /// 81 | /// The flags. 82 | public DebugViewFlags Flags { get; set; } 83 | 84 | /// 85 | /// Append flags to the current flags. 86 | /// 87 | /// The flags. 88 | public void AppendFlags(DebugViewFlags flags) 89 | { 90 | Flags |= flags; 91 | } 92 | 93 | /// 94 | /// Remove flags from the current flags. 95 | /// 96 | /// The flags. 97 | public void RemoveFlags(DebugViewFlags flags) 98 | { 99 | Flags &= ~flags; 100 | } 101 | 102 | /// 103 | /// Draw a closed polygon provided in CCW order. 104 | /// 105 | /// The vertices. 106 | /// The vertex count. 107 | /// The red value. 108 | /// The blue value. 109 | /// The green value. 110 | public abstract void DrawPolygon(Vector2[] vertices, int count, float red, float blue, float green, bool closed = true); 111 | 112 | /// 113 | /// Draw a solid closed polygon provided in CCW order. 114 | /// 115 | /// The vertices. 116 | /// The vertex count. 117 | /// The red value. 118 | /// The blue value. 119 | /// The green value. 120 | public abstract void DrawSolidPolygon(Vector2[] vertices, int count, float red, float blue, float green); 121 | 122 | /// 123 | /// Draw a circle. 124 | /// 125 | /// The center. 126 | /// The radius. 127 | /// The red value. 128 | /// The blue value. 129 | /// The green value. 130 | public abstract void DrawCircle(Vector2 center, float radius, float red, float blue, float green); 131 | 132 | /// 133 | /// Draw a solid circle. 134 | /// 135 | /// The center. 136 | /// The radius. 137 | /// The axis. 138 | /// The red value. 139 | /// The blue value. 140 | /// The green value. 141 | public abstract void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, float red, float blue, 142 | float green); 143 | 144 | /// 145 | /// Draw a line segment. 146 | /// 147 | /// The start. 148 | /// The end. 149 | /// The red value. 150 | /// The blue value. 151 | /// The green value. 152 | public abstract void DrawSegment(Vector2 start, Vector2 end, float red, float blue, float green); 153 | 154 | /// 155 | /// Draw a transform. Choose your own length scale. 156 | /// 157 | /// The transform. 158 | public abstract void DrawTransform(ref Transform transform); 159 | } 160 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/GameSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Testbed.Framework 2 | { 3 | public class GameSettings 4 | { 5 | public float Hz; 6 | public bool Pause; 7 | public bool SingleStep; 8 | 9 | public GameSettings() 10 | { 11 | 12 | Hz = 60.0f; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/KeyboardManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework.Input; 2 | 3 | namespace Testbed.Framework 4 | { 5 | public class KeyboardManager 6 | { 7 | internal KeyboardState _newKeyboardState; 8 | internal KeyboardState _oldKeyboardState; 9 | 10 | public bool IsNewKeyPress(Keys key) 11 | { 12 | return _newKeyboardState.IsKeyDown(key) && _oldKeyboardState.IsKeyUp(key); 13 | } 14 | 15 | public bool IsKeyDown(Keys key) 16 | { 17 | return _newKeyboardState.IsKeyDown(key); 18 | } 19 | 20 | internal bool IsKeyUp(Keys key) 21 | { 22 | return _newKeyboardState.IsKeyUp(key); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/PrimitiveBatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Xna.Framework; 3 | using Microsoft.Xna.Framework.Graphics; 4 | 5 | namespace Testbed.Framework 6 | { 7 | public class PrimitiveBatch : IDisposable 8 | { 9 | private const int DefaultBufferSize = 500; 10 | 11 | // a basic effect, which contains the shaders that we will use to draw our 12 | // primitives. 13 | private BasicEffect _basicEffect; 14 | 15 | // the device that we will issue draw calls to. 16 | private GraphicsDevice _device; 17 | 18 | // hasBegun is flipped to true once Begin is called, and is used to make 19 | // sure users don't call End before Begin is called. 20 | private bool _hasBegun; 21 | 22 | private bool _isDisposed; 23 | private VertexPositionColor[] _lineVertices; 24 | private int _lineVertsCount; 25 | private VertexPositionColor[] _triangleVertices; 26 | private int _triangleVertsCount; 27 | 28 | public PrimitiveBatch(GraphicsDevice graphicsDevice, int bufferSize = DefaultBufferSize) 29 | { 30 | if (graphicsDevice == null) 31 | throw new ArgumentNullException("graphicsDevice"); 32 | 33 | _device = graphicsDevice; 34 | 35 | _triangleVertices = new VertexPositionColor[bufferSize - bufferSize % 3]; 36 | _lineVertices = new VertexPositionColor[bufferSize - bufferSize % 2]; 37 | 38 | // set up a new basic effect, and enable vertex colors. 39 | _basicEffect = new BasicEffect(graphicsDevice); 40 | _basicEffect.VertexColorEnabled = true; 41 | } 42 | 43 | #region IDisposable Members 44 | 45 | public void Dispose() 46 | { 47 | Dispose(true); 48 | GC.SuppressFinalize(this); 49 | } 50 | 51 | #endregion 52 | 53 | public void SetProjection(ref Matrix projection) 54 | { 55 | _basicEffect.Projection = projection; 56 | } 57 | 58 | protected virtual void Dispose(bool disposing) 59 | { 60 | if (disposing && !_isDisposed) 61 | { 62 | if (_basicEffect != null) 63 | _basicEffect.Dispose(); 64 | 65 | _isDisposed = true; 66 | } 67 | } 68 | 69 | 70 | /// 71 | /// Begin is called to tell the PrimitiveBatch what kind of primitives will be 72 | /// drawn, and to prepare the graphics card to render those primitives. 73 | /// 74 | /// The projection. 75 | /// The view. 76 | public void Begin(ref Matrix projection, ref Matrix view) 77 | { 78 | if (_hasBegun) 79 | throw new InvalidOperationException("End must be called before Begin can be called again."); 80 | 81 | //tell our basic effect to begin. 82 | _basicEffect.Projection = projection; 83 | _basicEffect.View = view; 84 | _basicEffect.CurrentTechnique.Passes[0].Apply(); 85 | 86 | // flip the error checking boolean. It's now ok to call AddVertex, Flush, 87 | // and End. 88 | _hasBegun = true; 89 | } 90 | 91 | public bool IsReady() 92 | { 93 | return _hasBegun; 94 | } 95 | 96 | public void AddVertex(Vector2 vertex, Color color, PrimitiveType primitiveType) 97 | { 98 | if (!_hasBegun) 99 | throw new InvalidOperationException("Begin must be called before AddVertex can be called."); 100 | 101 | if (primitiveType == PrimitiveType.LineStrip || primitiveType == PrimitiveType.TriangleStrip) 102 | throw new NotSupportedException("The specified primitiveType is not supported by PrimitiveBatch."); 103 | 104 | if (primitiveType == PrimitiveType.TriangleList) 105 | { 106 | if (_triangleVertsCount >= _triangleVertices.Length) 107 | FlushTriangles(); 108 | 109 | _triangleVertices[_triangleVertsCount].Position = new Vector3(vertex, -0.1f); 110 | _triangleVertices[_triangleVertsCount].Color = color; 111 | _triangleVertsCount++; 112 | } 113 | 114 | if (primitiveType == PrimitiveType.LineList) 115 | { 116 | if (_lineVertsCount >= _lineVertices.Length) 117 | FlushLines(); 118 | 119 | _lineVertices[_lineVertsCount].Position = new Vector3(vertex, 0f); 120 | _lineVertices[_lineVertsCount].Color = color; 121 | _lineVertsCount++; 122 | } 123 | } 124 | 125 | /// 126 | /// End is called once all the primitives have been drawn using AddVertex. 127 | /// it will call Flush to actually submit the draw call to the graphics card, and 128 | /// then tell the basic effect to end. 129 | /// 130 | public void End() 131 | { 132 | if (!_hasBegun) 133 | { 134 | throw new InvalidOperationException("Begin must be called before End can be called."); 135 | } 136 | 137 | // Draw whatever the user wanted us to draw 138 | FlushTriangles(); 139 | FlushLines(); 140 | 141 | _hasBegun = false; 142 | } 143 | 144 | private void FlushTriangles() 145 | { 146 | if (!_hasBegun) 147 | { 148 | throw new InvalidOperationException("Begin must be called before Flush can be called."); 149 | } 150 | if (_triangleVertsCount >= 3) 151 | { 152 | int primitiveCount = _triangleVertsCount / 3; 153 | // submit the draw call to the graphics card 154 | _device.SamplerStates[0] = SamplerState.AnisotropicClamp; 155 | _device.DrawUserPrimitives(PrimitiveType.TriangleList, _triangleVertices, 0, primitiveCount); 156 | _triangleVertsCount -= primitiveCount * 3; 157 | } 158 | } 159 | 160 | private void FlushLines() 161 | { 162 | if (!_hasBegun) 163 | { 164 | throw new InvalidOperationException("Begin must be called before Flush can be called."); 165 | } 166 | if (_lineVertsCount >= 2) 167 | { 168 | int primitiveCount = _lineVertsCount / 2; 169 | // submit the draw call to the graphics card 170 | _device.SamplerStates[0] = SamplerState.AnisotropicClamp; 171 | _device.DrawUserPrimitives(PrimitiveType.LineList, _lineVertices, 0, primitiveCount); 172 | _lineVertsCount -= primitiveCount * 2; 173 | } 174 | } 175 | } 176 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/Rand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed.Framework 4 | { 5 | public static class Rand 6 | { 7 | private static readonly Random Random = new Random(); 8 | 9 | /// 10 | /// Random number in range [-1,1] 11 | /// 12 | /// 13 | public static float RandomFloat() 14 | { 15 | return (float)(Random.NextDouble() * 2.0 - 1.0); 16 | } 17 | 18 | /// 19 | /// Random floating point number in range [lo, hi] 20 | /// 21 | /// The lo. 22 | /// The hi. 23 | /// 24 | public static float RandomFloat(float lo, float hi) 25 | { 26 | float r = (float)Random.NextDouble(); 27 | r = (hi - lo) * r + lo; 28 | return r; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Box2DNet.Collision; 3 | using Box2DNet.Dynamics; 4 | using Microsoft.Xna.Framework; 5 | using Microsoft.Xna.Framework.Input; 6 | 7 | namespace Testbed.Framework 8 | { 9 | public class Test 10 | { 11 | internal DebugViewXNA DebugView; 12 | internal int StepCount; 13 | internal World World; 14 | private FixedMouseJoint _fixedMouseJoint; 15 | internal int TextLine; 16 | 17 | protected Test() 18 | { 19 | World = new World(new Vector2(0.0f, -10.0f)); 20 | 21 | TextLine = 30; 22 | 23 | World.JointRemoved += JointRemoved; 24 | World.ContactManager.PreSolve += PreSolve; 25 | World.ContactManager.PostSolve += PostSolve; 26 | 27 | StepCount = 0; 28 | } 29 | 30 | public Game1 GameInstance { protected get; set; } 31 | 32 | public virtual void Initialize() 33 | { 34 | DebugView = new DebugViewXNA(World); 35 | DebugView.LoadContent(GameInstance.GraphicsDevice, GameInstance.Content); 36 | } 37 | 38 | protected virtual void JointRemoved(Joint joint) 39 | { 40 | if (_fixedMouseJoint == joint) 41 | _fixedMouseJoint = null; 42 | } 43 | 44 | public void DrawTitle(int x, int y, string title) 45 | { 46 | DebugView.DrawString(x, y, title); 47 | } 48 | 49 | public virtual void Update(GameSettings settings, GameTime gameTime) 50 | { 51 | float timeStep = Math.Min((float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.001f, (1f / 30f)); 52 | 53 | if (settings.Pause) 54 | { 55 | if (settings.SingleStep) 56 | settings.SingleStep = false; 57 | else 58 | timeStep = 0.0f; 59 | 60 | DrawString("****PAUSED****"); 61 | } 62 | else 63 | World.Step(timeStep); 64 | 65 | if (timeStep > 0.0f) 66 | ++StepCount; 67 | } 68 | 69 | public virtual void Keyboard(KeyboardManager keyboardManager) 70 | { 71 | if (keyboardManager.IsNewKeyPress(Keys.F11)) 72 | WorldSerializer.Serialize(World, "out.xml"); 73 | 74 | if (keyboardManager.IsNewKeyPress(Keys.F12)) 75 | { 76 | World = WorldSerializer.Deserialize("out.xml"); 77 | Initialize(); 78 | } 79 | } 80 | 81 | public virtual void Gamepad(GamePadState state, GamePadState oldState) 82 | { 83 | } 84 | 85 | public virtual void Mouse(MouseState state, MouseState oldState) 86 | { 87 | Vector2 position = GameInstance.ConvertScreenToWorld(state.X, state.Y); 88 | 89 | if (state.LeftButton == ButtonState.Released && oldState.LeftButton == ButtonState.Pressed) 90 | MouseUp(); 91 | else if (state.LeftButton == ButtonState.Pressed && oldState.LeftButton == ButtonState.Released) 92 | MouseDown(position); 93 | 94 | MouseMove(position); 95 | } 96 | 97 | private void MouseDown(Vector2 p) 98 | { 99 | if (_fixedMouseJoint != null) 100 | return; 101 | 102 | Fixture fixture = World.TestPoint(p); 103 | 104 | if (fixture != null) 105 | { 106 | Body body = fixture.Body; 107 | _fixedMouseJoint = new FixedMouseJoint(body, p); 108 | _fixedMouseJoint.MaxForce = 1000.0f * body.Mass; 109 | World.AddJoint(_fixedMouseJoint); 110 | body.Awake = true; 111 | } 112 | } 113 | 114 | private void MouseUp() 115 | { 116 | if (_fixedMouseJoint != null) 117 | { 118 | World.RemoveJoint(_fixedMouseJoint); 119 | _fixedMouseJoint = null; 120 | } 121 | } 122 | 123 | private void MouseMove(Vector2 p) 124 | { 125 | if (_fixedMouseJoint != null) 126 | _fixedMouseJoint.WorldAnchorB = p; 127 | } 128 | 129 | protected virtual void PreSolve(Contact contact, ref Manifold oldManifold) 130 | { 131 | } 132 | 133 | protected virtual void PostSolve(Contact contact, ContactVelocityConstraint impulse) 134 | { 135 | } 136 | 137 | protected void DrawString(string text) 138 | { 139 | DebugView.DrawString(50, TextLine, text); 140 | TextLine += 15; 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/TestEntries.cs: -------------------------------------------------------------------------------- 1 | using Testbed.Tests; 2 | 3 | namespace Testbed.Framework 4 | { 5 | public static class TestEntries 6 | { 7 | public static readonly TestEntry[] TestList = 8 | { 9 | 10 | new TestEntry {Name = "Car", CreateTest = Car.Create}, 11 | 12 | new TestEntry {Name = "Bridge", CreateTest = Bridge.Create}, 13 | 14 | new TestEntry {Name = "Simple Test", CreateTest = SimpleTest.Create}, 15 | 16 | new TestEntry {Name = null, CreateTest = null} 17 | }; 18 | } 19 | } -------------------------------------------------------------------------------- /examples/Testbed/Framework/TestEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed.Framework 4 | { 5 | public struct TestEntry 6 | { 7 | public Func CreateTest; 8 | public string Name; 9 | } 10 | } -------------------------------------------------------------------------------- /examples/Testbed/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Testbed 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | using (var game = new Game1()) 10 | { 11 | game.Run(); 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/Testbed/Shaders/GLSL/imgui-frag.glsl: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D FontTexture; 4 | 5 | in vec4 color; 6 | in vec2 texCoord; 7 | 8 | out vec4 outputColor; 9 | 10 | void main() 11 | { 12 | outputColor = color * texture(FontTexture, texCoord); 13 | } 14 | -------------------------------------------------------------------------------- /examples/Testbed/Shaders/GLSL/imgui-vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform ProjectionMatrixBuffer 4 | { 5 | mat4 projection_matrix; 6 | }; 7 | 8 | in vec2 in_position; 9 | in vec2 in_texCoord; 10 | in vec4 in_color; 11 | 12 | out vec4 color; 13 | out vec2 texCoord; 14 | 15 | void main() 16 | { 17 | gl_Position = projection_matrix * vec4(in_position, 0, 1); 18 | color = in_color; 19 | texCoord = in_texCoord; 20 | } 21 | -------------------------------------------------------------------------------- /examples/Testbed/Shaders/HLSL/imgui-frag.hlsl: -------------------------------------------------------------------------------- 1 | struct PS_INPUT 2 | { 3 | float4 pos : SV_POSITION; 4 | float4 col : COLOR0; 5 | float2 uv : TEXCOORD0; 6 | }; 7 | 8 | Texture2D FontTexture : register(t0); 9 | sampler FontSampler : register(s0); 10 | 11 | float4 FS(PS_INPUT input) : SV_Target 12 | { 13 | float4 out_col = input.col * FontTexture.Sample(FontSampler, input.uv); 14 | return out_col; 15 | } -------------------------------------------------------------------------------- /examples/Testbed/Shaders/HLSL/imgui-frag.hlsl.bytes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/Testbed/Shaders/HLSL/imgui-frag.hlsl.bytes -------------------------------------------------------------------------------- /examples/Testbed/Shaders/HLSL/imgui-vertex.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer ProjectionMatrixBuffer : register(b0) 2 | { 3 | float4x4 ProjectionMatrix; 4 | }; 5 | 6 | struct VS_INPUT 7 | { 8 | float2 pos : POSITION; 9 | float2 uv : TEXCOORD0; 10 | float4 col : COLOR0; 11 | }; 12 | 13 | struct PS_INPUT 14 | { 15 | float4 pos : SV_POSITION; 16 | float4 col : COLOR0; 17 | float2 uv : TEXCOORD0; 18 | }; 19 | 20 | PS_INPUT VS(VS_INPUT input) 21 | { 22 | PS_INPUT output; 23 | output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f)); 24 | output.col = input.col; 25 | output.uv = input.uv; 26 | return output; 27 | } -------------------------------------------------------------------------------- /examples/Testbed/Shaders/HLSL/imgui-vertex.hlsl.bytes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/Testbed/Shaders/HLSL/imgui-vertex.hlsl.bytes -------------------------------------------------------------------------------- /examples/Testbed/Shaders/Metal/imgui-frag.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | 4 | struct PS_INPUT 5 | { 6 | float4 pos [[ position ]]; 7 | float4 col; 8 | float2 uv; 9 | }; 10 | 11 | fragment float4 FS( 12 | PS_INPUT input [[ stage_in ]], 13 | texture2d FontTexture [[ texture(0) ]], 14 | sampler FontSampler [[ sampler(0) ]]) 15 | { 16 | float4 out_col = input.col * FontTexture.sample(FontSampler, input.uv); 17 | return out_col; 18 | } -------------------------------------------------------------------------------- /examples/Testbed/Shaders/Metal/imgui-frag.metallib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/Testbed/Shaders/Metal/imgui-frag.metallib -------------------------------------------------------------------------------- /examples/Testbed/Shaders/Metal/imgui-vertex.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | 4 | struct VS_INPUT 5 | { 6 | float2 pos [[ attribute(0) ]]; 7 | float2 uv [[ attribute(1) ]]; 8 | float4 col [[ attribute(2) ]]; 9 | }; 10 | 11 | struct PS_INPUT 12 | { 13 | float4 pos [[ position ]]; 14 | float4 col; 15 | float2 uv; 16 | }; 17 | 18 | vertex PS_INPUT VS( 19 | VS_INPUT input [[ stage_in ]], 20 | constant float4x4 &ProjectionMatrix [[ buffer(1) ]]) 21 | { 22 | PS_INPUT output; 23 | output.pos = ProjectionMatrix * float4(input.pos.xy, 0.f, 1.f); 24 | output.col = input.col; 25 | output.uv = input.uv; 26 | return output; 27 | } -------------------------------------------------------------------------------- /examples/Testbed/Shaders/Metal/imgui-vertex.metallib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/Testbed/Shaders/Metal/imgui-vertex.metallib -------------------------------------------------------------------------------- /examples/Testbed/Shaders/SPIR-V/generate-spirv.bat: -------------------------------------------------------------------------------- 1 | glslangvalidator -V imgui-vertex.glsl -o imgui-vertex.spv -S vert 2 | glslangvalidator -V imgui-frag.glsl -o imgui-frag.spv -S frag 3 | -------------------------------------------------------------------------------- /examples/Testbed/Shaders/SPIR-V/imgui-frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #extension GL_ARB_separate_shader_objects : enable 4 | #extension GL_ARB_shading_language_420pack : enable 5 | 6 | layout(set = 1, binding = 0) uniform texture2D FontTexture; 7 | layout(set = 0, binding = 1) uniform sampler FontSampler; 8 | 9 | layout (location = 0) in vec4 color; 10 | layout (location = 1) in vec2 texCoord; 11 | layout (location = 0) out vec4 outputColor; 12 | 13 | void main() 14 | { 15 | outputColor = color * texture(sampler2D(FontTexture, FontSampler), texCoord); 16 | } 17 | -------------------------------------------------------------------------------- /examples/Testbed/Shaders/SPIR-V/imgui-frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/Testbed/Shaders/SPIR-V/imgui-frag.spv -------------------------------------------------------------------------------- /examples/Testbed/Shaders/SPIR-V/imgui-vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #extension GL_ARB_separate_shader_objects : enable 4 | #extension GL_ARB_shading_language_420pack : enable 5 | 6 | layout (location = 0) in vec2 vsin_position; 7 | layout (location = 1) in vec2 vsin_texCoord; 8 | layout (location = 2) in vec4 vsin_color; 9 | 10 | layout (binding = 0) uniform Projection 11 | { 12 | mat4 projection; 13 | }; 14 | 15 | layout (location = 0) out vec4 vsout_color; 16 | layout (location = 1) out vec2 vsout_texCoord; 17 | 18 | out gl_PerVertex 19 | { 20 | vec4 gl_Position; 21 | }; 22 | 23 | void main() 24 | { 25 | gl_Position = projection * vec4(vsin_position, 0, 1); 26 | vsout_color = vsin_color; 27 | vsout_texCoord = vsin_texCoord; 28 | gl_Position.y = -gl_Position.y; 29 | } 30 | -------------------------------------------------------------------------------- /examples/Testbed/Shaders/SPIR-V/imgui-vertex.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/examples/Testbed/Shaders/SPIR-V/imgui-vertex.spv -------------------------------------------------------------------------------- /examples/Testbed/Testbed.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/Testbed/Tests/Bridge.cs: -------------------------------------------------------------------------------- 1 | using Box2DNet.Collision; 2 | using Box2DNet.Dynamics; 3 | using Testbed.Framework; 4 | 5 | namespace Testbed.Tests 6 | { 7 | public class Bridge : Test 8 | { 9 | private const int Count = 30; 10 | 11 | private BridgeTest() 12 | { 13 | Body ground; 14 | { 15 | ground = new Body(World); 16 | 17 | EdgeShape shape = new EdgeShape(new Vector2(-40.0f, 0.0f), new Vector2(40.0f, 0.0f)); 18 | ground.CreateFixture(shape); 19 | } 20 | { 21 | Vertices box = PolygonTools.CreateRectangle(0.5f, 0.125f); 22 | PolygonShape shape = new PolygonShape(box, 20); 23 | 24 | Body prevBody = ground; 25 | for (int i = 0; i < Count; ++i) 26 | { 27 | Body body = BodyFactory.CreateBody(World); 28 | body.BodyType = Body.BodyType.Dynamic; 29 | body.Position = new Vector2(-14.5f + 1.0f * i, 5.0f); 30 | 31 | Fixture fixture = body.CreateFixture(shape); 32 | fixture.Friction = 0.2f; 33 | 34 | Vector2 anchor = new Vector2(-15f + 1.0f * i, 5.0f); 35 | RevoluteJoint jd = new RevoluteJoint(prevBody, body, anchor, true); 36 | World.AddJoint(jd); 37 | 38 | prevBody = body; 39 | } 40 | 41 | Vector2 anchor2 = new Vector2(-15.0f + 1.0f * Count, 5.0f); 42 | RevoluteJoint jd2 = new RevoluteJoint(ground, prevBody, anchor2, true); 43 | World.AddJoint(jd2); 44 | } 45 | 46 | Vertices vertices = new Vertices(3); 47 | vertices.Add(new Vector2(-0.5f, 0.0f)); 48 | vertices.Add(new Vector2(0.5f, 0.0f)); 49 | vertices.Add(new Vector2(0.0f, 1.5f)); 50 | 51 | for (int i = 0; i < 2; ++i) 52 | { 53 | PolygonShape shape = new PolygonShape(vertices, 1); 54 | 55 | Body body = BodyFactory.CreateBody(World); 56 | body.BodyType = Body.BodyType.Dynamic; 57 | body.Position = new Vector2(-8.0f + 8.0f * i, 12.0f); 58 | 59 | body.CreateFixture(shape); 60 | } 61 | 62 | for (int i = 0; i < 3; ++i) 63 | { 64 | CircleShape shape = new CircleShape(0.5f, 1); 65 | 66 | Body body = BodyFactory.CreateBody(World); 67 | body.BodyType = Body.BodyType.Dynamic; 68 | body.Position = new Vector2(-6.0f + 6.0f * i, 10.0f); 69 | 70 | body.CreateFixture(shape); 71 | } 72 | } 73 | 74 | internal static Test Create() 75 | { 76 | return new BridgeTest(); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /examples/Testbed/Tests/Car.cs: -------------------------------------------------------------------------------- 1 | using Box2DNet.Common; 2 | using Box2DNet.Dynamics; 3 | using Testbed.Framework; 4 | using Settings = Testbed.Framework.Settings; 5 | 6 | namespace Testbed.Tests 7 | { 8 | public class Car : Test 9 | { 10 | Body _leftWheel; 11 | Body _rightWheel; 12 | Body _vehicle; 13 | RevoluteJoint _leftJoint; 14 | RevoluteJoint _rightJoint; 15 | 16 | public Car() 17 | { 18 | { // car body 19 | PolygonDef poly1 = new PolygonDef(), poly2 = new PolygonDef(); 20 | 21 | // bottom half 22 | poly1.VertexCount = 5; 23 | poly1.Vertices[4].Set(-2.2f, -0.74f); 24 | poly1.Vertices[3].Set(-2.2f, 0); 25 | poly1.Vertices[2].Set(1.0f, 0); 26 | poly1.Vertices[1].Set(2.2f, -0.2f); 27 | poly1.Vertices[0].Set(2.2f, -0.74f); 28 | poly1.Filter.GroupIndex = -1; 29 | 30 | poly1.Density = 20.0f; 31 | poly1.Friction = 0.68f; 32 | poly1.Filter.GroupIndex = -1; 33 | 34 | // top half 35 | poly2.VertexCount = 4; 36 | poly2.Vertices[3].Set(-1.7f, 0); 37 | poly2.Vertices[2].Set(-1.3f, 0.7f); 38 | poly2.Vertices[1].Set(0.5f, 0.74f); 39 | poly2.Vertices[0].Set(1.0f, 0); 40 | poly2.Filter.GroupIndex = -1; 41 | 42 | poly2.Density = 5.0f; 43 | poly2.Friction = 0.68f; 44 | poly2.Filter.GroupIndex = -1; 45 | 46 | BodyDef bd = new BodyDef(); 47 | bd.Position.Set(-35.0f, 2.8f); 48 | 49 | _vehicle = _world.CreateBody(bd); 50 | _vehicle.CreateFixture(poly1); 51 | _vehicle.CreateFixture(poly2); 52 | _vehicle.SetMassFromShapes(); 53 | } 54 | 55 | { // vehicle wheels 56 | CircleDef circ = new CircleDef(); 57 | circ.Density = 40.0f; 58 | circ.Radius = 0.38608f; 59 | circ.Friction = 0.8f; 60 | circ.Filter.GroupIndex = -1; 61 | 62 | BodyDef bd = new BodyDef(); 63 | bd.AllowSleep = false; 64 | bd.Position.Set(-33.8f, 2.0f); 65 | 66 | _rightWheel = _world.CreateBody(bd); 67 | _rightWheel.CreateFixture(circ); 68 | _rightWheel.SetMassFromShapes(); 69 | 70 | bd.Position.Set(-36.2f, 2.0f); 71 | _leftWheel = _world.CreateBody(bd); 72 | _leftWheel.CreateFixture(circ); 73 | _leftWheel.SetMassFromShapes(); 74 | } 75 | 76 | { // join wheels to chassis 77 | Vec2 anchor = new Vec2(); 78 | RevoluteJointDef jd = new RevoluteJointDef(); 79 | jd.Initialize(_vehicle, _leftWheel, _leftWheel.GetWorldCenter()); 80 | jd.CollideConnected = false; 81 | jd.EnableMotor = true; 82 | jd.MaxMotorTorque = 10.0f; 83 | jd.MotorSpeed = 0.0f; 84 | _leftJoint = (RevoluteJoint)_world.CreateJoint(jd); 85 | 86 | jd.Initialize(_vehicle, _rightWheel, _rightWheel.GetWorldCenter()); 87 | jd.CollideConnected = false; 88 | _rightJoint = (RevoluteJoint)_world.CreateJoint(jd); 89 | } 90 | 91 | { // ground 92 | PolygonDef box = new PolygonDef(); 93 | box.SetAsBox(19.5f, 0.5f); 94 | box.Friction = 0.62f; 95 | 96 | BodyDef bd = new BodyDef(); 97 | bd.Position.Set(-25.0f, 1.0f); 98 | 99 | Body ground = _world.CreateBody(bd); 100 | ground.CreateFixture(box); 101 | } 102 | 103 | { // more ground 104 | PolygonDef box = new PolygonDef(); 105 | BodyDef bd = new BodyDef(); 106 | 107 | box.SetAsBox(9.5f, 0.5f, Vec2.Zero, 0.1f * Box2DNet.Common.Settings.Pi); 108 | box.Friction = 0.62f; 109 | bd.Position.Set(27.0f - 30.0f, 3.1f); 110 | 111 | Body ground = _world.CreateBody(bd); 112 | ground.CreateFixture(box); 113 | } 114 | 115 | { // more ground 116 | PolygonDef box = new PolygonDef(); 117 | BodyDef bd = new BodyDef(); 118 | 119 | box.SetAsBox(9.5f, 0.5f, Vec2.Zero, -0.1f * Box2DNet.Common.Settings.Pi); 120 | box.Friction = 0.62f; 121 | bd.Position.Set(55.0f - 30.0f, 3.1f); 122 | 123 | Body ground = _world.CreateBody(bd); 124 | ground.CreateFixture(box); 125 | } 126 | 127 | { // more ground 128 | PolygonDef box = new PolygonDef(); 129 | BodyDef bd = new BodyDef(); 130 | 131 | box.SetAsBox(9.5f, 0.5f, Vec2.Zero, 0.03f * Box2DNet.Common.Settings.Pi); 132 | box.Friction = 0.62f; 133 | bd.Position.Set(41.0f, 2.0f); 134 | 135 | Body ground = _world.CreateBody(bd); 136 | ground.CreateFixture(box); 137 | } 138 | 139 | { // more ground 140 | PolygonDef box = new PolygonDef(); 141 | BodyDef bd = new BodyDef(); 142 | 143 | box.SetAsBox(5.0f, 0.5f, Vec2.Zero, 0.15f * Box2DNet.Common.Settings.Pi); 144 | box.Friction = 0.62f; 145 | bd.Position.Set(50.0f, 4.0f); 146 | 147 | Body ground = _world.CreateBody(bd); 148 | ground.CreateFixture(box); 149 | } 150 | 151 | { // more ground 152 | PolygonDef box = new PolygonDef(); 153 | BodyDef bd = new BodyDef(); 154 | 155 | box.SetAsBox(20.0f, 0.5f); 156 | box.Friction = 0.62f; 157 | bd.Position.Set(85.0f, 2.0f); 158 | 159 | Body ground = _world.CreateBody(bd); 160 | ground.CreateFixture(box); 161 | } 162 | } 163 | 164 | public static Test Create() 165 | { 166 | return new Car(); 167 | } 168 | 169 | public override void Keyboard(System.Windows.Forms.Keys key) 170 | { 171 | switch (key) 172 | { 173 | case System.Windows.Forms.Keys.A: 174 | _leftJoint.SetMaxMotorTorque(800.0f); 175 | _leftJoint.MotorSpeed = 12.0f; 176 | break; 177 | 178 | case System.Windows.Forms.Keys.S: 179 | _leftJoint.SetMaxMotorTorque(100.0f); 180 | _leftJoint.MotorSpeed = 0.0f; 181 | break; 182 | 183 | case System.Windows.Forms.Keys.D: 184 | _leftJoint.SetMaxMotorTorque(1200.0f); 185 | _leftJoint.MotorSpeed = -36.0f; 186 | break; 187 | } 188 | } 189 | 190 | public override void Step(Settings settings) 191 | { 192 | OpenGLDebugDraw.DrawString(5, _textLine, "Keys: left = a, brake = s, right = d"); 193 | _textLine += 15; 194 | 195 | base.Step(settings); 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /examples/Testbed/Tests/SimpleTest.cs: -------------------------------------------------------------------------------- 1 | using Box2DNet.Dynamics; 2 | using Testbed.Framework; 3 | 4 | namespace Testbed.Tests 5 | { 6 | public class SimpleTest : Test 7 | { 8 | public SimpleTest() 9 | { 10 | // Define the ground body. 11 | BodyDef groundBodyDef = new BodyDef(); 12 | groundBodyDef.Position.Set(0.0f, -10.0f); 13 | 14 | // Call the body factory which creates the ground box shape. 15 | // The body is also added to the world. 16 | Body groundBody = _world.CreateBody(groundBodyDef); 17 | 18 | // Define the ground box shape. 19 | PolygonDef groundShapeDef = new PolygonDef(); 20 | 21 | // The extents are the half-widths of the box. 22 | groundShapeDef.SetAsBox(50.0f, 10.0f); 23 | 24 | // Add the ground shape to the ground body. 25 | groundBody.CreateFixture(groundShapeDef); 26 | 27 | for (int i = 0; i < 1; i++) 28 | { 29 | // Define the dynamic body. We set its position and call the body factory. 30 | BodyDef bodyDef = new BodyDef(); 31 | bodyDef.Position.Set(0.0f, 4.0f * (i + 1)); 32 | Body body = _world.CreateBody(bodyDef); 33 | 34 | // Define another box shape for our dynamic body. 35 | PolygonDef shapeDef = new PolygonDef(); 36 | shapeDef.SetAsBox(1.0f, 1.0f); 37 | 38 | // Set the box density to be non-zero, so it will be dynamic. 39 | shapeDef.Density = 1.0f; 40 | 41 | // Override the default friction. 42 | shapeDef.Friction = 0.3f; 43 | 44 | // Add the shape to the body. 45 | body.CreateFixture(shapeDef); 46 | 47 | // Now tell the dynamic body to compute it's mass properties base 48 | // on its shape. 49 | body.SetMassFromShapes(); 50 | } 51 | 52 | } 53 | 54 | public static Test Create() 55 | { 56 | return new SimpleTest(); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/src/.DS_Store -------------------------------------------------------------------------------- /src/Box2DNet/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyu/Box2DNet/46d00a414950b54a393d0571bb5fdd0235f7d167/src/Box2DNet/.DS_Store -------------------------------------------------------------------------------- /src/Box2DNet/Box2DNet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Box2DNet/Box2DXDebug.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; using System.Numerics; 20 | using System.Text; 21 | using System.Diagnostics; 22 | using System.Collections.Generic; 23 | 24 | namespace Box2DNet 25 | { 26 | public static class Box2DNetDebug 27 | { 28 | [Conditional("DEBUG")] 29 | public static void Assert(bool condition) 30 | { 31 | if (!condition) 32 | { 33 | condition = condition; 34 | } 35 | // Debug.Assert(condition); 36 | } 37 | 38 | [Conditional("DEBUG")] 39 | public static void Assert(bool condition, string message) 40 | { 41 | if (!condition) 42 | { 43 | condition = condition; 44 | } 45 | Debug.Assert(condition, message); 46 | } 47 | 48 | [Conditional("DEBUG")] 49 | public static void Assert(bool condition, string message, string detailMessage) 50 | { 51 | if (!condition) 52 | { 53 | condition = condition; 54 | } 55 | Debug.Assert(condition, message, detailMessage); 56 | } 57 | 58 | public static void ThrowBox2DNetException(String message) 59 | { 60 | string msg = $"Error: {message}"; 61 | throw new Exception(msg); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/Box2DNet/Collision/Collision.CollideCircle.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Common; 23 | using System.Numerics; 24 | 25 | using Transform = Box2DNet.Common.Transform; 26 | using System.Numerics; 27 | namespace Box2DNet.Collision 28 | { 29 | public partial class Collision 30 | { 31 | public static void CollideCircles(ref Manifold manifold, CircleShape circle1, Transform xf1, CircleShape circle2, Transform xf2) 32 | { 33 | manifold.PointCount = 0; 34 | 35 | Vector2 p1 = xf1.TransformPoint(circle1._position); 36 | Vector2 p2 = xf2.TransformPoint(circle2._position); 37 | 38 | Vector2 d = p2 - p1; 39 | float distSqr = Vector2.Dot(d, d); 40 | float radius = circle1._radius + circle2._radius; 41 | if (distSqr > radius * radius) 42 | { 43 | return; 44 | } 45 | 46 | manifold.Type = ManifoldType.Circles; 47 | manifold.LocalPoint = circle1._position; 48 | manifold.LocalPlaneNormal = Vector2.Zero; 49 | manifold.PointCount = 1; 50 | 51 | manifold.Points[0].LocalPoint = circle2._position; 52 | manifold.Points[0].ID.Key = 0; 53 | } 54 | 55 | public static void CollidePolygonAndCircle(ref Manifold manifold, PolygonShape polygon, Transform xf1, CircleShape circle, Transform xf2) 56 | { 57 | manifold.PointCount = 0; 58 | 59 | // Compute circle position in the frame of the polygon. 60 | Vector2 c = xf2.TransformPoint(circle._position); 61 | Vector2 cLocal = xf1.InverseTransformPoint(c); 62 | 63 | // Find the min separating edge. 64 | int normalIndex = 0; 65 | float separation = -Settings.FLT_MAX; 66 | float radius = polygon._radius + circle._radius; 67 | int vertexCount = polygon._vertexCount; 68 | Vector2[] vertices = polygon._vertices; 69 | Vector2[] normals = polygon._normals; 70 | 71 | for (int i = 0; i < vertexCount; ++i) 72 | { 73 | float s = Vector2.Dot(normals[i], cLocal - vertices[i]); 74 | if (s > radius) 75 | { 76 | // Early out. 77 | return; 78 | } 79 | 80 | if (s > separation) 81 | { 82 | separation = s; 83 | normalIndex = i; 84 | } 85 | } 86 | 87 | // Vertices that subtend the incident face. 88 | int vertIndex1 = normalIndex; 89 | int vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; 90 | Vector2 v1 = vertices[vertIndex1]; 91 | Vector2 v2 = vertices[vertIndex2]; 92 | 93 | // If the center is inside the polygon ... 94 | if (separation < Common.Settings.FLT_EPSILON) 95 | { 96 | manifold.PointCount = 1; 97 | manifold.Type = ManifoldType.FaceA; 98 | manifold.LocalPlaneNormal = normals[normalIndex]; 99 | manifold.LocalPoint = 0.5f * (v1 + v2); 100 | manifold.Points[0].LocalPoint = circle._position; 101 | manifold.Points[0].ID.Key = 0; 102 | return; 103 | } 104 | 105 | // Compute barycentric coordinates 106 | float u1 = Vector2.Dot(cLocal - v1, v2 - v1); 107 | float u2 = Vector2.Dot(cLocal - v2, v1 - v2); 108 | if (u1 <= 0.0f) 109 | { 110 | if ((cLocal - v1).LengthSquared() > radius * radius) 111 | { 112 | return; 113 | } 114 | 115 | manifold.PointCount = 1; 116 | manifold.Type = ManifoldType.FaceA; 117 | manifold.LocalPlaneNormal = cLocal - v1; 118 | manifold.LocalPlaneNormal.Normalize(); 119 | manifold.LocalPoint = v1; 120 | manifold.Points[0].LocalPoint = circle._position; 121 | manifold.Points[0].ID.Key = 0; 122 | } 123 | else if (u2 <= 0.0f) 124 | { 125 | if ((cLocal - v2).LengthSquared() > radius * radius) 126 | { 127 | return; 128 | } 129 | 130 | manifold.PointCount = 1; 131 | manifold.Type = ManifoldType.FaceA; 132 | manifold.LocalPlaneNormal = cLocal - v2; 133 | manifold.LocalPlaneNormal.Normalize(); 134 | manifold.LocalPoint = v2; 135 | manifold.Points[0].LocalPoint = circle._position; 136 | manifold.Points[0].ID.Key = 0; 137 | } 138 | else 139 | { 140 | Vector2 faceCenter = 0.5f * (v1 + v2); 141 | float separation_ = Vector2.Dot(cLocal - faceCenter, normals[vertIndex1]); 142 | if (separation_ > radius) 143 | { 144 | return; 145 | } 146 | 147 | manifold.PointCount = 1; 148 | manifold.Type = ManifoldType.FaceA; 149 | manifold.LocalPlaneNormal = normals[vertIndex1]; 150 | manifold.LocalPoint = faceCenter; 151 | manifold.Points[0].LocalPoint = circle._position; 152 | manifold.Points[0].ID.Key = 0; 153 | } 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/Box2DNet/Collision/Collision.CollideEdge.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Common; 23 | 24 | 25 | using Transform = Box2DNet.Common.Transform; 26 | using System.Numerics; 27 | namespace Box2DNet.Collision 28 | { 29 | public partial class Collision 30 | { 31 | // This implements 2-sided edge vs circle collision. 32 | public static void CollideEdgeAndCircle(ref Manifold manifold, EdgeShape edge, Transform transformA, CircleShape circle, Transform transformB) 33 | { 34 | manifold.PointCount = 0; 35 | Vector2 cLocal = Common.Math.MulT(transformA, Common.Math.Mul(transformB, circle._position)); 36 | Vector2 normal = edge._normal; 37 | Vector2 v1 = edge._v1; 38 | Vector2 v2 = edge._v2; 39 | float radius = edge._radius + circle._radius; 40 | 41 | // Barycentric coordinates 42 | float u1 = Vector2.Dot(cLocal - v1, v2 - v1); 43 | float u2 = Vector2.Dot(cLocal - v2, v1 - v2); 44 | 45 | if (u1 <= 0.0f) 46 | { 47 | // Behind v1 48 | if ((cLocal- v1).LengthSquared() > radius * radius) 49 | { 50 | return; 51 | } 52 | 53 | manifold.PointCount = 1; 54 | manifold.Type = ManifoldType.FaceA; 55 | manifold.LocalPlaneNormal = cLocal - v1; 56 | manifold.LocalPlaneNormal.Normalize(); 57 | manifold.LocalPoint = v1; 58 | manifold.Points[0].LocalPoint = circle._position; 59 | manifold.Points[0].ID.Key = 0; 60 | } 61 | else if (u2 <= 0.0f) 62 | { 63 | // Ahead of v2 64 | if ((cLocal- v2).LengthSquared() > radius * radius) 65 | { 66 | return; 67 | } 68 | 69 | manifold.PointCount = 1; 70 | manifold.Type = ManifoldType.FaceA; 71 | manifold.LocalPlaneNormal = cLocal - v2; 72 | manifold.LocalPlaneNormal.Normalize(); 73 | manifold.LocalPoint = v2; 74 | manifold.Points[0].LocalPoint = circle._position; 75 | manifold.Points[0].ID.Key = 0; 76 | } 77 | else 78 | { 79 | float separation = Vector2.Dot(cLocal - v1, normal); 80 | if (separation < -radius || radius < separation) 81 | { 82 | return; 83 | } 84 | 85 | manifold.PointCount = 1; 86 | manifold.Type = ManifoldType.FaceA; 87 | manifold.LocalPlaneNormal = separation < 0.0f ? -normal : normal; 88 | manifold.LocalPoint = 0.5f * (v1 + v2); 89 | manifold.Points[0].LocalPoint = circle._position; 90 | manifold.Points[0].ID.Key = 0; 91 | } 92 | } 93 | 94 | // Polygon versus 2-sided edge. 95 | public static void CollidePolyAndEdge(ref Manifold manifold, PolygonShape polygon, Transform TransformA, EdgeShape edge, Transform TransformB) 96 | { 97 | PolygonShape polygonB = new PolygonShape(); 98 | polygonB.SetAsEdge(edge._v1, edge._v2); 99 | 100 | CollidePolygons(ref manifold, polygon, TransformA, polygonB, TransformB); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Box2DNet/Collision/Shapes/CircleShape.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Common; 23 | using System.Numerics; 24 | 25 | using Transform = Box2DNet.Common.Transform; 26 | 27 | namespace Box2DNet.Collision 28 | { 29 | /// 30 | /// A circle shape. 31 | /// 32 | public class CircleShape : Shape 33 | { 34 | // Position 35 | internal Vector2 _position; 36 | 37 | public CircleShape() 38 | { 39 | _type = ShapeType.CircleShape; 40 | } 41 | 42 | public override bool TestPoint(Transform xf, Vector2 p) 43 | { 44 | Vector2 center = xf.position + xf.TransformDirection(_position); 45 | Vector2 d = p - center; 46 | return Vector2.Dot(d, d) <= _radius * _radius; 47 | } 48 | 49 | // Collision Detection in Interactive 3D Environments by Gino van den Bergen 50 | // From Section 3.1.2 51 | // x = s + a * r 52 | // norm(x) = radius 53 | public override SegmentCollide TestSegment(Transform xf, out float lambda, out Vector2 normal, Segment segment, float maxLambda) 54 | { 55 | lambda = 0f; 56 | normal = Vector2.Zero; 57 | 58 | Vector2 position = xf.position + xf.TransformDirection(_position); 59 | Vector2 s = segment.P1 - position; 60 | float b = Vector2.Dot(s, s) - _radius * _radius; 61 | 62 | // Does the segment start inside the circle? 63 | if (b < 0.0f) 64 | { 65 | lambda = 0f; 66 | return SegmentCollide.StartInsideCollide; 67 | } 68 | 69 | // Solve quadratic equation. 70 | Vector2 r = segment.P2 - segment.P1; 71 | float c = Vector2.Dot(s, r); 72 | float rr = Vector2.Dot(r, r); 73 | float sigma = c * c - rr * b; 74 | 75 | // Check for negative discriminant and short segment. 76 | if (sigma < 0.0f || rr < Common.Settings.FLT_EPSILON) 77 | { 78 | return SegmentCollide.MissCollide; 79 | } 80 | 81 | // Find the point of intersection of the line with the circle. 82 | float a = -(c + Common.Math.Sqrt(sigma)); 83 | 84 | // Is the intersection point on the segment? 85 | if (0.0f <= a && a <= maxLambda * rr) 86 | { 87 | a /= rr; 88 | lambda = a; 89 | normal = s + a * r; 90 | normal.Normalize(); 91 | return SegmentCollide.HitCollide; 92 | } 93 | 94 | return SegmentCollide.MissCollide; 95 | } 96 | 97 | public override void ComputeAABB(out AABB aabb, Transform xf) 98 | { 99 | aabb = new AABB(); 100 | 101 | Vector2 p = xf.position + xf.TransformDirection(_position); 102 | aabb.LowerBound = new Vector2(p.X - _radius, p.Y - _radius); 103 | aabb.UpperBound = new Vector2(p.X + _radius, p.Y + _radius); 104 | } 105 | 106 | public override void ComputeMass(out MassData massData, float density) 107 | { 108 | massData = new MassData(); 109 | 110 | massData.Mass = density * (float)System.Math.PI * _radius * _radius; 111 | massData.Center = _position; 112 | 113 | // inertia about the local origin 114 | massData.I = massData.Mass * (0.5f * _radius * _radius + Vector2.Dot(_position, _position)); 115 | } 116 | 117 | public override float ComputeSubmergedArea(Vector2 normal, float offset, Transform xf, out Vector2 c) 118 | { 119 | Vector2 p = xf.TransformPoint(_position); 120 | float l = -(Vector2.Dot(normal, p) - offset); 121 | if (l < -_radius + Box2DNet.Common.Settings.FLT_EPSILON) 122 | { 123 | //Completely dry 124 | c = new Vector2(); 125 | return 0; 126 | } 127 | if (l > _radius) 128 | { 129 | //Completely wet 130 | c = p; 131 | return Box2DNet.Common.Settings.Pi * _radius * _radius; 132 | } 133 | 134 | //Magic 135 | float r2 = _radius * _radius; 136 | float l2 = l * l; 137 | float area = r2 * ((float)System.Math.Asin(l / _radius) + Box2DNet.Common.Settings.Pi / 2) + 138 | l * Box2DNet.Common.Math.Sqrt(r2 - l2); 139 | float com = -2.0f / 3.0f * (float)System.Math.Pow(r2 - l2, 1.5f) / area; 140 | 141 | c.X = p.X + normal.X * com; 142 | c.Y = p.Y + normal.Y * com; 143 | 144 | return area; 145 | } 146 | 147 | /// 148 | /// Get the supporting vertex index in the given direction. 149 | /// 150 | public override int GetSupport(Vector2 d) 151 | { 152 | return 0; 153 | } 154 | 155 | /// 156 | /// Get the supporting vertex in the given direction. 157 | /// 158 | public override Vector2 GetSupportVertex(Vector2 d) 159 | { 160 | return _position; 161 | } 162 | 163 | /// 164 | /// Get a vertex by index. Used by Distance. 165 | /// 166 | public override Vector2 GetVertex(int index) 167 | { 168 | Box2DNetDebug.Assert(index == 0); 169 | return _position; 170 | } 171 | 172 | public override float ComputeSweepRadius(Vector2 pivot) 173 | { 174 | return Box2DNet.Common.Math.Distance(_position, pivot); 175 | } 176 | 177 | /// 178 | /// Get the vertex count. 179 | /// 180 | public int VertexCount { get { return 1; } } 181 | } 182 | } -------------------------------------------------------------------------------- /src/Box2DNet/Collision/Shapes/EdgeShape.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using System; using System.Numerics; 23 | using System.Collections.Generic; 24 | using System.Text; 25 | using Box2DNet.Common; 26 | 27 | 28 | using Transform = Box2DNet.Common.Transform; 29 | 30 | namespace Box2DNet.Collision 31 | { 32 | public class EdgeShape : Shape 33 | { 34 | public Vector2 _v1; 35 | public Vector2 _v2; 36 | 37 | public float _length; 38 | 39 | public Vector2 _normal; 40 | 41 | public Vector2 _direction; 42 | 43 | // Unit vector halfway between m_direction and m_prevEdge.m_direction: 44 | public Vector2 _cornerDir1; 45 | 46 | // Unit vector halfway between m_direction and m_nextEdge.m_direction: 47 | public Vector2 _cornerDir2; 48 | 49 | public bool _cornerConvex1; 50 | public bool _cornerConvex2; 51 | 52 | public EdgeShape _nextEdge; 53 | public EdgeShape _prevEdge; 54 | 55 | public EdgeShape() 56 | { 57 | _type = ShapeType.EdgeShape; 58 | _radius = Settings.PolygonRadius; 59 | } 60 | 61 | public override void Dispose() 62 | { 63 | if (_prevEdge != null) 64 | { 65 | _prevEdge._nextEdge = null; 66 | } 67 | 68 | if (_nextEdge != null) 69 | { 70 | _nextEdge._prevEdge = null; 71 | } 72 | } 73 | 74 | public void Set(Vector2 v1, Vector2 v2) 75 | { 76 | _v1 = v1; 77 | _v2 = v2; 78 | 79 | _direction = _v2 - _v1; 80 | _length = _direction.Length(); 81 | _direction.Normalize(); 82 | _normal = _direction.CrossScalarPostMultiply(1.0f); 83 | 84 | _cornerDir1 = _normal; 85 | _cornerDir2 = -1.0f * _normal; 86 | } 87 | 88 | public override bool TestPoint(Transform xf, Vector2 p) 89 | { 90 | return false; 91 | } 92 | 93 | public override SegmentCollide TestSegment(Transform xf, out float lambda, out Vector2 normal, Segment segment, float maxLambda) 94 | { 95 | Vector2 r = segment.P2 - segment.P1; 96 | Vector2 v1 = xf.TransformPoint(_v1); 97 | Vector2 d = ((Vector2)xf.TransformPoint(_v2)) - v1; 98 | Vector2 n = d.CrossScalarPostMultiply(1.0f); 99 | 100 | float k_slop = 100.0f * Common.Settings.FLT_EPSILON; 101 | float denom = -Vector2.Dot(r, n); 102 | 103 | // Cull back facing collision and ignore parallel segments. 104 | if (denom > k_slop) 105 | { 106 | // Does the segment intersect the infinite line associated with this segment? 107 | Vector2 b = segment.P1 - v1; 108 | float a = Vector2.Dot(b, n); 109 | 110 | if (0.0f <= a && a <= maxLambda * denom) 111 | { 112 | float mu2 = -r.X * b.Y + r.Y * b.X; 113 | 114 | // Does the segment intersect this segment? 115 | if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0f + k_slop)) 116 | { 117 | a /= denom; 118 | n.Normalize(); 119 | lambda = a; 120 | normal = n; 121 | return SegmentCollide.HitCollide; 122 | } 123 | } 124 | } 125 | 126 | lambda = 0; 127 | normal = new Vector2(); 128 | return SegmentCollide.MissCollide; 129 | } 130 | 131 | public override void ComputeAABB(out AABB aabb, Transform xf) 132 | { 133 | Vector2 v1 = xf.TransformPoint(_v1); 134 | Vector2 v2 = xf.TransformPoint(_v2); 135 | 136 | Vector2 r = new Vector2(_radius, _radius); 137 | aabb.LowerBound = Vector2.Min(v1, v2) - r; 138 | aabb.UpperBound = Vector2.Max(v1, v2) + r; 139 | } 140 | 141 | public override void ComputeMass(out MassData massData, float density) 142 | { 143 | massData.Mass = 0.0f; 144 | massData.Center = _v1; 145 | massData.I = 0.0f; 146 | } 147 | 148 | public void SetPrevEdge(EdgeShape edge, Vector2 cornerDir, bool convex) 149 | { 150 | _prevEdge = edge; 151 | _cornerDir1 = cornerDir; 152 | _cornerConvex1 = convex; 153 | } 154 | 155 | public void SetNextEdge(EdgeShape edge, Vector2 cornerDir, bool convex) 156 | { 157 | _nextEdge = edge; 158 | _cornerDir2 = cornerDir; 159 | _cornerConvex2 = convex; 160 | } 161 | 162 | public override float ComputeSubmergedArea(Vector2 normal, float offset, Transform xf, out Vector2 c) 163 | { 164 | //Note that v0 is independent of any details of the specific edge 165 | //We are relying on v0 being consistent between multiple edges of the same body 166 | Vector2 v0 = offset * normal; 167 | //b2Vec2 v0 = xf.position + (offset - b2Dot(normal, xf.position)) * normal; 168 | 169 | Vector2 v1 = xf.TransformPoint(_v1); 170 | Vector2 v2 = xf.TransformPoint(_v2); 171 | 172 | float d1 = Vector2.Dot(normal, v1) - offset; 173 | float d2 = Vector2.Dot(normal, v2) - offset; 174 | 175 | if (d1 > 0.0f) 176 | { 177 | if (d2 > 0.0f) 178 | { 179 | c = new Vector2(); 180 | return 0.0f; 181 | } 182 | else 183 | { 184 | v1 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2; 185 | } 186 | } 187 | else 188 | { 189 | if (d2 > 0.0f) 190 | { 191 | v2 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2; 192 | } 193 | else 194 | { 195 | //Nothing 196 | } 197 | } 198 | 199 | // v0,v1,v2 represents a fully submerged triangle 200 | float k_inv3 = 1.0f / 3.0f; 201 | 202 | // Area weighted centroid 203 | c = k_inv3 * (v0 + v1 + v2); 204 | 205 | Vector2 e1 = v1 - v0; 206 | Vector2 e2 = v2 - v0; 207 | 208 | return 0.5f * e1.Cross(e2); 209 | } 210 | 211 | public float Length 212 | { 213 | get { return _length; } 214 | } 215 | 216 | public Vector2 Vertex1 217 | { 218 | get { return _v1; } 219 | } 220 | 221 | public Vector2 Vertex2 222 | { 223 | get { return _v2; } 224 | } 225 | 226 | public Vector2 NormalVector 227 | { 228 | get { return _normal; } 229 | } 230 | 231 | public Vector2 DirectionVector 232 | { 233 | get { return _direction; } 234 | } 235 | 236 | public Vector2 Corner1Vector 237 | { 238 | get { return _cornerDir1; } 239 | } 240 | 241 | public Vector2 Corner2Vector 242 | { 243 | get { return _cornerDir2; } 244 | } 245 | 246 | public override int GetSupport(Vector2 d) 247 | { 248 | return Vector2.Dot(_v1, d) > Vector2.Dot(_v2, d) ? 0 : 1; 249 | } 250 | 251 | public override Vector2 GetSupportVertex(Vector2 d) 252 | { 253 | return Vector2.Dot(_v1, d) > Vector2.Dot(_v2, d) ? _v1 : _v2; 254 | } 255 | 256 | public override Vector2 GetVertex(int index) 257 | { 258 | Box2DNetDebug.Assert(0 <= index && index < 2); 259 | if (index == 0) return _v1; 260 | else return _v2; 261 | } 262 | 263 | public bool Corner1IsConvex 264 | { 265 | get { return _cornerConvex1; } 266 | } 267 | 268 | public bool Corner2IsConvex 269 | { 270 | get { return _cornerConvex2; } 271 | } 272 | 273 | public override float ComputeSweepRadius(Vector2 pivot) 274 | { 275 | float ds1 = (_v1 - pivot).LengthSquared(); 276 | float ds2 = (_v2 - pivot).LengthSquared(); 277 | return (float)System.Math.Sqrt((float)System.Math.Max(ds1, ds2)); 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/Box2DNet/Collision/Shapes/Shape.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using System; using System.Numerics; 23 | using Box2DNet.Common; 24 | 25 | 26 | using Transform = Box2DNet.Common.Transform; 27 | 28 | namespace Box2DNet.Collision 29 | { 30 | /// 31 | /// This holds the mass data computed for a shape. 32 | /// 33 | public struct MassData 34 | { 35 | /// 36 | /// The mass of the shape, usually in kilograms. 37 | /// 38 | public float Mass; 39 | 40 | /// 41 | /// The position of the shape's centroid relative to the shape's origin. 42 | /// 43 | public Vector2 Center; 44 | 45 | /// 46 | /// The rotational inertia of the shape. 47 | /// 48 | public float I; 49 | } 50 | 51 | /// 52 | /// The various collision shape types supported by Box2D. 53 | /// 54 | public enum ShapeType 55 | { 56 | UnknownShape = -1, 57 | CircleShape, 58 | PolygonShape, 59 | EdgeShape, 60 | ShapeTypeCount, 61 | } 62 | 63 | /// 64 | /// Returns code from TestSegment 65 | /// 66 | public enum SegmentCollide 67 | { 68 | StartInsideCollide = -1, 69 | MissCollide = 0, 70 | HitCollide = 1 71 | } 72 | 73 | /// 74 | /// A shape is used for collision detection. You can create a shape however you like. 75 | /// Shapes used for simulation in World are created automatically when a Fixture is created. 76 | /// 77 | public abstract class Shape : IDisposable 78 | { 79 | #region Fields 80 | 81 | protected ShapeType _type = ShapeType.UnknownShape; 82 | internal float _radius; 83 | 84 | #endregion Fields 85 | 86 | protected Shape() { } 87 | 88 | /// 89 | /// Test a point for containment in this shape. This only works for convex shapes. 90 | /// 91 | /// The shape world Transform. 92 | /// A point in world coordinates. 93 | /// 94 | public abstract bool TestPoint(Transform xf, Vector2 p); 95 | 96 | /// 97 | /// Perform a ray cast against this shape. 98 | /// 99 | /// The shape world Transform. 100 | /// Returns the hit fraction. You can use this to compute the contact point 101 | /// p = (1 - lambda) * segment.P1 + lambda * segment.P2. 102 | /// Returns the normal at the contact point. If there is no intersection, 103 | /// the normal is not set. 104 | /// Defines the begin and end point of the ray cast. 105 | /// A number typically in the range [0,1]. 106 | public abstract SegmentCollide TestSegment(Transform xf, out float lambda, out Vector2 normal, Segment segment, float maxLambda); 107 | 108 | /// 109 | /// Given a Transform, compute the associated axis aligned bounding box for this shape. 110 | /// 111 | /// Returns the axis aligned box. 112 | /// The world Transform of the shape. 113 | public abstract void ComputeAABB(out AABB aabb, Transform xf); 114 | 115 | /// 116 | /// Compute the mass properties of this shape using its dimensions and density. 117 | /// The inertia tensor is computed about the local origin, not the centroid. 118 | /// 119 | /// Returns the mass data for this shape 120 | public abstract void ComputeMass(out MassData massData, float density); 121 | 122 | /// 123 | /// Compute the volume and centroid of this shape intersected with a half plane. 124 | /// 125 | /// Normal the surface normal. 126 | /// Offset the surface offset along normal. 127 | /// The shape Transform. 128 | /// Returns the centroid. 129 | /// The total volume less than offset along normal. 130 | public abstract float ComputeSubmergedArea(Vector2 normal, float offset, Transform xf, out Vector2 c); 131 | 132 | /// 133 | /// Compute the sweep radius. This is used for conservative advancement (continuous collision detection). 134 | /// 135 | /// Pivot is the pivot point for rotation. 136 | /// The distance of the furthest point from the pivot. 137 | public abstract float ComputeSweepRadius(Vector2 pivot); 138 | 139 | public abstract Vector2 GetVertex(int index); 140 | 141 | public abstract int GetSupport(Vector2 d); 142 | 143 | public abstract Vector2 GetSupportVertex(Vector2 d); 144 | 145 | public virtual void Dispose(){} 146 | } 147 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Mar33.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | //r175 20 | 21 | using System; using System.Numerics; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | 25 | 26 | namespace Box2DNet.Common 27 | { 28 | /// 29 | /// A 3-by-3 matrix. Stored in column-major order. 30 | /// 31 | public struct Mat33 32 | { 33 | /// 34 | /// Construct this matrix using columns. 35 | /// 36 | public Mat33(Vector3 c1, Vector3 c2, Vector3 c3) 37 | { 38 | Col1 = c1; 39 | Col2 = c2; 40 | Col3 = c3; 41 | } 42 | 43 | /// 44 | /// Set this matrix to all zeros. 45 | /// 46 | public void SetZero() 47 | { 48 | Col1 = Vector3.Zero; 49 | Col2 = Vector3.Zero; 50 | Col3 = Vector3.Zero; 51 | } 52 | 53 | /// 54 | /// Solve A * x = b, where b is a column vector. This is more efficient 55 | /// than computing the inverse in one-shot cases. 56 | /// 57 | public Vector3 Solve33(Vector3 b) 58 | { 59 | float det = Vector3.Dot(Col1, Vector3.Cross(Col2, Col3)); 60 | Box2DNetDebug.Assert(det != 0.0f); 61 | det = 1.0f / det; 62 | Vector3 x = new Vector3(); 63 | x.X = det * Vector3.Dot(b, Vector3.Cross(Col2, Col3)); 64 | x.Y = det * Vector3.Dot(Col1, Vector3.Cross(b, Col3)); 65 | x.Z = det * Vector3.Dot(Col1, Vector3.Cross(Col2, b)); 66 | return x; 67 | } 68 | 69 | /// 70 | /// Solve A * x = b, where b is a column vector. This is more efficient 71 | /// than computing the inverse in one-shot cases. Solve only the upper 72 | /// 2-by-2 matrix equation. 73 | /// 74 | public Vector2 Solve22(Vector2 b) 75 | { 76 | float a11 = Col1.X, a12 = Col2.X, a21 = Col1.Y, a22 = Col2.Y; 77 | float det = a11 * a22 - a12 * a21; 78 | Box2DNetDebug.Assert(det != 0.0f); 79 | det = 1.0f / det; 80 | Vector2 x = new Vector2(); 81 | x.X = det * (a22 * b.X - a12 * b.Y); 82 | x.Y = det * (a11 * b.Y - a21 * b.X); 83 | return x; 84 | } 85 | 86 | public Vector3 Col1; 87 | public Vector3 Col2; 88 | public Vector3 Col3; 89 | } 90 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Mat22.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; using System.Numerics; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | 24 | namespace Box2DNet.Common 25 | { 26 | /// 27 | /// A 2-by-2 matrix. Stored in column-major order. 28 | /// 29 | public struct Mat22 30 | { 31 | public Vector2 Col1; 32 | public Vector2 Col2; 33 | 34 | /// 35 | /// Construct this matrix using columns. 36 | /// 37 | public Mat22(Vector2 c1, Vector2 c2) 38 | { 39 | Col1 = c1; 40 | Col2 = c2; 41 | } 42 | 43 | /// 44 | /// Construct this matrix using scalars. 45 | /// 46 | public Mat22(float a11, float a12, float a21, float a22) 47 | { 48 | Col1.X = a11; Col1.Y = a21; 49 | Col2.X = a12; Col2.Y = a22; 50 | } 51 | 52 | /// 53 | /// Construct this matrix using an angle. 54 | /// This matrix becomes an orthonormal rotation matrix. 55 | /// 56 | public Mat22(float angle) 57 | { 58 | float c = (float)System.Math.Cos(angle); 59 | float s = (float)System.Math.Sin(angle); 60 | Col1.X = c; Col2.X = -s; 61 | Col1.Y = s; Col2.Y = c; 62 | } 63 | 64 | /// 65 | /// Initialize this matrix using columns. 66 | /// 67 | public void Set(Vector2 c1, Vector2 c2) 68 | { 69 | Col1 = c1; 70 | Col2 = c2; 71 | } 72 | 73 | /// 74 | /// Initialize this matrix using an angle. 75 | /// This matrix becomes an orthonormal rotation matrix. 76 | /// 77 | public void Set(float angle) 78 | { 79 | float c = (float)System.Math.Cos(angle); 80 | float s = (float)System.Math.Sin(angle); 81 | Col1.X = c; Col2.X = -s; 82 | Col1.Y = s; Col2.Y = c; 83 | } 84 | 85 | /// 86 | /// Extract the angle from this matrix (assumed to be a rotation matrix). 87 | /// 88 | public float GetAngle() 89 | { 90 | return Math.Atan2(Col1.Y, Col1.X); 91 | } 92 | 93 | public Vector2 Multiply(Vector2 vector) { 94 | return new Vector2(Col1.X * vector.Y + Col2.X * vector.Y, Col1.Y * vector.X + Col2.Y * vector.Y); 95 | } 96 | 97 | /// 98 | /// Compute the inverse of this matrix, such that inv(A) * A = identity. 99 | /// 100 | public Mat22 GetInverse() 101 | { 102 | float a = Col1.X, b = Col2.X, c = Col1.Y, d = Col2.Y; 103 | Mat22 B = new Mat22(); 104 | float det = a * d - b * c; 105 | Box2DNetDebug.Assert(det != 0.0f); 106 | det = 1.0f / det; 107 | B.Col1.X = det * d; B.Col2.X = -det * b; 108 | B.Col1.Y = -det * c; B.Col2.Y = det * a; 109 | return B; 110 | } 111 | 112 | /// 113 | /// Solve A * x = b, where b is a column vector. This is more efficient 114 | /// than computing the inverse in one-shot cases. 115 | /// 116 | public Vector2 Solve(Vector2 b) 117 | { 118 | float a11 = Col1.X, a12 = Col2.X, a21 = Col1.Y, a22 = Col2.Y; 119 | float det = a11 * a22 - a12 * a21; 120 | Box2DNetDebug.Assert(det != 0.0f); 121 | det = 1.0f / det; 122 | Vector2 x = new Vector2(); 123 | x.X = det * (a22 * b.X - a12 * b.Y); 124 | x.Y = det * (a11 * b.Y - a21 * b.X); 125 | return x; 126 | } 127 | 128 | public static Mat22 Identity { get { return new Mat22(1, 0, 0, 1); } } 129 | 130 | public static Mat22 operator +(Mat22 A, Mat22 B) 131 | { 132 | Mat22 C = new Mat22(); 133 | C.Set(A.Col1 + B.Col1, A.Col2 + B.Col2); 134 | return C; 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Math.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; using System.Numerics; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | 24 | using Random = System.Random; 25 | 26 | namespace Box2DNet.Common 27 | { 28 | public static class Vector2Extension 29 | { 30 | public static float Rad2Deg = (float)360.0f / (float)(System.Math.PI * 2); 31 | public static Vector3 ToVector3(this Vector2 vector) 32 | { 33 | return new Vector3(vector.X, vector.Y, 0.0f); 34 | } 35 | 36 | public static bool IsValid(this Vector2 vector) 37 | { 38 | return Math.IsValid(vector.X) && Math.IsValid(vector.Y); 39 | } 40 | 41 | public static float Cross(this Vector2 vector, Vector2 other) 42 | { 43 | return vector.X * other.Y - vector.Y * other.X; 44 | } 45 | 46 | public static Vector2 CrossScalarPostMultiply(this Vector2 vector, float s) 47 | { 48 | return new Vector2(s * vector.Y, -s * vector.X); 49 | } 50 | 51 | public static Vector2 CrossScalarPreMultiply(this Vector2 vector, float s) 52 | { 53 | return new Vector2(-s * vector.Y, s * vector.X); 54 | } 55 | 56 | public static Vector2 Abs(this Vector2 vector) { 57 | return new Vector2(Math.Abs(vector.X), Math.Abs(vector.Y)); 58 | } 59 | } 60 | 61 | public static class Vector3Extension 62 | { 63 | public static Vector2 ToVector2(this Vector3 vector) 64 | { 65 | return new Vector2(vector.X, vector.Y); 66 | } 67 | } 68 | 69 | public static class QuaternionExtension 70 | { 71 | public static Quaternion FromAngle2D(float radians) 72 | { 73 | return Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), radians * ((float)360.0f / (float)(System.Math.PI * 2))); 74 | } 75 | } 76 | 77 | public class Math 78 | { 79 | public static readonly ushort USHRT_MAX = 0xffff; 80 | public static readonly byte UCHAR_MAX = 0xff; 81 | public static readonly int RAND_LIMIT = 32767; 82 | 83 | /// 84 | /// This function is used to ensure that a floating point number is 85 | /// not a NaN or infinity. 86 | /// 87 | public static bool IsValid(float x) 88 | { 89 | return !(float.IsNaN(x) || float.IsNegativeInfinity(x) || float.IsPositiveInfinity(x)); 90 | } 91 | 92 | [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)] 93 | public struct Convert 94 | { 95 | [System.Runtime.InteropServices.FieldOffset(0)] 96 | public float x; 97 | 98 | [System.Runtime.InteropServices.FieldOffset(0)] 99 | public int i; 100 | } 101 | 102 | 103 | #if USE_MATRIX_FOR_ROTATION 104 | public static Mat22 AngleToRotation(float angle) 105 | { 106 | return new Mat22(angle); 107 | } 108 | #else 109 | public static Quaternion AngleToRotation(float angle) 110 | { 111 | return QuaternionExtension.FromAngle2D(angle); 112 | } 113 | #endif 114 | 115 | /// 116 | /// This is a approximate yet fast inverse square-root. 117 | /// 118 | public static float InvSqrt(float x) 119 | { 120 | Convert convert = new Convert(); 121 | convert.x = x; 122 | float xhalf = 0.5f * x; 123 | convert.i = 0x5f3759df - (convert.i >> 1); 124 | x = convert.x; 125 | x = x * (1.5f - xhalf * x * x); 126 | return x; 127 | } 128 | 129 | public static float Clamp(float f, float min, float max) { 130 | if (f < min) 131 | return min; 132 | else if (f > max) 133 | return max; 134 | else return f; 135 | } 136 | public static float Rad2Deg = 57.29578f; 137 | public static float Epsilon = 1.401298E-45f; 138 | public static float Sqrt(float x) 139 | { 140 | return Math.Sqrt(x); 141 | } 142 | public static float Distance(Vector2 v1, Vector2 v2) { 143 | return (float)System.Math.Sqrt(System.Math.Pow(v2.X - v1.X, 2) + System.Math.Pow(v2.Y - v1.Y, 2)); 144 | } 145 | 146 | /// 147 | /// Random floating point number in range [lo, hi] 148 | /// 149 | 150 | /// 151 | /// "Next Largest Power of 2 152 | /// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm 153 | /// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with 154 | /// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next 155 | /// largest power of 2. For a 32-bit value:" 156 | /// 157 | public static uint NextPowerOfTwo(uint x) 158 | { 159 | x |= (x >> 1); 160 | x |= (x >> 2); 161 | x |= (x >> 4); 162 | x |= (x >> 8); 163 | x |= (x >> 16); 164 | return x + 1; 165 | } 166 | 167 | public static bool IsPowerOfTwo(uint x) 168 | { 169 | bool result = x > 0 && (x & (x - 1)) == 0; 170 | return result; 171 | } 172 | 173 | public static float Abs(float a) 174 | { 175 | return a > 0.0f ? a : -a; 176 | } 177 | 178 | public static Vector2 Abs(Vector2 a) 179 | { 180 | return new Vector2(Math.Abs(a.X), Math.Abs(a.Y)); 181 | } 182 | 183 | public static Mat22 Abs(Mat22 A) 184 | { 185 | Mat22 B = new Mat22(); 186 | B.Set(Math.Abs(A.Col1), Math.Abs(A.Col2)); 187 | return B; 188 | } 189 | 190 | public static float Min(float a, float b) 191 | { 192 | return a < b ? a : b; 193 | } 194 | 195 | public static int Min(int a, int b) 196 | { 197 | return a < b ? a : b; 198 | } 199 | 200 | public static float Max(float a, float b) 201 | { 202 | return a > b ? a : b; 203 | } 204 | 205 | public static int Max(int a, int b) 206 | { 207 | return a > b ? a : b; 208 | } 209 | 210 | public static Vector2 Clamp(Vector2 a, Vector2 low, Vector2 high) 211 | { 212 | return Vector2.Max(low, Vector2.Min(a, high)); 213 | } 214 | 215 | public static void Swap(ref T a, ref T b) 216 | { 217 | T tmp = a; 218 | a = b; 219 | b = tmp; 220 | } 221 | 222 | /// 223 | /// Multiply a matrix times a vector. If a rotation matrix is provided, 224 | /// then this Transforms the vector from one frame to another. 225 | /// 226 | public static Vector2 Mul(Mat22 A, Vector2 v) 227 | { 228 | return new Vector2(A.Col1.X * v.X + A.Col2.X * v.Y, A.Col1.Y * v.X + A.Col2.Y * v.Y); 229 | } 230 | 231 | /// 232 | /// Multiply a matrix transpose times a vector. If a rotation matrix is provided, 233 | /// then this Transforms the vector from one frame to another (inverse Transform). 234 | /// 235 | public static Vector2 MulT(Mat22 A, Vector2 v) 236 | { 237 | return new Vector2(Vector2.Dot(v, A.Col1), Vector2.Dot(v, A.Col2)); 238 | } 239 | 240 | /// 241 | /// A * B 242 | /// 243 | public static Mat22 Mul(Mat22 A, Mat22 B) 244 | { 245 | Mat22 C = new Mat22(); 246 | C.Set(Math.Mul(A, B.Col1), Math.Mul(A, B.Col2)); 247 | return C; 248 | } 249 | 250 | /// 251 | /// A^T * B 252 | /// 253 | public static Mat22 MulT(Mat22 A, Mat22 B) 254 | { 255 | Vector2 c1 = new Vector2(Vector2.Dot(A.Col1, B.Col1), Vector2.Dot(A.Col2, B.Col1)); 256 | Vector2 c2 = new Vector2(Vector2.Dot(A.Col1, B.Col2), Vector2.Dot(A.Col2, B.Col2)); 257 | return new Mat22(c1, c2); 258 | } 259 | 260 | public static Vector2 Mul(Transform T, Vector2 v) 261 | { 262 | #if USE_MATRIX_FOR_ROTATION 263 | return T.position + Math.Mul(T.R, v); 264 | #else 265 | return T.position + T.TransformDirection(v); 266 | #endif 267 | } 268 | 269 | public static Vector2 MulT(Transform T, Vector2 v) 270 | { 271 | #if USE_MATRIX_FOR_ROTATION 272 | return Math.MulT(T.R, v - T.position); 273 | #else 274 | return T.InverseTransformDirection(v - T.position); 275 | #endif 276 | } 277 | 278 | /// 279 | /// Multiply a matrix times a vector. 280 | /// 281 | public static Vector3 Mul(Mat33 A, Vector3 v) 282 | { 283 | return v.X * A.Col1 + v.Y * A.Col2 + v.Z * A.Col3; 284 | } 285 | 286 | public static float Atan2(float y, float x) 287 | { 288 | return (float)System.Math.Atan2(y, x); 289 | } 290 | } 291 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Settings.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; using System.Numerics; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | namespace Box2DNet.Common 24 | { 25 | public class Settings 26 | { 27 | #if TARGET_FLOAT32_IS_FIXED 28 | public static readonly float FLT_EPSILON = FIXED_EPSILON; 29 | public static readonly float FLT_MAX = FIXED_MAX; 30 | public static float FORCE_SCALE2(x){ return x<<7;} 31 | public static float FORCE_INV_SCALE2(x) {return x>>7;} 32 | #else 33 | public static readonly float FLT_EPSILON = 1.192092896e-07F;//smallest such that 1.0f+FLT_EPSILON != 1.0f 34 | public static readonly float FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;//smallest such that 1.0f+FLT_EPSILON != 1.0f 35 | public static readonly float FLT_MAX = 3.402823466e+38F; 36 | public static float FORCE_SCALE(float x) { return x; } 37 | public static float FORCE_INV_SCALE(float x) { return x; } 38 | #endif 39 | 40 | public static readonly float Pi = 3.14159265359f; 41 | 42 | // Global tuning constants based on meters-kilograms-seconds (MKS) units. 43 | 44 | // Collision 45 | public static readonly int MaxManifoldPoints = 2; 46 | public static readonly int MaxPolygonVertices = 8; 47 | public static readonly int MaxProxies = 512; // this must be a power of two 48 | public static readonly int MaxPairs = 8 * MaxProxies; // this must be a power of two 49 | 50 | // Dynamics 51 | 52 | /// 53 | /// A small length used as a collision and constraint tolerance. Usually it is 54 | /// chosen to be numerically significant, but visually insignificant. 55 | /// 56 | public static readonly float LinearSlop = 0.005f; // 0.5 cm 57 | 58 | /// 59 | /// A small angle used as a collision and constraint tolerance. Usually it is 60 | /// chosen to be numerically significant, but visually insignificant. 61 | /// 62 | public static readonly float AngularSlop = 2.0f / 180.0f * Pi; // 2 degrees 63 | 64 | /// 65 | /// The radius of the polygon/edge shape skin. This should not be modified. Making 66 | /// this smaller means polygons will have and insufficient for continuous collision. 67 | /// Making it larger may create artifacts for vertex collision. 68 | /// 69 | public static readonly float PolygonRadius = 2.0f * LinearSlop; 70 | 71 | /// 72 | /// Continuous collision detection (CCD) works with core, shrunken shapes. This is amount 73 | /// by which shapes are automatically shrunk to work with CCD. 74 | /// This must be larger than LinearSlop. 75 | /// 76 | public static readonly float ToiSlop = 8.0f * LinearSlop; 77 | 78 | /// 79 | /// Maximum number of contacts to be handled to solve a TOI island. 80 | /// 81 | public static readonly int MaxTOIContactsPerIsland = 32; 82 | 83 | /// 84 | /// Maximum number of joints to be handled to solve a TOI island. 85 | /// 86 | public static readonly int MaxTOIJointsPerIsland = 32; 87 | 88 | /// 89 | /// A velocity threshold for elastic collisions. Any collision with a relative linear 90 | /// velocity below this threshold will be treated as inelastic. 91 | /// 92 | public static readonly float VelocityThreshold = 1.0f; // 1 m/s 93 | 94 | /// 95 | /// The maximum linear position correction used when solving constraints. 96 | /// This helps to prevent overshoot. 97 | /// 98 | public static readonly float MaxLinearCorrection = 0.2f; // 20 cm 99 | 100 | /// 101 | /// The maximum angular position correction used when solving constraints. 102 | /// This helps to prevent overshoot. 103 | /// 104 | public static readonly float MaxAngularCorrection = 8.0f / 180.0f * Pi; // 8 degrees 105 | 106 | /// 107 | /// The maximum linear velocity of a body. This limit is very large and is used 108 | /// to prevent numerical problems. You shouldn't need to adjust this. 109 | /// 110 | #if TARGET_FLOAT32_IS_FIXED 111 | public static readonly float MaxLinearVelocity = 100.0f; 112 | #else 113 | public static readonly float MaxLinearVelocity = 200.0f; 114 | public static readonly float MaxLinearVelocitySquared = MaxLinearVelocity * MaxLinearVelocity; 115 | #endif 116 | /// 117 | /// The maximum angular velocity of a body. This limit is very large and is used 118 | /// to prevent numerical problems. You shouldn't need to adjust this. 119 | /// 120 | public static readonly float MaxAngularVelocity = 250.0f; 121 | #if !TARGET_FLOAT32_IS_FIXED 122 | public static readonly float MaxAngularVelocitySquared = MaxAngularVelocity * MaxAngularVelocity; 123 | #endif 124 | 125 | /// 126 | /// The maximum linear velocity of a body. This limit is very large and is used 127 | /// to prevent numerical problems. You shouldn't need to adjust this. 128 | /// 129 | public static readonly float MaxTranslation = 2.0f; 130 | public static readonly float MaxTranslationSquared = (MaxTranslation * MaxTranslation); 131 | 132 | /// 133 | /// The maximum angular velocity of a body. This limit is very large and is used 134 | /// to prevent numerical problems. You shouldn't need to adjust this. 135 | /// 136 | public static readonly float MaxRotation = (0.5f * Pi); 137 | public static readonly float MaxRotationSquared = (MaxRotation * MaxRotation); 138 | 139 | /// 140 | /// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so 141 | /// that overlap is removed in one time step. However using values close to 1 often lead to overshoot. 142 | /// 143 | public static readonly float ContactBaumgarte = 0.2f; 144 | 145 | // Sleep 146 | 147 | /// 148 | /// The time that a body must be still before it will go to sleep. 149 | /// 150 | public static readonly float TimeToSleep = 0.5f; // half a second 151 | 152 | /// 153 | /// A body cannot sleep if its linear velocity is above this tolerance. 154 | /// 155 | public static readonly float LinearSleepTolerance = 0.01f; // 1 cm/s 156 | 157 | /// 158 | /// A body cannot sleep if its angular velocity is above this tolerance. 159 | /// 160 | public static readonly float AngularSleepTolerance = 2.0f / 180.0f; // 2 degrees/s 161 | 162 | /// 163 | /// Friction mixing law. Feel free to customize this. 164 | /// 165 | public static float MixFriction(float friction1, float friction2) 166 | { 167 | return (float)System.Math.Sqrt(friction1 * friction2); 168 | } 169 | 170 | /// 171 | /// Restitution mixing law. Feel free to customize this. 172 | /// 173 | public static float MixRestitution(float restitution1, float restitution2) 174 | { 175 | return restitution1 > restitution2 ? restitution1 : restitution2; 176 | } 177 | } 178 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Sweep.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | //r175 20 | 21 | using System; using System.Numerics; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | 25 | 26 | namespace Box2DNet.Common 27 | { 28 | public struct Sweep 29 | { 30 | public Vector2 LocalCenter; //local center of mass position 31 | public Vector2 C0, C; //local center of mass position 32 | public float A0, A; //world angles 33 | public float T0; //time interval = [T0,1], where T0 is in [0,1] 34 | 35 | /// 36 | /// Get the interpolated Transform at a specific time. 37 | /// 38 | /// Alpha is a factor in [0,1], where 0 indicates t0. 39 | public void GetTransform(out Transform xf, float alpha) 40 | { 41 | xf = new Transform(); 42 | xf.position = (1.0f - alpha) * C0 + alpha * C; 43 | float angle = (1.0f - alpha) * A0 + alpha * A; 44 | 45 | xf.rotation = Box2DNet.Common.Math.AngleToRotation(angle); 46 | //xf.R = new Mat22(angle); 47 | 48 | // Shift to origin 49 | xf.position -= xf.TransformDirection(LocalCenter); 50 | } 51 | 52 | /// 53 | /// Advance the sweep forward, yielding a new initial state. 54 | /// 55 | /// The new initial time. 56 | public void Advance(float t) 57 | { 58 | if (T0 < t && 1.0f - T0 > Settings.FLT_EPSILON) 59 | { 60 | float alpha = (t - T0) / (1.0f - T0); 61 | C0 = (1.0f - alpha) * C0 + alpha * C; 62 | A0 = (1.0f - alpha) * A0 + alpha * A; 63 | T0 = t; 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Transform.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; 20 | using System.Numerics; 21 | using System.Collections.Generic; 22 | using System.Text; 23 | 24 | 25 | 26 | namespace Box2DNet.Common 27 | { 28 | /// 29 | /// A Transform contains translation and rotation. 30 | /// It is used to represent the position and orientation of rigid frames. 31 | /// 32 | public struct Transform 33 | { 34 | public Vector2 position; 35 | #if USE_MATRIX_FOR_ROTATION 36 | public Mat22 rotation; 37 | #else 38 | public Quaternion rotation; 39 | #endif 40 | 41 | #if USE_MATRIX_FOR_ROTATION 42 | /// 43 | /// Initialize using a position vector and a rotation matrix. 44 | /// 45 | /// 46 | /// 47 | public Transform(Vector2 position, Mat22 rotation) 48 | { 49 | this.position = position; 50 | this.rotation = rotation; 51 | } 52 | #else 53 | /// 54 | /// Initialize using a position vector and a rotation matrix. 55 | /// 56 | /// 57 | /// 58 | public Transform(Vector2 position, Quaternion rotation) 59 | { 60 | this.position = position; 61 | this.rotation = rotation; 62 | } 63 | #endif 64 | 65 | public Vector2 InverseTransformPoint(Vector2 vector) 66 | { 67 | #if USE_MATRIX_FOR_ROTATION 68 | return Math.MulT(rotation, vector - position); 69 | #else 70 | return Quaternion.Inverse(rotation).Xyz().ToVector2() * (vector - position); 71 | #endif 72 | } 73 | 74 | public Vector2 InverseTransformDirection(Vector2 vector) 75 | { 76 | #if USE_MATRIX_FOR_ROTATION 77 | return Math.MulT(rotation, vector); 78 | #else 79 | return Quaternion.Inverse(rotation).Xyz().ToVector2() * vector; 80 | #endif 81 | } 82 | 83 | public Vector2 TransformPoint(Vector2 vector) 84 | { 85 | #if USE_MATRIX_FOR_ROTATION 86 | return position + Math.Mul(rotation, vector); 87 | #else 88 | return position + (rotation.Xyz() * vector.ToVector3()).ToVector2(); 89 | #endif 90 | 91 | } 92 | 93 | // 94 | // Transforms direction from local space to world space. 95 | // 96 | public Vector2 TransformDirection(Vector2 vector) 97 | { 98 | #if USE_MATRIX_FOR_ROTATION 99 | return Math.Mul(rotation, vector); 100 | #else 101 | return (rotation.Xyz() * vector.ToVector3()).ToVector2(); 102 | #endif 103 | } 104 | 105 | #if USE_MATRIX_FOR_ROTATION 106 | public static readonly Transform identify = new Transform(Vector2.zero, Mat22.Identity); 107 | #else 108 | public static readonly Transform identity = new Transform(Vector2.Zero, Quaternion.Identity); 109 | #endif 110 | } 111 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | 4 | namespace Box2DNet.Common 5 | { 6 | public static class Utils 7 | { 8 | public static Vector3 Xyz(this Quaternion q) 9 | { 10 | return new Vector3(q.X,q.Y,q.Z); 11 | } 12 | 13 | public static void Normalize(this Vector2 v2) 14 | { 15 | var scale = 1.0f / v2.Length(); 16 | v2.X *= scale; 17 | v2.Y *= scale; 18 | } 19 | 20 | public static Vector2 Normalized(this Vector2 v2) 21 | { 22 | 23 | var scale = 1.0f / v2.Length(); 24 | v2.X *= scale; 25 | v2.Y *= scale; 26 | return v2; 27 | } 28 | /// 29 | /// Gets or sets the value at the index of the Vector. 30 | /// 31 | public static float GetByIndex(this Vector2 v2, int index) 32 | { 33 | 34 | if (index == 0) 35 | { 36 | return v2.X; 37 | } 38 | else if (index == 1) 39 | { 40 | return v2.Y; 41 | } 42 | throw new IndexOutOfRangeException("You tried to access this vector at index: " + index); 43 | 44 | } 45 | 46 | public static void SetByIndex(this Vector2 v2, int index, float value) 47 | { 48 | switch (index) 49 | { 50 | case 0: 51 | v2.X = value; 52 | break; 53 | case 1: 54 | v2.Y = value; 55 | break; 56 | default: 57 | throw new IndexOutOfRangeException("You tried to set this vector at index: " + index); 58 | } 59 | } 60 | 61 | } 62 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Vec2.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; using System.Numerics; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | namespace Box2DNet.Common 24 | { 25 | /// 26 | /// A 2D column vector. 27 | /// 28 | public struct Vec2 29 | { 30 | public float X, Y; 31 | 32 | public float this[int i] 33 | { 34 | get 35 | { 36 | if (i == 0) return X; 37 | else if (i == 1) return Y; 38 | else 39 | { 40 | Box2DNetDebug.Assert(false, "Incorrect Vec2 element!"); 41 | return 0; 42 | } 43 | } 44 | set 45 | { 46 | if (i == 0) X = value; 47 | else if (i == 1) Y = value; 48 | else 49 | { 50 | Box2DNetDebug.Assert(false, "Incorrect Vec2 element!"); 51 | } 52 | } 53 | } 54 | 55 | /// 56 | /// Construct using coordinates. 57 | /// 58 | public Vec2(float x) 59 | { 60 | X = x; 61 | Y = x; 62 | } 63 | 64 | /// 65 | /// Construct using coordinates. 66 | /// 67 | public Vec2(float x, float y) 68 | { 69 | X = x; 70 | Y = y; 71 | } 72 | 73 | /// 74 | /// Set this vector to all zeros. 75 | /// 76 | public void SetZero() { X = 0.0f; Y = 0.0f; } 77 | 78 | /// 79 | /// Set this vector to some specified coordinates. 80 | /// 81 | public void Set(float x, float y) { X = x; Y = y; } 82 | 83 | public void Set(float xy) { X = xy; Y = xy; } 84 | 85 | /// 86 | /// Get the length of this vector (the norm). 87 | /// 88 | public float Length() 89 | { 90 | return (float)System.Math.Sqrt(X * X + Y * Y); 91 | } 92 | 93 | /// 94 | /// Get the length squared. For performance, use this instead of 95 | /// Length (if possible). 96 | /// 97 | public float LengthSquared() 98 | { 99 | return X * X + Y * Y; 100 | } 101 | 102 | /// 103 | /// Convert this vector into a unit vector. Returns the length. 104 | /// 105 | public float Normalize() 106 | { 107 | float length = Length(); 108 | if (length < Settings.FLT_EPSILON) 109 | { 110 | return 0.0f; 111 | } 112 | float invLength = 1.0f / length; 113 | X *= invLength; 114 | Y *= invLength; 115 | 116 | return length; 117 | } 118 | 119 | /// 120 | /// Does this vector contain finite coordinates? 121 | /// 122 | public bool IsValid 123 | { 124 | get { return Math.IsValid(X) && Math.IsValid(Y); } 125 | } 126 | 127 | /// 128 | /// Negate this vector. 129 | /// 130 | public static Vec2 operator -(Vec2 v1) 131 | { 132 | Vec2 v = new Vec2(); 133 | v.Set(-v1.X, -v1.Y); 134 | return v; 135 | } 136 | 137 | public static Vec2 operator +(Vec2 v1, Vec2 v2) 138 | { 139 | Vec2 v = new Vec2(); 140 | v.Set(v1.X + v2.X, v1.Y + v2.Y); 141 | return v; 142 | } 143 | 144 | public static Vec2 operator -(Vec2 v1, Vec2 v2) 145 | { 146 | Vec2 v = new Vec2(); 147 | v.Set(v1.X - v2.X, v1.Y - v2.Y); 148 | return v; 149 | } 150 | 151 | public static Vec2 operator *(Vec2 v1, float a) 152 | { 153 | Vec2 v = new Vec2(); 154 | v.Set(v1.X * a, v1.Y * a); 155 | return v; 156 | } 157 | 158 | public static Vec2 operator *(float a, Vec2 v1) 159 | { 160 | Vec2 v = new Vec2(); 161 | v.Set(v1.X * a, v1.Y * a); 162 | return v; 163 | } 164 | 165 | public static bool operator ==(Vec2 a, Vec2 b) 166 | { 167 | return a.X == b.X && a.Y == b.Y; 168 | } 169 | 170 | public static bool operator !=(Vec2 a, Vec2 b) 171 | { 172 | return a.X != b.X || a.Y != b.Y; 173 | } 174 | 175 | public static Vec2 Zero { get { return new Vec2(0, 0); } } 176 | 177 | /// 178 | /// Peform the dot product on two vectors. 179 | /// 180 | public static float Dot(Vec2 a, Vec2 b) 181 | { 182 | return a.X * b.X + a.Y * b.Y; 183 | } 184 | 185 | /// 186 | /// Perform the cross product on two vectors. In 2D this produces a scalar. 187 | /// 188 | public static float Cross(Vec2 a, Vec2 b) 189 | { 190 | return a.X * b.Y - a.Y * b.X; 191 | } 192 | 193 | /// 194 | /// Perform the cross product on a vector and a scalar. 195 | /// In 2D this produces a vector. 196 | /// 197 | public static Vec2 Cross(Vec2 a, float s) 198 | { 199 | Vec2 v = new Vec2(); 200 | v.Set(s * a.Y, -s * a.X); 201 | return v; 202 | } 203 | 204 | /// 205 | /// Perform the cross product on a scalar and a vector. 206 | /// In 2D this produces a vector. 207 | /// 208 | public static Vec2 Cross(float s, Vec2 a) 209 | { 210 | Vec2 v = new Vec2(); 211 | v.Set(-s * a.Y, s * a.X); 212 | return v; 213 | } 214 | 215 | public static float Distance(Vec2 a, Vec2 b) 216 | { 217 | Vec2 c = a - b; 218 | return c.Length(); 219 | } 220 | 221 | public static float DistanceSquared(Vec2 a, Vec2 b) 222 | { 223 | Vec2 c = a - b; 224 | return Vec2.Dot(c, c); 225 | } 226 | } 227 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/Vec3.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | //r175 20 | 21 | using System; using System.Numerics; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | 25 | namespace Box2DNet.Common 26 | { 27 | /// 28 | /// A 2D column vector with 3 elements. 29 | /// 30 | public struct Vec3 31 | { 32 | /// 33 | /// Construct using coordinates. 34 | /// 35 | public Vec3(float x, float y, float z) { X = x; Y = y; Z = z; } 36 | 37 | /// 38 | /// Set this vector to all zeros. 39 | /// 40 | public void SetZero() { X = 0.0f; Y = 0.0f; Z = 0.0f; } 41 | 42 | /// 43 | /// Set this vector to some specified coordinates. 44 | /// 45 | public void Set(float x, float y, float z) { X = x; Y = y; Z = z; } 46 | 47 | /// 48 | /// Perform the dot product on two vectors. 49 | /// 50 | public static float Dot(Vec3 a, Vec3 b) 51 | { 52 | return a.X * b.X + a.Y * b.Y + a.Z * b.Z; 53 | } 54 | 55 | /// 56 | /// Perform the cross product on two vectors. 57 | /// 58 | public static Vec3 Cross(Vec3 a, Vec3 b) 59 | { 60 | return new Vec3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X); 61 | } 62 | 63 | /// 64 | /// Negate this vector. 65 | /// 66 | public static Vec3 operator -(Vec3 v) 67 | { 68 | return new Vec3(-v.X, -v.Y, -v.Z); 69 | } 70 | 71 | /// 72 | /// Add two vectors component-wise. 73 | /// 74 | public static Vec3 operator +(Vec3 v1, Vec3 v2) 75 | { 76 | return new Vec3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); 77 | } 78 | 79 | /// 80 | /// Subtract two vectors component-wise. 81 | /// 82 | public static Vec3 operator -(Vec3 v1, Vec3 v2) 83 | { 84 | return new Vec3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); 85 | } 86 | 87 | /// 88 | /// Multiply this vector by a scalar. 89 | /// 90 | public static Vec3 operator *(Vec3 v, float s) 91 | { 92 | return new Vec3(v.X * s, v.Y * s, v.Z * s); 93 | } 94 | 95 | /// 96 | /// Multiply this vector by a scalar. 97 | /// 98 | public static Vec3 operator *(float s, Vec3 v) 99 | { 100 | return new Vec3(v.X * s, v.Y * s, v.Z * s); 101 | } 102 | 103 | public float X, Y, Z; 104 | } 105 | } -------------------------------------------------------------------------------- /src/Box2DNet/Common/XForm.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 1. The origin of this software must not be misrepresented; you must not 11 | claim that you wrote the original software. If you use this software 12 | in a product, an acknowledgment in the product documentation would be 13 | appreciated but is not required. 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original software. 16 | 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System; using System.Numerics; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | 24 | namespace Box2DNet.Common 25 | { 26 | /// 27 | /// A transform contains translation and rotation. 28 | /// It is used to represent the position and orientation of rigid frames. 29 | /// 30 | public struct XForm 31 | { 32 | public Vector2 position; 33 | public Mat22 R; 34 | 35 | /// 36 | /// Initialize using a position vector and a rotation matrix. 37 | /// 38 | /// 39 | /// 40 | public XForm(Vector2 p, Mat22 rotation) 41 | { 42 | position = p; 43 | R = rotation; 44 | } 45 | 46 | /// 47 | /// Set this to the identity transform. 48 | /// 49 | public void SetIdentity() 50 | { 51 | position = Vector2.Zero; 52 | R = Mat22.Identity; 53 | } 54 | 55 | /// Set this based on the position and angle. 56 | public void Set(Vector2 p, float angle) 57 | { 58 | position = p; 59 | R = new Mat22(angle); 60 | } 61 | 62 | /// Calculate the angle that the rotation matrix represents. 63 | public float GetAngle() 64 | { 65 | return Math.Atan2(R.Col1.Y, R.Col1.X); 66 | } 67 | 68 | public Vector2 TransformDirection(Vector2 vector) 69 | { 70 | return Math.Mul(R, vector); 71 | } 72 | 73 | public Vector2 InverseTransformDirection(Vector2 vector) 74 | { 75 | return Math.MulT(R, vector); 76 | } 77 | 78 | public Vector2 TransformPoint(Vector2 vector) 79 | { 80 | return position + Math.Mul(R, vector); 81 | } 82 | 83 | public Vector2 InverseTransformPoint(Vector2 vector) 84 | { 85 | return Math.MulT(R, vector - position); 86 | } 87 | 88 | public static XForm Identity { get { return new XForm(Vector2.Zero, Mat22.Identity); } } 89 | } 90 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/ContactManager.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | 24 | namespace Box2DNet.Dynamics 25 | { 26 | /// 27 | // Delegate of World. 28 | /// 29 | public class ContactManager : PairCallback 30 | { 31 | public World _world; 32 | 33 | // This lets us provide broadphase proxy pair user data for 34 | // contacts that shouldn't exist. 35 | public NullContact _nullContact; 36 | 37 | public bool _destroyImmediate; 38 | 39 | public ContactManager() { } 40 | 41 | // This is a callback from the broadphase when two AABB proxies begin 42 | // to overlap. We create a Contact to manage the narrow phase. 43 | public override object PairAdded(object proxyUserDataA, object proxyUserDataB) 44 | { 45 | Fixture fixtureA = proxyUserDataA as Fixture; 46 | Fixture fixtureB = proxyUserDataB as Fixture; 47 | 48 | Body bodyA = fixtureA.Body; 49 | Body bodyB = fixtureB.Body; 50 | 51 | if (bodyA.IsStatic() && bodyB.IsStatic()) 52 | { 53 | return _nullContact; 54 | } 55 | 56 | if (fixtureA.Body == fixtureB.Body) 57 | { 58 | return _nullContact; 59 | } 60 | 61 | if (bodyB.IsConnected(bodyA)) 62 | { 63 | return _nullContact; 64 | } 65 | 66 | if (_world._contactFilter != null && _world._contactFilter.ShouldCollide(fixtureA, fixtureB) == false) 67 | { 68 | return _nullContact; 69 | } 70 | 71 | // Call the factory. 72 | Contact c = Contact.Create(fixtureA, fixtureB); 73 | 74 | if (c == null) 75 | { 76 | return _nullContact; 77 | } 78 | 79 | // Contact creation may swap shapes. 80 | fixtureA = c.FixtureA; 81 | fixtureB = c.FixtureB; 82 | bodyA = fixtureA.Body; 83 | bodyB = fixtureB.Body; 84 | 85 | // Insert into the world. 86 | c._prev = null; 87 | c._next = _world._contactList; 88 | if (_world._contactList != null) 89 | { 90 | _world._contactList._prev = c; 91 | } 92 | _world._contactList = c; 93 | 94 | // Connect to island graph. 95 | 96 | // Connect to body 1 97 | c._nodeA.Contact = c; 98 | c._nodeA.Other = bodyB; 99 | 100 | c._nodeA.Prev = null; 101 | c._nodeA.Next = bodyA._contactList; 102 | if (bodyA._contactList != null) 103 | { 104 | bodyA._contactList.Prev = c._nodeA; 105 | } 106 | bodyA._contactList = c._nodeA; 107 | 108 | // Connect to body 2 109 | c._nodeB.Contact = c; 110 | c._nodeB.Other = bodyA; 111 | 112 | c._nodeB.Prev = null; 113 | c._nodeB.Next = bodyB._contactList; 114 | if (bodyB._contactList != null) 115 | { 116 | bodyB._contactList.Prev = c._nodeB; 117 | } 118 | bodyB._contactList = c._nodeB; 119 | 120 | ++_world._contactCount; 121 | return c; 122 | } 123 | 124 | // This is a callback from the broadphase when two AABB proxies cease 125 | // to overlap. We retire the Contact. 126 | public override void PairRemoved(object proxyUserData1, object proxyUserData2, object pairUserData) 127 | { 128 | //B2_NOT_USED(proxyUserData1); 129 | //B2_NOT_USED(proxyUserData2); 130 | 131 | if (pairUserData == null) 132 | { 133 | return; 134 | } 135 | 136 | Contact c = pairUserData as Contact; 137 | if (c == _nullContact) 138 | { 139 | return; 140 | } 141 | 142 | // An attached body is being destroyed, we must destroy this contact 143 | // immediately to avoid orphaned shape pointers. 144 | Destroy(c); 145 | } 146 | 147 | public void Destroy(Contact c) 148 | { 149 | Fixture fixtureA = c.FixtureA; 150 | Fixture fixtureB = c.FixtureB; 151 | Body bodyA = fixtureA.Body; 152 | Body bodyB = fixtureB.Body; 153 | 154 | if (c.Manifold.PointCount > 0) 155 | { 156 | if(_world._contactListener!=null) 157 | _world._contactListener.EndContact(c); 158 | } 159 | 160 | // Remove from the world. 161 | if (c._prev != null) 162 | { 163 | c._prev._next = c._next; 164 | } 165 | 166 | if (c._next != null) 167 | { 168 | c._next._prev = c._prev; 169 | } 170 | 171 | if (c == _world._contactList) 172 | { 173 | _world._contactList = c._next; 174 | } 175 | 176 | // Remove from body 1 177 | if (c._nodeA.Prev != null) 178 | { 179 | c._nodeA.Prev.Next = c._nodeA.Next; 180 | } 181 | 182 | if (c._nodeA.Next != null) 183 | { 184 | c._nodeA.Next.Prev = c._nodeA.Prev; 185 | } 186 | 187 | if (c._nodeA == bodyA._contactList) 188 | { 189 | bodyA._contactList = c._nodeA.Next; 190 | } 191 | 192 | // Remove from body 2 193 | if (c._nodeB.Prev != null) 194 | { 195 | c._nodeB.Prev.Next = c._nodeB.Next; 196 | } 197 | 198 | if (c._nodeB.Next != null) 199 | { 200 | c._nodeB.Next.Prev = c._nodeB.Prev; 201 | } 202 | 203 | if (c._nodeB == bodyB._contactList) 204 | { 205 | bodyB._contactList = c._nodeB.Next; 206 | } 207 | 208 | // Call the factory. 209 | Contact.Destroy(ref c); 210 | --_world._contactCount; 211 | } 212 | 213 | // This is the top level collision call for the time step. Here 214 | // all the narrow phase collision is processed for the world 215 | // contact list. 216 | public void Collide() 217 | { 218 | // Update awake contacts. 219 | for (Contact c = _world._contactList; c != null; c = c.GetNext()) 220 | { 221 | Body bodyA = c._fixtureA.Body; 222 | Body bodyB = c._fixtureB.Body; 223 | if (bodyA.IsSleeping() && bodyB.IsSleeping()) 224 | { 225 | continue; 226 | } 227 | 228 | c.Update(_world._contactListener); 229 | } 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Contacts/CircleContact.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | using Box2DNet.Common; 24 | 25 | namespace Box2DNet.Dynamics 26 | { 27 | public class CircleContact : Contact 28 | { 29 | public CircleContact(Fixture fixtureA, Fixture fixtureB) 30 | : base(fixtureA, fixtureB) 31 | { 32 | Box2DNetDebug.Assert(fixtureA.ShapeType == ShapeType.CircleShape); 33 | Box2DNetDebug.Assert(fixtureB.ShapeType == ShapeType.CircleShape); 34 | CollideShapeFunction = CollideCircles; 35 | } 36 | 37 | private static void CollideCircles(ref Manifold manifold, Shape shape1, Transform xf1, Shape shape2, Transform xf2) 38 | { 39 | Collision.Collision.CollideCircles(ref manifold, (CircleShape)shape1, xf1, (CircleShape)shape2, xf2); 40 | } 41 | 42 | new public static Contact Create(Fixture fixtureA, Fixture fixtureB) 43 | { 44 | return new CircleContact(fixtureA, fixtureB); 45 | } 46 | 47 | new public static void Destroy(ref Contact contact) 48 | { 49 | contact = null; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Contacts/EdgeAndCircleContact.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | using Box2DNet.Common; 24 | 25 | namespace Box2DNet.Dynamics 26 | { 27 | public class EdgeAndCircleContact : Contact 28 | { 29 | public EdgeAndCircleContact(Fixture fixtureA, Fixture fixtureB) 30 | : base(fixtureA, fixtureB) 31 | { 32 | Box2DNetDebug.Assert(fixtureA.ShapeType == ShapeType.EdgeShape); 33 | Box2DNetDebug.Assert(fixtureB.ShapeType == ShapeType.CircleShape); 34 | _manifold.PointCount = 0; 35 | _manifold.Points[0].NormalImpulse = 0.0f; 36 | _manifold.Points[0].TangentImpulse = 0.0f; 37 | CollideShapeFunction = CollideEdgeAndCircle; 38 | } 39 | 40 | private static void CollideEdgeAndCircle(ref Manifold manifold, Shape shape1, Transform xf1, Shape shape2, Transform xf2) 41 | { 42 | Collision.Collision.CollideEdgeAndCircle(ref manifold, (EdgeShape)shape1, xf1, (CircleShape)shape2, xf2); 43 | } 44 | 45 | new public static Contact Create(Fixture fixtureA, Fixture fixtureB) 46 | { 47 | return new EdgeAndCircleContact(fixtureA, fixtureB); 48 | } 49 | 50 | new public static void Destroy(ref Contact contact) 51 | { 52 | contact = null; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Contacts/NullContact.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | using Box2DNet.Common; 24 | 25 | namespace Box2DNet.Dynamics 26 | { 27 | public class NullContact : Contact 28 | { 29 | public NullContact() 30 | { 31 | CollideShapeFunction = Collide; 32 | } 33 | private static void Collide(ref Manifold manifold, Shape shape1, Transform xf1, Shape shape2, Transform xf2) { } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Contacts/PolyAndCircleContact.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | using Box2DNet.Common; 24 | 25 | using Transform = Box2DNet.Common.Transform; 26 | 27 | namespace Box2DNet.Dynamics 28 | { 29 | public class PolyAndCircleContact : Contact 30 | { 31 | public PolyAndCircleContact(Fixture fixtureA, Fixture fixtureB) 32 | : base(fixtureA, fixtureB) 33 | { 34 | Box2DNetDebug.Assert(fixtureA.ShapeType == ShapeType.PolygonShape); 35 | Box2DNetDebug.Assert(fixtureB.ShapeType == ShapeType.CircleShape); 36 | CollideShapeFunction = CollidePolygonCircle; 37 | } 38 | 39 | private static void CollidePolygonCircle(ref Manifold manifold, Shape shape1, Transform xf1, Shape shape2, Transform xf2) 40 | { 41 | Collision.Collision.CollidePolygonAndCircle(ref manifold, (PolygonShape)shape1, xf1, (CircleShape)shape2, xf2); 42 | } 43 | 44 | new public static Contact Create(Fixture fixtureA, Fixture fixtureB) 45 | { 46 | return new PolyAndCircleContact(fixtureA, fixtureB); 47 | } 48 | 49 | new public static void Destroy(ref Contact contact) 50 | { 51 | contact = null; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Contacts/PolyAndEdgeContact.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | using Box2DNet.Common; 24 | 25 | using Transform = Box2DNet.Common.Transform; 26 | 27 | namespace Box2DNet.Dynamics 28 | { 29 | public class PolyAndEdgeContact : Contact 30 | { 31 | public PolyAndEdgeContact(Fixture fixtureA, Fixture fixtureB) 32 | : base(fixtureA, fixtureB) 33 | { 34 | Box2DNetDebug.Assert(fixtureA.ShapeType == ShapeType.PolygonShape); 35 | Box2DNetDebug.Assert(fixtureB.ShapeType == ShapeType.EdgeShape); 36 | CollideShapeFunction = CollidePolyAndEdgeContact; 37 | } 38 | 39 | private static void CollidePolyAndEdgeContact(ref Manifold manifold, Shape shape1, Transform xf1, Shape shape2, Transform xf2) 40 | { 41 | Collision.Collision.CollidePolyAndEdge(ref manifold, (PolygonShape)shape1, xf1, (EdgeShape)shape2, xf2); 42 | } 43 | 44 | new public static Contact Create(Fixture fixtureA, Fixture fixtureB) 45 | { 46 | return new PolyAndEdgeContact(fixtureA, fixtureB); 47 | } 48 | 49 | new public static void Destroy(ref Contact contact) 50 | { 51 | contact = null; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Contacts/PolyContact.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using Box2DNet.Collision; 23 | using Box2DNet.Common; 24 | 25 | namespace Box2DNet.Dynamics 26 | { 27 | public class PolygonContact : Contact 28 | { 29 | public PolygonContact(Fixture fixtureA, Fixture fixtureB) 30 | : base(fixtureA, fixtureB) 31 | { 32 | Box2DNetDebug.Assert(fixtureA.ShapeType == ShapeType.PolygonShape); 33 | Box2DNetDebug.Assert(fixtureB.ShapeType == ShapeType.PolygonShape); 34 | CollideShapeFunction = CollidePolygons; 35 | } 36 | 37 | private static void CollidePolygons(ref Manifold manifold, Shape shape1, Transform xf1, Shape shape2, Transform xf2) 38 | { 39 | Collision.Collision.CollidePolygons(ref manifold, (PolygonShape)shape1, xf1, (PolygonShape)shape2, xf2); 40 | } 41 | 42 | new public static Contact Create(Fixture fixtureA, Fixture fixtureB) 43 | { 44 | return new PolygonContact(fixtureA, fixtureB); 45 | } 46 | 47 | new public static void Destroy(ref Contact contact) 48 | { 49 | contact = null; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Controllers/BuoyancyController.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Box2DNet.Common; 3 | 4 | 5 | namespace Box2DNet.Dynamics.Controllers 6 | { 7 | /// 8 | /// This class is used to build buoyancy controllers 9 | /// 10 | public class BuoyancyControllerDef 11 | { 12 | /// The outer surface normal 13 | public Vector2 Normal; 14 | /// The height of the fluid surface along the normal 15 | public float Offset; 16 | /// The fluid density 17 | public float Density; 18 | /// Fluid velocity, for drag calculations 19 | public Vector2 Velocity; 20 | /// Linear drag co-efficient 21 | public float LinearDrag; 22 | /// Linear drag co-efficient 23 | public float AngularDrag; 24 | /// If false, bodies are assumed to be uniformly dense, otherwise use the shapes densities 25 | public bool UseDensity; //False by default to prevent a gotcha 26 | /// If true, gravity is taken from the world instead of the gravity parameter. 27 | public bool UseWorldGravity; 28 | /// Gravity vector, if the world's gravity is not used 29 | public Vector2 Gravity; 30 | 31 | public BuoyancyControllerDef() 32 | { 33 | Normal = new Vector2(0, 1); 34 | Offset = 0; 35 | Density = 0; 36 | Velocity = Vector2.Zero; 37 | LinearDrag = 0; 38 | AngularDrag = 0; 39 | UseDensity = false; 40 | UseWorldGravity = true; 41 | Gravity = Vector2.Zero; 42 | } 43 | } 44 | 45 | /// 46 | /// Calculates buoyancy forces for fluids in the form of a half plane. 47 | /// 48 | public class BuoyancyController : Controller 49 | { 50 | /// The outer surface normal 51 | public Vector2 Normal; 52 | /// The height of the fluid surface along the normal 53 | public float Offset; 54 | /// The fluid density 55 | public float Density; 56 | /// Fluid velocity, for drag calculations 57 | public Vector2 Velocity; 58 | /// Linear drag co-efficient 59 | public float LinearDrag; 60 | /// Linear drag co-efficient 61 | public float AngularDrag; 62 | /// If false, bodies are assumed to be uniformly dense, otherwise use the shapes densities 63 | public bool UseDensity; //False by default to prevent a gotcha 64 | /// If true, gravity is taken from the world instead of the gravity parameter. 65 | public bool UseWorldGravity; 66 | /// Gravity vector, if the world's gravity is not used 67 | public Vector2 Gravity; 68 | 69 | public BuoyancyController(BuoyancyControllerDef buoyancyControllerDef) 70 | { 71 | Normal = buoyancyControllerDef.Normal; 72 | Offset = buoyancyControllerDef.Offset; 73 | Density = buoyancyControllerDef.Density; 74 | Velocity = buoyancyControllerDef.Velocity; 75 | LinearDrag = buoyancyControllerDef.LinearDrag; 76 | AngularDrag = buoyancyControllerDef.AngularDrag; 77 | UseDensity = buoyancyControllerDef.UseDensity; 78 | UseWorldGravity = buoyancyControllerDef.UseWorldGravity; 79 | Gravity = buoyancyControllerDef.Gravity; 80 | } 81 | 82 | public override void Step(TimeStep step) 83 | { 84 | //B2_NOT_USED(step); 85 | if (_bodyList == null) 86 | return; 87 | 88 | if (UseWorldGravity) 89 | { 90 | Gravity = _world.Gravity; 91 | } 92 | for (ControllerEdge i = _bodyList; i != null; i = i.nextBody) 93 | { 94 | Body body = i.body; 95 | if (body.IsSleeping()) 96 | { 97 | //Buoyancy force is just a function of position, 98 | //so unlike most forces, it is safe to ignore sleeping bodes 99 | continue; 100 | } 101 | Vector2 areac = Vector2.Zero; 102 | Vector2 massc = Vector2.Zero; 103 | float area = 0; 104 | float mass = 0; 105 | for (Fixture shape = body.GetFixtureList(); shape != null; shape = shape.Next) 106 | { 107 | Vector2 sc; 108 | float sarea = shape.ComputeSubmergedArea(Normal, Offset, out sc); 109 | area += sarea; 110 | areac.X += sarea * sc.X; 111 | areac.Y += sarea * sc.Y; 112 | float shapeDensity = 0; 113 | if (UseDensity) 114 | { 115 | //TODO: Expose density publicly 116 | shapeDensity = shape.Density; 117 | } 118 | else 119 | { 120 | shapeDensity = 1; 121 | } 122 | mass += sarea * shapeDensity; 123 | massc.X += sarea * sc.X * shapeDensity; 124 | massc.Y += sarea * sc.Y * shapeDensity; 125 | } 126 | areac.X /= area; 127 | areac.Y /= area; 128 | //Vec2 localCentroid = Math.MulT(body.GetTransform(), areac); 129 | massc.X /= mass; 130 | massc.Y /= mass; 131 | if (area < Settings.FLT_EPSILON) 132 | continue; 133 | //Buoyancy 134 | Vector2 buoyancyForce = -Density * area * Gravity; 135 | body.ApplyForce(buoyancyForce, massc); 136 | //Linear drag 137 | Vector2 dragForce = body.GetLinearVelocityFromWorldPoint(areac) - Velocity; 138 | dragForce *= -LinearDrag * area; 139 | body.ApplyForce(dragForce, areac); 140 | //Angular drag 141 | //TODO: Something that makes more physical sense? 142 | body.ApplyTorque(-body.GetInertia() / body.GetMass() * area * body.GetAngularVelocity() * AngularDrag); 143 | 144 | } 145 | } 146 | 147 | public override void Draw(DebugDraw debugDraw) 148 | { 149 | float r = 1000; 150 | Vector2 p1 = Offset * Normal + Normal.CrossScalarPostMultiply(r); 151 | Vector2 p2 = Offset * Normal - Normal.CrossScalarPostMultiply(r); 152 | 153 | Color color = new Color(0, 0, 0.8f); 154 | 155 | debugDraw.DrawSegment(p1, p2, color); 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Controllers/ConstantAccelController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked as such, and must not be 15 | * misrepresented as being the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using Box2DNet.Common; 20 | using System.Numerics; 21 | 22 | namespace Box2DNet.Dynamics.Controllers 23 | { 24 | 25 | /// This class is used to build constant acceleration controllers 26 | public class ConstantAccelControllerDef 27 | { 28 | /// 29 | /// The force to apply 30 | /// 31 | public Vector2 A; 32 | } 33 | 34 | public class ConstantAccelController : Controller 35 | { 36 | /// 37 | /// The force to apply 38 | /// 39 | public Vector2 A; 40 | 41 | public ConstantAccelController(ConstantAccelControllerDef def) 42 | { 43 | A = def.A; 44 | } 45 | 46 | public override void Step(TimeStep step) 47 | { 48 | for (ControllerEdge i = _bodyList; i != null; i = i.nextBody) 49 | { 50 | Body body = i.body; 51 | if (body.IsSleeping()) 52 | continue; 53 | body.SetLinearVelocity(body.GetLinearVelocity() + step.Dt * A); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Controllers/ConstantForceController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked as such, and must not be 15 | * misrepresented as being the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using Box2DNet.Common; 20 | 21 | using System.Numerics; 22 | namespace Box2DNet.Dynamics.Controllers 23 | { 24 | 25 | /// 26 | /// This class is used to build constant force controllers 27 | /// 28 | public class ConstantForceControllerDef 29 | { 30 | /// The force to apply 31 | public Vector2 F; 32 | } 33 | 34 | public class ConstantForceController : Controller 35 | { 36 | /// 37 | /// The force to apply 38 | /// 39 | Vector2 F; 40 | 41 | public ConstantForceController(ConstantForceControllerDef def) 42 | { 43 | F = def.F; 44 | } 45 | 46 | public override void Step(TimeStep step) 47 | { 48 | //B2_NOT_USED(step); 49 | for (ControllerEdge i = _bodyList; i != null; i = i.nextBody) 50 | { 51 | Body body = i.body; 52 | if (body.IsSleeping()) 53 | continue; 54 | body.ApplyForce(F, body.GetWorldCenter()); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Controllers/Controller.cs: -------------------------------------------------------------------------------- 1 | using System; using System.Numerics; 2 | 3 | namespace Box2DNet.Dynamics.Controllers 4 | { 5 | /// 6 | /// A controller edge is used to connect bodies and controllers together 7 | /// in a bipartite graph. 8 | /// 9 | public class ControllerEdge 10 | { 11 | public Controller controller; // provides quick access to other end of this edge. 12 | public Body body; // the body 13 | public ControllerEdge prevBody; // the previous controller edge in the controllers's joint list 14 | public ControllerEdge nextBody; // the next controller edge in the controllers's joint list 15 | public ControllerEdge prevController; // the previous controller edge in the body's joint list 16 | public ControllerEdge nextController; // the next controller edge in the body's joint list 17 | } 18 | 19 | /// 20 | /// Base class for controllers. Controllers are a convience for encapsulating common 21 | /// per-step functionality. 22 | /// 23 | public abstract class Controller : IDisposable 24 | { 25 | internal Controller _prev; 26 | internal Controller _next; 27 | 28 | internal World _world; 29 | protected ControllerEdge _bodyList; 30 | protected int _bodyCount; 31 | 32 | public Controller() 33 | { 34 | _bodyList = null; 35 | _bodyCount = 0; 36 | } 37 | 38 | public Controller(World world) 39 | { 40 | _bodyList = null; 41 | _bodyCount = 0; 42 | 43 | _world = world; 44 | } 45 | 46 | public void Dispose() 47 | { 48 | //Remove attached bodies 49 | 50 | //Previus implementation: 51 | //while (_bodyCount > 0) 52 | // RemoveBody(_bodyList.body); 53 | 54 | Clear(); 55 | } 56 | 57 | /// 58 | /// Controllers override this to implement per-step functionality. 59 | /// 60 | public abstract void Step(TimeStep step); 61 | 62 | /// 63 | /// Controllers override this to provide debug drawing. 64 | /// 65 | public virtual void Draw(DebugDraw debugDraw) { } 66 | 67 | /// 68 | /// Adds a body to the controller list. 69 | /// 70 | public void AddBody(Body body) 71 | { 72 | ControllerEdge edge = new ControllerEdge(); 73 | 74 | edge.body = body; 75 | edge.controller = this; 76 | 77 | //Add edge to controller list 78 | edge.nextBody = _bodyList; 79 | edge.prevBody = null; 80 | if (_bodyList != null) 81 | _bodyList.prevBody = edge; 82 | _bodyList = edge; 83 | ++_bodyCount; 84 | 85 | //Add edge to body list 86 | edge.nextController = body._controllerList; 87 | edge.prevController = null; 88 | if (body._controllerList != null) 89 | body._controllerList.prevController = edge; 90 | body._controllerList = edge; 91 | } 92 | 93 | /// 94 | /// Removes a body from the controller list. 95 | /// 96 | public void RemoveBody(Body body) 97 | { 98 | //Assert that the controller is not empty 99 | Box2DNetDebug.Assert(_bodyCount > 0); 100 | 101 | //Find the corresponding edge 102 | ControllerEdge edge = _bodyList; 103 | while (edge != null && edge.body != body) 104 | edge = edge.nextBody; 105 | 106 | //Assert that we are removing a body that is currently attached to the controller 107 | Box2DNetDebug.Assert(edge != null); 108 | 109 | //Remove edge from controller list 110 | if (edge.prevBody != null) 111 | edge.prevBody.nextBody = edge.nextBody; 112 | if (edge.nextBody != null) 113 | edge.nextBody.prevBody = edge.prevBody; 114 | if (edge == _bodyList) 115 | _bodyList = edge.nextBody; 116 | --_bodyCount; 117 | 118 | //Remove edge from body list 119 | if (edge.prevController != null) 120 | edge.prevController.nextController = edge.nextController; 121 | if (edge.nextController != null) 122 | edge.nextController.prevController = edge.prevController; 123 | if (edge == body._controllerList) 124 | body._controllerList = edge.nextController; 125 | 126 | //Free the edge 127 | edge = null; 128 | } 129 | 130 | /// 131 | /// Removes all bodies from the controller list. 132 | /// 133 | public void Clear() 134 | { 135 | #warning "Check this" 136 | ControllerEdge current = _bodyList; 137 | while (current != null) 138 | { 139 | ControllerEdge edge = current; 140 | 141 | //Remove edge from controller list 142 | _bodyList = edge.nextBody; 143 | 144 | //Remove edge from body list 145 | if (edge.prevController != null) 146 | edge.prevController.nextController = edge.nextController; 147 | if (edge.nextController != null) 148 | edge.nextController.prevController = edge.prevController; 149 | if (edge == edge.body._controllerList) 150 | edge.body._controllerList = edge.nextController; 151 | 152 | //Free the edge 153 | //m_world->m_blockAllocator.Free(edge, sizeof(b2ControllerEdge)); 154 | } 155 | 156 | _bodyCount = 0; 157 | } 158 | 159 | /// 160 | /// Get the next body in the world's body list. 161 | /// 162 | internal Controller GetNext() { return _next; } 163 | 164 | /// 165 | /// Get the parent world of this body. 166 | /// 167 | internal World GetWorld() { return _world; } 168 | 169 | /// 170 | /// Get the attached body list 171 | /// 172 | internal ControllerEdge GetBodyList() { return _bodyList; } 173 | } 174 | } -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Controllers/GravityController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked as such, and must not be 15 | * misrepresented as being the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using System.Numerics; 20 | using Box2DNet.Common; 21 | using Math = Box2DNet.Common.Math; 22 | 23 | 24 | 25 | namespace Box2DNet.Dynamics.Controllers 26 | { 27 | /// This class is used to build gravity controllers 28 | public class GravityControllerDef 29 | { 30 | /// 31 | /// Specifies the strength of the gravitiation force 32 | /// 33 | public float G; 34 | 35 | /// 36 | /// If true, gravity is proportional to r^-2, otherwise r^-1 37 | /// 38 | public bool InvSqr; 39 | } 40 | 41 | public class GravityController : Controller 42 | { 43 | /// 44 | /// Specifies the strength of the gravitiation force 45 | /// 46 | public float G; 47 | 48 | /// If true, gravity is proportional to r^-2, otherwise r^-1 49 | public bool InvSqr; 50 | 51 | public GravityController(GravityControllerDef def) 52 | { 53 | G = def.G; 54 | InvSqr = def.InvSqr; 55 | } 56 | 57 | public override void Step(TimeStep step) 58 | { 59 | //B2_NOT_USED(step); 60 | if (InvSqr) 61 | { 62 | for (ControllerEdge i = _bodyList; i != null; i = i.nextBody) 63 | { 64 | Body body1 = i.body; 65 | for (ControllerEdge j = _bodyList; j != i; j = j.nextBody) 66 | { 67 | Body body2 = j.body; 68 | Vector2 d = body2.GetWorldCenter() - body1.GetWorldCenter(); 69 | float r2 = d.LengthSquared(); 70 | if (r2 < Settings.FLT_EPSILON) 71 | continue; 72 | 73 | Vector2 f = G / r2 / Math.Sqrt(r2) * body1.GetMass() * body2.GetMass() * d; 74 | body1.ApplyForce(f, body1.GetWorldCenter()); 75 | body2.ApplyForce(-1.0f * f, body2.GetWorldCenter()); 76 | } 77 | } 78 | } 79 | else 80 | { 81 | for (ControllerEdge i = _bodyList; i != null; i = i.nextBody) 82 | { 83 | Body body1 = i.body; 84 | for (ControllerEdge j = _bodyList; j != i; j = j.nextBody) 85 | { 86 | Body body2 = j.body; 87 | Vector2 d = body2.GetWorldCenter() - body1.GetWorldCenter(); 88 | float r2 = d.LengthSquared(); 89 | if (r2 < Settings.FLT_EPSILON) 90 | continue; 91 | Vector2 f = G / r2 * body1.GetMass() * body2.GetMass() * d; 92 | body1.ApplyForce(f, body1.GetWorldCenter()); 93 | body2.ApplyForce(-1.0f * f, body2.GetWorldCenter()); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Controllers/TensorDampingController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked as such, and must not be 15 | * misrepresented as being the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | using Box2DNet.Common; 20 | 21 | using System.Numerics; 22 | 23 | namespace Box2DNet.Dynamics.Controllers 24 | { 25 | 26 | /// 27 | /// This class is used to build tensor damping controllers 28 | /// 29 | public class b2TensorDampingControllerDef 30 | { 31 | /// Tensor to use in damping model 32 | Mat22 T; 33 | /// Set this to a positive number to clamp the maximum amount of damping done. 34 | float maxTimestep; 35 | }; 36 | 37 | public class TensorDampingController : Controller 38 | { 39 | 40 | /// 41 | /// Tensor to use in damping model 42 | /// Some examples (matrixes in format (row1; row2) ) 43 | ///(-a 0;0 -a) Standard isotropic damping with strength a 44 | ///(0 a;-a 0) Electron in fixed field - a force at right angles to velocity with proportional magnitude 45 | ///(-a 0;0 -b) Differing x and y damping. Useful e.g. for top-down wheels. 46 | ///By the way, tensor in this case just means matrix, don't let the terminology get you down. 47 | /// 48 | Mat22 T; 49 | 50 | /// 51 | /// Set this to a positive number to clamp the maximum amount of damping done. 52 | /// Typically one wants maxTimestep to be 1/(max eigenvalue of T), so that damping will never cause something to reverse direction 53 | /// 54 | float MaxTimestep; 55 | 56 | /// Sets damping independantly along the x and y axes 57 | public void SetAxisAligned(float xDamping, float yDamping) 58 | { 59 | T.Col1.X = -xDamping; 60 | T.Col1.Y = 0; 61 | T.Col2.X = 0; 62 | T.Col2.Y = -yDamping; 63 | if (xDamping > 0 || yDamping > 0) 64 | { 65 | MaxTimestep = 1 / Math.Max(xDamping, yDamping); 66 | } 67 | else 68 | { 69 | MaxTimestep = 0; 70 | } 71 | } 72 | 73 | public override void Step(TimeStep step) 74 | { 75 | float timestep = step.Dt; 76 | if (timestep <= Settings.FLT_EPSILON) 77 | return; 78 | if (timestep > MaxTimestep && MaxTimestep > 0) 79 | timestep = MaxTimestep; 80 | for (ControllerEdge i = _bodyList; i != null; i = i.nextBody) 81 | { 82 | Body body = i.body; 83 | if (body.IsSleeping()) 84 | continue; 85 | 86 | Vector2 damping = body.GetWorldVector(T.Multiply(body.GetLocalVector(body.GetLinearVelocity()))); 87 | body.SetLinearVelocity(body.GetLinearVelocity() + timestep*damping); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Joints/DistanceJoint.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | // 1-D constrained system 23 | // m (v2 - v1) = lambda 24 | // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. 25 | // x2 = x1 + h * v2 26 | 27 | // 1-D mass-damper-spring system 28 | // m (v2 - v1) + h * d * v2 + h * k * 29 | 30 | // C = norm(p2 - p1) - L 31 | // u = (p2 - p1) / norm(p2 - p1) 32 | // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) 33 | // J = [-u -cross(r1, u) u cross(r2, u)] 34 | // K = J * invM * JT 35 | // = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 36 | 37 | using System; using System.Numerics; 38 | using System.Collections.Generic; 39 | using System.Text; 40 | 41 | using Box2DNet.Common; 42 | 43 | 44 | namespace Box2DNet.Dynamics 45 | { 46 | /// 47 | /// Distance joint definition. This requires defining an 48 | /// anchor point on both bodies and the non-zero length of the 49 | /// distance joint. The definition uses local anchor points 50 | /// so that the initial configuration can violate the constraint 51 | /// slightly. This helps when saving and loading a game. 52 | /// @warning Do not use a zero or short length. 53 | /// 54 | public class DistanceJointDef : JointDef 55 | { 56 | public DistanceJointDef() 57 | { 58 | Type = JointType.DistanceJoint; 59 | LocalAnchor1 = Vector2.Zero; 60 | LocalAnchor2 = Vector2.Zero; 61 | Length = 1.0f; 62 | FrequencyHz = 0.0f; 63 | DampingRatio = 0.0f; 64 | } 65 | 66 | /// 67 | /// Initialize the bodies, anchors, and length using the world anchors. 68 | /// 69 | public void Initialize(Body body1, Body body2, Vector2 anchor1, Vector2 anchor2) 70 | { 71 | Body1 = body1; 72 | Body2 = body2; 73 | LocalAnchor1 = body1.GetLocalPoint(anchor1); 74 | LocalAnchor2 = body2.GetLocalPoint(anchor2); 75 | var d = anchor2 - anchor1; 76 | Length = d.Length(); 77 | } 78 | 79 | /// 80 | /// The local anchor point relative to body1's origin. 81 | /// 82 | public Vector2 LocalAnchor1; 83 | 84 | /// 85 | /// The local anchor point relative to body2's origin. 86 | /// 87 | public Vector2 LocalAnchor2; 88 | 89 | /// 90 | /// The equilibrium length between the anchor points. 91 | /// 92 | public float Length; 93 | 94 | /// 95 | /// The response speed. 96 | /// 97 | public float FrequencyHz; 98 | 99 | /// 100 | /// The damping ratio. 0 = no damping, 1 = critical damping. 101 | /// 102 | public float DampingRatio; 103 | } 104 | 105 | /// 106 | /// A distance joint constrains two points on two bodies 107 | /// to remain at a fixed distance from each other. You can view 108 | /// this as a massless, rigid rod. 109 | /// 110 | public class DistanceJoint : Joint 111 | { 112 | public Vector2 _localAnchor1; 113 | public Vector2 _localAnchor2; 114 | public Vector2 _u; 115 | public float _frequencyHz; 116 | public float _dampingRatio; 117 | public float _gamma; 118 | public float _bias; 119 | public float _impulse; 120 | public float _mass; // effective mass for the constraint. 121 | public float _length; 122 | 123 | public override Vector2 Anchor1 124 | { 125 | get { return _body1.GetWorldPoint(_localAnchor1);} 126 | } 127 | 128 | public override Vector2 Anchor2 129 | { 130 | get { return _body2.GetWorldPoint(_localAnchor2);} 131 | } 132 | 133 | public override Vector2 GetReactionForce(float inv_dt) 134 | { 135 | return (inv_dt * _impulse) * _u; 136 | } 137 | 138 | public override float GetReactionTorque(float inv_dt) 139 | { 140 | return 0.0f; 141 | } 142 | 143 | public DistanceJoint(DistanceJointDef def) 144 | : base(def) 145 | { 146 | _localAnchor1 = def.LocalAnchor1; 147 | _localAnchor2 = def.LocalAnchor2; 148 | _length = def.Length; 149 | _frequencyHz = def.FrequencyHz; 150 | _dampingRatio = def.DampingRatio; 151 | _impulse = 0.0f; 152 | _gamma = 0.0f; 153 | _bias = 0.0f; 154 | } 155 | 156 | internal override void InitVelocityConstraints(TimeStep step) 157 | { 158 | Body b1 = _body1; 159 | Body b2 = _body2; 160 | 161 | // Compute the effective mass matrix. 162 | Vector2 r1 = b1.GetTransform().TransformDirection(_localAnchor1 - b1.GetLocalCenter()); 163 | Vector2 r2 = b2.GetTransform().TransformDirection(_localAnchor2 - b2.GetLocalCenter()); 164 | _u = b2._sweep.C + r2 - b1._sweep.C - r1; 165 | 166 | // Handle singularity. 167 | float length = _u.Length(); 168 | if (length > Settings.LinearSlop) 169 | { 170 | _u *= 1.0f / length; 171 | } 172 | else 173 | { 174 | _u = Vector2.Zero; 175 | } 176 | 177 | float cr1u = r1.Cross(_u); 178 | float cr2u = r2.Cross(_u); 179 | float invMass = b1._invMass + b1._invI * cr1u * cr1u + b2._invMass + b2._invI * cr2u * cr2u; 180 | Box2DNetDebug.Assert(invMass > Settings.FLT_EPSILON); 181 | _mass = 1.0f / invMass; 182 | 183 | if (_frequencyHz > 0.0f) 184 | { 185 | float C = length - _length; 186 | 187 | // Frequency 188 | float omega = 2.0f * Settings.Pi * _frequencyHz; 189 | 190 | // Damping coefficient 191 | float d = 2.0f * _mass * _dampingRatio * omega; 192 | 193 | // Spring stiffness 194 | float k = _mass * omega * omega; 195 | 196 | // magic formulas 197 | _gamma = 1.0f / (step.Dt * (d + step.Dt * k)); 198 | _bias = C * step.Dt * k * _gamma; 199 | 200 | _mass = 1.0f / (invMass + _gamma); 201 | } 202 | 203 | if (step.WarmStarting) 204 | { 205 | //Scale the inpulse to support a variable timestep. 206 | _impulse *= step.DtRatio; 207 | Vector2 P = _impulse * _u; 208 | b1._linearVelocity -= b1._invMass * P; 209 | b1._angularVelocity -= b1._invI * r1.Cross(P); 210 | b2._linearVelocity += b2._invMass * P; 211 | b2._angularVelocity += b2._invI * r2.Cross(P); 212 | } 213 | else 214 | { 215 | _impulse = 0.0f; 216 | } 217 | } 218 | 219 | internal override bool SolvePositionConstraints(float baumgarte) 220 | { 221 | if (_frequencyHz > 0.0f) 222 | { 223 | //There is no possition correction for soft distace constraint. 224 | return true; 225 | } 226 | 227 | Body b1 = _body1; 228 | Body b2 = _body2; 229 | 230 | Vector2 r1 = b1.GetTransform().TransformDirection(_localAnchor1 - b1.GetLocalCenter()); 231 | Vector2 r2 = b2.GetTransform().TransformDirection(_localAnchor2 - b2.GetLocalCenter()); 232 | 233 | Vector2 d = b2._sweep.C + r2 - b1._sweep.C - r1; 234 | 235 | var length = d.Length(); 236 | d.Normalize(); 237 | var C = length - _length; 238 | C = Box2DNet.Common.Math.Clamp(C, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection); 239 | 240 | var impulse = -_mass * C; 241 | _u = d; 242 | var P = impulse * _u; 243 | 244 | b1._sweep.C -= b1._invMass * P; 245 | b1._sweep.A -= b1._invI * r1.Cross(P); 246 | b2._sweep.C += b2._invMass * P; 247 | b2._sweep.A += b2._invI * r2.Cross(P); 248 | 249 | b1.SynchronizeTransform(); 250 | b2.SynchronizeTransform(); 251 | 252 | return System.Math.Abs(C) < Settings.LinearSlop; 253 | } 254 | 255 | internal override void SolveVelocityConstraints(TimeStep step) 256 | { 257 | //B2_NOT_USED(step); 258 | 259 | var b1 = _body1; 260 | var b2 = _body2; 261 | 262 | var r1 = b1.GetTransform().TransformDirection( _localAnchor1 - b1.GetLocalCenter()); 263 | var r2 = b2.GetTransform().TransformDirection(_localAnchor2 - b2.GetLocalCenter()); 264 | 265 | // Cdot = dot(u, v + cross(w, r)) 266 | var v1 = b1._linearVelocity + r1.CrossScalarPreMultiply(b1._angularVelocity); 267 | var v2 = b2._linearVelocity + r2.CrossScalarPreMultiply(b2._angularVelocity); 268 | var cdot = Vector2.Dot(_u, v2 - v1); 269 | var impulse = -_mass * (cdot + _bias + _gamma * _impulse); 270 | _impulse += impulse; 271 | 272 | var p = impulse * _u; 273 | b1._linearVelocity -= b1._invMass * p; 274 | b1._angularVelocity -= b1._invI * r1.Cross(p); 275 | b2._linearVelocity += b2._invMass * p; 276 | b2._angularVelocity += b2._invI * r2.Cross(p); 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Joints/GearJoint.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | // Gear Joint: 23 | // C0 = (coordinate1 + ratio * coordinate2)_initial 24 | // C = C0 - (cordinate1 + ratio * coordinate2) = 0 25 | // Cdot = -(Cdot1 + ratio * Cdot2) 26 | // J = -[J1 ratio * J2] 27 | // K = J * invM * JT 28 | // = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T 29 | // 30 | // Revolute: 31 | // coordinate = rotation 32 | // Cdot = angularVelocity 33 | // J = [0 0 1] 34 | // K = J * invM * JT = invI 35 | // 36 | // Prismatic: 37 | // coordinate = dot(p - pg, ug) 38 | // Cdot = dot(v + cross(w, r), ug) 39 | // J = [ug cross(r, ug)] 40 | // K = J * invM * JT = invMass + invI * cross(r, ug)^2 41 | 42 | using System; using System.Numerics; 43 | using System.Collections.Generic; 44 | using System.Text; 45 | 46 | using Box2DNet.Common; 47 | 48 | 49 | namespace Box2DNet.Dynamics 50 | { 51 | /// 52 | /// Gear joint definition. This definition requires two existing 53 | /// revolute or prismatic joints (any combination will work). 54 | /// The provided joints must attach a dynamic body to a static body. 55 | /// 56 | public class GearJointDef : JointDef 57 | { 58 | public GearJointDef() 59 | { 60 | Type = JointType.GearJoint; 61 | Joint1 = null; 62 | Joint2 = null; 63 | Ratio = 1.0f; 64 | } 65 | 66 | /// 67 | /// The first revolute/prismatic joint attached to the gear joint. 68 | /// 69 | public Joint Joint1; 70 | 71 | /// 72 | /// The second revolute/prismatic joint attached to the gear joint. 73 | /// 74 | public Joint Joint2; 75 | 76 | /// 77 | /// The gear ratio. 78 | /// @see GearJoint for explanation. 79 | /// 80 | public float Ratio; 81 | } 82 | 83 | /// 84 | /// A gear joint is used to connect two joints together. Either joint 85 | /// can be a revolute or prismatic joint. You specify a gear ratio 86 | /// to bind the motions together: 87 | /// coordinate1 + ratio * coordinate2 = constant 88 | /// The ratio can be negative or positive. If one joint is a revolute joint 89 | /// and the other joint is a prismatic joint, then the ratio will have units 90 | /// of length or units of 1/length. 91 | /// @warning The revolute and prismatic joints must be attached to 92 | /// fixed bodies (which must be body1 on those joints). 93 | /// 94 | public class GearJoint : Joint 95 | { 96 | public Body _ground1; 97 | public Body _ground2; 98 | 99 | // One of these is NULL. 100 | public RevoluteJoint _revolute1; 101 | public PrismaticJoint _prismatic1; 102 | 103 | // One of these is NULL. 104 | public RevoluteJoint _revolute2; 105 | public PrismaticJoint _prismatic2; 106 | 107 | public Vector2 _groundAnchor1; 108 | public Vector2 _groundAnchor2; 109 | 110 | public Vector2 _localAnchor1; 111 | public Vector2 _localAnchor2; 112 | 113 | public Jacobian _J; 114 | 115 | public float _constant; 116 | public float _ratio; 117 | 118 | // Effective mass 119 | public float _mass; 120 | 121 | // Impulse for accumulation/warm starting. 122 | public float _impulse; 123 | 124 | public override Vector2 Anchor1 { get { return _body1.GetWorldPoint(_localAnchor1); } } 125 | public override Vector2 Anchor2 { get { return _body2.GetWorldPoint(_localAnchor2); } } 126 | 127 | public override Vector2 GetReactionForce(float inv_dt) 128 | { 129 | // TODO_ERIN not tested 130 | Vector2 P = _impulse * _J.Linear2; 131 | return inv_dt * P; 132 | } 133 | 134 | public override float GetReactionTorque(float inv_dt) 135 | { 136 | // TODO_ERIN not tested 137 | Vector2 r = _body2.GetTransform().TransformDirection(_localAnchor2 - _body2.GetLocalCenter()); 138 | Vector2 P = _impulse * _J.Linear2; 139 | float L = _impulse * _J.Angular2 - r.Cross(P); 140 | return inv_dt * L; 141 | } 142 | 143 | /// 144 | /// Get the gear ratio. 145 | /// 146 | public float Ratio { get { return _ratio; } } 147 | 148 | public GearJoint(GearJointDef def) 149 | : base(def) 150 | { 151 | JointType type1 = def.Joint1.GetType(); 152 | JointType type2 = def.Joint2.GetType(); 153 | 154 | Box2DNetDebug.Assert(type1 == JointType.RevoluteJoint || type1 == JointType.PrismaticJoint); 155 | Box2DNetDebug.Assert(type2 == JointType.RevoluteJoint || type2 == JointType.PrismaticJoint); 156 | Box2DNetDebug.Assert(def.Joint1.GetBody1().IsStatic()); 157 | Box2DNetDebug.Assert(def.Joint2.GetBody1().IsStatic()); 158 | 159 | _revolute1 = null; 160 | _prismatic1 = null; 161 | _revolute2 = null; 162 | _prismatic2 = null; 163 | 164 | float coordinate1, coordinate2; 165 | 166 | _ground1 = def.Joint1.GetBody1(); 167 | _body1 = def.Joint1.GetBody2(); 168 | if (type1 == JointType.RevoluteJoint) 169 | { 170 | _revolute1 = (RevoluteJoint)def.Joint1; 171 | _groundAnchor1 = _revolute1._localAnchor1; 172 | _localAnchor1 = _revolute1._localAnchor2; 173 | coordinate1 = _revolute1.JointAngle; 174 | } 175 | else 176 | { 177 | _prismatic1 = (PrismaticJoint)def.Joint1; 178 | _groundAnchor1 = _prismatic1._localAnchor1; 179 | _localAnchor1 = _prismatic1._localAnchor2; 180 | coordinate1 = _prismatic1.JointTranslation; 181 | } 182 | 183 | _ground2 = def.Joint2.GetBody1(); 184 | _body2 = def.Joint2.GetBody2(); 185 | if (type2 == JointType.RevoluteJoint) 186 | { 187 | _revolute2 = (RevoluteJoint)def.Joint2; 188 | _groundAnchor2 = _revolute2._localAnchor1; 189 | _localAnchor2 = _revolute2._localAnchor2; 190 | coordinate2 = _revolute2.JointAngle; 191 | } 192 | else 193 | { 194 | _prismatic2 = (PrismaticJoint)def.Joint2; 195 | _groundAnchor2 = _prismatic2._localAnchor1; 196 | _localAnchor2 = _prismatic2._localAnchor2; 197 | coordinate2 = _prismatic2.JointTranslation; 198 | } 199 | 200 | _ratio = def.Ratio; 201 | 202 | _constant = coordinate1 + _ratio * coordinate2; 203 | 204 | _impulse = 0.0f; 205 | } 206 | 207 | internal override void InitVelocityConstraints(TimeStep step) 208 | { 209 | Body g1 = _ground1; 210 | Body g2 = _ground2; 211 | Body b1 = _body1; 212 | Body b2 = _body2; 213 | 214 | float K = 0.0f; 215 | _J.SetZero(); 216 | 217 | if (_revolute1!=null) 218 | { 219 | _J.Angular1 = -1.0f; 220 | K += b1._invI; 221 | } 222 | else 223 | { 224 | Vector2 ug = g1.GetTransform().TransformDirection(_prismatic1._localXAxis1); 225 | Vector2 r = b1.GetTransform().TransformDirection(_localAnchor1 - b1.GetLocalCenter()); 226 | float crug = r.Cross(ug); 227 | _J.Linear1 = -ug; 228 | _J.Angular1 = -crug; 229 | K += b1._invMass + b1._invI * crug * crug; 230 | } 231 | 232 | if (_revolute2!=null) 233 | { 234 | _J.Angular2 = -_ratio; 235 | K += _ratio * _ratio * b2._invI; 236 | } 237 | else 238 | { 239 | Vector2 ug = g2.GetTransform().TransformDirection(_prismatic2._localXAxis1); 240 | Vector2 r = b2.GetTransform().TransformDirection(_localAnchor2 - b2.GetLocalCenter()); 241 | float crug = r.Cross(ug); 242 | _J.Linear2 = -_ratio * ug; 243 | _J.Angular2 = -_ratio * crug; 244 | K += _ratio * _ratio * (b2._invMass + b2._invI * crug * crug); 245 | } 246 | 247 | // Compute effective mass. 248 | Box2DNetDebug.Assert(K > 0.0f); 249 | _mass = 1.0f / K; 250 | 251 | if (step.WarmStarting) 252 | { 253 | // Warm starting. 254 | b1._linearVelocity += b1._invMass * _impulse * _J.Linear1; 255 | b1._angularVelocity += b1._invI * _impulse * _J.Angular1; 256 | b2._linearVelocity += b2._invMass * _impulse * _J.Linear2; 257 | b2._angularVelocity += b2._invI * _impulse * _J.Angular2; 258 | } 259 | else 260 | { 261 | _impulse = 0.0f; 262 | } 263 | } 264 | 265 | internal override void SolveVelocityConstraints(TimeStep step) 266 | { 267 | Body b1 = _body1; 268 | Body b2 = _body2; 269 | 270 | float Cdot = _J.Compute(b1._linearVelocity, b1._angularVelocity, b2._linearVelocity, b2._angularVelocity); 271 | 272 | float impulse = _mass * (-Cdot); 273 | _impulse += impulse; 274 | 275 | b1._linearVelocity += b1._invMass * impulse * _J.Linear1; 276 | b1._angularVelocity += b1._invI * impulse * _J.Angular1; 277 | b2._linearVelocity += b2._invMass * impulse * _J.Linear2; 278 | b2._angularVelocity += b2._invI * impulse * _J.Angular2; 279 | } 280 | 281 | internal override bool SolvePositionConstraints(float baumgarte) 282 | { 283 | float linearError = 0.0f; 284 | 285 | Body b1 = _body1; 286 | Body b2 = _body2; 287 | 288 | float coordinate1, coordinate2; 289 | if (_revolute1 != null) 290 | { 291 | coordinate1 = _revolute1.JointAngle; 292 | } 293 | else 294 | { 295 | coordinate1 = _prismatic1.JointTranslation; 296 | } 297 | 298 | if (_revolute2 != null) 299 | { 300 | coordinate2 = _revolute2.JointAngle; 301 | } 302 | else 303 | { 304 | coordinate2 = _prismatic2.JointTranslation; 305 | } 306 | 307 | float C = _constant - (coordinate1 + _ratio * coordinate2); 308 | 309 | float impulse = _mass * (-C); 310 | 311 | b1._sweep.C += b1._invMass * impulse * _J.Linear1; 312 | b1._sweep.A += b1._invI * impulse * _J.Angular1; 313 | b2._sweep.C += b2._invMass * impulse * _J.Linear2; 314 | b2._sweep.A += b2._invI * impulse * _J.Angular2; 315 | 316 | b1.SynchronizeTransform(); 317 | b2.SynchronizeTransform(); 318 | 319 | //TODO_ERIN not implemented 320 | return linearError < Settings.LinearSlop; 321 | } 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Joints/Joint.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using System; using System.Numerics; 23 | using System.Collections.Generic; 24 | using System.Text; 25 | 26 | using Box2DNet.Common; 27 | 28 | using Transform = Box2DNet.Common.Transform; 29 | 30 | namespace Box2DNet.Dynamics 31 | { 32 | public enum JointType 33 | { 34 | UnknownJoint, 35 | RevoluteJoint, 36 | PrismaticJoint, 37 | DistanceJoint, 38 | PulleyJoint, 39 | MouseJoint, 40 | GearJoint, 41 | LineJoint 42 | } 43 | 44 | public enum LimitState 45 | { 46 | InactiveLimit, 47 | AtLowerLimit, 48 | AtUpperLimit, 49 | EqualLimits 50 | } 51 | 52 | public struct Jacobian 53 | { 54 | public Vector2 Linear1; 55 | public float Angular1; 56 | public Vector2 Linear2; 57 | public float Angular2; 58 | 59 | public void SetZero() 60 | { 61 | Linear1 = Vector2.Zero; 62 | Angular1 = 0.0f; 63 | Linear2 = Vector2.Zero; 64 | Angular2 = 0.0f; 65 | } 66 | 67 | public void Set(Vector2 x1, float a1, Vector2 x2, float a2) 68 | { 69 | Linear1 = x1; Angular1 = a1; 70 | Linear2 = x2; Angular2 = a2; 71 | } 72 | 73 | public float Compute(Vector2 x1, float a1, Vector2 x2, float a2) 74 | { 75 | return Vector2.Dot(Linear1, x1) + Angular1 * a1 + Vector2.Dot(Linear2, x2) + Angular2 * a2; 76 | } 77 | } 78 | 79 | #warning "CAS" 80 | /// 81 | /// A joint edge is used to connect bodies and joints together 82 | /// in a joint graph where each body is a node and each joint 83 | /// is an edge. A joint edge belongs to a doubly linked list 84 | /// maintained in each attached body. Each joint has two joint 85 | /// nodes, one for each attached body. 86 | /// 87 | public class JointEdge 88 | { 89 | /// 90 | /// Provides quick access to the other body attached. 91 | /// 92 | public Body Other; 93 | 94 | /// 95 | /// The joint. 96 | /// 97 | public Joint Joint; 98 | 99 | /// 100 | /// The previous joint edge in the body's joint list. 101 | /// 102 | public JointEdge Prev; 103 | 104 | /// 105 | /// The next joint edge in the body's joint list. 106 | /// 107 | public JointEdge Next; 108 | } 109 | 110 | #warning "CAS" 111 | /// 112 | /// Joint definitions are used to construct joints. 113 | /// 114 | public class JointDef 115 | { 116 | public JointDef() 117 | { 118 | Type = JointType.UnknownJoint; 119 | UserData = null; 120 | Body1 = null; 121 | Body2 = null; 122 | CollideConnected = false; 123 | } 124 | 125 | /// 126 | /// The joint type is set automatically for concrete joint types. 127 | /// 128 | public JointType Type; 129 | 130 | /// 131 | /// Use this to attach application specific data to your joints. 132 | /// 133 | public object UserData; 134 | 135 | /// 136 | /// The first attached body. 137 | /// 138 | public Body Body1; 139 | 140 | /// 141 | /// The second attached body. 142 | /// 143 | public Body Body2; 144 | 145 | /// 146 | /// Set this flag to true if the attached bodies should collide. 147 | /// 148 | public bool CollideConnected; 149 | } 150 | 151 | /// 152 | /// The base joint class. Joints are used to constraint two bodies together in 153 | /// various fashions. Some joints also feature limits and motors. 154 | /// 155 | public abstract class Joint 156 | { 157 | protected JointType _type; 158 | internal Joint _prev; 159 | internal Joint _next; 160 | internal JointEdge _node1 = new JointEdge(); 161 | internal JointEdge _node2 = new JointEdge(); 162 | internal Body _body1; 163 | internal Body _body2; 164 | 165 | internal bool _islandFlag; 166 | internal bool _collideConnected; 167 | 168 | protected object _userData; 169 | 170 | // Cache here per time step to reduce cache misses. 171 | protected Vector2 _localCenter1, _localCenter2; 172 | protected float _invMass1, _invI1; 173 | protected float _invMass2, _invI2; 174 | 175 | /// 176 | /// Get the type of the concrete joint. 177 | /// 178 | public new JointType GetType() 179 | { 180 | return _type; 181 | } 182 | 183 | /// 184 | /// Get the first body attached to this joint. 185 | /// 186 | /// 187 | public Body GetBody1() 188 | { 189 | return _body1; 190 | } 191 | 192 | /// 193 | /// Get the second body attached to this joint. 194 | /// 195 | /// 196 | public Body GetBody2() 197 | { 198 | return _body2; 199 | } 200 | 201 | /// 202 | /// Get the anchor point on body1 in world coordinates. 203 | /// 204 | /// 205 | public abstract Vector2 Anchor1 { get; } 206 | 207 | /// 208 | /// Get the anchor point on body2 in world coordinates. 209 | /// 210 | /// 211 | public abstract Vector2 Anchor2 { get; } 212 | 213 | /// 214 | /// Get the reaction force on body2 at the joint anchor. 215 | /// 216 | public abstract Vector2 GetReactionForce(float inv_dt); 217 | 218 | /// 219 | /// Get the reaction torque on body2. 220 | /// 221 | public abstract float GetReactionTorque(float inv_dt); 222 | 223 | /// 224 | /// Get the next joint the world joint list. 225 | /// 226 | /// 227 | public Joint GetNext() 228 | { 229 | return _next; 230 | } 231 | 232 | /// 233 | /// Get/Set the user data pointer. 234 | /// 235 | /// 236 | public object UserData 237 | { 238 | get { return _userData; } 239 | set { _userData = value; } 240 | } 241 | 242 | protected Joint(JointDef def) 243 | { 244 | _type = def.Type; 245 | _prev = null; 246 | _next = null; 247 | _body1 = def.Body1; 248 | _body2 = def.Body2; 249 | _collideConnected = def.CollideConnected; 250 | _islandFlag = false; 251 | _userData = def.UserData; 252 | } 253 | 254 | internal static Joint Create(JointDef def) 255 | { 256 | Joint joint = null; 257 | 258 | switch (def.Type) 259 | { 260 | case JointType.DistanceJoint: 261 | { 262 | joint = new DistanceJoint((DistanceJointDef)def); 263 | } 264 | break; 265 | case JointType.MouseJoint: 266 | { 267 | joint = new MouseJoint((MouseJointDef)def); 268 | } 269 | break; 270 | case JointType.PrismaticJoint: 271 | { 272 | joint = new PrismaticJoint((PrismaticJointDef)def); 273 | } 274 | break; 275 | case JointType.RevoluteJoint: 276 | { 277 | joint = new RevoluteJoint((RevoluteJointDef)def); 278 | } 279 | break; 280 | case JointType.PulleyJoint: 281 | { 282 | joint = new PulleyJoint((PulleyJointDef)def); 283 | } 284 | break; 285 | case JointType.GearJoint: 286 | { 287 | joint = new GearJoint((GearJointDef)def); 288 | } 289 | break; 290 | case JointType.LineJoint: 291 | { 292 | joint = new LineJoint((LineJointDef)def); 293 | } 294 | break; 295 | default: 296 | Box2DNetDebug.Assert(false); 297 | break; 298 | } 299 | 300 | return joint; 301 | } 302 | 303 | internal static void Destroy(Joint joint) 304 | { 305 | joint = null; 306 | } 307 | 308 | internal abstract void InitVelocityConstraints(TimeStep step); 309 | internal abstract void SolveVelocityConstraints(TimeStep step); 310 | 311 | // This returns true if the position errors are within tolerance. 312 | internal abstract bool SolvePositionConstraints(float baumgarte); 313 | 314 | internal void ComputeTransform(ref Transform xf, Vector2 center, Vector2 localCenter, float angle) 315 | { 316 | xf.rotation = Box2DNet.Common.Math.AngleToRotation(angle); 317 | //xf.R = new Mat22(angle); 318 | xf.position = center - xf.TransformDirection(localCenter); 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/Joints/MouseJoint.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2018 codeyu https://github.com/codeyu/Box2DNet 3 | Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | // p = attached point, m = mouse point 23 | // C = p - m 24 | // Cdot = v 25 | // = v + cross(w, r) 26 | // J = [I r_skew] 27 | // Identity used: 28 | // w k % (rx i + ry j) = w * (-ry i + rx j) 29 | 30 | using System; using System.Numerics; 31 | using System.Collections.Generic; 32 | using System.Text; 33 | 34 | using Box2DNet.Common; 35 | 36 | 37 | namespace Box2DNet.Dynamics 38 | { 39 | /// 40 | /// Mouse joint definition. This requires a world target point, 41 | /// tuning parameters, and the time step. 42 | /// 43 | public class MouseJointDef : JointDef 44 | { 45 | public MouseJointDef() 46 | { 47 | Type = JointType.MouseJoint; 48 | Target = Vector2.Zero; 49 | MaxForce = 0.0f; 50 | FrequencyHz = 5.0f; 51 | DampingRatio = 0.7f; 52 | } 53 | 54 | /// 55 | /// The initial world target point. This is assumed 56 | /// to coincide with the body anchor initially. 57 | /// 58 | public Vector2 Target; 59 | 60 | /// 61 | /// The maximum constraint force that can be exerted 62 | /// to move the candidate body. Usually you will express 63 | /// as some multiple of the weight (multiplier * mass * gravity). 64 | /// 65 | public float MaxForce; 66 | 67 | /// 68 | /// The response speed. 69 | /// 70 | public float FrequencyHz; 71 | 72 | /// 73 | /// The damping ratio. 0 = no damping, 1 = critical damping. 74 | /// 75 | public float DampingRatio; 76 | } 77 | 78 | /// 79 | /// A mouse joint is used to make a point on a body track a 80 | /// specified world point. This a soft constraint with a maximum 81 | /// force. This allows the constraint to stretch and without 82 | /// applying huge forces. 83 | /// 84 | public class MouseJoint : Joint 85 | { 86 | public Vector2 _localAnchor; 87 | public Vector2 _target; 88 | public Vector2 _impulse; 89 | 90 | public Mat22 _mass; // effective mass for point-to-point constraint. 91 | public Vector2 _C; // position error 92 | public float _maxForce; 93 | public float _frequencyHz; 94 | public float _dampingRatio; 95 | public float _beta; 96 | public float _gamma; 97 | 98 | public override Vector2 Anchor1 99 | { 100 | get { return _target; } 101 | } 102 | 103 | public override Vector2 Anchor2 104 | { 105 | get { return _body2.GetWorldPoint(_localAnchor); } 106 | } 107 | 108 | public override Vector2 GetReactionForce(float inv_dt) 109 | { 110 | return inv_dt * _impulse; 111 | } 112 | 113 | public override float GetReactionTorque(float inv_dt) 114 | { 115 | return inv_dt * 0.0f; 116 | } 117 | 118 | /// 119 | /// Use this to update the target point. 120 | /// 121 | public void SetTarget(Vector2 target) 122 | { 123 | if (_body2.IsSleeping()) 124 | { 125 | _body2.WakeUp(); 126 | } 127 | _target = target; 128 | } 129 | 130 | public MouseJoint(MouseJointDef def) 131 | : base(def) 132 | { 133 | _target = def.Target; 134 | _localAnchor = _body2.GetTransform().InverseTransformPoint(_target); 135 | 136 | _maxForce = def.MaxForce; 137 | _impulse = Vector2.Zero; 138 | 139 | _frequencyHz = def.FrequencyHz; 140 | _dampingRatio = def.DampingRatio; 141 | 142 | _beta = 0.0f; 143 | _gamma = 0.0f; 144 | } 145 | 146 | internal override void InitVelocityConstraints(TimeStep step) 147 | { 148 | Body b = _body2; 149 | 150 | float mass = b.GetMass(); 151 | 152 | // Frequency 153 | float omega = 2.0f * Settings.Pi * _frequencyHz; 154 | 155 | // Damping coefficient 156 | float d = 2.0f * mass * _dampingRatio * omega; 157 | 158 | // Spring stiffness 159 | float k = mass * (omega * omega); 160 | 161 | // magic formulas 162 | // gamma has units of inverse mass. 163 | // beta has units of inverse time. 164 | Box2DNetDebug.Assert(d + step.Dt * k > Settings.FLT_EPSILON); 165 | _gamma = 1.0f / (step.Dt * (d + step.Dt * k)); 166 | _beta = step.Dt * k * _gamma; 167 | 168 | // Compute the effective mass matrix. 169 | Vector2 r = b.GetTransform().TransformDirection(_localAnchor - b.GetLocalCenter()); 170 | 171 | // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] 172 | // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] 173 | // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] 174 | float invMass = b._invMass; 175 | float invI = b._invI; 176 | 177 | Mat22 K1 = new Mat22(); 178 | K1.Col1.X = invMass; K1.Col2.X = 0.0f; 179 | K1.Col1.Y = 0.0f; K1.Col2.Y = invMass; 180 | 181 | Mat22 K2 = new Mat22(); 182 | K2.Col1.X = invI * r.Y * r.Y; K2.Col2.X = -invI * r.X * r.Y; 183 | K2.Col1.Y = -invI * r.X * r.Y; K2.Col2.Y = invI * r.X * r.X; 184 | 185 | Mat22 K = K1 + K2; 186 | K.Col1.X += _gamma; 187 | K.Col2.Y += _gamma; 188 | 189 | _mass = K.GetInverse(); 190 | 191 | _C = b._sweep.C + r - _target; 192 | 193 | // Cheat with some damping 194 | b._angularVelocity *= 0.98f; 195 | 196 | // Warm starting. 197 | _impulse *= step.DtRatio; 198 | b._linearVelocity += invMass * _impulse; 199 | b._angularVelocity += invI * r.Cross(_impulse); 200 | } 201 | 202 | internal override void SolveVelocityConstraints(TimeStep step) 203 | { 204 | Body b = _body2; 205 | 206 | Vector2 r = b.GetTransform().TransformDirection(_localAnchor - b.GetLocalCenter()); 207 | 208 | // Cdot = v + cross(w, r) 209 | Vector2 Cdot = b._linearVelocity + r.CrossScalarPreMultiply(b._angularVelocity); 210 | Vector2 impulse = _mass.Multiply(-(Cdot + _beta * _C + _gamma * _impulse)); 211 | 212 | Vector2 oldImpulse = _impulse; 213 | _impulse += impulse; 214 | float maxImpulse = step.Dt * _maxForce; 215 | if (_impulse.LengthSquared() > maxImpulse * maxImpulse) 216 | { 217 | _impulse *= maxImpulse / _impulse.Length(); 218 | } 219 | impulse = _impulse - oldImpulse; 220 | 221 | b._linearVelocity += b._invMass * impulse; 222 | b._angularVelocity += b._invI * r.Cross(impulse); 223 | } 224 | 225 | internal override bool SolvePositionConstraints(float baumgarte) 226 | { 227 | return true; 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/Box2DNet/Dynamics/WorldCallbacks.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Box2DNet Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx 3 | Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | */ 21 | 22 | using System; 23 | using System.Numerics; 24 | using Box2DNet.Common; 25 | using Box2DNet.Collision; 26 | 27 | 28 | using Transform = Box2DNet.Common.Transform; 29 | 30 | namespace Box2DNet.Dynamics 31 | { 32 | /// 33 | /// Joints and shapes are destroyed when their associated 34 | /// body is destroyed. Implement this listener so that you 35 | /// may nullify references to these joints and shapes. 36 | /// 37 | public abstract class DestructionListener 38 | { 39 | /// 40 | /// Called when any joint is about to be destroyed due 41 | /// to the destruction of one of its attached bodies. 42 | /// 43 | public abstract void SayGoodbye(Joint joint); 44 | 45 | /// 46 | /// Called when any shape is about to be destroyed due 47 | /// to the destruction of its parent body. 48 | /// 49 | public abstract void SayGoodbye(Fixture fixture); 50 | } 51 | 52 | /// 53 | /// This is called when a body's shape passes outside of the world boundary. 54 | /// 55 | public abstract class BoundaryListener 56 | { 57 | /// 58 | /// This is called for each body that leaves the world boundary. 59 | /// @warning you can't modify the world inside this callback. 60 | /// 61 | public abstract void Violation(Body body); 62 | } 63 | 64 | /// 65 | /// Implement this class to provide collision filtering. In other words, you can implement 66 | /// this class if you want finer control over contact creation. 67 | /// 68 | public class ContactFilter 69 | { 70 | /// 71 | /// Return true if contact calculations should be performed between these two shapes. 72 | /// If you implement your own collision filter you may want to build from this implementation. 73 | /// @warning for performance reasons this is only called when the AABBs begin to overlap. 74 | /// 75 | public virtual bool ShouldCollide(Fixture fixtureA, Fixture fixtureB) 76 | { 77 | FilterData filterA = fixtureA.Filter; 78 | FilterData filterB = fixtureB.Filter; 79 | 80 | if (filterA.GroupIndex == filterB.GroupIndex && filterA.GroupIndex != 0) 81 | { 82 | return filterA.GroupIndex > 0; 83 | } 84 | 85 | bool collide = (filterA.MaskBits & filterB.CategoryBits) != 0 && (filterA.CategoryBits & filterB.MaskBits) != 0; 86 | return collide; 87 | } 88 | 89 | /// 90 | /// Return true if the given shape should be considered for ray intersection. 91 | /// 92 | public bool RayCollide(object userData, Fixture fixture) 93 | { 94 | //By default, cast userData as a shape, and then collide if the shapes would collide 95 | if (userData == null) 96 | { 97 | return true; 98 | } 99 | 100 | return ShouldCollide((Fixture)userData, fixture); 101 | } 102 | } 103 | 104 | /// Contact impulses for reporting. Impulses are used instead of forces because 105 | /// sub-step forces may approach infinity for rigid body collisions. These 106 | /// match up one-to-one with the contact points in b2Manifold. 107 | public class ContactImpulse 108 | { 109 | public float[] normalImpulses = new float[Settings.MaxManifoldPoints]; 110 | public float[] tangentImpulses = new float[Settings.MaxManifoldPoints]; 111 | } 112 | 113 | /// Implement this class to get contact information. You can use these results for 114 | /// things like sounds and game logic. You can also get contact results by 115 | /// traversing the contact lists after the time step. However, you might miss 116 | /// some contacts because continuous physics leads to sub-stepping. 117 | /// Additionally you may receive multiple callbacks for the same contact in a 118 | /// single time step. 119 | /// You should strive to make your callbacks efficient because there may be 120 | /// many callbacks per time step. 121 | /// @warning You cannot create/destroy Box2DNet entities inside these callbacks. 122 | public interface ContactListener 123 | { 124 | /// Called when two fixtures begin to touch. 125 | void BeginContact(Contact contact); 126 | 127 | /// Called when two fixtures cease to touch. 128 | void EndContact(Contact contact); 129 | 130 | /// This is called after a contact is updated. This allows you to inspect a 131 | /// contact before it goes to the solver. If you are careful, you can modify the 132 | /// contact manifold (e.g. disable contact). 133 | /// A copy of the old manifold is provided so that you can detect changes. 134 | /// Note: this is called only for awake bodies. 135 | /// Note: this is called even when the number of contact points is zero. 136 | /// Note: this is not called for sensors. 137 | /// Note: if you set the number of contact points to zero, you will not 138 | /// get an EndContact callback. However, you may get a BeginContact callback 139 | /// the next step. 140 | void PreSolve(Contact contact, Manifold oldManifold); 141 | 142 | /// This lets you inspect a contact after the solver is finished. This is useful 143 | /// for inspecting impulses. 144 | /// Note: the contact manifold does not include time of impact impulses, which can be 145 | /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly 146 | /// in a separate data structure. 147 | /// Note: this is only called for contacts that are touching, solid, and awake. 148 | void PostSolve(Contact contact, ContactImpulse impulse); 149 | } 150 | 151 | /// 152 | /// Color for debug drawing. Each value has the range [0,1]. 153 | /// 154 | public struct Color 155 | { 156 | public float R, G, B; 157 | 158 | public Color(float r, float g, float b) 159 | { 160 | R = r; G = g; B = b; 161 | } 162 | public void Set(float r, float g, float b) 163 | { 164 | R = r; G = g; B = b; 165 | } 166 | } 167 | 168 | /// 169 | /// Implement and register this class with a b2World to provide debug drawing of physics 170 | /// entities in your game. 171 | /// 172 | public abstract class DebugDraw 173 | { 174 | [Flags] 175 | public enum DrawFlags 176 | { 177 | Shape = 0x0001, // draw shapes 178 | Joint = 0x0002, // draw joint connections 179 | CoreShape = 0x0004, // draw core (TOI) shapes // should be removed in this revision? 180 | Aabb = 0x0008, // draw axis aligned bounding boxes 181 | Obb = 0x0010, // draw oriented bounding boxes // should be removed in this revision? 182 | Pair = 0x0020, // draw broad-phase pairs 183 | CenterOfMass = 0x0040, // draw center of mass frame 184 | Controller = 0x0080 // draw center of mass frame 185 | }; 186 | 187 | protected DrawFlags _drawFlags; 188 | 189 | public DebugDraw() 190 | { 191 | _drawFlags = 0; 192 | } 193 | 194 | public DrawFlags Flags { get { return _drawFlags; } set { _drawFlags = value; } } 195 | 196 | /// 197 | /// Append flags to the current flags. 198 | /// 199 | public void AppendFlags(DrawFlags flags) 200 | { 201 | _drawFlags |= flags; 202 | } 203 | 204 | /// 205 | /// Clear flags from the current flags. 206 | /// 207 | public void ClearFlags(DrawFlags flags) 208 | { 209 | _drawFlags &= ~flags; 210 | } 211 | 212 | /// 213 | /// Draw a closed polygon provided in CCW order. 214 | /// 215 | public abstract void DrawPolygon(Vector2[] vertices, int vertexCount, Color color); 216 | 217 | /// 218 | /// Draw a solid closed polygon provided in CCW order. 219 | /// 220 | public abstract void DrawSolidPolygon(Vector2[] vertices, int vertexCount, Color color); 221 | 222 | /// 223 | /// Draw a circle. 224 | /// 225 | public abstract void DrawCircle(Vector2 center, float radius, Color color); 226 | 227 | /// 228 | /// Draw a solid circle. 229 | /// 230 | public abstract void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, Color color); 231 | 232 | /// 233 | /// Draw a line segment. 234 | /// 235 | public abstract void DrawSegment(Vector2 p1, Vector2 p2, Color color); 236 | 237 | /// 238 | /// Draw a Transform. Choose your own length scale. 239 | /// 240 | /// A Transform. 241 | public abstract void DrawTransform(Transform xf); 242 | } 243 | } 244 | --------------------------------------------------------------------------------