From 5134f21607726958ce8739ce13dc8ed62f19e592 Mon Sep 17 00:00:00 2001 From: Kai Angulo Date: Wed, 9 Oct 2024 23:55:18 -0700 Subject: [PATCH] build: finish move of BepuPhysics2 to seperate branch --- Prowl.Editor/Editor/ProjectSettingsWindow.cs | 1 - Prowl.Editor/Program.cs | 2 - Prowl.Runtime/Application.cs | 1 - .../Components/Physics/CharacterController.cs | 79 -- .../Physics/Colliders/BoxCollider.cs | 42 - .../Physics/Colliders/CapsuleCollider.cs | 60 -- .../Components/Physics/Colliders/Collider.cs | 48 - .../Physics/Colliders/CylinderCollider.cs | 60 -- .../Physics/Colliders/SphereCollider.cs | 44 - .../Physics/Colliders/TriangleCollider.cs | 61 -- ...AngularAxisGearMotorConstraintComponent.cs | 53 -- .../AngularAxisMotorConstraintComponent.cs | 53 -- .../AngularHingeConstraintComponent.cs | 53 -- .../AngularServoConstraintComponent.cs | 115 --- .../AngularSwivelHingeConstraintComponent.cs | 83 -- .../Constraints/AreaConstraintComponent.cs | 67 -- .../BallSocketConstraintComponent.cs | 76 -- .../BallSocketMotorConstraintComponent.cs | 80 -- .../BallSocketServoConstraintComponent.cs | 129 --- .../CenterDistanceConstraintComponent.cs | 66 -- .../CenterDistanceLimitConstraintComponent.cs | 76 -- .../DistanceLimitConstraintComponent.cs | 104 --- .../DistanceServoConstraintComponent.cs | 149 ---- .../Constraints/HingeConstraintComponent.cs | 114 --- .../LinearAxisLimitConstraintComponent.cs | 117 --- .../LinearAxisMotorConstraintComponent.cs | 105 --- .../LinearAxisServoConstraintComponent.cs | 158 ---- .../OneBodyAngularMotorConstraintComponent.cs | 65 -- .../OneBodyAngularServoConstraintComponent.cs | 115 --- .../OneBodyLinearMotorConstraintComponent.cs | 79 -- .../OneBodyLinearServoConstraintComponent.cs | 136 --- .../PointOnLineServoConstraintComponent.cs | 146 --- .../SwingLimitConstraintComponent.cs | 104 --- .../SwivelHingeConstraintComponent.cs | 116 --- .../TwistLimitConstraintComponent.cs | 109 --- .../TwistMotorConstraintComponent.cs | 105 --- .../TwistServoConstraintComponent.cs | 148 ---- .../Constraints/VolumeConstraintComponent.cs | 62 -- .../Constraints/WeldConstraintComponent.cs | 82 -- .../Constraints/_ConstraintComponent.cs | 27 - .../Constraints/_ConstraintComponentBase.cs | 125 --- .../_FourBodyConstraintComponent.cs | 39 - .../_OneBodyConstraintComponent.cs | 18 - .../_ThreeBodyConstraintComponent.cs | 32 - .../_TwoBodyConstraintComponent.cs | 25 - .../Components/Physics/PhysicsBody.cs | 229 ----- Prowl.Runtime/Components/Physics/Rigidbody.cs | 303 ------- .../Components/Physics/Staticbody.cs | 126 --- .../Physics/Types/BepuNarrowPhaseCallbacks.cs | 74 -- .../Types/BepuPoseIntegratorCallbacks.cs | 102 --- .../Types/Contacts/ContactEventsManager.cs | 476 ---------- .../Types/Contacts/IContactEventHandler.cs | 116 --- .../Controller/CharacterControllerData.cs | 59 -- .../Controller/CharacterControllersManager.cs | 834 ------------------ .../Controller/CharacterMotionConstraint.cs | 603 ------------- .../Components/Physics/Types/Interpolation.cs | 22 - .../Physics/Types/PhysicsMaterial.cs | 22 - .../Physics/Types/Raycast/HitInfo.cs | 34 - .../Physics/Types/Raycast/OverlapHandler.cs | 114 --- .../Physics/Types/Raycast/RayHitHandler.cs | 206 ----- .../Components/Physics/Types/Trigger.cs | 28 - Prowl.Runtime/Physics.cs | 308 ------- Prowl.Runtime/Prowl.Runtime.csproj | 2 - Prowl.Runtime/SceneManager.cs | 5 - Prowl.Runtime/Time.cs | 1 - 65 files changed, 7193 deletions(-) delete mode 100644 Prowl.Runtime/Components/Physics/CharacterController.cs delete mode 100644 Prowl.Runtime/Components/Physics/Colliders/BoxCollider.cs delete mode 100644 Prowl.Runtime/Components/Physics/Colliders/CapsuleCollider.cs delete mode 100644 Prowl.Runtime/Components/Physics/Colliders/Collider.cs delete mode 100644 Prowl.Runtime/Components/Physics/Colliders/CylinderCollider.cs delete mode 100644 Prowl.Runtime/Components/Physics/Colliders/SphereCollider.cs delete mode 100644 Prowl.Runtime/Components/Physics/Colliders/TriangleCollider.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/AngularAxisGearMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/AngularAxisMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/AngularHingeConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/AngularServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/AngularSwivelHingeConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/AreaConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/BallSocketConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/BallSocketMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/BallSocketServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/CenterDistanceConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/CenterDistanceLimitConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/DistanceLimitConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/DistanceServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/HingeConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/LinearAxisLimitConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/LinearAxisMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/LinearAxisServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/PointOnLineServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/SwingLimitConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/SwivelHingeConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/TwistLimitConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/TwistMotorConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/TwistServoConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/VolumeConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/WeldConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponentBase.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/_FourBodyConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/_OneBodyConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/_ThreeBodyConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/Constraints/_TwoBodyConstraintComponent.cs delete mode 100644 Prowl.Runtime/Components/Physics/PhysicsBody.cs delete mode 100644 Prowl.Runtime/Components/Physics/Rigidbody.cs delete mode 100644 Prowl.Runtime/Components/Physics/Staticbody.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/BepuNarrowPhaseCallbacks.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/BepuPoseIntegratorCallbacks.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Contacts/ContactEventsManager.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Contacts/IContactEventHandler.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllerData.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllersManager.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Controller/CharacterMotionConstraint.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Interpolation.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/PhysicsMaterial.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Raycast/HitInfo.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Raycast/OverlapHandler.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Raycast/RayHitHandler.cs delete mode 100644 Prowl.Runtime/Components/Physics/Types/Trigger.cs delete mode 100644 Prowl.Runtime/Physics.cs diff --git a/Prowl.Editor/Editor/ProjectSettingsWindow.cs b/Prowl.Editor/Editor/ProjectSettingsWindow.cs index 58ca8a4bc..66c95db0a 100644 --- a/Prowl.Editor/Editor/ProjectSettingsWindow.cs +++ b/Prowl.Editor/Editor/ProjectSettingsWindow.cs @@ -21,7 +21,6 @@ public ProjectSettingsWindow(Type settingToOpen) : base(settingToOpen, "Project public override void RenderSideView() { - RenderSideViewElement(PhysicsSetting.Instance); RenderSideViewElement(BuildProjectSettings.Instance); } } diff --git a/Prowl.Editor/Program.cs b/Prowl.Editor/Program.cs index 72308f9e9..becbc27a9 100644 --- a/Prowl.Editor/Program.cs +++ b/Prowl.Editor/Program.cs @@ -81,8 +81,6 @@ private static int Run(CliOpenOptions options) // Editor-specific update code if (Project.HasProject) { - Physics.Initialize(); - if (!s_createdDefaultWindows) { s_createdDefaultWindows = true; diff --git a/Prowl.Runtime/Application.cs b/Prowl.Runtime/Application.cs index 4802cad93..6aee491b0 100644 --- a/Prowl.Runtime/Application.cs +++ b/Prowl.Runtime/Application.cs @@ -123,7 +123,6 @@ static void AppClose() IsRunning = false; Quitting?.Invoke(); Graphics.Dispose(); - Physics.Dispose(); AudioSystem.Dispose(); AssemblyManager.Dispose(); Debug.Log("Is terminating..."); diff --git a/Prowl.Runtime/Components/Physics/CharacterController.cs b/Prowl.Runtime/Components/Physics/CharacterController.cs deleted file mode 100644 index 2b102d3d7..000000000 --- a/Prowl.Runtime/Components/Physics/CharacterController.cs +++ /dev/null @@ -1,79 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; - -using BepuPhysics; - -using Prowl.Icons; - -namespace Prowl.Runtime; - -[RequireComponent(typeof(CapsuleCollider))] -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Person} Character Controller")] -public sealed class CharacterController : Rigidbody -{ - public float speed = 4f; - public float jumpVelocity = 6f; - public float maxSlope = (MathF.PI * 0.25f).ToDeg(); - public float maxVerticalForce = 100; - public float maxHoriztonalForce = 20; - public float supportDepth = -0.05f; - public float supportContinuationDepth = -0.1f; - - [ShowInInspector] - public Vector2 TargetVelocity { get; set; } = Vector2.zero; - public bool IsGrounded { get; private set; } = false; - - public override bool Kinematic - { - get => false; - set => Debug.LogWarning("CharacterController cannot be kinematic"); - } - - protected override void RigidbodyAttached() - { - ref var character = ref Physics.Characters.AllocateCharacter(BodyReference.Value.Handle); - character.LocalUp = new Vector3(0, 1, 0); - character.JumpVelocity = jumpVelocity; - character.MaximumVerticalForce = maxVerticalForce; - character.MaximumHorizontalForce = maxHoriztonalForce; - character.MinimumSupportDepth = supportDepth; - character.MinimumSupportContinuationDepth = supportContinuationDepth; - character.CosMaximumSlope = MathF.Cos(maxSlope.ToRad()); - - character.TargetVelocity = TargetVelocity; - - BodyReference.Value.SetLocalInertia(new BodyInertia { InverseMass = 1f / Mass }); - } - - protected override void RigidbodyDetached() - { - Physics.Characters.RemoveCharacterByBodyHandle(BodyReference.Value.Handle); - } - - public override void Update() - { - ref var character = ref Physics.Characters.GetCharacterByBodyHandle(BodyReference.Value.Handle); - - character.CosMaximumSlope = MathF.Cos(maxSlope.ToRad()); - character.JumpVelocity = jumpVelocity; - - if (!BodyReference.Value.Awake && - ((character.TryJump && character.Supported) || - TargetVelocity.ToFloat() != character.TargetVelocity || - (TargetVelocity != Vector2.zero && character.ViewDirection != Transform.forward.ToFloat()))) - { - Physics.Sim.Awakener.AwakenBody(character.BodyHandle); - } - - character.ViewDirection = Transform.forward; - character.TargetVelocity = TargetVelocity; - IsGrounded = character.Supported; - - if (!base.Kinematic) - BodyReference.Value.LocalInertia = new BodyInertia { InverseMass = 1f / Mass }; - } - - public void TryJump() => Physics.Characters.GetCharacterByBodyHandle(BodyReference.Value.Handle).TryJump = true; -} diff --git a/Prowl.Runtime/Components/Physics/Colliders/BoxCollider.cs b/Prowl.Runtime/Components/Physics/Colliders/BoxCollider.cs deleted file mode 100644 index d81cd638e..000000000 --- a/Prowl.Runtime/Components/Physics/Colliders/BoxCollider.cs +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics; -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using Prowl.Icons; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Box} Box Collider")] -public sealed class BoxCollider : Collider -{ - [SerializeField, HideInInspector] private Vector3 _size = new(1, 1, 1); - - [ShowInInspector] - public Vector3 Size - { - get => _size; - set - { - _size = value; - Container?.ReAttach(); - } - } - - public Vector3 WorldSize - { - get - { - return _size * Transform.lossyScale; - } - } - - internal override void AddToCompoundBuilder(BufferPool pool, ref CompoundBuilder builder, RigidPose localPose) - { - var size = WorldSize; - builder.Add(new Box((float)size.x, (float)size.y, (float)size.z), localPose, Mass); - } -} diff --git a/Prowl.Runtime/Components/Physics/Colliders/CapsuleCollider.cs b/Prowl.Runtime/Components/Physics/Colliders/CapsuleCollider.cs deleted file mode 100644 index c9688930b..000000000 --- a/Prowl.Runtime/Components/Physics/Colliders/CapsuleCollider.cs +++ /dev/null @@ -1,60 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using Prowl.Icons; - -using NRigidPose = BepuPhysics.RigidPose; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Capsules} Capsule Collider")] -public sealed class CapsuleCollider : Collider -{ - [SerializeField, HideInInspector] private float _radius = 0.5f; - [SerializeField, HideInInspector] private float _length = 1f; - - [ShowInInspector] - public float Radius - { - get => _radius; - set - { - _radius = value; - Container?.ReAttach(); - } - } - - [ShowInInspector] - public float Length - { - get => _length; - set - { - _length = value; - Container?.ReAttach(); - } - } - - public float WorldRadius - { - get - { - var scale = Transform.lossyScale; - return _length * (float)MathD.Max(scale.x, scale.z); - } - } - - public float WorldLength - { - get => _length * (float)Transform.lossyScale.y; - } - - internal override void AddToCompoundBuilder(BufferPool pool, ref CompoundBuilder builder, NRigidPose localPose) - { - builder.Add(new Capsule(WorldRadius, WorldLength), localPose, Mass); - } -} diff --git a/Prowl.Runtime/Components/Physics/Colliders/Collider.cs b/Prowl.Runtime/Components/Physics/Colliders/Collider.cs deleted file mode 100644 index ccf2dd310..000000000 --- a/Prowl.Runtime/Components/Physics/Colliders/Collider.cs +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using NRigidPose = BepuPhysics.RigidPose; - -namespace Prowl.Runtime; - -public abstract class Collider : MonoBehaviour -{ - [SerializeField, HideInInspector] private float _mass = 1f; - private uint _transformVersion = 1; - - public PhysicsBody? Container { get; internal set; } - - [ShowInInspector] - public float Mass - { - get => _mass; - set - { - _mass = value; - Container?.ReAttach(); - } - } - - public override void OnEnable() - { - base.OnEnable(); - _transformVersion = Transform.version; - } - - public override void LateUpdate() - { - if (Transform.version != _transformVersion) - { - if (Container.Transform != Transform) - Container?.ReAttach(); - _transformVersion = Transform.version; - } - } - - - internal abstract void AddToCompoundBuilder(BufferPool pool, ref CompoundBuilder builder, NRigidPose localPose); -} diff --git a/Prowl.Runtime/Components/Physics/Colliders/CylinderCollider.cs b/Prowl.Runtime/Components/Physics/Colliders/CylinderCollider.cs deleted file mode 100644 index 107e2d49c..000000000 --- a/Prowl.Runtime/Components/Physics/Colliders/CylinderCollider.cs +++ /dev/null @@ -1,60 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using Prowl.Icons; - -using NRigidPose = BepuPhysics.RigidPose; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Capsules} Cylinder Collider")] -public sealed class CylinderCollider : Collider -{ - [SerializeField, HideInInspector] private float _radius = 0.5f; - [SerializeField, HideInInspector] private float _length = 1f; - - [ShowInInspector] - public float Radius - { - get => _radius; - set - { - _radius = value; - Container?.ReAttach(); - } - } - - [ShowInInspector] - public float Length - { - get => _length; - set - { - _length = value; - Container?.ReAttach(); - } - } - - public float WorldRadius - { - get - { - var scale = Transform.lossyScale; - return _length * (float)MathD.Max(scale.x, scale.z); - } - } - - public float WorldLength - { - get => _length * (float)Transform.lossyScale.y; - } - - internal override void AddToCompoundBuilder(BufferPool pool, ref CompoundBuilder builder, NRigidPose localPose) - { - builder.Add(new Cylinder(WorldRadius, WorldLength), localPose, Mass); - } -} diff --git a/Prowl.Runtime/Components/Physics/Colliders/SphereCollider.cs b/Prowl.Runtime/Components/Physics/Colliders/SphereCollider.cs deleted file mode 100644 index a8f7745ae..000000000 --- a/Prowl.Runtime/Components/Physics/Colliders/SphereCollider.cs +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using Prowl.Icons; - -using NRigidPose = BepuPhysics.RigidPose; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Circle} Sphere Collider")] -public sealed class SphereCollider : Collider -{ - [SerializeField, HideInInspector] private float _radius = 0.5f; - - [ShowInInspector] - public float Radius - { - get => _radius; - set - { - _radius = value; - Container?.ReAttach(); - } - } - - public float WorldRadius - { - get - { - var worldScale = Transform.lossyScale; - return _radius * (float)MathD.Max(worldScale.x, worldScale.y, worldScale.z); - } - } - - - internal override void AddToCompoundBuilder(BufferPool pool, ref CompoundBuilder builder, NRigidPose localPose) - { - builder.Add(new Sphere(WorldRadius), localPose, Mass); - } -} diff --git a/Prowl.Runtime/Components/Physics/Colliders/TriangleCollider.cs b/Prowl.Runtime/Components/Physics/Colliders/TriangleCollider.cs deleted file mode 100644 index d8a0e761b..000000000 --- a/Prowl.Runtime/Components/Physics/Colliders/TriangleCollider.cs +++ /dev/null @@ -1,61 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using Prowl.Icons; - -using NRigidPose = BepuPhysics.RigidPose; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.ChevronUp} Triangle Collider")] -public sealed class TriangleCollider : Collider -{ - [SerializeField, HideInInspector] private Vector3 _a = new Vector3(-0.5f, 0, 0); - [SerializeField, HideInInspector] private Vector3 _b = new Vector3(0.5f, 0, 0); - [SerializeField, HideInInspector] private Vector3 _c = new Vector3(0, 1, 0); - - [ShowInInspector] - public Vector3 A - { - get => _a; - set - { - _a = value; - Container?.ReAttach(); - } - } - - [ShowInInspector] - public Vector3 B - { - get => _b; - set - { - _b = value; - Container?.ReAttach(); - } - } - - [ShowInInspector] - public Vector3 C - { - get => _c; - set - { - _c = value; - Container?.ReAttach(); - } - } - - internal override void AddToCompoundBuilder(BufferPool pool, ref CompoundBuilder builder, NRigidPose localPose) - { - var localA = A * Transform.lossyScale; - var localB = B * Transform.lossyScale; - var localC = C * Transform.lossyScale; - builder.Add(new Triangle(localA, localB, localC), localPose, Mass); - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/AngularAxisGearMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/AngularAxisGearMotorConstraintComponent.cs deleted file mode 100644 index 610cbf97d..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/AngularAxisGearMotorConstraintComponent.cs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Rotate} Angular Axis Gear Motor Constraint")] -public sealed class AngularAxisGearMotorConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localAxisA; - [SerializeField, HideInInspector] private float _velocityScale; - [SerializeField, HideInInspector] private float _motorSoftness = 0; - [SerializeField, HideInInspector] private float _motorMaximumForce = 1000; - - [ShowInInspector] - public Vector3 LocalAxisA - { - get { return _localAxisA; } - set { _localAxisA = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float VelocityScale - { - get { return _velocityScale; } - set { _velocityScale = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float MotorSoftness - { - get { return _motorSoftness; } - set { _motorSoftness = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get { return _motorMaximumForce; } - set { _motorMaximumForce = value; ConstraintData?.TryUpdateDescription(); } - } - - internal override AngularAxisGearMotor CreateConstraint() - { - return new AngularAxisGearMotor - { - LocalAxisA = _localAxisA, - VelocityScale = _velocityScale, - Settings = new MotorSettings(_motorMaximumForce, _motorSoftness) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/AngularAxisMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/AngularAxisMotorConstraintComponent.cs deleted file mode 100644 index 770840455..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/AngularAxisMotorConstraintComponent.cs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Rotate} Angular Axis Motor Constraint")] -public sealed class AngularAxisMotorConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localAxisA; - [SerializeField, HideInInspector] private float _targetVelocity; - [SerializeField, HideInInspector] private float _motorSoftness = 0; - [SerializeField, HideInInspector] private float _motorMaximumForce = 1000; - - [ShowInInspector] - public Vector3 LocalAxisA - { - get { return _localAxisA; } - set { _localAxisA = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float TargetVelocity - { - get { return _targetVelocity; } - set { _targetVelocity = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float MotorSoftness - { - get { return _motorSoftness; } - set { _motorSoftness = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get { return _motorMaximumForce; } - set { _motorMaximumForce = value; ConstraintData?.TryUpdateDescription(); } - } - - internal override AngularAxisMotor CreateConstraint() - { - return new AngularAxisMotor - { - LocalAxisA = _localAxisA, - TargetVelocity = _targetVelocity, - Settings = new MotorSettings(_motorMaximumForce, _motorSoftness) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/AngularHingeConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/AngularHingeConstraintComponent.cs deleted file mode 100644 index 24e5d86dd..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/AngularHingeConstraintComponent.cs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Rotate} Angular Hinge Constraint")] -public sealed class AngularHingeConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localHingeAxisA; - [SerializeField, HideInInspector] private Vector3 _localHingeAxisB; - [SerializeField, HideInInspector] private float _springFrequency = 30; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalHingeAxisA - { - get { return _localHingeAxisA; } - set { _localHingeAxisA = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public Vector3 LocalHingeAxisB - { - get { return _localHingeAxisB; } - set { _localHingeAxisB = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float SpringFrequency - { - get { return _springFrequency; } - set { _springFrequency = value; ConstraintData?.TryUpdateDescription(); } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get { return _springDampingRatio; } - set { _springDampingRatio = value; ConstraintData?.TryUpdateDescription(); } - } - - internal override AngularHinge CreateConstraint() - { - return new AngularHinge - { - LocalHingeAxisA = _localHingeAxisA, - LocalHingeAxisB = _localHingeAxisB, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/AngularServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/AngularServoConstraintComponent.cs deleted file mode 100644 index 15a6ae605..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/AngularServoConstraintComponent.cs +++ /dev/null @@ -1,115 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.ClockRotateLeft} Angular Servo")] -public sealed class AngularServoConstraintComponent : TwoBodyConstraintComponent -{ - - [SerializeField, HideInInspector] private Quaternion _targetRelativeRotationLocalA = Quaternion.identity; - - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Quaternion TargetRelativeRotationLocalA - { - get - { - return _targetRelativeRotationLocalA; - } - set - { - _targetRelativeRotationLocalA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override AngularServo CreateConstraint() - { - return new AngularServo - { - TargetRelativeRotationLocalA = _targetRelativeRotationLocalA, - ServoSettings = new ServoSettings(_servoMaximumSpeed, _servoBaseSpeed, _servoMaximumForce), - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/AngularSwivelHingeConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/AngularSwivelHingeConstraintComponent.cs deleted file mode 100644 index 33a38e0ec..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/AngularSwivelHingeConstraintComponent.cs +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.ClockRotateLeft} Angular Swivel Hinge")] -public sealed class AngularSwivelHingeConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localSwivelAxisA; - [SerializeField, HideInInspector] private Vector3 _localHingeAxisB; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalSwivelAxisA - { - get - { - return _localSwivelAxisA; - } - set - { - _localSwivelAxisA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalHingeAxisB - { - get - { - return _localHingeAxisB; - } - set - { - _localHingeAxisB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override AngularSwivelHinge CreateConstraint() - { - return new AngularSwivelHinge - { - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio), - LocalSwivelAxisA = _localSwivelAxisA, - LocalHingeAxisB = _localHingeAxisB - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/AreaConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/AreaConstraintComponent.cs deleted file mode 100644 index 7039c455f..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/AreaConstraintComponent.cs +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Square} Area Constraint")] -public sealed class AreaConstraintComponent : ThreeBodyConstraintComponent -{ - [SerializeField, HideInInspector] private float _targetScaledArea; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public float TargetScaledArea - { - get - { - return _targetScaledArea; - } - set - { - _targetScaledArea = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override AreaConstraint CreateConstraint() - { - return new() - { - TargetScaledArea = _targetScaledArea, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/BallSocketConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/BallSocketConstraintComponent.cs deleted file mode 100644 index 3ba3afd3f..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/BallSocketConstraintComponent.cs +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Circle} Ball Socket")] -public sealed class BallSocketConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override BallSocket CreateConstraint() - { - return new BallSocket - { - LocalOffsetA = _localOffsetA, - LocalOffsetB = _localOffsetB, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/BallSocketMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/BallSocketMotorConstraintComponent.cs deleted file mode 100644 index f1e6013f3..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/BallSocketMotorConstraintComponent.cs +++ /dev/null @@ -1,80 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Circle} Ball Socket Motor")] -public sealed class BallSocketMotorConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _targetVelocityLocalA; - - [SerializeField, HideInInspector] private float _motorSoftness = 0; - [SerializeField, HideInInspector] private float _motorMaximumForce = 1000; - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 TargetVelocityLocalA - { - get - { - return _targetVelocityLocalA; - } - set - { - _targetVelocityLocalA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorSoftness - { - get - { - return _motorSoftness; - } - set - { - _motorSoftness = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get - { - return _motorMaximumForce; - } - set - { - _motorMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override BallSocketMotor CreateConstraint() - { - return new BallSocketMotor - { - LocalOffsetB = _localOffsetB, - TargetVelocityLocalA = _targetVelocityLocalA, - Settings = new MotorSettings(_motorMaximumForce, _motorSoftness) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/BallSocketServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/BallSocketServoConstraintComponent.cs deleted file mode 100644 index e2731da77..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/BallSocketServoConstraintComponent.cs +++ /dev/null @@ -1,129 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Circle} Ball Socket Servo")] -public sealed class BallSocketServoConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override BallSocketServo CreateConstraint() - { - return new BallSocketServo - { - LocalOffsetA = _localOffsetA, - LocalOffsetB = _localOffsetB, - ServoSettings = new ServoSettings - { - MaximumSpeed = _servoMaximumSpeed, - BaseSpeed = _servoBaseSpeed, - MaximumForce = _servoMaximumForce, - }, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/CenterDistanceConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/CenterDistanceConstraintComponent.cs deleted file mode 100644 index 4786f73d8..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/CenterDistanceConstraintComponent.cs +++ /dev/null @@ -1,66 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.ArrowsToDot} Center Distance Constraint")] -public sealed class CenterDistanceConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private float _targetDistance = 0; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public float TargetDistance - { - get - { - return _targetDistance; - } - set - { - _targetDistance = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override CenterDistanceConstraint CreateConstraint() - { - return new CenterDistanceConstraint - { - TargetDistance = _targetDistance, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/CenterDistanceLimitConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/CenterDistanceLimitConstraintComponent.cs deleted file mode 100644 index 9d018bed9..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/CenterDistanceLimitConstraintComponent.cs +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.ArrowsToDot} Center Distance Limit")] -public sealed class CenterDistanceLimitConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private float _minimumDistance = 0; - [SerializeField, HideInInspector] private float _maximumDistance = 0; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public float MinimumDistance - { - get { return _minimumDistance; } - set - { - _minimumDistance = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MaximumDistance - { - get { return _maximumDistance; } - set - { - _maximumDistance = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override CenterDistanceLimit CreateConstraint() - { - return new CenterDistanceLimit - { - MinimumDistance = _minimumDistance, - MaximumDistance = _maximumDistance, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/DistanceLimitConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/DistanceLimitConstraintComponent.cs deleted file mode 100644 index 319ff81d6..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/DistanceLimitConstraintComponent.cs +++ /dev/null @@ -1,104 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Ruler} Distance Limit")] -public sealed class DistanceLimitConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private float _minimumDistance; - [SerializeField, HideInInspector] private float _maximumDistance; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - - [ShowInInspector] - public float MinimumAngle - { - get { return _minimumDistance; } - set - { - _minimumDistance = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MaximumAngle - { - get { return _maximumDistance; } - set - { - _maximumDistance = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override DistanceLimit CreateConstraint() - { - return new DistanceLimit - { - LocalOffsetA = _localOffsetA, - LocalOffsetB = _localOffsetB, - MinimumDistance = _minimumDistance, - MaximumDistance = _maximumDistance, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/DistanceServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/DistanceServoConstraintComponent.cs deleted file mode 100644 index 32c7e76fe..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/DistanceServoConstraintComponent.cs +++ /dev/null @@ -1,149 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Ruler} Distance Servo")] -public sealed class DistanceServoConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - - [SerializeField, HideInInspector] private float _targetDistance; - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float TargetDistance - { - get - { - return _targetDistance; - } - set - { - _targetDistance = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override DistanceServo CreateConstraint() - { - return new DistanceServo - { - LocalOffsetA = LocalOffsetA, - LocalOffsetB = LocalOffsetB, - TargetDistance = TargetDistance, - ServoSettings = new ServoSettings - { - MaximumSpeed = ServoMaximumSpeed, - BaseSpeed = ServoBaseSpeed, - MaximumForce = ServoMaximumForce - }, - SpringSettings = new SpringSettings - { - Frequency = SpringFrequency, - DampingRatio = SpringDampingRatio - } - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/HingeConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/HingeConstraintComponent.cs deleted file mode 100644 index 742e3710c..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/HingeConstraintComponent.cs +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Rotate} Hinge Constraint")] -public sealed class HingeConstraintComponent : TwoBodyConstraintComponent -{ - - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localHingeAxisA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localHingeAxisB; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get - { - return _localOffsetA; - } - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalHingeAxisA - { - get - { - return _localHingeAxisA; - } - set - { - _localHingeAxisA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get - { - return _localOffsetB; - } - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalHingeAxisB - { - get - { - return _localHingeAxisB; - } - set - { - _localHingeAxisB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override Hinge CreateConstraint() - { - return new Hinge - { - LocalOffsetA = _localOffsetA, - LocalHingeAxisA = _localHingeAxisA, - LocalOffsetB = _localOffsetB, - LocalHingeAxisB = _localHingeAxisB, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/LinearAxisLimitConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/LinearAxisLimitConstraintComponent.cs deleted file mode 100644 index a42093e87..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/LinearAxisLimitConstraintComponent.cs +++ /dev/null @@ -1,117 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} Linear Axis Limit Constraint")] -public sealed class LinearAxisLimitConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localAxis; - [SerializeField, HideInInspector] private float _minimumOffset = 0; - [SerializeField, HideInInspector] private float _maximumOffset = 0; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalAxis - { - get => _localAxis; - set - { - _localAxis = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MinimumOffset - { - get => _minimumOffset; - set - { - _minimumOffset = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MaximumOffset - { - get => _maximumOffset; - set - { - _maximumOffset = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override LinearAxisLimit CreateConstraint() - { - return new LinearAxisLimit - { - LocalOffsetA = _localOffsetA, - LocalOffsetB = _localOffsetB, - LocalAxis = _localAxis, - - MinimumOffset = _minimumOffset, - MaximumOffset = _maximumOffset, - - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/LinearAxisMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/LinearAxisMotorConstraintComponent.cs deleted file mode 100644 index 44755fff8..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/LinearAxisMotorConstraintComponent.cs +++ /dev/null @@ -1,105 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} Linear Axis Motor")] -public sealed class LinearAxisMotorConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localAxis; - [SerializeField, HideInInspector] private float _targetVelocity; - [SerializeField, HideInInspector] private float _motorSoftness = 0; - [SerializeField, HideInInspector] private float _motorMaximumForce = 1000; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalAxis - { - get => _localAxis; - set - { - _localAxis = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float TargetVelocity - { - get - { - return _targetVelocity; - } - set - { - _targetVelocity = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorSoftness - { - get - { - return _motorSoftness; - } - set - { - _motorSoftness = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get - { - return _motorMaximumForce; - } - set - { - _motorMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override LinearAxisMotor CreateConstraint() - { - return new LinearAxisMotor - { - LocalOffsetA = _localOffsetA, - LocalOffsetB = _localOffsetB, - LocalAxis = _localAxis, - TargetVelocity = _targetVelocity, - Settings = new MotorSettings(_motorMaximumForce, _motorSoftness) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/LinearAxisServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/LinearAxisServoConstraintComponent.cs deleted file mode 100644 index a1220a4db..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/LinearAxisServoConstraintComponent.cs +++ /dev/null @@ -1,158 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} Linear Axis Servo")] -public sealed class LinearAxisServoConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localPlaneNormal; - - [SerializeField, HideInInspector] private float _targetOffset; - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalPlaneNormal - { - get => _localPlaneNormal; - set - { - _localPlaneNormal = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float TargetOffset - { - get - { - return _targetOffset; - } - set - { - _targetOffset = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override LinearAxisServo CreateConstraint() - { - return new LinearAxisServo - { - LocalOffsetA = LocalOffsetA, - LocalOffsetB = LocalOffsetB, - LocalPlaneNormal = LocalPlaneNormal, - TargetOffset = TargetOffset, - ServoSettings = new ServoSettings - { - MaximumSpeed = ServoMaximumSpeed, - BaseSpeed = ServoBaseSpeed, - MaximumForce = ServoMaximumForce - }, - SpringSettings = new SpringSettings(SpringFrequency, SpringDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularMotorConstraintComponent.cs deleted file mode 100644 index b15725497..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularMotorConstraintComponent.cs +++ /dev/null @@ -1,65 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.ArrowsSpin} One Body Angular Motor")] -public sealed class OneBodyAngularMotorConstraintComponent : OneBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _targetVelocity; - [SerializeField, HideInInspector] private float _motorSoftness = 0.02f; - [SerializeField, HideInInspector] private float _motorMaximumForce = 10000000; - - public Vector3 TargetVelocity - { - get - { - return _targetVelocity; - } - set - { - _targetVelocity = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorSoftness - { - get - { - return _motorSoftness; - } - set - { - _motorSoftness = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get - { - return _motorMaximumForce; - } - set - { - _motorMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override OneBodyAngularMotor CreateConstraint() - { - return new() - { - TargetVelocity = _targetVelocity, - Settings = new MotorSettings(_motorMaximumForce, _motorSoftness) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularServoConstraintComponent.cs deleted file mode 100644 index bb30410ce..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/OneBodyAngularServoConstraintComponent.cs +++ /dev/null @@ -1,115 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} One Body Angular Servo")] -public sealed class OneBodyAngularServoConstraintComponent : OneBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Quaternion _targetOrientation = Quaternion.identity; - - [SerializeField, HideInInspector] private float _targetOffset; - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Quaternion TargetOrientation - { - get - { - return _targetOrientation; - } - set - { - _targetOrientation = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override OneBodyAngularServo CreateConstraint() - { - return new OneBodyAngularServo - { - TargetOrientation = _targetOrientation, - ServoSettings = new ServoSettings(_servoMaximumSpeed, _servoBaseSpeed, _servoMaximumForce), - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearMotorConstraintComponent.cs deleted file mode 100644 index d041d45da..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearMotorConstraintComponent.cs +++ /dev/null @@ -1,79 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} One Body Linear Motor")] -public sealed class OneBodyLinearMotorConstraintComponent : OneBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffset; - [SerializeField, HideInInspector] private Vector3 _targetVelocity; - [SerializeField, HideInInspector] private float _motorSoftness = 0; - [SerializeField, HideInInspector] private float _motorMaximumForce = 1000; - - [ShowInInspector] - public Vector3 LocalOffset - { - get => _localOffset; - set - { - _localOffset = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 TargetVelocity - { - get - { - return _targetVelocity; - } - set - { - _targetVelocity = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorSoftness - { - get - { - return _motorSoftness; - } - set - { - _motorSoftness = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get - { - return _motorMaximumForce; - } - set - { - _motorMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override OneBodyLinearMotor CreateConstraint() - { - return new() - { - LocalOffset = _localOffset, - TargetVelocity = _targetVelocity, - Settings = new MotorSettings(_motorMaximumForce, _motorSoftness) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearServoConstraintComponent.cs deleted file mode 100644 index e1835b5f0..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/OneBodyLinearServoConstraintComponent.cs +++ /dev/null @@ -1,136 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} One Body Linear Servo")] -public sealed class OneBodyLinearServoConstraintComponent : OneBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffset; - [SerializeField, HideInInspector] private Vector3 _target; - - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 100; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffset - { - get => _localOffset; - set - { - _localOffset = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 Target - { - get - { - return _target; - } - set - { - _target = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override OneBodyLinearServo CreateConstraint() - { - return new OneBodyLinearServo - { - LocalOffset = LocalOffset, - Target = Target, - ServoSettings = new ServoSettings - { - MaximumSpeed = ServoMaximumSpeed, - BaseSpeed = ServoBaseSpeed, - MaximumForce = ServoMaximumForce - }, - SpringSettings = new SpringSettings - { - Frequency = SpringFrequency, - DampingRatio = SpringDampingRatio - } - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/PointOnLineServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/PointOnLineServoConstraintComponent.cs deleted file mode 100644 index 6480ab956..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/PointOnLineServoConstraintComponent.cs +++ /dev/null @@ -1,146 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LinesLeaning} Point On Line Servo")] -public sealed class PointOnLineServoConstraintComponent : TwoBodyConstraintComponent -{ - - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localDirection; - - [SerializeField, HideInInspector] private float _targetOffset; - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - public Vector3 LocalDirection - { - get - { - return _localDirection; - } - set - { - _localDirection = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override PointOnLineServo CreateConstraint() - { - return new PointOnLineServo - { - LocalOffsetA = LocalOffsetA, - LocalOffsetB = LocalOffsetB, - LocalDirection = LocalDirection, - ServoSettings = new ServoSettings - { - MaximumSpeed = ServoMaximumSpeed, - BaseSpeed = ServoBaseSpeed, - MaximumForce = ServoMaximumForce, - }, - SpringSettings = new SpringSettings(SpringFrequency, SpringDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/SwingLimitConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/SwingLimitConstraintComponent.cs deleted file mode 100644 index a797f8e3e..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/SwingLimitConstraintComponent.cs +++ /dev/null @@ -1,104 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.U} Swing Limit")] -public sealed class SwingLimitConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _axisLocalA; - [SerializeField, HideInInspector] private Vector3 _axisLocalB; - [SerializeField, HideInInspector] private float _minimumDot = 0; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - public Vector3 AxisLocalA - { - get - { - return _axisLocalA; - } - set - { - _axisLocalA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - public Vector3 AxisLocalB - { - get - { - return _axisLocalB; - } - set - { - _axisLocalB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MinimumDot - { - get { return _minimumDot; } - set - { - _minimumDot = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MaximumSwingAngle - { - get { return (float)MathD.Acos(MinimumDot); } - set - { - MinimumDot = (float)MathD.Cos(value); - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override SwingLimit CreateConstraint() - { - return new SwingLimit - { - AxisLocalA = AxisLocalA, - AxisLocalB = AxisLocalB, - MinimumDot = MinimumDot, - SpringSettings = new SpringSettings(SpringFrequency, SpringDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/SwivelHingeConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/SwivelHingeConstraintComponent.cs deleted file mode 100644 index 93c30a6e8..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/SwivelHingeConstraintComponent.cs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.U} Swing Hinge")] -public sealed class SwivelHingeConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localSwivelAxisA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localHingeAxisB; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get - { - return _localOffsetA; - } - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalSwivelAxisA - { - get - { - return _localSwivelAxisA; - } - set - { - _localSwivelAxisA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get - { - return _localOffsetB; - } - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalHingeAxisB - { - get - { - return _localHingeAxisB; - } - set - { - _localHingeAxisB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override SwivelHinge CreateConstraint() - { - return new SwivelHinge - { - LocalOffsetA = LocalOffsetA, - LocalSwivelAxisA = LocalSwivelAxisA, - LocalOffsetB = LocalOffsetB, - LocalHingeAxisB = LocalHingeAxisB, - SpringSettings = new SpringSettings(SpringFrequency, SpringDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/TwistLimitConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/TwistLimitConstraintComponent.cs deleted file mode 100644 index d91ef377f..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/TwistLimitConstraintComponent.cs +++ /dev/null @@ -1,109 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.GroupArrowsRotate} Twist Limit")] -public sealed class TwistLimitConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Quaternion _localBasisA; - [SerializeField, HideInInspector] private Quaternion _localBasisB; - - [SerializeField, HideInInspector] private float _minimumAngle = 0; - [SerializeField, HideInInspector] private float _maximumAngle = 0; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Quaternion LocalBasisA - { - get - { - return _localBasisA; - } - set - { - _localBasisA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Quaternion LocalBasisB - { - get - { - return _localBasisB; - } - set - { - _localBasisB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MinimumAngle - { - get { return _minimumAngle; } - set - { - _minimumAngle = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MaximumAngle - { - get { return _maximumAngle; } - set - { - _maximumAngle = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override TwistLimit CreateConstraint() - { - return new TwistLimit - { - LocalBasisA = _localBasisA, - LocalBasisB = _localBasisB, - MinimumAngle = _minimumAngle, - MaximumAngle = _maximumAngle, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/TwistMotorConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/TwistMotorConstraintComponent.cs deleted file mode 100644 index 560c38aae..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/TwistMotorConstraintComponent.cs +++ /dev/null @@ -1,105 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.GroupArrowsRotate} Twist Motor")] -public sealed class TwistMotorConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffsetA; - [SerializeField, HideInInspector] private Vector3 _localOffsetB; - [SerializeField, HideInInspector] private Vector3 _localAxis; - [SerializeField, HideInInspector] private float _targetVelocity; - [SerializeField, HideInInspector] private float _motorSoftness = 0; - [SerializeField, HideInInspector] private float _motorMaximumForce = 1000; - - [ShowInInspector] - public Vector3 LocalOffsetA - { - get => _localOffsetA; - set - { - _localOffsetA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalOffsetB - { - get => _localOffsetB; - set - { - _localOffsetB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Vector3 LocalAxis - { - get => _localAxis; - set - { - _localAxis = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float TargetVelocity - { - get - { - return _targetVelocity; - } - set - { - _targetVelocity = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorSoftness - { - get - { - return _motorSoftness; - } - set - { - _motorSoftness = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float MotorMaximumForce - { - get - { - return _motorMaximumForce; - } - set - { - _motorMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override TwistMotor CreateConstraint() - { - return new() - { - LocalAxisA = _localAxis, - LocalAxisB = _localAxis, - TargetVelocity = _targetVelocity, - Settings = new MotorSettings(_motorSoftness, _motorMaximumForce) - - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/TwistServoConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/TwistServoConstraintComponent.cs deleted file mode 100644 index 6f24390ac..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/TwistServoConstraintComponent.cs +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.GroupArrowsRotate} Twist Servo")] -public sealed class TwistServoConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Quaternion _localBasisA; - [SerializeField, HideInInspector] private Quaternion _localBasisB; - - [SerializeField, HideInInspector] private float _targetAngle; - [SerializeField, HideInInspector] private float _servoMaximumSpeed = 10; - [SerializeField, HideInInspector] private float _servoBaseSpeed = 1; - [SerializeField, HideInInspector] private float _servoMaximumForce = 1000; - - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - [ShowInInspector] - public Quaternion LocalBasisA - { - get - { - return _localBasisA; - } - set - { - _localBasisA = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Quaternion LocalBasisB - { - get - { - return _localBasisB; - } - set - { - _localBasisB = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float TargetAngle - { - get { return _targetAngle; } - set - { - _targetAngle = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumSpeed - { - get - { - return _servoMaximumSpeed; - } - set - { - _servoMaximumSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoBaseSpeed - { - get - { - return _servoBaseSpeed; - } - set - { - _servoBaseSpeed = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float ServoMaximumForce - { - get - { - return _servoMaximumForce; - } - set - { - _servoMaximumForce = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override TwistServo CreateConstraint() - { - return new TwistServo - { - LocalBasisA = _localBasisA, - LocalBasisB = _localBasisB, - TargetAngle = _targetAngle, - ServoSettings = new ServoSettings - { - MaximumSpeed = _servoMaximumSpeed, - BaseSpeed = _servoBaseSpeed, - MaximumForce = _servoMaximumForce - }, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/VolumeConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/VolumeConstraintComponent.cs deleted file mode 100644 index 1d6725c83..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/VolumeConstraintComponent.cs +++ /dev/null @@ -1,62 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.Square} Volume Constraint")] -public sealed class VolumeConstraintComponent : FourBodyConstraintComponent -{ - [SerializeField, HideInInspector] private float _targetScaledVolume = 35; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - public float TargetScaledVolume - { - get { return _targetScaledVolume; } - set - { - _targetScaledVolume = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override VolumeConstraint CreateConstraint() - { - return new VolumeConstraint() - { - TargetScaledVolume = _targetScaledVolume, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/WeldConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/WeldConstraintComponent.cs deleted file mode 100644 index 0175b3be4..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/WeldConstraintComponent.cs +++ /dev/null @@ -1,82 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{Icons.FontAwesome6.HillRockslide} Physics/{Icons.FontAwesome6.Joint} Constraints/{Icons.FontAwesome6.LocationPin} Weld Constraint")] -public sealed class WeldConstraintComponent : TwoBodyConstraintComponent -{ - [SerializeField, HideInInspector] private Vector3 _localOffset; - [SerializeField, HideInInspector] private Quaternion _localOrientation = Quaternion.identity; - [SerializeField, HideInInspector] private float _springFrequency = 35; - [SerializeField, HideInInspector] private float _springDampingRatio = 5; - - - [ShowInInspector] - public Vector3 LocalOffset - { - get - { - return _localOffset; - } - set - { - _localOffset = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public Quaternion LocalOrientation - { - get - { - return _localOrientation; - } - set - { - _localOrientation = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - ConstraintData?.TryUpdateDescription(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - ConstraintData?.TryUpdateDescription(); - } - } - - internal override Weld CreateConstraint() - { - return new Weld - { - LocalOffset = _localOffset, - LocalOrientation = _localOrientation, - SpringSettings = new SpringSettings(_springFrequency, _springDampingRatio) - }; - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponent.cs deleted file mode 100644 index 4ecdd84b9..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponent.cs +++ /dev/null @@ -1,27 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public abstract class ConstraintComponent : ConstraintComponentBase where T : unmanaged, IConstraintDescription -{ - /// - /// ContainerData is the bridge to Bepu. - /// Set through the processor when it calls . - /// - internal ConstraintData? ConstraintData { get; set; } - - internal override void RemoveDataRef() - { - ConstraintData = null; - } - - internal override ConstraintDataBase? UntypedConstraintData => ConstraintData; - - internal abstract T CreateConstraint(); - - internal override ConstraintDataBase CreateProcessorData() => ConstraintData = new(this); - protected ConstraintComponent(int bodies) : base(bodies) { } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponentBase.cs b/Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponentBase.cs deleted file mode 100644 index 3da64fe0b..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/_ConstraintComponentBase.cs +++ /dev/null @@ -1,125 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; - -using BepuPhysics; -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public abstract class ConstraintComponentBase : MonoBehaviour -{ - [SerializeField, HideInInspector] private readonly Rigidbody?[] _bodies; - - public ReadOnlySpan Bodies => _bodies; - - protected ConstraintComponentBase(int bodies) => _bodies = new Rigidbody?[bodies]; - - protected Rigidbody? this[int i] - { - get => _bodies[i]; - set - { - _bodies[i] = value; - UntypedConstraintData?.RebuildConstraint(); - } - } - - public override void OnEnable() - { - if (UntypedConstraintData == null) - CreateProcessorData(); - //UntypedConstraintData.RebuildConstraint(); - } - - public override void OnDisable() - { - UntypedConstraintData?.DestroyConstraint(); - RemoveDataRef(); - } - - public override void LateUpdate() - { - //timer += Time.deltaTimeF; - //if(timer > 0.1) - { - if (UntypedConstraintData?.Exist == false) - UntypedConstraintData.RebuildConstraint(); - } - } - - internal abstract void RemoveDataRef(); - - internal abstract ConstraintDataBase? UntypedConstraintData { get; } - - internal abstract ConstraintDataBase CreateProcessorData(); -} - -internal abstract class ConstraintDataBase -{ - public abstract bool Exist { get; } - - internal abstract void RebuildConstraint(); - internal abstract void DestroyConstraint(); - internal abstract void TryUpdateDescription(); -} - -internal sealed class ConstraintData : ConstraintDataBase where T : unmanaged, IConstraintDescription -{ - private readonly ConstraintComponent _constraintComponent; - private ConstraintHandle _cHandle = new(-1); - private bool _exist = false; - - public override bool Exist => _exist; - - public ConstraintData(ConstraintComponent constraintComponent) - { - _constraintComponent = constraintComponent; - } - - internal override void RebuildConstraint() - { - DestroyConstraint(); - - if (!_constraintComponent.Enabled && Physics.IsReady) - return; - - foreach (var container in _constraintComponent.Bodies) - { - if (container is null || container.BodyReference.HasValue == false) - return; // need to wait for a body to be attached or instanced - } - - Span bodies = stackalloc BodyHandle[_constraintComponent.Bodies.Length]; - int count = 0; - - foreach (var component in _constraintComponent.Bodies) - bodies[count++] = component.BodyReference.Value.Handle; - - Span validBodies = bodies[..count]; - - _cHandle = Physics.Sim.Solver.Add(validBodies, _constraintComponent.CreateConstraint()); - - _exist = true; - } - - internal override void DestroyConstraint() - { - if (_cHandle.Value != -1 && Physics.IsReady && Physics.Sim.Solver.ConstraintExists(_cHandle)) - { - Physics.Sim.Solver.Remove(_cHandle); - _cHandle = new(-1); - } - - _exist = false; - } - - internal override void TryUpdateDescription() - { - if (Physics.IsReady && _cHandle.Value != -1 && Physics.Sim.Solver.ConstraintExists(_cHandle)) - { - Physics.Sim.Solver.ApplyDescription(_cHandle, _constraintComponent.CreateConstraint()); - } - } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/_FourBodyConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/_FourBodyConstraintComponent.cs deleted file mode 100644 index 583f60a74..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/_FourBodyConstraintComponent.cs +++ /dev/null @@ -1,39 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public abstract class FourBodyConstraintComponent : ConstraintComponent where T : unmanaged, IConstraintDescription, IFourBodyConstraintDescription -{ - [ShowInInspector] - public Rigidbody? A - { - get => this[0]; - set => this[0] = value; - } - - [ShowInInspector] - public Rigidbody? B - { - get => this[1]; - set => this[1] = value; - } - - [ShowInInspector] - public Rigidbody? C - { - get => this[2]; - set => this[2] = value; - } - - [ShowInInspector] - public Rigidbody? D - { - get => this[3]; - set => this[3] = value; - } - - public FourBodyConstraintComponent() : base(4) { } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/_OneBodyConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/_OneBodyConstraintComponent.cs deleted file mode 100644 index ecf9e0aa5..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/_OneBodyConstraintComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public abstract class OneBodyConstraintComponent : ConstraintComponent where T : unmanaged, IConstraintDescription, IOneBodyConstraintDescription -{ - [ShowInInspector] - public Rigidbody? A - { - get => this[0]; - set => this[0] = value; - } - - public OneBodyConstraintComponent() : base(1) { } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/_ThreeBodyConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/_ThreeBodyConstraintComponent.cs deleted file mode 100644 index b332acec3..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/_ThreeBodyConstraintComponent.cs +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public abstract class ThreeBodyConstraintComponent : ConstraintComponent where T : unmanaged, IConstraintDescription, IThreeBodyConstraintDescription -{ - [ShowInInspector] - public Rigidbody? A - { - get => this[0]; - set => this[0] = value; - } - - [ShowInInspector] - public Rigidbody? B - { - get => this[1]; - set => this[1] = value; - } - - [ShowInInspector] - public Rigidbody? C - { - get => this[2]; - set => this[2] = value; - } - - public ThreeBodyConstraintComponent() : base(3) { } -} diff --git a/Prowl.Runtime/Components/Physics/Constraints/_TwoBodyConstraintComponent.cs b/Prowl.Runtime/Components/Physics/Constraints/_TwoBodyConstraintComponent.cs deleted file mode 100644 index ada08b3b6..000000000 --- a/Prowl.Runtime/Components/Physics/Constraints/_TwoBodyConstraintComponent.cs +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public abstract class TwoBodyConstraintComponent : ConstraintComponent where T : unmanaged, IConstraintDescription, ITwoBodyConstraintDescription -{ - [ShowInInspector] - public Rigidbody? A - { - get => this[0]; - set => this[0] = value; - } - - [ShowInInspector] - public Rigidbody? B - { - get => this[1]; - set => this[1] = value; - } - - public TwoBodyConstraintComponent() : base(2) { } -} diff --git a/Prowl.Runtime/Components/Physics/PhysicsBody.cs b/Prowl.Runtime/Components/Physics/PhysicsBody.cs deleted file mode 100644 index 91647499a..000000000 --- a/Prowl.Runtime/Components/Physics/PhysicsBody.cs +++ /dev/null @@ -1,229 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; -using System.Collections.Generic; -using System.Linq; - -using BepuPhysics; -using BepuPhysics.Collidables; - -using BepuUtilities.Memory; - -using Prowl.Runtime.Contacts; - -namespace Prowl.Runtime; - -public abstract class PhysicsBody : MonoBehaviour -{ - [SerializeField, HideInInspector] private float _springFrequency = 30; - [SerializeField, HideInInspector] private float _springDampingRatio = 3; - [SerializeField, HideInInspector] private float _frictionCoefficient = 1f; - [SerializeField, HideInInspector] private float _maximumRecoveryVelocity = 1000; - - public enum BodyType { Small, Big } - public BodyType Type; - private IContactEventHandler? _trigger; - - protected TypedIndex ShapeIndex { get; private set; } - - public IContactEventHandler? ContactEventHandler - { - get - { - return _trigger; - } - set - { - if (IsContactHandlerRegistered()) - UnregisterContactHandler(); - - _trigger = value; - RegisterContactHandler(); - TryUpdateMaterialProperties(); - } - } - - [ShowInInspector] - public float SpringFrequency - { - get - { - return _springFrequency; - } - set - { - _springFrequency = value; - TryUpdateMaterialProperties(); - } - } - - [ShowInInspector] - public float SpringDampingRatio - { - get - { - return _springDampingRatio; - } - set - { - _springDampingRatio = value; - TryUpdateMaterialProperties(); - } - } - - [ShowInInspector] - public float FrictionCoefficient - { - get => _frictionCoefficient; - set - { - _frictionCoefficient = value; - TryUpdateMaterialProperties(); - } - } - - public float MaximumRecoveryVelocity - { - get => _maximumRecoveryVelocity; - set - { - _maximumRecoveryVelocity = value; - TryUpdateMaterialProperties(); - } - } - - public Vector3 CenterOfMass { get; private set; } - - public override void OnEnable() => ReAttach(); - public override void OnDisable() => Detach(); - -#warning TODO: Work on making ReAttach more Seamless, Ideally you should be able to change the scale of a collider, the mass or something else and have it be completely seamlessly updated - - internal void ReAttach() - { - Debug.Assert(Physics.IsReady, "Physics is not ready, cannot reattach"); - - Detach(); - - if (!TryGetShape(out var index, out var centerOfMass, out var shapeInertia)) - return; - - ShapeIndex = index; - CenterOfMass = centerOfMass; - - AttachInner(new(Transform.position + Transform.rotation * CenterOfMass, Transform.rotation), shapeInertia, ShapeIndex); - - if (ContactEventHandler != null && !IsContactHandlerRegistered()) - RegisterContactHandler(); - - TryUpdateMaterialProperties(); - } - - internal void Detach() - { - Debug.Assert(Physics.IsReady, "Physics is not ready, cannot detach"); - - CenterOfMass = new(); - - if (IsContactHandlerRegistered()) - UnregisterContactHandler(); - - if (ShapeIndex.Exists) - { - Physics.Sim.Shapes.RemoveAndDispose(ShapeIndex, Physics.Sim.BufferPool); - ShapeIndex = default; - } - - DetachInner(); - } - - bool TryGetShape(out TypedIndex index, out Vector3 centerOfMass, out BodyInertia inertia) - { - List colliders = GetComponentsInChildren().ToList(); - - if (colliders.Count == 0) - { - index = default; - centerOfMass = default; - inertia = default; - return false; - } - - var compoundBuilder = new CompoundBuilder(Physics.Sim.BufferPool, Physics.Sim.Shapes, colliders.Count); - try - { - foreach (var collider in colliders) - { - if (collider.Container != null && collider.Container != this) - { - Debug.LogError("Collider is already attached to another container! Do you have a rigidbody as a child of another rigidbody?"); - throw new InvalidOperationException("Collider is already attached to another container."); - } - - Vector3 localTranslation = Vector3.zero; - Quaternion localRotation = Quaternion.identity; - if (collider.Transform != Transform) - { - localTranslation = collider.Transform.localPosition; - localRotation = collider.Transform.localRotation; - } - - var compoundChildLocalPose = new RigidPose(localTranslation, localRotation); - collider.AddToCompoundBuilder(Physics.Sim.BufferPool, ref compoundBuilder, compoundChildLocalPose); - collider.Container = this; - } - - compoundBuilder.BuildDynamicCompound(out Buffer compoundChildren, out inertia, out System.Numerics.Vector3 shapeCenter); - centerOfMass = shapeCenter; - if (Type == BodyType.Small) - index = Physics.Sim.Shapes.Add(new Compound(compoundChildren)); - else - index = Physics.Sim.Shapes.Add(new BigCompound(compoundChildren, Physics.Sim.Shapes, Physics.Sim.BufferPool)); - } - finally - { - compoundBuilder.Dispose(); - } - - return true; - } - - protected void TryUpdateMaterialProperties() - { - if (!Physics.IsReady) - return; - - ref var mat = ref MaterialProperties; - - mat.SpringSettings = new(SpringFrequency, SpringDampingRatio); - mat.FrictionCoefficient = FrictionCoefficient; - mat.MaximumRecoveryVelocity = MaximumRecoveryVelocity; - mat.IsTrigger = ContactEventHandler != null && ContactEventHandler.NoContactResponse; - } - - #region Abstract - - protected abstract ref PhysicsMaterial MaterialProperties { get; } - protected internal abstract RigidPose? Pose { get; } - - /// - /// Called every time the container is added to a simulation - /// - /// - /// May occur when certain larger changes are made to the object, is the one this object is being added to - /// - protected abstract void AttachInner(RigidPose containerPose, BodyInertia shapeInertia, TypedIndex shapeIndex); - /// - /// Called every time the container is removed from the simulation - /// - /// - /// May occur right before when certain larger changes are made to the object, is the one this object was on prior to detaching - /// - protected abstract void DetachInner(); - protected abstract void RegisterContactHandler(); - protected abstract void UnregisterContactHandler(); - protected abstract bool IsContactHandlerRegistered(); - - #endregion -} diff --git a/Prowl.Runtime/Components/Physics/Rigidbody.cs b/Prowl.Runtime/Components/Physics/Rigidbody.cs deleted file mode 100644 index 2e2565103..000000000 --- a/Prowl.Runtime/Components/Physics/Rigidbody.cs +++ /dev/null @@ -1,303 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; - -using BepuPhysics; -using BepuPhysics.Collidables; - -using Prowl.Icons; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Cubes} Rigidbody")] -public class Rigidbody : PhysicsBody -{ - [SerializeField, HideInInspector] private bool _kinematic = false; - [SerializeField, HideInInspector] private ContinuousDetection _continuous = ContinuousDetection.Discrete; - [SerializeField, HideInInspector] private float _sleepThreshold = 0.01f; - [SerializeField, HideInInspector] private byte _minimumTimestepCountUnderThreshold = 32; - [SerializeField, HideInInspector] private InterpolationMode _interpolationMode = InterpolationMode.None; - - /// Can be null when it isn't part of a simulation yet/anymore - internal BodyReference? BodyReference { get; private set; } - - internal RigidPose PreviousPose, CurrentPose; - - private uint _transformVersion = 1; - - [ShowInInspector] - public virtual bool Kinematic - { - get => _kinematic; - set - { - if (_kinematic == value) - return; - - _kinematic = value; - if (BodyReference is { } bRef) - { - bRef.LocalInertia = Kinematic ? new BodyInertia() : _nativeIntertia; - } - } - } - - public float SleepThreshold - { - get => _sleepThreshold; - set - { - if (MathD.ApproximatelyEquals(_sleepThreshold, value)) - return; - - _sleepThreshold = value; - if (BodyReference is { } bRef) - { - bRef.Activity.SleepThreshold = value; - } - } - } - - public byte MinimumTimestepCountUnderThreshold - { - get => _minimumTimestepCountUnderThreshold; - set - { - if (_minimumTimestepCountUnderThreshold == value) - return; - - _minimumTimestepCountUnderThreshold = value; - if (BodyReference is { } bRef) - { - bRef.Activity.MinimumTimestepsUnderThreshold = value; - } - } - } - - [ShowInInspector] - public InterpolationMode InterpolationMode - { - get => _interpolationMode; - set => _interpolationMode = value; - } - - /// - /// Shortcut to . - /// - [ShowInInspector] - public ContinuousDetectionMode ContinuousDetectionMode - { - get => _continuous.Mode; - set - { - if (_continuous.Mode == value) - return; - - _continuous = value switch - { - ContinuousDetectionMode.Discrete => ContinuousDetection.Discrete, - ContinuousDetectionMode.Passive => ContinuousDetection.Passive, - ContinuousDetectionMode.Continuous => ContinuousDetection.Continuous(), - _ => throw new ArgumentOutOfRangeException(nameof(value), value, null) - }; - } - } - - public bool IsAwake - { - get => BodyReference?.Awake ?? false; - set - { - if (BodyReference is { } bodyRef) - bodyRef.Awake = value; - } - } - - public Vector3 LinearVelocity - { - get => BodyReference?.Velocity.Linear ?? default; - set - { - if (BodyReference is { } bodyRef) - bodyRef.Velocity.Linear = value; - } - } - - public Vector3 AngularVelocity - { - get => BodyReference?.Velocity.Angular ?? default; - set - { - if (BodyReference is { } bodyRef) - bodyRef.Velocity.Angular = value; - } - } - - public Vector3 Position - { - get => BodyReference?.Pose.Position ?? default; - set - { - if (BodyReference is { } bodyRef) - bodyRef.Pose.Position = value; - } - } - - public Quaternion Orientation - { - get => BodyReference?.Pose.Orientation ?? Quaternion.identity; - set - { - if (BodyReference is { } bodyRef) - bodyRef.Pose.Orientation = value; - } - } - - public BodyInertia BodyInertia - { - get => BodyReference?.LocalInertia ?? default; - set - { - if (BodyReference is { } bodyRef) - bodyRef.LocalInertia = value; - } - } - - [ShowInInspector] - public float SpeculativeMargin - { - get => BodyReference?.Collidable.SpeculativeMargin ?? default; - set - { - if (BodyReference is { } bodyRef) - bodyRef.Collidable.SpeculativeMargin = value; - } - } - - [ShowInInspector] - public ContinuousDetection ContinuousDetection - { - get => _continuous; - set - { - _continuous = value; - if (BodyReference is { } bodyRef) - bodyRef.Collidable.Continuity = _continuous; - } - } - - public float Mass => _mass; - - public override void OnEnable() - { - base.OnEnable(); - _transformVersion = Transform.version; - } - - public void ApplyImpulse(Vector3 impulse, Vector3 impulseOffset) - { - BodyReference?.ApplyImpulse(impulse, impulseOffset); - } - - public void ApplyAngularImpulse(Vector3 impulse) - { - BodyReference?.ApplyAngularImpulse(impulse); - } - - public void ApplyLinearImpulse(Vector3 impulse) - { - BodyReference?.ApplyLinearImpulse(impulse); - } - - protected override ref PhysicsMaterial MaterialProperties => ref Physics.CollidableMaterials[BodyReference!.Value]; - protected internal override RigidPose? Pose => BodyReference?.Pose; - - private BodyInertia _nativeIntertia; - private float _mass; - - protected override void AttachInner(RigidPose containerPose, BodyInertia shapeInertia, TypedIndex shapeIndex) - { - Debug.Assert(Physics.IsReady); - - _nativeIntertia = shapeInertia; - _mass = 1f / shapeInertia.InverseMass; - if (Kinematic) - shapeInertia = new BodyInertia(); - - var bDescription = BodyDescription.CreateDynamic(containerPose, shapeInertia, shapeIndex, new(SleepThreshold, MinimumTimestepCountUnderThreshold)); - - if (BodyReference is { } bRef) - { - bRef.GetDescription(out var previousDesc); - bDescription.Velocity = previousDesc.Velocity; //Keep velocity when updating - bRef.ApplyDescription(bDescription); - } - else - { - var bHandle = Physics.Sim.Bodies.Add(bDescription); - BodyReference = Physics.Sim.Bodies[bHandle]; - BodyReference.Value.Collidable.Continuity = ContinuousDetection; - - while (Physics.Bodies.Count <= bHandle.Value) // There may be more than one add if soft physics inserted a couple of bodies - Physics.Bodies.Add(null); - Physics.Bodies[bHandle.Value] = this; - - Physics.CollidableMaterials.Allocate(bHandle) = new(); - } - - RigidbodyAttached(); - } - - protected virtual void RigidbodyAttached() { } - - protected override void DetachInner() - { - Debug.Assert(Physics.IsReady); - - if (BodyReference == null) - return; - - Physics.Sim.Bodies.Remove(BodyReference.Value.Handle); - Physics.Bodies[BodyReference.Value.Handle.Value] = null; - - RigidbodyDetached(); - - BodyReference = null; - - } - - protected virtual void RigidbodyDetached() { } - - public void SyncTransform() - { - if (Transform.version != _transformVersion) - { - Position = Transform.position; - Orientation = Transform.rotation; - LinearVelocity = Vector3.zero; - AngularVelocity = Vector3.zero; - IsAwake = true; - _transformVersion = Transform.version; - } - } - - protected override void RegisterContactHandler() - { - if (Physics.IsReady && ContactEventHandler is not null && BodyReference is { } bRef) - Physics.ContactEvents.Register(bRef.Handle, ContactEventHandler); - } - - protected override void UnregisterContactHandler() - { - if (Physics.IsReady && BodyReference is { } bRef) - Physics.ContactEvents.Unregister(bRef.Handle); - } - - protected override bool IsContactHandlerRegistered() - { - if (Physics.IsReady && BodyReference is { } bRef) - return Physics.ContactEvents.IsListener(bRef.Handle); - return false; - } -} diff --git a/Prowl.Runtime/Components/Physics/Staticbody.cs b/Prowl.Runtime/Components/Physics/Staticbody.cs deleted file mode 100644 index a57986c36..000000000 --- a/Prowl.Runtime/Components/Physics/Staticbody.cs +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics; -using BepuPhysics.Collidables; - -using Prowl.Icons; - -namespace Prowl.Runtime; - -[AddComponentMenu($"{FontAwesome6.HillRockslide} Physics/{FontAwesome6.Cubes} Staticbody")] -public class Staticbody : PhysicsBody -{ - [SerializeField, HideInInspector] private ContinuousDetection _continuous = ContinuousDetection.Discrete; - - /// Can be null when it isn't part of a simulation yet/anymore - internal StaticReference? StaticReference { get; private set; } - - internal RigidPose PreviousPose, CurrentPose; - - private uint _transformVersion = 1; - - public Vector3 Position - { - get => StaticReference?.Pose.Position ?? default; - set - { - if (StaticReference is { } bodyRef) - bodyRef.Pose.Position = value; - } - } - - public Quaternion Orientation - { - get => StaticReference?.Pose.Orientation ?? Quaternion.identity; - set - { - if (StaticReference is { } bodyRef) - bodyRef.Pose.Orientation = value; - } - } - - [ShowInInspector] - public ContinuousDetection ContinuousDetection - { - get => StaticReference?.Continuity ?? default; - set - { - if (StaticReference is { } bodyRef) - bodyRef.Continuity = value; - } - } - - public override void OnEnable() - { - base.OnEnable(); - _transformVersion = Transform.version; - } - - protected override ref PhysicsMaterial MaterialProperties => ref Physics.CollidableMaterials[StaticReference!.Value.Handle]; - protected internal override RigidPose? Pose => StaticReference?.Pose; - - protected override void AttachInner(RigidPose containerPose, BodyInertia shapeInertia, TypedIndex shapeIndex) - { - Debug.Assert(Physics.IsReady); - - var sDescription = new StaticDescription(containerPose, shapeIndex); - - if (StaticReference is { } sRef) - { - sRef.ApplyDescription(sDescription); - } - else - { - var sHandle = Physics.Sim.Statics.Add(sDescription); - StaticReference = Physics.Sim.Statics[sHandle]; - - while (Physics.Statics.Count <= sHandle.Value) // There may be more than one add if soft physics inserted a couple of bodies - Physics.Statics.Add(null); - Physics.Statics[sHandle.Value] = this; - - Physics.CollidableMaterials.Allocate(sHandle) = new(); - } - } - - protected override void DetachInner() - { - Debug.Assert(Physics.IsReady); - - if (StaticReference == null) - return; - - Physics.Sim.Statics.Remove(StaticReference.Value.Handle); - Physics.Statics[StaticReference.Value.Handle.Value] = null; - StaticReference = null; - } - - public void SyncTransform() - { - if (Transform.version != _transformVersion) - { - Position = Transform.position; - Orientation = Transform.rotation; - _transformVersion = Transform.version; - } - } - - protected override void RegisterContactHandler() - { - if (Physics.IsReady && ContactEventHandler is not null && StaticReference is { } sRef) - Physics.ContactEvents.Register(sRef.Handle, ContactEventHandler); - } - - protected override void UnregisterContactHandler() - { - if (Physics.IsReady && StaticReference is { } sRef) - Physics.ContactEvents.Unregister(sRef.Handle); - } - - protected override bool IsContactHandlerRegistered() - { - if (Physics.IsReady && StaticReference is { } sRef) - return Physics.ContactEvents.IsListener(sRef.Handle); - return false; - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/BepuNarrowPhaseCallbacks.cs b/Prowl.Runtime/Components/Physics/Types/BepuNarrowPhaseCallbacks.cs deleted file mode 100644 index 482bb74ff..000000000 --- a/Prowl.Runtime/Components/Physics/Types/BepuNarrowPhaseCallbacks.cs +++ /dev/null @@ -1,74 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; -using System.Runtime.CompilerServices; - -using BepuPhysics; -using BepuPhysics.Collidables; -using BepuPhysics.CollisionDetection; - -using Prowl.Runtime.Contacts; - -namespace Prowl.Runtime; - -public unsafe struct BepuNarrowPhaseCallbacks : INarrowPhaseCallbacks -{ - internal CollidableProperty CollidableMaterials { get; set; } - - internal ContactEventsManager ContactEvents { get; set; } - - public void Initialize(Simulation simulation) - { - //Often, the callbacks type is created before the simulation instance is fully constructed, so the simulation will call this function when it's ready. - //Any logic which depends on the simulation existing can be put here. - Physics.Characters.Initialize(simulation); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowContactGeneration(int workerIndex, CollidableReference a, CollidableReference b, ref float speculativeMargin) - { - return a.Mobility == CollidableMobility.Dynamic || b.Mobility == CollidableMobility.Dynamic; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowContactGeneration(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB) - { - var matA = CollidableMaterials[pair.A]; - var matB = CollidableMaterials[pair.B]; - - return PhysicsMaterial.AllowContactGeneration(matA, matB); - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe bool ConfigureContactManifold(int workerIndex, CollidablePair pair, ref TManifold manifold, out PairMaterialProperties pairMaterial) where TManifold : unmanaged, IContactManifold - { - //For the purposes of this demo, we'll use multiplicative blending for the friction and choose spring properties according to which collidable has a higher maximum recovery velocity. - var a = CollidableMaterials[pair.A]; - var b = CollidableMaterials[pair.B]; - pairMaterial.FrictionCoefficient = a.FrictionCoefficient * b.FrictionCoefficient; - pairMaterial.MaximumRecoveryVelocity = (float)MathD.Max(a.MaximumRecoveryVelocity, b.MaximumRecoveryVelocity); - pairMaterial.SpringSettings = MathD.ApproximatelyEquals(pairMaterial.MaximumRecoveryVelocity, a.MaximumRecoveryVelocity) ? a.SpringSettings : b.SpringSettings; - //For the purposes of the demo, contact constraints are always generated. - ContactEvents.HandleManifold(workerIndex, pair, ref manifold); - Physics.Characters.TryReportContacts(pair, ref manifold, workerIndex, ref pairMaterial); - - if (a.IsTrigger || b.IsTrigger) - { - return false; - } - - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ConfigureContactManifold(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB, ref ConvexContactManifold manifold) - { - return true; - } - - public void Dispose() - { - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/BepuPoseIntegratorCallbacks.cs b/Prowl.Runtime/Components/Physics/Types/BepuPoseIntegratorCallbacks.cs deleted file mode 100644 index 8c0ed3c1c..000000000 --- a/Prowl.Runtime/Components/Physics/Types/BepuPoseIntegratorCallbacks.cs +++ /dev/null @@ -1,102 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System.Numerics; - -using BepuPhysics; - -using BepuUtilities; - - -namespace Prowl.Runtime; - -internal struct BepuPoseIntegratorCallbacks : IPoseIntegratorCallbacks -{ - private Vector3Wide _gravityWideDt = default; - private Vector _linearDampingDt = default; - private Vector _angularDampingDt = default; - - /// - /// Gravity to apply to dynamic bodies in the simulation. - /// - public Vector3 Gravity { get; set; } = new(0, -9.8f, 0); - /// - /// Fraction of dynamic body linear velocity to remove per unit of time. Values range from 0 to 1. 0 is fully undamped, while values very close to 1 will remove most velocity. - /// - public float LinearDamping { get; set; } = 0.05f; - /// - /// Fraction of dynamic body angular velocity to remove per unit of time. Values range from 0 to 1. 0 is fully undamped, while values very close to 1 will remove most velocity. - /// - public float AngularDamping { get; set; } = 0.05f; - - - /// - /// Gets how the pose integrator should handle angular velocity integration. - /// - public readonly AngularIntegrationMode AngularIntegrationMode => AngularIntegrationMode.Nonconserving; - - /// - /// Gets whether the integrator should use substepping for unconstrained bodies when using a substepping solver. - /// If true, unconstrained bodies will be integrated with the same number of substeps as the constrained bodies in the solver. - /// If false, unconstrained bodies use a single step of length equal to the dt provided to Simulation.Timestep. - /// - public readonly bool AllowSubstepsForUnconstrainedBodies => false; - - /// - /// Gets whether the velocity integration callback should be called for kinematic bodies. - /// If true, IntegrateVelocity will be called for bundles including kinematic bodies. - /// If false, kinematic bodies will just continue using whatever velocity they have set. - /// Most use cases should set this to false. - /// - public readonly bool IntegrateVelocityForKinematics => false; - - - public BepuPoseIntegratorCallbacks() - { - } - - public void Initialize(Simulation simulation) - { - } - - /// - /// Callback invoked ahead of dispatches that may call into . - /// It may be called more than once with different values over a frame. For example, when performing bounding box prediction, velocity is integrated with a full frame time step duration. - /// During substepped solves, integration is split into substepCount steps, each with fullFrameDuration / substepCount duration. - /// The final integration pass for unconstrained bodies may be either fullFrameDuration or fullFrameDuration / substepCount, depending on the value of AllowSubstepsForUnconstrainedBodies. - /// - /// Current integration time step duration. - /// This is typically used for precomputing anything expensive that will be used across velocity integration. - public void PrepareForIntegration(float dt) - { - //No reason to recalculate gravity * dt for every body; just cache it ahead of time. - //Since these callbacks don't use per-body damping values, we can precalculate everything. - _linearDampingDt = new Vector((float)MathD.Pow(MathHelper.Clamp(1 - LinearDamping, 0, 1), dt)); - _angularDampingDt = new Vector((float)MathD.Pow(MathHelper.Clamp(1 - AngularDamping, 0, 1), dt)); - _gravityWideDt = Vector3Wide.Broadcast(Gravity * dt); - } - - /// - /// Callback for a bundle of bodies being integrated. - /// - /// Indices of the bodies being integrated in this bundle. - /// Current body positions. - /// Current body orientations. - /// Body's current local inertia. - /// Mask indicating which lanes are active in the bundle. Active lanes will contain 0xFFFFFFFF, inactive lanes will contain 0. - /// Index of the worker thread processing this bundle. - /// Durations to integrate the velocity over. Can vary over lanes. - /// Velocity of bodies in the bundle. Any changes to lanes which are not active by the integrationMask will be discarded. - public void IntegrateVelocity(Vector bodyIndices, Vector3Wide position, QuaternionWide orientation, BodyInertiaWide localInertia, Vector integrationMask, int workerIndex, Vector dt, ref BodyVelocityWide velocity) - { - - //This is a handy spot to implement things like position dependent gravity or per-body damping. - //This implementation uses a single damping value for all bodies that allows it to be precomputed. - //We don't have to check for kinematics; IntegrateVelocityForKinematics returns false, so we'll never see them in this callback. - //Note that these are SIMD operations and "Wide" types. There are Vector.Count lanes of execution being evaluated simultaneously. - //The types are laid out in array-of-structures-of-arrays (AOSOA) format. That's because this function is frequently called from vectorized contexts within the solver. - //Transforming to "array of structures" (AOS) format for the callback and then back to AOSOA would involve a lot of overhead, so instead the callback works on the AOSOA representation directly. - velocity.Linear = (velocity.Linear + _gravityWideDt) * _linearDampingDt; - velocity.Angular = velocity.Angular * _angularDampingDt; - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Contacts/ContactEventsManager.cs b/Prowl.Runtime/Components/Physics/Types/Contacts/ContactEventsManager.cs deleted file mode 100644 index 726be7bc4..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Contacts/ContactEventsManager.cs +++ /dev/null @@ -1,476 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using BepuPhysics; -using BepuPhysics.Collidables; -using BepuPhysics.CollisionDetection; - -using BepuUtilities; -using BepuUtilities.Collections; -using BepuUtilities.Memory; - -namespace Prowl.Runtime.Contacts; - -/// -/// Watches a set of bodies and statics for contact changes and reports events. -/// -internal class ContactEventsManager : IDisposable -{ - //To know what events to emit, we have to track the previous state of a collision. We don't need to keep around old positions/offets/normals/depths, so it's quite a bit lighter. - [StructLayout(LayoutKind.Sequential)] - struct PreviousCollision - { - public CollidableReference Collidable; - public bool Fresh; - public bool WasTouching; - public int ContactCount; - //FeatureIds are identifiers encoding what features on the involved shapes contributed to the contact. We store up to 4 feature ids, one for each potential contact. - //A "feature" is things like a face, vertex, or edge. There is no single interpretation for what a feature is- the mapping is defined on a per collision pair level. - //In this demo, we only care to check whether a given contact in the current frame maps onto a contact from a previous frame. - //We can use this to only emit 'contact added' events when a new contact with an unrecognized id is reported. - public int FeatureId0; - public int FeatureId1; - public int FeatureId2; - public int FeatureId3; - } - - readonly IThreadDispatcher? threadDispatcher; - BufferPool? pool; - - //We'll use a handle->index mapping in a CollidableProperty to point at our contiguously stored listeners (in the later listeners array). - //Note that there's also IndexSets for the statics and bodies; those will be checked first before accessing the listenerIndices. - //The CollidableProperty is quite barebones- it doesn't try to stop all invalid accesses, and the backing memory isn't guaranteed to be zero initialized. - //IndexSets are tightly bitpacked and are cheap to access, so they're an easy way to check if a collidable can trigger an event before doing any further processing. - CollidableProperty listenerIndices; - IndexSet staticListenerFlags; - IndexSet bodyListenerFlags; - int listenerCount; - - //For the purpose of this demo, we'll use some regular ol' interfaces rather than using the struct-implementing-interface for specialization. - //This array will be GC tracked as a result, but that should be mostly fine. If you've got hundreds of thousands of event handlers, you may want to consider alternatives. - struct Listener - { - public CollidableReference Source; - public IContactEventHandler Handler; - public QuickList PreviousCollisions; - } - Listener[] listeners; - - //The callbacks are invoked from a multithreaded context, and we don't know how many pairs will exist. - //Rather than attempting to synchronize all accesses, every worker thread spits out the results into a worker-local list to be processed later by the main thread flush. - struct PendingWorkerAdd - { - public int ListenerIndex; - public PreviousCollision Collision; - } - QuickList[] pendingWorkerAdds; - - /// - /// Creates a new contact events stream. - /// - /// Thread dispatcher to pull per-thread buffer pools from, if any. - /// Buffer pool used to manage resources internally. If null, the simulation's pool will be used. - /// Number of listeners to allocate space for initially. -#pragma warning disable CS8618 // Unassigned null fields, will be initialized through Initialize() below - public ContactEventsManager(IThreadDispatcher? threadDispatcher = null, BufferPool? pool = null, int initialListenerCapacity = 64) -#pragma warning restore CS8618 - { - this.threadDispatcher = threadDispatcher; - this.pool = pool; - listeners = new Listener[initialListenerCapacity]; - } - - BufferPool? GetPoolForWorker(int workerIndex) - { - return threadDispatcher == null ? pool : threadDispatcher.WorkerPools[workerIndex]; - } - - /// - /// Initializes the contact events system with a simulation. - /// - /// Simulation to use with the contact events demo. - /// The constructor and initialization are split because of how this class is expected to be used. - /// It will be passed into a simulation's constructor as a part of its contact callbacks, so there is no simulation available at the time of construction. - public void Initialize() - { - pool ??= Physics.Sim.BufferPool; - Physics.Sim.Timestepper.BeforeCollisionDetection += SetFreshnessForCurrentActivityStatus; - listenerIndices = new CollidableProperty(Physics.Sim, pool); - pendingWorkerAdds = new QuickList[threadDispatcher == null ? 1 : threadDispatcher.ThreadCount]; - } - - /// - /// Begins listening for events related to the given collidable. - /// - /// Collidable to monitor for events. - /// Handlers to use for the collidable. - public void Register(CollidableReference collidable, IContactEventHandler handler) - { - if (collidable.Mobility == CollidableMobility.Static) - staticListenerFlags.Add(collidable.RawHandleValue, pool); - else - bodyListenerFlags.Add(collidable.RawHandleValue, pool); - if (listenerCount >= listeners.Length) - { - Array.Resize(ref listeners, listeners.Length * 2); - } - //Note that allocations for the previous collision list are deferred until they actually exist. - listeners[listenerCount] = new Listener { Handler = handler, Source = collidable }; - listenerIndices[collidable] = listenerCount; - ++listenerCount; - } - - /// - /// Begins listening for events related to the given body. - /// - /// Body to monitor for events. - /// Handlers to use for the body. - public void Register(BodyHandle body, IContactEventHandler handler) - { - Register(Physics.Sim.Bodies[body].CollidableReference, handler); - } - - /// - /// Begins listening for events related to the given static. - /// - /// Static to monitor for events. - /// Handlers to use for the static. - public void Register(StaticHandle staticHandle, IContactEventHandler handler) - { - Register(new CollidableReference(staticHandle), handler); - } - - /// - /// Stops listening for events related to the given collidable. - /// - /// Collidable to stop listening for. - public void Unregister(CollidableReference collidable) - { - if (collidable.Mobility == CollidableMobility.Static) - { - staticListenerFlags.Remove(collidable.RawHandleValue); - } - else - { - bodyListenerFlags.Remove(collidable.RawHandleValue); - } - var index = listenerIndices[collidable]; - --listenerCount; - ref var removedSlot = ref listeners[index]; - if (removedSlot.PreviousCollisions.Span.Allocated) - removedSlot.PreviousCollisions.Dispose(pool); - ref var lastSlot = ref listeners[listenerCount]; - if (index < listenerCount) - { - listenerIndices[lastSlot.Source] = index; - removedSlot = lastSlot; - } - lastSlot = default; - } - - /// - /// Stops listening for events related to the given body. - /// - /// Body to stop listening for. - public void Unregister(BodyHandle body) - { - Unregister(Physics.Sim.Bodies[body].CollidableReference); - } - - /// - /// Stops listening for events related to the given static. - /// - /// Static to stop listening for. - public void Unregister(StaticHandle staticHandle) - { - Unregister(new CollidableReference(staticHandle)); - } - - /// - /// Checks if a collidable is registered as a listener. - /// - /// Collidable to check. - /// True if the collidable has been registered as a listener, false otherwise. - public bool IsListener(CollidableReference collidable) - { - if (collidable.Mobility == CollidableMobility.Static) - { - return staticListenerFlags.Contains(collidable.RawHandleValue); - } - else - { - return bodyListenerFlags.Contains(collidable.RawHandleValue); - } - } - - /// - /// Checks if a collidable is registered as a listener. - /// - public bool IsListener(BodyHandle body) - { - return IsListener(Physics.Sim.Bodies[body].CollidableReference); - } - /// - /// Checks if a collidable is registered as a listener. - /// - public bool IsListener(StaticHandle staticHandle) - { - return IsListener(Physics.Sim.Statics[staticHandle].CollidableReference); - } - /// - /// Callback attached to the simulation's ITimestepper which executes just prior to collision detection to take a snapshot of activity states to determine which pairs we should expect updates in. - /// - void SetFreshnessForCurrentActivityStatus(float dt, IThreadDispatcher threadDispatcher) - { - //Every single pair tracked by the contact events has a 'freshness' flag. If the final flush sees a pair that is stale, it'll remove it - //and any necessary events to represent the end of that pair are reported. - //HandleManifoldForCollidable sets 'Fresh' to true for any processed pair, but pairs between sleeping or static bodies will not show up in HandleManifoldForCollidable since they're not active. - //We don't want Flush to report that sleeping pairs have stopped colliding, so we pre-initialize any such sleeping/static pair as 'fresh'. - - //This could be multithreaded reasonably easily if there are a ton of listeners or collisions, but that would be a pretty high bar. - //For simplicity, the demo will keep it single threaded. - var bodyHandleToLocation = Physics.Sim.Bodies.HandleToLocation; - for (int listenerIndex = 0; listenerIndex < listenerCount; ++listenerIndex) - { - ref var listener = ref listeners[listenerIndex]; - var source = listener.Source; - //If it's a body, and it's in the active set (index 0), then every pair associated with the listener should expect updates. - var sourceExpectsUpdates = source.Mobility != CollidableMobility.Static && bodyHandleToLocation[source.BodyHandle.Value].SetIndex == 0; - if (sourceExpectsUpdates) - { - var previousCollisions = listeners[listenerIndex].PreviousCollisions; - for (int j = 0; j < previousCollisions.Count; ++j) - { - //Pair updates will set the 'freshness' to true when they happen, so that they won't be considered 'stale' in the flush and removed. - previousCollisions[j].Fresh = false; - } - } - else - { - //The listener is either static or sleeping. We should only expect updates if the other collidable is awake. - var previousCollisions = listeners[listenerIndex].PreviousCollisions; - for (int j = 0; j < previousCollisions.Count; ++j) - { - ref var previousCollision = ref previousCollisions[j]; - previousCollision.Fresh = previousCollision.Collidable.Mobility == CollidableMobility.Static || bodyHandleToLocation[previousCollision.Collidable.BodyHandle.Value].SetIndex > 0; - } - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void UpdatePreviousCollision(ref PreviousCollision collision, ref TManifold manifold, bool isTouching) where TManifold : unmanaged, IContactManifold - { - //If the above assert gets hit because of a change to nonconvex manifold capacities, the packed feature id representation this uses will need to be updated. - //I very much doubt the nonconvex manifold will ever use more than 8 contacts, so addressing this wouldn't require much of a change. - for (int j = 0; j < manifold.Count; ++j) - { - Unsafe.Add(ref collision.FeatureId0, j) = manifold.GetFeatureId(j); - } - collision.ContactCount = manifold.Count; - collision.Fresh = true; - collision.WasTouching = isTouching; - } - - void HandleManifoldForCollidable(int workerIndex, CollidableReference source, CollidableReference other, ref TManifold manifold) where TManifold : unmanaged, IContactManifold - { - //The "source" refers to the object that an event handler was (potentially) attached to, so we look for listeners registered for it. - //(This function is called for both orders of the pair, so we'll catch listeners for either.) - if (!IsListener(source)) - return; - - var listenerIndex = listenerIndices[source]; - //This collidable is registered. Is the opposing collidable present? - ref var listener = ref listeners[listenerIndex]; - - int previousCollisionIndex = -1; - bool isTouching = false; - for (int i = 0; i < listener.PreviousCollisions.Count; ++i) - { - ref var collision = ref listener.PreviousCollisions[i]; - //Since the 'Packed' field contains both the handle type (dynamic, kinematic, or static) and the handle index packed into a single bitfield, an equal value guarantees we are dealing with the same collidable. - if (collision.Collidable.Packed == other.Packed) - { - previousCollisionIndex = i; - //This manifold is associated with an existing collision. - //For every contact in the old collsion still present (by feature id), set a flag in this bitmask so we can know when a contact is removed. - int previousContactsStillExist = 0; - for (int contactIndex = 0; contactIndex < manifold.Count; ++contactIndex) - { - //We can check if each contact was already present in the previous frame by looking at contact feature ids. See the 'PreviousCollision' type for a little more info on FeatureIds. - var featureId = manifold.GetFeatureId(contactIndex); - var featureIdWasInPreviousCollision = false; - for (int previousContactIndex = 0; previousContactIndex < collision.ContactCount; ++previousContactIndex) - { - if (featureId == Unsafe.Add(ref collision.FeatureId0, previousContactIndex)) - { - featureIdWasInPreviousCollision = true; - previousContactsStillExist |= 1 << previousContactIndex; - break; - } - } - if (!featureIdWasInPreviousCollision) - { - listener.Handler.OnContactAdded(source, other, ref manifold, contactIndex, workerIndex); - } - if (manifold.GetDepth(contactIndex) >= 0) - isTouching = true; - } - if (previousContactsStillExist != (1 << collision.ContactCount) - 1) - { - //At least one contact that used to exist no longer does. - for (int previousContactIndex = 0; previousContactIndex < collision.ContactCount; ++previousContactIndex) - { - if ((previousContactsStillExist & 1 << previousContactIndex) == 0) - { - listener.Handler.OnContactRemoved(source, other, ref manifold, Unsafe.Add(ref collision.FeatureId0, previousContactIndex), workerIndex); - } - } - } - if (!collision.WasTouching && isTouching) - { - listener.Handler.OnStartedTouching(source, other, ref manifold, workerIndex); - } - else if (collision.WasTouching && !isTouching) - { - listener.Handler.OnStoppedTouching(source, other, ref manifold, workerIndex); - } - if (isTouching) - { - listener.Handler.OnTouching(source, other, ref manifold, workerIndex); - } - UpdatePreviousCollision(ref collision, ref manifold, isTouching); - break; - } - } - if (previousCollisionIndex < 0) - { - //There was no collision previously. - ref var addsforWorker = ref pendingWorkerAdds[workerIndex]; - //EnsureCapacity will create the list if it doesn't already exist. - addsforWorker.EnsureCapacity(Math.Max(addsforWorker.Count + 1, 64), GetPoolForWorker(workerIndex)); - ref var pendingAdd = ref addsforWorker.AllocateUnsafely(); - pendingAdd.ListenerIndex = listenerIndex; - pendingAdd.Collision.Collidable = other; - listener.Handler.OnPairCreated(source, other, ref manifold, workerIndex); - //Dispatch events for all contacts in this new manifold. - for (int i = 0; i < manifold.Count; ++i) - { - listener.Handler.OnContactAdded(source, other, ref manifold, i, workerIndex); - if (manifold.GetDepth(i) >= 0) - isTouching = true; - } - if (isTouching) - { - listener.Handler.OnStartedTouching(source, other, ref manifold, workerIndex); - listener.Handler.OnTouching(source, other, ref manifold, workerIndex); - } - UpdatePreviousCollision(ref pendingAdd.Collision, ref manifold, isTouching); - } - listener.Handler.OnPairUpdated(source, other, ref manifold, workerIndex); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void HandleManifold(int workerIndex, CollidablePair pair, ref TManifold manifold) where TManifold : unmanaged, IContactManifold - { - HandleManifoldForCollidable(workerIndex, pair.A, pair.B, ref manifold); - HandleManifoldForCollidable(workerIndex, pair.B, pair.A, ref manifold); - } - - //For final events fired by the flush that still expect a manifold, we'll provide a special empty type. - struct EmptyManifold : IContactManifold - { - public int Count => 0; - public bool Convex => true; - //This type never has any contacts, so there's no need for any property grabbers. - public Contact this[int contactIndex] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public static ref ConvexContact GetConvexContactReference(ref EmptyManifold manifold, int contactIndex) => throw new NotImplementedException(); - public static ref float GetDepthReference(ref EmptyManifold manifold, int contactIndex) => throw new NotImplementedException(); - public static ref int GetFeatureIdReference(ref EmptyManifold manifold, int contactIndex) => throw new NotImplementedException(); - public static ref Contact GetNonconvexContactReference(ref EmptyManifold manifold, int contactIndex) => throw new NotImplementedException(); - public static ref System.Numerics.Vector3 GetNormalReference(ref EmptyManifold manifold, int contactIndex) => throw new NotImplementedException(); - public static ref System.Numerics.Vector3 GetOffsetReference(ref EmptyManifold manifold, int contactIndex) => throw new NotImplementedException(); - public void GetContact(int contactIndex, out System.Numerics.Vector3 offset, out System.Numerics.Vector3 normal, out float depth, out int featureId) => throw new NotImplementedException(); - public void GetContact(int contactIndex, out Contact contactData) => throw new NotImplementedException(); - public float GetDepth(int contactIndex) => throw new NotImplementedException(); - public int GetFeatureId(int contactIndex) => throw new NotImplementedException(); - public System.Numerics.Vector3 GetNormal(int contactIndex) => throw new NotImplementedException(); - public System.Numerics.Vector3 GetOffset(int contactIndex) => throw new NotImplementedException(); - } - - public void Flush() - { - //For simplicity, this is completely sequential. Note that it's technically possible to extract more parallelism, but the complexity cost is high and you would need - //very large numbers of events being processed to make it worth it. - - //Remove any stale collisions. Stale collisions are those which should have received a new manifold update but did not because the manifold is no longer active. - for (int i = 0; i < listenerCount; ++i) - { - ref var listener = ref listeners[i]; - //Note reverse order. We remove during iteration. - for (int j = listener.PreviousCollisions.Count - 1; j >= 0; --j) - { - ref var collision = ref listener.PreviousCollisions[j]; - if (!collision.Fresh) - { - //Sort the references to be consistent with the direct narrow phase results. - CollidablePair pair; - NarrowPhase.SortCollidableReferencesForPair(listener.Source, collision.Collidable, out _, out _, out pair.A, out pair.B); - if (collision.ContactCount > 0) - { - var emptyManifold = new EmptyManifold(); - for (int previousContactCount = 0; previousContactCount < collision.ContactCount; ++previousContactCount) - { - listener.Handler.OnContactRemoved(listener.Source, collision.Collidable, ref emptyManifold, Unsafe.Add(ref collision.FeatureId0, previousContactCount), 0); - } - if (collision.WasTouching) - listener.Handler.OnStoppedTouching(listener.Source, collision.Collidable, ref emptyManifold, 0); - } - listener.Handler.OnPairEnded(collision.Collidable, collision.Collidable); - //This collision was not updated since the last flush despite being active. It should be removed. - listener.PreviousCollisions.FastRemoveAt(j); - if (listener.PreviousCollisions.Count == 0) - { - listener.PreviousCollisions.Dispose(pool); - listener.PreviousCollisions = default; - } - } - else - { - collision.Fresh = false; - } - } - } - - for (int i = 0; i < pendingWorkerAdds.Length; ++i) - { - ref var pendingAdds = ref pendingWorkerAdds[i]; - for (int j = 0; j < pendingAdds.Count; ++j) - { - ref var add = ref pendingAdds[j]; - ref var collisions = ref listeners[add.ListenerIndex].PreviousCollisions; - //Ensure capacity will initialize the slot if necessary. - collisions.EnsureCapacity(Math.Max(8, collisions.Count + 1), pool); - collisions.AllocateUnsafely() = pendingAdds[j].Collision; - } - if (pendingAdds.Span.Allocated) - pendingAdds.Dispose(GetPoolForWorker(i)); - //We rely on zeroing out the count for lazy initialization. - pendingAdds = default; - } - } - - public void Dispose() - { - if (bodyListenerFlags.Flags.Allocated) - bodyListenerFlags.Dispose(pool); - if (staticListenerFlags.Flags.Allocated) - staticListenerFlags.Dispose(pool); - listenerIndices.Dispose(); - Physics.Sim.Timestepper.BeforeCollisionDetection -= SetFreshnessForCurrentActivityStatus; - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Contacts/IContactEventHandler.cs b/Prowl.Runtime/Components/Physics/Types/Contacts/IContactEventHandler.cs deleted file mode 100644 index 8d940194d..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Contacts/IContactEventHandler.cs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; -using BepuPhysics.CollisionDetection; - -namespace Prowl.Runtime.Contacts; - -/// -/// Implements handlers for various collision events. -/// -public interface IContactEventHandler -{ - /// - /// Whether the object this is attached to should let colliders pass through it - /// - public bool NoContactResponse { get; } - - /// - /// Fires when a contact is added. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Index of the new contact in the contact manifold. - /// Index of the worker thread that fired this event. - void OnContactAdded(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int contactIndex, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - /// - /// Fires when a contact is removed. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Feature id of the contact that was removed and is no longer present in the contact manifold. - /// Index of the worker thread that fired this event. - void OnContactRemoved(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int removedFeatureId, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - /// - /// Fires the first time a pair is observed to be touching. Touching means that there are contacts with nonnegative depths in the manifold. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Index of the worker thread that fired this event. - void OnStartedTouching(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - /// - /// Fires whenever a pair is observed to be touching. Touching means that there are contacts with nonnegative depths in the manifold. Will not fire for sleeping pairs. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Index of the worker thread that fired this event. - void OnTouching(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - - /// - /// Fires when a pair stops touching. Touching means that there are contacts with nonnegative depths in the manifold. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Index of the worker thread that fired this event. - void OnStoppedTouching(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - - /// - /// Fires when a pair is observed for the first time. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Index of the worker thread that fired this event. - void OnPairCreated(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - /// - /// Fires whenever a pair is updated. Will not fire for sleeping pairs. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - /// Set of remaining contacts in the collision. - /// Index of the worker thread that fired this event. - void OnPairUpdated(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int workerIndex) where TManifold : unmanaged, IContactManifold - { - } - - /// - /// Fires when a pair ends. - /// - /// Type of the contact manifold detected. - /// Collidable that the event was attached to. - /// Other collider collided with. - void OnPairEnded(CollidableReference eventSource, CollidableReference other) - { - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllerData.cs b/Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllerData.cs deleted file mode 100644 index 6aa4c1bd0..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllerData.cs +++ /dev/null @@ -1,59 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics; -using BepuPhysics.Collidables; - -namespace Prowl.Runtime.Controller; - -/// Raw data for a dynamic character controller instance. -public struct CharacterControllerData -{ - /// Direction the character is looking in world space. Defines the forward direction for movement. - public System.Numerics.Vector3 ViewDirection; - - /// - /// Target horizontal velocity. - /// X component refers to desired velocity along the strafing direction (perpendicular to the view direction projected down to the surface), - /// Y component refers to the desired velocity along the forward direction (aligned with the view direction projected down to the surface). - /// - public System.Numerics.Vector2 TargetVelocity; - - /// If true, the character will try to jump on the next time step. Will be reset to false after being processed. - public bool TryJump; - - /// Handle of the body associated with the character. - public BodyHandle BodyHandle; - - /// Character's up direction in the local space of the character's body. - public System.Numerics.Vector3 LocalUp; - - /// Velocity at which the character pushes off the support during a jump. - public float JumpVelocity; - - /// Maximum force the character can apply tangent to the supporting surface to move. - public float MaximumHorizontalForce; - - /// Maximum force the character can apply to glue itself to the supporting surface. - public float MaximumVerticalForce; - - /// Cosine of the maximum slope angle that the character can treat as a support. - public float CosMaximumSlope; - - /// Depth threshold beyond which a contact is considered a support if it the normal allows it. - public float MinimumSupportDepth; - - /// - /// Depth threshold beyond which a contact is considered a support if the previous frame had support, even if it isn't deep enough to meet the MinimumSupportDepth. - /// - public float MinimumSupportContinuationDepth; - - /// Whether the character is currently supported. - public bool Supported; - - /// Collidable supporting the character, if any. Only valid if Supported is true. - public CollidableReference Support; - - /// Handle of the character's motion constraint, if any. Only valid if Supported is true. - public ConstraintHandle MotionConstraintHandle; -} diff --git a/Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllersManager.cs b/Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllersManager.cs deleted file mode 100644 index f561697a9..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Controller/CharacterControllersManager.cs +++ /dev/null @@ -1,834 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; -using System.Runtime.CompilerServices; -using System.Threading; - -using BepuPhysics; -using BepuPhysics.Collidables; -using BepuPhysics.CollisionDetection; - -using BepuUtilities; -using BepuUtilities.Collections; -using BepuUtilities.Memory; - -namespace Prowl.Runtime.Controller; - -// The majority of code in this file came from the BEPUPhysicsv2 demos. - -/// System that manages all the characters in a simulation. Responsible for updating movement constraints based on character goals and contact states. -public unsafe class CharacterControllersManager : IDisposable -{ - readonly BufferPool pool; - - Buffer bodyHandleToCharacterIndex; - QuickList characters; - - /// - /// Gets the number of characters being controlled. - /// - public int CharacterCount { get { return characters.Count; } } - - /// - /// Creates a character controller systme. - /// - /// Pool to allocate resources from. - /// Number of characters to initially allocate space for. - /// Number of body handles to initially allocate space for in the body handle->character mapping. - public CharacterControllersManager(BufferPool pool, int initialCharacterCapacity = 4096, int initialBodyHandleCapacity = 4096) - { - this.pool = pool; - characters = new QuickList(initialCharacterCapacity, pool); - ResizeBodyHandleCapacity(initialBodyHandleCapacity); - analyzeContactsWorker = AnalyzeContactsWorker; - expandBoundingBoxesWorker = ExpandBoundingBoxesWorker; - } - - /// - /// Caches the simulation associated with the characters. - /// - /// Simulation to be associated with the characters. - public void Initialize(Simulation simulation) - { - simulation.Solver.Register(); - simulation.Solver.Register(); - simulation.Timestepper.BeforeCollisionDetection += PrepareForContacts; - simulation.Timestepper.CollisionsDetected += AnalyzeContacts; - } - - private void ResizeBodyHandleCapacity(int bodyHandleCapacity) - { - var oldCapacity = bodyHandleToCharacterIndex.Length; - pool.ResizeToAtLeast(ref bodyHandleToCharacterIndex, bodyHandleCapacity, bodyHandleToCharacterIndex.Length); - if (bodyHandleToCharacterIndex.Length > oldCapacity) - { - Unsafe.InitBlockUnaligned(ref Unsafe.As(ref bodyHandleToCharacterIndex[oldCapacity]), 0xFF, (uint)((bodyHandleToCharacterIndex.Length - oldCapacity) * sizeof(int))); - } - } - - /// - /// Gets the current memory slot index of a character using its associated body handle. - /// - /// Body handle associated with the character to look up the index of. - /// Index of the character associated with the body handle. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetCharacterIndexForBodyHandle(int bodyHandle) - { - Debug.Assert(bodyHandle >= 0 && bodyHandle < bodyHandleToCharacterIndex.Length && bodyHandleToCharacterIndex[bodyHandle] >= 0, "Can only look up indices for body handles associated with characters in this CharacterControllers instance."); - return bodyHandleToCharacterIndex[bodyHandle]; - } - - /// - /// Gets a reference to the character at the given memory slot index. - /// - /// Index of the character to retrieve. - /// Reference to the character at the given memory slot index. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref CharacterControllerData GetCharacterByIndex(int index) - { - return ref characters[index]; - } - - /// - /// Gets a reference to the character using the handle of the character's body. - /// - /// Body handle of the character to look up. - /// Reference to the character associated with the given body handle. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref CharacterControllerData GetCharacterByBodyHandle(BodyHandle bodyHandle) - { - Debug.Assert(bodyHandle.Value >= 0 && bodyHandle.Value < bodyHandleToCharacterIndex.Length && bodyHandleToCharacterIndex[bodyHandle.Value] >= 0, "Can only look up indices for body handles associated with characters in this CharacterControllers instance."); - return ref characters[bodyHandleToCharacterIndex[bodyHandle.Value]]; - } - - /// - /// Allocates a character. - /// - /// Body handle associated with the character. - /// Reference to the allocated character. - public ref CharacterControllerData AllocateCharacter(BodyHandle bodyHandle) - { - Debug.Assert(bodyHandle.Value >= 0 && (bodyHandle.Value >= bodyHandleToCharacterIndex.Length || bodyHandleToCharacterIndex[bodyHandle.Value] == -1), - "Cannot allocate more than one character for the same body handle."); - if (bodyHandle.Value >= bodyHandleToCharacterIndex.Length) - ResizeBodyHandleCapacity(Math.Max(bodyHandle.Value + 1, bodyHandleToCharacterIndex.Length * 2)); - var characterIndex = characters.Count; - ref var character = ref characters.Allocate(pool); - character = default; - character.BodyHandle = bodyHandle; - bodyHandleToCharacterIndex[bodyHandle.Value] = characterIndex; - return ref character; - } - - /// - /// Removes a character from the character controllers set by the character's index. - /// - /// Index of the character to remove. - public void RemoveCharacterByIndex(int characterIndex) - { - Debug.Assert(characterIndex >= 0 && characterIndex < characters.Count, "Character index must exist in the set of characters."); - ref var character = ref characters[characterIndex]; - Debug.Assert(character.BodyHandle.Value >= 0 && character.BodyHandle.Value < bodyHandleToCharacterIndex.Length && bodyHandleToCharacterIndex[character.BodyHandle.Value] == characterIndex, - "Character must exist in the set of characters."); - bodyHandleToCharacterIndex[character.BodyHandle.Value] = -1; - characters.FastRemoveAt(characterIndex); - //If the removal moved a character, update the body handle mapping. - if (characters.Count > characterIndex) - { - bodyHandleToCharacterIndex[characters[characterIndex].BodyHandle.Value] = characterIndex; - } - } - - /// - /// Removes a character from the character controllers set by the body handle associated with the character. - /// - /// Body handle associated with the character to remove. - public void RemoveCharacterByBodyHandle(BodyHandle bodyHandle) - { - Debug.Assert(bodyHandle.Value >= 0 && bodyHandle.Value < bodyHandleToCharacterIndex.Length && bodyHandleToCharacterIndex[bodyHandle.Value] >= 0, - "Removing a character by body handle requires that a character associated with the given body handle actually exists."); - RemoveCharacterByIndex(bodyHandleToCharacterIndex[bodyHandle.Value]); - } - - struct SupportCandidate - { - public System.Numerics.Vector3 OffsetFromCharacter; - public float Depth; - public System.Numerics.Vector3 OffsetFromSupport; - public System.Numerics.Vector3 Normal; - public CollidableReference Support; - } - - struct ContactCollectionWorkerCache - { - public Buffer SupportCandidates; - - public unsafe ContactCollectionWorkerCache(int maximumCharacterCount, BufferPool pool) - { - pool.Take(maximumCharacterCount, out SupportCandidates); - for (int i = 0; i < maximumCharacterCount; ++i) - { - //Initialize the depths to a value that guarantees replacement. - SupportCandidates[i].Depth = float.MinValue; - } - } - - public void Dispose(BufferPool pool) - { - pool.Return(ref SupportCandidates); - } - } - - - Buffer contactCollectionWorkerCaches; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - bool TryReportContacts(CollidableReference characterCollidable, CollidableReference supportCollidable, CollidablePair pair, ref TManifold manifold, int workerIndex) where TManifold : struct, IContactManifold - { - if (characterCollidable.Mobility == CollidableMobility.Dynamic && characterCollidable.BodyHandle.Value < bodyHandleToCharacterIndex.Length) - { - var characterBodyHandle = characterCollidable.BodyHandle; - var characterIndex = bodyHandleToCharacterIndex[characterBodyHandle.Value]; - if (characterIndex >= 0) - { - //This is actually a character. - ref var character = ref characters[characterIndex]; - //Our job here is to process the manifold into a support representation. That means a single point, normal, and importance heuristic. - //Note that we cannot safely pick from the candidates in this function- it is likely executed from a multithreaded context, so all we can do is - //output the pair's result into a worker-exclusive buffer. - - //Contacts with sufficiently negative depth will not be considered support candidates. - //Contacts with intermediate depth (above minimum threshold, but still below negative epsilon) may be candidates if the character previously had support. - //Contacts with depth above negative epsilon always pass the depth test. - - //Maximum depth is used to heuristically choose which contact represents the support. - //Note that this could be changed to subtly modify the behavior- for example, dotting the movement direction with the support normal and such. - //A more careful choice of heuristic could make the character more responsive when trying to 'step' up obstacles. - - //Note that the body may be inactive during this callback even though it will be activated by new constraints after the narrow phase flushes. - //Have to take into account the current potentially inactive location. - ref var bodyLocation = ref Physics.Sim.Bodies.HandleToLocation[character.BodyHandle.Value]; - ref var set = ref Physics.Sim.Bodies.Sets[bodyLocation.SetIndex]; - ref var pose = ref set.DynamicsState[bodyLocation.Index].Motion.Pose; - QuaternionEx.Transform(character.LocalUp, pose.Orientation, out var up); - //Note that this branch is compiled out- the generic constraints force type specialization. - if (manifold.Convex) - { - ref var convexManifold = ref Unsafe.As(ref manifold); - var normalUpDot = System.Numerics.Vector3.Dot(convexManifold.Normal, up); - //The narrow phase generates contacts with normals pointing from B to A by convention. - //If the character is collidable B, then we need to negate the comparison. - if ((pair.B.Packed == characterCollidable.Packed ? -normalUpDot : normalUpDot) > character.CosMaximumSlope) - { - //This manifold has a slope that is potentially supportive. - //Can the maximum depth contact be used as a support? - var maximumDepth = convexManifold.Contact0.Depth; - var maximumDepthIndex = 0; - for (int i = 1; i < convexManifold.Count; ++i) - { - ref var candidateDepth = ref Unsafe.Add(ref convexManifold.Contact0, i).Depth; - if (candidateDepth > maximumDepth) - { - maximumDepth = candidateDepth; - maximumDepthIndex = i; - } - } - if (maximumDepth >= character.MinimumSupportDepth || (character.Supported && maximumDepth > character.MinimumSupportContinuationDepth)) - { - ref var supportCandidate = ref contactCollectionWorkerCaches[workerIndex].SupportCandidates[characterIndex]; - if (supportCandidate.Depth < maximumDepth) - { - //This support candidate should be replaced. - supportCandidate.Depth = maximumDepth; - ref var deepestContact = ref Unsafe.Add(ref convexManifold.Contact0, maximumDepthIndex); - var offsetFromB = deepestContact.Offset - convexManifold.OffsetB; - if (pair.B.Packed == characterCollidable.Packed) - { - supportCandidate.Normal = -convexManifold.Normal; - supportCandidate.OffsetFromCharacter = offsetFromB; - supportCandidate.OffsetFromSupport = deepestContact.Offset; - } - else - { - supportCandidate.Normal = convexManifold.Normal; - supportCandidate.OffsetFromCharacter = deepestContact.Offset; - supportCandidate.OffsetFromSupport = offsetFromB; - } - supportCandidate.Support = supportCollidable; - } - } - } - } - else - { - ref var nonconvexManifold = ref Unsafe.As(ref manifold); - //The narrow phase generates contacts with normals pointing from B to A by convention. - //If the character is collidable B, then we need to negate the comparison. - //This manifold has a slope that is potentially supportive. - //Can the maximum depth contact be used as a support? - var maximumDepth = float.MinValue; - var maximumDepthIndex = -1; - for (int i = 0; i < nonconvexManifold.Count; ++i) - { - ref var candidate = ref Unsafe.Add(ref nonconvexManifold.Contact0, i); - if (candidate.Depth > maximumDepth) - { - //All the nonconvex candidates can have different normals, so we have to perform the (calibrated) normal test on every single one. - var upDot = System.Numerics.Vector3.Dot(candidate.Normal, up); - if ((pair.B.Packed == characterCollidable.Packed ? -upDot : upDot) > character.CosMaximumSlope) - { - maximumDepth = candidate.Depth; - maximumDepthIndex = i; - } - } - } - if (maximumDepth >= character.MinimumSupportDepth || (character.Supported && maximumDepth > character.MinimumSupportContinuationDepth)) - { - ref var supportCandidate = ref contactCollectionWorkerCaches[workerIndex].SupportCandidates[characterIndex]; - if (supportCandidate.Depth < maximumDepth) - { - //This support candidate should be replaced. - ref var deepestContact = ref Unsafe.Add(ref nonconvexManifold.Contact0, maximumDepthIndex); - supportCandidate.Depth = maximumDepth; - var offsetFromB = deepestContact.Offset - nonconvexManifold.OffsetB; - if (pair.B.Packed == characterCollidable.Packed) - { - supportCandidate.Normal = -deepestContact.Normal; - supportCandidate.OffsetFromCharacter = offsetFromB; - supportCandidate.OffsetFromSupport = deepestContact.Offset; - } - else - { - supportCandidate.Normal = deepestContact.Normal; - supportCandidate.OffsetFromCharacter = deepestContact.Offset; - supportCandidate.OffsetFromSupport = offsetFromB; - } - supportCandidate.Support = supportCollidable; - } - } - } - return true; - } - } - return false; - } - - - /// - /// Reports contacts about a collision to the character system. If the pair does not involve a character or there are no contacts, does nothing and returns false. - /// - /// Pair of objects associated with the contact manifold. - /// Contact manifold between the colliding objects. - /// Index of the currently executing worker thread. - /// Material properties for this pair. Will be modified if the pair involves a character. - /// True if the pair involved a character pair and has contacts, false otherwise. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryReportContacts(in CollidablePair pair, ref TManifold manifold, int workerIndex, ref PairMaterialProperties materialProperties) where TManifold : struct, IContactManifold - { - Debug.Assert(contactCollectionWorkerCaches.Allocated && workerIndex < contactCollectionWorkerCaches.Length && contactCollectionWorkerCaches[workerIndex].SupportCandidates.Allocated, - "Worker caches weren't properly allocated; did you forget to call PrepareForContacts before collision detection?"); - if (manifold.Count == 0) - return false; - //It's possible for neither, one, or both collidables to be a character. Check each one, treating the other as a potential support. - var aIsCharacter = TryReportContacts(pair.A, pair.B, pair, ref manifold, workerIndex); - var bIsCharacter = TryReportContacts(pair.B, pair.A, pair, ref manifold, workerIndex); - if (aIsCharacter || bIsCharacter) - { - //The character's motion over the surface should be controlled entirely by the horizontal motion constraint. - //Note- you could use the friction coefficient to change the horizontal motion constraint's maximum force to simulate different environments if you want. - //That would just require caching a bit more information for the AnalyzeContacts function to use. - materialProperties.FrictionCoefficient = 0; - return true; - } - return false; - } - - Buffer<(int Start, int Count)> boundingBoxExpansionJobs; - unsafe void ExpandBoundingBoxes(int start, int count) - { - var end = start + count; - for (int i = start; i < end; ++i) - { - ref var character = ref characters[i]; - var characterBody = Physics.Sim.Bodies[character.BodyHandle]; - if (characterBody.Awake) - { - Physics.Sim.BroadPhase.GetActiveBoundsPointers(characterBody.Collidable.BroadPhaseIndex, out var min, out var max); - QuaternionEx.Transform(character.LocalUp, characterBody.Pose.Orientation, out var characterUp); - var supportExpansion = character.MinimumSupportContinuationDepth * characterUp; - *min += System.Numerics.Vector3.Min(System.Numerics.Vector3.Zero, supportExpansion); - *max += System.Numerics.Vector3.Max(System.Numerics.Vector3.Zero, supportExpansion); - } - } - } - - int boundingBoxExpansionJobIndex; - readonly Action expandBoundingBoxesWorker; - unsafe void ExpandBoundingBoxesWorker(int workerIndex) - { - while (true) - { - var jobIndex = Interlocked.Increment(ref boundingBoxExpansionJobIndex); - if (jobIndex < boundingBoxExpansionJobs.Length) - { - ref var job = ref boundingBoxExpansionJobs[jobIndex]; - ExpandBoundingBoxes(job.Start, job.Count); - } - else - { - break; - } - } - } - - /// - /// Preallocates space for support data collected during the narrow phase. Should be called before the narrow phase executes. - /// - void PrepareForContacts(float dt, IThreadDispatcher threadDispatcher = null) - { - Debug.Assert(!contactCollectionWorkerCaches.Allocated, "Worker caches were already allocated; did you forget to call AnalyzeContacts after collision detection to flush the previous frame's results?"); - var threadCount = threadDispatcher == null ? 1 : threadDispatcher.ThreadCount; - pool.Take(threadCount, out contactCollectionWorkerCaches); - for (int i = 0; i < contactCollectionWorkerCaches.Length; ++i) - { - contactCollectionWorkerCaches[i] = new ContactCollectionWorkerCache(characters.Count, pool); - } - //While the character will retain support with contacts with depths above the MinimumSupportContinuationDepth if there was support in the previous frame, - //it's possible for the contacts to be lost because the bounding box isn't expanded by MinimumSupportContinuationDepth and the broad phase doesn't see the support collidable. - //Here, we expand the bounding boxes to compensate. - if (threadCount == 1 || characters.Count < 256) - { - ExpandBoundingBoxes(0, characters.Count); - } - else - { - var jobCount = Math.Min(characters.Count, threadCount); - var charactersPerJob = characters.Count / jobCount; - var baseCharacterCount = charactersPerJob * jobCount; - var remainder = characters.Count - baseCharacterCount; - pool.Take(jobCount, out boundingBoxExpansionJobs); - var previousEnd = 0; - for (int jobIndex = 0; jobIndex < jobCount; ++jobIndex) - { - var charactersForJob = jobIndex < remainder ? charactersPerJob + 1 : charactersPerJob; - ref var job = ref boundingBoxExpansionJobs[jobIndex]; - job.Start = previousEnd; - job.Count = charactersForJob; - previousEnd += job.Count; - } - - boundingBoxExpansionJobIndex = -1; - threadDispatcher.DispatchWorkers(expandBoundingBoxesWorker, boundingBoxExpansionJobs.Length); - pool.Return(ref boundingBoxExpansionJobs); - - } - } - - struct PendingDynamicConstraint - { - public int CharacterIndex; - public DynamicCharacterMotionConstraint Description; - } - struct PendingStaticConstraint - { - public int CharacterIndex; - public StaticCharacterMotionConstraint Description; - } - struct Jump - { - //Note that not every jump will contain a support body, so this can waste memory. - //That's not really a concern- jumps are very rare (relatively speaking), so all we're wasting is capacity, not bandwidth. - public int CharacterBodyIndex; - public System.Numerics.Vector3 CharacterVelocityChange; - public int SupportBodyIndex; - public System.Numerics.Vector3 SupportImpulseOffset; - } - - struct AnalyzeContactsWorkerCache - { - //The solver does not permit multithreaded removals and additions. We handle all of them in a sequential postpass. - public QuickList ConstraintHandlesToRemove; - public QuickList DynamicConstraintsToAdd; - public QuickList StaticConstraintsToAdd; - public QuickList Jumps; - - public AnalyzeContactsWorkerCache(int maximumCharacterCount, BufferPool pool) - { - ConstraintHandlesToRemove = new QuickList(maximumCharacterCount, pool); - DynamicConstraintsToAdd = new QuickList(maximumCharacterCount, pool); - StaticConstraintsToAdd = new QuickList(maximumCharacterCount, pool); - Jumps = new QuickList(maximumCharacterCount, pool); - } - - public void Dispose(BufferPool pool) - { - ConstraintHandlesToRemove.Dispose(pool); - DynamicConstraintsToAdd.Dispose(pool); - StaticConstraintsToAdd.Dispose(pool); - Jumps.Dispose(pool); - } - } - - Buffer analyzeContactsWorkerCaches; - - void AnalyzeContactsForCharacterRegion(int start, int exclusiveEnd, int workerIndex) - { - ref var analyzeContactsWorkerCache = ref analyzeContactsWorkerCaches[workerIndex]; - for (int characterIndex = start; characterIndex < exclusiveEnd; ++characterIndex) - { - //Note that this iterates over both active and inactive characters rather than segmenting inactive characters into their own collection. - //This demands branching, but the expectation is that the vast majority of characters will be active, so there is less value in copying them into stasis. - ref var character = ref characters[characterIndex]; - ref var bodyLocation = ref Physics.Sim.Bodies.HandleToLocation[character.BodyHandle.Value]; - if (bodyLocation.SetIndex == 0) - { - var supportCandidate = contactCollectionWorkerCaches[0].SupportCandidates[characterIndex]; - for (int j = 1; j < contactCollectionWorkerCaches.Length; ++j) - { - ref var workerCandidate = ref contactCollectionWorkerCaches[j].SupportCandidates[characterIndex]; - if (workerCandidate.Depth > supportCandidate.Depth) - { - supportCandidate = workerCandidate; - } - } - //We need to protect against one possible corner case: if the body supporting the character was removed, the associated motion constraint was also removed. - //Arbitrarily un-support the character if we detect this. - if (character.Supported) - { - //If the constraint no longer exists at all, - if (!Physics.Sim.Solver.ConstraintExists(character.MotionConstraintHandle) || - //or if the constraint does exist but is now used by a different constraint type, - (Physics.Sim.Solver.HandleToConstraint[character.MotionConstraintHandle.Value].TypeId != DynamicCharacterMotionTypeProcessor.BatchTypeId && - Physics.Sim.Solver.HandleToConstraint[character.MotionConstraintHandle.Value].TypeId != StaticCharacterMotionTypeProcessor.BatchTypeId)) - { - //then the character isn't actually supported anymore. - character.Supported = false; - } - //Note that it's sufficient to only check that the type matches the dynamic motion constraint type id because no other systems ever create dynamic character motion constraints. - //Other systems may result in the constraint's removal, but no other system will ever *create* it. - //Further, during this analysis loop, we do not create any constraints. We only set up pending additions to be processed after the multithreaded analysis completes. - } - - //The body is active. We may need to remove the associated constraint from the solver. Remove if any of the following hold: - //1) The character was previously supported but is no longer. - //2) The character was previously supported by a body, and is now supported by a different body. - //3) The character was previously supported by a static, and is now supported by a body. - //4) The character was previously supported by a body, and is now supported by a static. - var shouldRemove = character.Supported && (character.TryJump || MathD.ApproximatelyEquals(supportCandidate.Depth, float.MinValue) || character.Support.Packed != supportCandidate.Support.Packed); - if (shouldRemove) - { - //Mark the constraint for removal. - analyzeContactsWorkerCache.ConstraintHandlesToRemove.AllocateUnsafely() = character.MotionConstraintHandle; - } - - //If the character is jumping, don't create a constraint. - if (supportCandidate.Depth > float.MinValue && character.TryJump) - { - QuaternionEx.Transform(character.LocalUp, Physics.Sim.Bodies.ActiveSet.DynamicsState[bodyLocation.Index].Motion.Pose.Orientation, out var characterUp); - //Note that we assume that character orientations are constant. This isn't necessarily the case in all uses, but it's a decent approximation. - var characterUpVelocity = System.Numerics.Vector3.Dot(Physics.Sim.Bodies.ActiveSet.DynamicsState[bodyLocation.Index].Motion.Velocity.Linear, characterUp); - //We don't want the character to be able to 'superboost' by simply adding jump speed on top of horizontal motion. - //Instead, jumping targets a velocity change necessary to reach character.JumpVelocity along the up axis. - if (character.Support.Mobility != CollidableMobility.Static) - { - ref var supportingBodyLocation = ref Physics.Sim.Bodies.HandleToLocation[character.Support.BodyHandle.Value]; - Debug.Assert(supportingBodyLocation.SetIndex == 0, "If the character is active, any support should be too."); - ref var supportVelocity = ref Physics.Sim.Bodies.ActiveSet.DynamicsState[supportingBodyLocation.Index].Motion.Velocity; - var wxr = System.Numerics.Vector3.Cross(supportVelocity.Angular, supportCandidate.OffsetFromSupport); - var supportContactVelocity = supportVelocity.Linear + wxr; - var supportUpVelocity = System.Numerics.Vector3.Dot(supportContactVelocity, characterUp); - - //If the support is dynamic, apply an opposing impulse. Note that velocity changes cannot safely be applied during multithreaded execution; - //characters could share support bodies, and a character might be a support of another character. - //That's really not concerning from a performance perspective- characters don't jump many times per frame. - ref var jump = ref analyzeContactsWorkerCache.Jumps.AllocateUnsafely(); - jump.CharacterBodyIndex = bodyLocation.Index; - jump.CharacterVelocityChange = characterUp * MathF.Max(0, character.JumpVelocity - (characterUpVelocity - supportUpVelocity)); - if (character.Support.Mobility == CollidableMobility.Dynamic) - { - jump.SupportBodyIndex = supportingBodyLocation.Index; - jump.SupportImpulseOffset = supportCandidate.OffsetFromSupport; - } - else - { - //No point in applying impulses to kinematics. - jump.SupportBodyIndex = -1; - } - } - else - { - //Static bodies have no velocity, so we don't have to consider the support. - ref var jump = ref analyzeContactsWorkerCache.Jumps.AllocateUnsafely(); - jump.CharacterBodyIndex = bodyLocation.Index; - jump.CharacterVelocityChange = characterUp * MathF.Max(0, character.JumpVelocity - characterUpVelocity); - jump.SupportBodyIndex = -1; - } - character.Supported = false; - } - else if (supportCandidate.Depth > float.MinValue) - { - //If a support currently exists and there is still an old constraint, then update it. - //If a support currently exists and there is not an old constraint, add the new constraint. - - //Project the view direction down onto the surface as represented by the contact normal. - Matrix3x3 surfaceBasis; - surfaceBasis.Y = supportCandidate.Normal; - //Note negation: we're using a right handed basis where -Z is forward, +Z is backward. - QuaternionEx.Transform(character.LocalUp, Physics.Sim.Bodies.ActiveSet.DynamicsState[bodyLocation.Index].Motion.Pose.Orientation, out var up); - var rayDistance = System.Numerics.Vector3.Dot(character.ViewDirection, surfaceBasis.Y); - var rayVelocity = System.Numerics.Vector3.Dot(up, surfaceBasis.Y); - Debug.Assert(rayVelocity > 0, - "The calibrated support normal and the character's up direction should have a positive dot product if the maximum slope is working properly. Is the maximum slope >= pi/2?"); - surfaceBasis.Z = up * (rayDistance / rayVelocity) - character.ViewDirection; - var zLengthSquared = surfaceBasis.Z.LengthSquared(); - if (zLengthSquared > 1e-12f) - { - surfaceBasis.Z /= MathF.Sqrt(zLengthSquared); - } - else - { - QuaternionEx.GetQuaternionBetweenNormalizedVectors(System.Numerics.Vector3.UnitY, surfaceBasis.Y, out var rotation); - QuaternionEx.TransformUnitZ(rotation, out surfaceBasis.Z); - } - surfaceBasis.X = System.Numerics.Vector3.Cross(surfaceBasis.Y, surfaceBasis.Z); - QuaternionEx.CreateFromRotationMatrix(surfaceBasis, out var surfaceBasisQuaternion); - if (supportCandidate.Support.Mobility != CollidableMobility.Static) - { - //The character is supported by a body. - var motionConstraint = new DynamicCharacterMotionConstraint - { - MaximumHorizontalForce = character.MaximumHorizontalForce, - MaximumVerticalForce = character.MaximumVerticalForce, - OffsetFromCharacterToSupportPoint = supportCandidate.OffsetFromCharacter, - OffsetFromSupportToSupportPoint = supportCandidate.OffsetFromSupport, - SurfaceBasis = surfaceBasisQuaternion, - TargetVelocity = character.TargetVelocity, - Depth = supportCandidate.Depth - }; - if (character.Supported && !shouldRemove) - { - //Already exists, update it. - Physics.Sim.Solver.ApplyDescriptionWithoutWaking(character.MotionConstraintHandle, motionConstraint); - } - else - { - //Doesn't exist, mark it for addition. - ref var pendingConstraint = ref analyzeContactsWorkerCache.DynamicConstraintsToAdd.AllocateUnsafely(); - pendingConstraint.Description = motionConstraint; - pendingConstraint.CharacterIndex = characterIndex; - } - } - else - { - //The character is supported by a static. - var motionConstraint = new StaticCharacterMotionConstraint - { - MaximumHorizontalForce = character.MaximumHorizontalForce, - MaximumVerticalForce = character.MaximumVerticalForce, - OffsetFromCharacterToSupportPoint = supportCandidate.OffsetFromCharacter, - SurfaceBasis = surfaceBasisQuaternion, - TargetVelocity = character.TargetVelocity, - Depth = supportCandidate.Depth - }; - if (character.Supported && !shouldRemove) - { - //Already exists, update it. - Physics.Sim.Solver.ApplyDescriptionWithoutWaking(character.MotionConstraintHandle, motionConstraint); - } - else - { - //Doesn't exist, mark it for addition. - ref var pendingConstraint = ref analyzeContactsWorkerCache.StaticConstraintsToAdd.AllocateUnsafely(); - pendingConstraint.Description = motionConstraint; - pendingConstraint.CharacterIndex = characterIndex; - } - } - character.Supported = true; - character.Support = supportCandidate.Support; - } - else - { - character.Supported = false; - } - } - //The TryJump flag is always reset even if the attempt failed. - character.TryJump = false; - } - } - - struct AnalyzeContactsJob - { - public int Start; - public int ExclusiveEnd; - } - - int analysisJobIndex; - int analysisJobCount; - Buffer jobs; - readonly Action analyzeContactsWorker; - unsafe void AnalyzeContactsWorker(int workerIndex) - { - int jobIndex; - while ((jobIndex = Interlocked.Increment(ref analysisJobIndex)) < analysisJobCount) - { - ref var job = ref jobs[jobIndex]; - AnalyzeContactsForCharacterRegion(job.Start, job.ExclusiveEnd, workerIndex); - } - } - - - /// - /// Updates all character support states and motion constraints based on the current character goals and all the contacts collected since the last call to AnalyzeContacts. - /// Attach to a simulation callback where the most recent contact is available and before the solver executes. - /// - void AnalyzeContacts(float dt, IThreadDispatcher threadDispatcher) - { - //var start = Stopwatch.GetTimestamp(); - Debug.Assert(contactCollectionWorkerCaches.Allocated, "Worker caches weren't properly allocated; did you forget to call PrepareForContacts before collision detection?"); - - if (threadDispatcher == null) - { - pool.Take(1, out analyzeContactsWorkerCaches); - analyzeContactsWorkerCaches[0] = new AnalyzeContactsWorkerCache(characters.Count, pool); - AnalyzeContactsForCharacterRegion(0, characters.Count, 0); - } - else - { - analysisJobCount = Math.Min(characters.Count, threadDispatcher.ThreadCount * 4); - if (analysisJobCount > 0) - { - pool.Take(threadDispatcher.ThreadCount, out analyzeContactsWorkerCaches); - pool.Take(analysisJobCount, out jobs); - for (int i = 0; i < threadDispatcher.ThreadCount; ++i) - { - analyzeContactsWorkerCaches[i] = new AnalyzeContactsWorkerCache(characters.Count, pool); - } - var baseCount = characters.Count / analysisJobCount; - var remainder = characters.Count - baseCount * analysisJobCount; - var previousEnd = 0; - for (int i = 0; i < analysisJobCount; ++i) - { - ref var job = ref jobs[i]; - job.Start = previousEnd; - job.ExclusiveEnd = job.Start + (i < remainder ? baseCount + 1 : baseCount); - previousEnd = job.ExclusiveEnd; - } - analysisJobIndex = -1; - threadDispatcher.DispatchWorkers(analyzeContactsWorker, analysisJobCount); - pool.Return(ref jobs); - } - } - //We're done with all the contact collection worker caches. - for (int i = 0; i < contactCollectionWorkerCaches.Length; ++i) - { - contactCollectionWorkerCaches[i].Dispose(pool); - } - pool.Return(ref contactCollectionWorkerCaches); - - if (analyzeContactsWorkerCaches.Allocated) - { - //Flush all the worker caches. Note that we perform all removals before moving onto any additions to avoid unnecessary constraint batches - //caused by the new and old constraint affecting the same bodies. - for (int threadIndex = 0; threadIndex < analyzeContactsWorkerCaches.Length; ++threadIndex) - { - ref var cache = ref analyzeContactsWorkerCaches[threadIndex]; - for (int i = 0; i < cache.ConstraintHandlesToRemove.Count; ++i) - { - Physics.Sim.Solver.Remove(cache.ConstraintHandlesToRemove[i]); - } - } - for (int threadIndex = 0; threadIndex < analyzeContactsWorkerCaches.Length; ++threadIndex) - { - ref var workerCache = ref analyzeContactsWorkerCaches[threadIndex]; - for (int i = 0; i < workerCache.StaticConstraintsToAdd.Count; ++i) - { - ref var pendingConstraint = ref workerCache.StaticConstraintsToAdd[i]; - ref var character = ref characters[pendingConstraint.CharacterIndex]; - Debug.Assert(character.Support.Mobility == CollidableMobility.Static); - character.MotionConstraintHandle = Physics.Sim.Solver.Add(character.BodyHandle, pendingConstraint.Description); - } - for (int i = 0; i < workerCache.DynamicConstraintsToAdd.Count; ++i) - { - ref var pendingConstraint = ref workerCache.DynamicConstraintsToAdd[i]; - ref var character = ref characters[pendingConstraint.CharacterIndex]; - Debug.Assert(character.Support.Mobility != CollidableMobility.Static); - character.MotionConstraintHandle = Physics.Sim.Solver.Add(character.BodyHandle, character.Support.BodyHandle, pendingConstraint.Description); - } - ref var activeSet = ref Physics.Sim.Bodies.ActiveSet; - for (int i = 0; i < workerCache.Jumps.Count; ++i) - { - ref var jump = ref workerCache.Jumps[i]; - activeSet.DynamicsState[jump.CharacterBodyIndex].Motion.Velocity.Linear += jump.CharacterVelocityChange; - if (jump.SupportBodyIndex >= 0) - { - BodyReference.ApplyImpulse(Physics.Sim.Bodies.ActiveSet, jump.SupportBodyIndex, jump.CharacterVelocityChange / -activeSet.DynamicsState[jump.CharacterBodyIndex].Inertia.Local.InverseMass, jump.SupportImpulseOffset); - } - } - workerCache.Dispose(pool); - } - pool.Return(ref analyzeContactsWorkerCaches); - } - - //var end = Stopwatch.GetTimestamp(); - //Console.WriteLine($"Time (ms): {(end - start) / (1e-3 * Stopwatch.Frequency)}"); - } - - /// - /// Ensures that the internal structures of the character controllers system can handle the given number of characters and body handles, resizing if necessary. - /// - /// Minimum character capacity to require. - /// Minimum number of body handles to allocate space for. - public void EnsureCapacity(int characterCapacity, int bodyHandleCapacity) - { - characters.EnsureCapacity(characterCapacity, pool); - if (bodyHandleToCharacterIndex.Length < bodyHandleCapacity) - { - ResizeBodyHandleCapacity(bodyHandleCapacity); - } - } - - /// - /// Resizes the internal structures of the character controllers system for the target sizes. Will not shrink below the currently active data size. - /// - /// Target character capacity to allocate space for. - /// Target number of body handles to allocate space for. - public void Resize(int characterCapacity, int bodyHandleCapacity) - { - int lastOccupiedIndex = -1; - for (int i = bodyHandleToCharacterIndex.Length - 1; i >= 0; --i) - { - if (bodyHandleToCharacterIndex[i] != -1) - { - lastOccupiedIndex = i; - break; - } - } - var targetHandleCapacity = BufferPool.GetCapacityForCount(Math.Max(lastOccupiedIndex + 1, bodyHandleCapacity)); - if (targetHandleCapacity != bodyHandleToCharacterIndex.Length) - ResizeBodyHandleCapacity(targetHandleCapacity); - - var targetCharacterCapacity = BufferPool.GetCapacityForCount(Math.Max(characters.Count, characterCapacity)); - if (targetCharacterCapacity != characters.Span.Length) - characters.Resize(targetCharacterCapacity, pool); - } - - bool disposed; - /// - /// Returns pool-allocated resources. - /// - public void Dispose() - { - if (!Physics.IsReady) return; - - if (!disposed) - { - disposed = true; - Physics.Sim.Timestepper.BeforeCollisionDetection -= PrepareForContacts; - Physics.Sim.Timestepper.CollisionsDetected -= AnalyzeContacts; - characters.Dispose(pool); - pool.Return(ref bodyHandleToCharacterIndex); - GC.SuppressFinalize(this); - } - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Controller/CharacterMotionConstraint.cs b/Prowl.Runtime/Components/Physics/Types/Controller/CharacterMotionConstraint.cs deleted file mode 100644 index 44fb382f7..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Controller/CharacterMotionConstraint.cs +++ /dev/null @@ -1,603 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -using BepuPhysics; -using BepuPhysics.Constraints; - -using BepuUtilities; -using BepuUtilities.Memory; - -using static BepuUtilities.GatherScatter; - -namespace Prowl.Runtime.Controller; - -public struct CharacterMotionAccumulatedImpulse -{ - public Vector2Wide Horizontal; - public Vector Vertical; -} - -//IMPORTANT NOTE: The static and dynamic motion constraint variants were autogenerated from a text template. To modify the constraint, modify the text template instead. -//Using code generators to generate these sorts of constraint variants can work around some of the limitations in compile time expressiveness- -//here, we avoid creating a bunch of duplicate math for the one and two body constraint cases which would have to be separately maintained. -//There are other cases where this is pushed even further. Within the engine, the dozens of contact constraint variants are generated by text templates. -//This isn't the most wonderful solution in terms of development experience or tooling, -//but it maximizes performance and avoids the need for in-language turing complete metaprogramming, so I'm okay with it. - -//Constraint descriptions provide an explicit mapping from the array-of-structures format to the internal array-of-structures-of-arrays format used by the solver. -//Note that there is a separate description for the one and two body case- constraint implementations take advantage of the lack of a second body to reduce data gathering requirements. -/// -/// Description of a character motion constraint where the support is static. -/// -public struct StaticCharacterMotionConstraint : IOneBodyConstraintDescription -{ - /// - /// Maximum force that the horizontal motion constraint can apply to reach the current velocity goal. - /// - public float MaximumHorizontalForce; - /// - /// Maximum force that the vertical motion constraint can apply to fight separation. - /// - public float MaximumVerticalForce; - /// - /// Target horizontal velocity in terms of the basis X and -Z axes. - /// - public System.Numerics.Vector2 TargetVelocity; - /// - /// Depth of the supporting contact. The vertical motion constraint permits separating velocity if, after a frame, the objects will still be touching. - /// - public float Depth; - /// - /// Stores the quaternion-packed orthonormal basis for the motion constraint. When expanded into a matrix, X and Z will represent the Right and Backward directions respectively. Y will represent Up. - /// In other words, a target tangential velocity of (4, 2) will result in a goal velocity of 4 along the (1, 0, 0) * Basis direction and a goal velocity of 2 along the (0, 0, -1) * Basis direction. - /// All motion moving along the (0, 1, 0) * Basis axis will be fought against by the vertical motion constraint. - /// - public System.Numerics.Quaternion SurfaceBasis; - /// - /// World space offset from the character's center to apply impulses at. - /// - public System.Numerics.Vector3 OffsetFromCharacterToSupportPoint; - - //It's possible to create multiple descriptions for the same underlying constraint type id which can update different parts of the constraint data. - //This functionality isn't used very often, though- you'll notice that the engine has a 1:1 mapping (at least at the time of this writing). - //But in principle, it doesn't have to be that way. So, the description must provide information about the type and type id. - /// - /// Gets the constraint type id that this description is associated with. - /// - public static int ConstraintTypeId => StaticCharacterMotionTypeProcessor.BatchTypeId; - - /// - /// Gets the TypeProcessor type that is associated with this description. - /// - public static Type TypeProcessorType => typeof(StaticCharacterMotionTypeProcessor); - /// - /// Creates a type processor for this constraint type. - /// - public static TypeProcessor CreateTypeProcessor() => new StaticCharacterMotionTypeProcessor(); - - //Note that these mapping functions use a "GetOffsetInstance" function. Each CharacterMotionPrestep is a bundle of multiple constraints; - //by grabbing an offset instance, we're selecting a specific slot in the bundle to modify. For simplicity and to guarantee consistency of field strides, - //we refer to that slot using the same struct and then write only to the first slot. - //(Note that accessing slots after the first may result in access violations; the 'offset instance' is not guaranteed to refer to valid data beyond the first slot!) - public readonly void ApplyDescription(ref TypeBatch batch, int bundleIndex, int innerIndex) - { - ref var target = ref GetOffsetInstance(ref Buffer.Get(ref batch.PrestepData, bundleIndex), innerIndex); - QuaternionWide.WriteFirst(SurfaceBasis, ref target.SurfaceBasis); - GetFirst(ref target.MaximumHorizontalForce) = MaximumHorizontalForce; - GetFirst(ref target.MaximumVerticalForce) = MaximumVerticalForce; - Vector2Wide.WriteFirst(TargetVelocity, ref target.TargetVelocity); - GetFirst(ref target.Depth) = Depth; - Vector3Wide.WriteFirst(OffsetFromCharacterToSupportPoint, ref target.OffsetFromCharacter); - } - - public static void BuildDescription(ref TypeBatch batch, int bundleIndex, int innerIndex, out StaticCharacterMotionConstraint description) - { - ref var source = ref GetOffsetInstance(ref Buffer.Get(ref batch.PrestepData, bundleIndex), innerIndex); - QuaternionWide.ReadFirst(source.SurfaceBasis, out description.SurfaceBasis); - description.MaximumHorizontalForce = GetFirst(ref source.MaximumHorizontalForce); - description.MaximumVerticalForce = GetFirst(ref source.MaximumVerticalForce); - Vector2Wide.ReadFirst(source.TargetVelocity, out description.TargetVelocity); - description.Depth = GetFirst(ref source.Depth); - Vector3Wide.ReadFirst(source.OffsetFromCharacter, out description.OffsetFromCharacterToSupportPoint); - } -} - -//Note that all the solver-side data is in terms of 'Wide' data types- the solver never works on just one constraint at a time. Instead, -//it executes them in bundles of width equal to the runtime/hardware exposed SIMD unit width. This lets the solver scale with wider compute units. -//(This is important for machines that can perform 8 or more operations per instruction- there's no good way to map a single constraint instance's -//computation onto such a wide instruction, so if the solver tried to do such a thing, it would leave a huge amount of performance on the table.) - -//"Prestep" data can be thought of as the input to the solver. It describes everything the solver needs to know about. -/// -/// AOSOA formatted bundle of prestep data for multiple static-supported character motion constraints. -/// -public struct StaticCharacterMotionPrestep -{ - //Note that the prestep data layout is important. The solver tends to be severely memory bandwidth bound, so using a minimal representation is valuable. - //That's why the Basis is stored as a quaternion and not a full Matrix- the cost of the arithmetic operations to expand it back into the original matrix form is far less - //than the cost of loading all the extra lanes of data when scaled up to many cores. - public QuaternionWide SurfaceBasis; - public Vector MaximumHorizontalForce; - public Vector MaximumVerticalForce; - public Vector Depth; - public Vector2Wide TargetVelocity; - public Vector3Wide OffsetFromCharacter; -} - -public struct StaticCharacterMotionFunctions : IOneBodyConstraintFunctions -{ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void ComputeJacobians(in Vector3Wide offsetA, in QuaternionWide basisQuaternion, - out Matrix3x3Wide basis, - out Matrix2x3Wide horizontalAngularJacobianA, - out Vector3Wide verticalAngularJacobianA) - { - //Both of the motion constraints are velocity motors, like tangent friction. They don't actually have a position level goal. - //But if we did want to make such a position level goal, it could be expressed as: - //dot(basis.X, constrainedPointOnA - constrainedPointOnB) = 0 - //dot(basis.Y, constrainedPointOnA - constrainedPointOnB) <= 0 - //dot(basis.Z, constrainedPointOnA - constrainedPointOnB) = 0 - //Note that the Y axis, corresponding to the vertical motion constraint, is an inequality. It pulls toward the surface, but never pushes away. - //It also has a separate maximum force and acts on an independent axis; that's why we solve it as a separate constraint. - //To get a velocity constraint out of these position goals, differentiate with respect to time: - //d/dt(dot(basis.X, constrainedPointOnA - constrainedPointOnB)) = dot(basis.X, d/dt(constrainedPointOnA - constrainedPointOnB)) - // = dot(basis.X, a.LinearVelocity + a.AngularVelocity x offsetToConstrainedPointOnA - b.linearVelocity - b.AngularVelocity x offsetToConstrainedPointOnB) - //Throwing some algebra and identities at it: - //dot(basis.X, a.LinearVelocity) + dot(basis.X, a.AngularVelocity x offsetToConstrainedPointOnA) + dot(-basis.X, b.LinearVelocity) + dot(basis.X, offsetToConstrainedPointOnB x b.AngularVelocity) - //dot(basis.X, a.LinearVelocity) + dot(a.AngularVelocity, offsetToConstrainedPointOnA x basis.X) + dot(-basis.X, b.LinearVelocity) + dot(b.AngularVelocity, basis.X x offsetToConstrainedPointOnB) - //The (transpose) jacobian is the transform that pulls the body velocity into constraint space- - //and here, we can see that we have an axis being dotted with each component of the velocity. That's gives us the jacobian for that degree of freedom. - //The same form applies to all three axes of the basis, since they're all doing the same thing (just on different directions and with different force bounds). - //Note that we don't explicitly output linear jacobians- they are just the axes of the basis, and the linear jacobians of B are just the negated linear jacobians of A. - Matrix3x3Wide.CreateFromQuaternion(basisQuaternion, out basis); - Vector3Wide.CrossWithoutOverlap(offsetA, basis.X, out horizontalAngularJacobianA.X); - Vector3Wide.CrossWithoutOverlap(offsetA, basis.Y, out verticalAngularJacobianA); - Vector3Wide.CrossWithoutOverlap(offsetA, basis.Z, out horizontalAngularJacobianA.Y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ApplyHorizontalImpulse(in Matrix3x3Wide basis, - in Matrix2x3Wide angularJacobianA, in Vector2Wide constraintSpaceImpulse, - in BodyInertiaWide inertiaA, - ref BodyVelocityWide velocityA) - { - //Transform the constraint space impulse into world space by using the jacobian and then apply each body's inverse inertia to get the velocity change. - Vector3Wide.Scale(basis.X, constraintSpaceImpulse.X, out var linearImpulseAX); - Vector3Wide.Scale(basis.Z, constraintSpaceImpulse.Y, out var linearImpulseAY); - Vector3Wide.Add(linearImpulseAX, linearImpulseAY, out var linearImpulseA); - Vector3Wide.Scale(linearImpulseA, inertiaA.InverseMass, out var linearChangeA); - Vector3Wide.Add(velocityA.Linear, linearChangeA, out velocityA.Linear); - - Matrix2x3Wide.Transform(constraintSpaceImpulse, angularJacobianA, out var angularImpulseA); - Symmetric3x3Wide.TransformWithoutOverlap(angularImpulseA, inertiaA.InverseInertiaTensor, out var angularChangeA); - Vector3Wide.Add(velocityA.Angular, angularChangeA, out velocityA.Angular); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ApplyVerticalImpulse(in Matrix3x3Wide basis, - in Vector3Wide angularJacobianA, in Vector constraintSpaceImpulse, - in BodyInertiaWide inertiaA, - ref BodyVelocityWide velocityA) - { - Vector3Wide.Scale(basis.Y, constraintSpaceImpulse, out var linearImpulseA); - Vector3Wide.Scale(linearImpulseA, inertiaA.InverseMass, out var linearChangeA); - Vector3Wide.Add(velocityA.Linear, linearChangeA, out velocityA.Linear); - - Vector3Wide.Scale(angularJacobianA, constraintSpaceImpulse, out var angularImpulseA); - Symmetric3x3Wide.TransformWithoutOverlap(angularImpulseA, inertiaA.InverseInertiaTensor, out var angularChangeA); - Vector3Wide.Add(velocityA.Angular, angularChangeA, out velocityA.Angular); - } - - - public static void WarmStart(in Vector3Wide positionA, in QuaternionWide orientationA, in BodyInertiaWide inertiaA, ref StaticCharacterMotionPrestep prestep, ref CharacterMotionAccumulatedImpulse accumulatedImpulses, ref BodyVelocityWide velocityA) - { - ComputeJacobians(prestep.OffsetFromCharacter, prestep.SurfaceBasis, - out var basis, out var horizontalAngularJacobianA, out var verticalAngularJacobianA); - ApplyHorizontalImpulse(basis, horizontalAngularJacobianA, accumulatedImpulses.Horizontal, inertiaA, ref velocityA); - ApplyVerticalImpulse(basis, verticalAngularJacobianA, accumulatedImpulses.Vertical, inertiaA, ref velocityA); - } - - public static void Solve(in Vector3Wide positionA, in QuaternionWide orientationA, in BodyInertiaWide inertiaA, float dt, float inverseDt, ref StaticCharacterMotionPrestep prestep, ref CharacterMotionAccumulatedImpulse accumulatedImpulses, ref BodyVelocityWide velocityA) - { - //The motion constraint is split into two parts: the horizontal constraint, and the vertical constraint. - //The horizontal constraint acts almost exactly like the TangentFriction, but we'll duplicate some of the logic to keep this implementation self-contained. - ComputeJacobians(prestep.OffsetFromCharacter, prestep.SurfaceBasis, - out var basis, out var horizontalAngularJacobianA, out var verticalAngularJacobianA); - - //Compute the velocity error by projecting the body velocity into constraint space using the transposed jacobian. - Vector2Wide horizontalLinearA; - Vector3Wide.Dot(basis.X, velocityA.Linear, out horizontalLinearA.X); - Vector3Wide.Dot(basis.Z, velocityA.Linear, out horizontalLinearA.Y); - Matrix2x3Wide.TransformByTransposeWithoutOverlap(velocityA.Angular, horizontalAngularJacobianA, out var horizontalAngularA); - Vector2Wide.Add(horizontalLinearA, horizontalAngularA, out var horizontalVelocity); - - //I'll omit the details of where this comes from, but you can check out the other constraints or the sorta-tutorial Inequality1DOF constraint to explain the details, - //plus some other references. The idea is that we need a way to transform the constraint space velocity (that we get from transforming body velocities - //by the transpose jacobian) into a corrective impulse for the solver iterations. That corrective impulse is then used to update the velocities on each iteration execution. - //This transform is the 'effective mass', representing the mass felt by the constraint in its local space. - //In concept, this constraint is actually two separate constraints solved iteratively, so we have two separate such effective mass transforms. - Symmetric3x3Wide.MatrixSandwich(horizontalAngularJacobianA, inertiaA.InverseInertiaTensor, out var inverseHorizontalEffectiveMass); - //The linear jacobians are unit length vectors, so J * M^-1 * JT is just M^-1. - inverseHorizontalEffectiveMass.XX += inertiaA.InverseMass; - inverseHorizontalEffectiveMass.YY += inertiaA.InverseMass; - Symmetric2x2Wide.InvertWithoutOverlap(inverseHorizontalEffectiveMass, out var horizontalEffectiveMass); - - Vector2Wide horizontalConstraintSpaceVelocityChange; - horizontalConstraintSpaceVelocityChange.X = prestep.TargetVelocity.X - horizontalVelocity.X; - //The surface basis's Z axis points in the opposite direction to the view direction, so negate the target velocity along the Z axis to point it in the expected direction. - horizontalConstraintSpaceVelocityChange.Y = -prestep.TargetVelocity.Y - horizontalVelocity.Y; - Symmetric2x2Wide.TransformWithoutOverlap(horizontalConstraintSpaceVelocityChange, horizontalEffectiveMass, out var horizontalCorrectiveImpulse); - - //Limit the force applied by the horizontal motion constraint. Note that this clamps the *accumulated* impulse applied this time step, not just this one iterations' value. - var previousHorizontalAccumulatedImpulse = accumulatedImpulses.Horizontal; - Vector2Wide.Add(accumulatedImpulses.Horizontal, horizontalCorrectiveImpulse, out accumulatedImpulses.Horizontal); - Vector2Wide.Length(accumulatedImpulses.Horizontal, out var horizontalImpulseMagnitude); - //Note division by zero guard. - var dtWide = new Vector(dt); - var maximumHorizontalImpulse = prestep.MaximumHorizontalForce * dtWide; - var scale = Vector.Min(Vector.One, maximumHorizontalImpulse / Vector.Max(new Vector(1e-16f), horizontalImpulseMagnitude)); - Vector2Wide.Scale(accumulatedImpulses.Horizontal, scale, out accumulatedImpulses.Horizontal); - Vector2Wide.Subtract(accumulatedImpulses.Horizontal, previousHorizontalAccumulatedImpulse, out horizontalCorrectiveImpulse); - - ApplyHorizontalImpulse(basis, horizontalAngularJacobianA, horizontalCorrectiveImpulse, inertiaA, ref velocityA); - - //Same thing for the vertical constraint. - Vector3Wide.Dot(basis.Y, velocityA.Linear, out var verticalLinearA); - Vector3Wide.Dot(velocityA.Angular, verticalAngularJacobianA, out var verticalAngularA); - //If the character is deeply penetrating, the vertical motion constraint will allow some separating velocity- just enough for one frame of integration to reach zero depth. - var verticalBiasVelocity = Vector.Max(Vector.Zero, prestep.Depth * inverseDt); - - //The vertical constraint just targets zero velocity, but does not attempt to fight any velocity which would merely push the character out of penetration. - //Note that many characters will just have zero inverse inertia tensors to prevent them from rotating, so this could be optimized. - //We don't take advantage of this optimization for simplicity, and so that you could use this constraint unchanged in a simulation - //where the orientation is instead controlled by some other constraint or torque- imagine a game with gravity that points in different directions. - Symmetric3x3Wide.VectorSandwich(verticalAngularJacobianA, inertiaA.InverseInertiaTensor, out var verticalAngularContributionA); - var inverseVerticalEffectiveMass = verticalAngularContributionA + inertiaA.InverseMass; - var verticalCorrectiveImpulse = (verticalBiasVelocity - verticalLinearA - verticalAngularA) / inverseVerticalEffectiveMass; - - //Clamp the vertical constraint's impulse, but note that this is a bit different than above- the vertical constraint is not allowed to *push*, so there's an extra bound at zero. - var previousVerticalAccumulatedImpulse = accumulatedImpulses.Vertical; - var maximumVerticalImpulse = prestep.MaximumVerticalForce * dtWide; - accumulatedImpulses.Vertical = Vector.Min(Vector.Zero, Vector.Max(accumulatedImpulses.Vertical + verticalCorrectiveImpulse, -maximumVerticalImpulse)); - verticalCorrectiveImpulse = accumulatedImpulses.Vertical - previousVerticalAccumulatedImpulse; - - ApplyVerticalImpulse(basis, verticalAngularJacobianA, verticalCorrectiveImpulse, inertiaA, ref velocityA); - } - - - public static bool RequiresIncrementalSubstepUpdates => true; - public static void IncrementallyUpdateForSubstep(in Vector dt, in BodyVelocityWide velocityA, ref StaticCharacterMotionPrestep prestep) - { - //Since collision detection doesn't run for every substep, we approximate the change in depth for the vertical motion constraint by integrating the velocity along the support normal. - //This is pretty subtle. If you disable it entirely (return false from "RequiresIncrementalSubstepUpdates" above), you might not even notice. - //If you disable the vertical motion constraint, then it can definitely be disabled. - - //Any movement of the character or its support along N results in a change in the vertical motion constraint's perception of depth. - //estimatedPenetrationDepthChange = dot(normal, velocityDtA.Linear + velocityDtA.Angular x contactOffsetA) - dot(normal, velocityDtB.Linear + velocityDtB.Angular x contactOffsetB) - Vector3Wide.CrossWithoutOverlap(velocityA.Angular, prestep.OffsetFromCharacter, out var wxra); - Vector3Wide.Add(wxra, velocityA.Linear, out var contactVelocityA); - - var normal = QuaternionWide.TransformUnitY(prestep.SurfaceBasis); - Vector3Wide.Dot(normal, contactVelocityA, out var estimatedDepthChangeVelocity); - prestep.Depth -= estimatedDepthChangeVelocity * dt; - } -} - -//Each constraint type has its own 'type processor'- it acts as the outer loop that handles all the common logic across batches of constraints and invokes -//the per-constraint logic as needed. The CharacterMotionFunctions type provides the actual implementation. -public class StaticCharacterMotionTypeProcessor : OneBodyTypeProcessor -{ - /// - /// Simulation-wide unique id for the character motion constraint. Every type has needs a unique compile time id; this is a little bit annoying to guarantee given that there is no central - /// registry of all types that can exist (custom ones, like this one, can always be created), but having it be constant helps simplify and optimize its internal usage. - /// - public const int BatchTypeId = 50; -} -//Constraint descriptions provide an explicit mapping from the array-of-structures format to the internal array-of-structures-of-arrays format used by the solver. -//Note that there is a separate description for the one and two body case- constraint implementations take advantage of the lack of a second body to reduce data gathering requirements. -/// -/// Description of a character motion constraint where the support is dynamic. -/// -public struct DynamicCharacterMotionConstraint : ITwoBodyConstraintDescription -{ - /// - /// Maximum force that the horizontal motion constraint can apply to reach the current velocity goal. - /// - public float MaximumHorizontalForce; - /// - /// Maximum force that the vertical motion constraint can apply to fight separation. - /// - public float MaximumVerticalForce; - /// - /// Target horizontal velocity in terms of the basis X and -Z axes. - /// - public System.Numerics.Vector2 TargetVelocity; - /// - /// Depth of the supporting contact. The vertical motion constraint permits separating velocity if, after a frame, the objects will still be touching. - /// - public float Depth; - /// - /// Stores the quaternion-packed orthonormal basis for the motion constraint. When expanded into a matrix, X and Z will represent the Right and Backward directions respectively. Y will represent Up. - /// In other words, a target tangential velocity of (4, 2) will result in a goal velocity of 4 along the (1, 0, 0) * Basis direction and a goal velocity of 2 along the (0, 0, -1) * Basis direction. - /// All motion moving along the (0, 1, 0) * Basis axis will be fought against by the vertical motion constraint. - /// - public System.Numerics.Quaternion SurfaceBasis; - /// - /// World space offset from the character's center to apply impulses at. - /// - public System.Numerics.Vector3 OffsetFromCharacterToSupportPoint; - /// - /// World space offset from the support's center to apply impulses at. - /// - public System.Numerics.Vector3 OffsetFromSupportToSupportPoint; - - //It's possible to create multiple descriptions for the same underlying constraint type id which can update different parts of the constraint data. - //This functionality isn't used very often, though- you'll notice that the engine has a 1:1 mapping (at least at the time of this writing). - //But in principle, it doesn't have to be that way. So, the description must provide information about the type and type id. - /// - /// Gets the constraint type id that this description is associated with. - /// - public static int ConstraintTypeId => DynamicCharacterMotionTypeProcessor.BatchTypeId; - - /// - /// Gets the TypeProcessor type that is associated with this description. - /// - public static Type TypeProcessorType => typeof(DynamicCharacterMotionTypeProcessor); - /// - /// Creates a type processor for this constraint type. - /// - public static TypeProcessor CreateTypeProcessor() => new DynamicCharacterMotionTypeProcessor(); - - //Note that these mapping functions use a "GetOffsetInstance" function. Each CharacterMotionPrestep is a bundle of multiple constraints; - //by grabbing an offset instance, we're selecting a specific slot in the bundle to modify. For simplicity and to guarantee consistency of field strides, - //we refer to that slot using the same struct and then write only to the first slot. - //(Note that accessing slots after the first may result in access violations; the 'offset instance' is not guaranteed to refer to valid data beyond the first slot!) - public readonly void ApplyDescription(ref TypeBatch batch, int bundleIndex, int innerIndex) - { - ref var target = ref GetOffsetInstance(ref Buffer.Get(ref batch.PrestepData, bundleIndex), innerIndex); - QuaternionWide.WriteFirst(SurfaceBasis, ref target.SurfaceBasis); - GetFirst(ref target.MaximumHorizontalForce) = MaximumHorizontalForce; - GetFirst(ref target.MaximumVerticalForce) = MaximumVerticalForce; - Vector2Wide.WriteFirst(TargetVelocity, ref target.TargetVelocity); - GetFirst(ref target.Depth) = Depth; - Vector3Wide.WriteFirst(OffsetFromCharacterToSupportPoint, ref target.OffsetFromCharacter); - Vector3Wide.WriteFirst(OffsetFromSupportToSupportPoint, ref target.OffsetFromSupport); - } - - public static void BuildDescription(ref TypeBatch batch, int bundleIndex, int innerIndex, out DynamicCharacterMotionConstraint description) - { - ref var source = ref GetOffsetInstance(ref Buffer.Get(ref batch.PrestepData, bundleIndex), innerIndex); - QuaternionWide.ReadFirst(source.SurfaceBasis, out description.SurfaceBasis); - description.MaximumHorizontalForce = GetFirst(ref source.MaximumHorizontalForce); - description.MaximumVerticalForce = GetFirst(ref source.MaximumVerticalForce); - Vector2Wide.ReadFirst(source.TargetVelocity, out description.TargetVelocity); - description.Depth = GetFirst(ref source.Depth); - Vector3Wide.ReadFirst(source.OffsetFromCharacter, out description.OffsetFromCharacterToSupportPoint); - Vector3Wide.ReadFirst(source.OffsetFromSupport, out description.OffsetFromSupportToSupportPoint); - } -} - -//Note that all the solver-side data is in terms of 'Wide' data types- the solver never works on just one constraint at a time. Instead, -//it executes them in bundles of width equal to the runtime/hardware exposed SIMD unit width. This lets the solver scale with wider compute units. -//(This is important for machines that can perform 8 or more operations per instruction- there's no good way to map a single constraint instance's -//computation onto such a wide instruction, so if the solver tried to do such a thing, it would leave a huge amount of performance on the table.) - -//"Prestep" data can be thought of as the input to the solver. It describes everything the solver needs to know about. -/// -/// AOSOA formatted bundle of prestep data for multiple dynamic-supported character motion constraints. -/// -public struct DynamicCharacterMotionPrestep -{ - //Note that the prestep data layout is important. The solver tends to be severely memory bandwidth bound, so using a minimal representation is valuable. - //That's why the Basis is stored as a quaternion and not a full Matrix- the cost of the arithmetic operations to expand it back into the original matrix form is far less - //than the cost of loading all the extra lanes of data when scaled up to many cores. - public QuaternionWide SurfaceBasis; - public Vector MaximumHorizontalForce; - public Vector MaximumVerticalForce; - public Vector Depth; - public Vector2Wide TargetVelocity; - public Vector3Wide OffsetFromCharacter; - public Vector3Wide OffsetFromSupport; -} - -public struct DynamicCharacterMotionFunctions : ITwoBodyConstraintFunctions -{ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void ComputeJacobians(in Vector3Wide offsetA, in Vector3Wide offsetB, in QuaternionWide basisQuaternion, - out Matrix3x3Wide basis, - out Matrix2x3Wide horizontalAngularJacobianA, out Matrix2x3Wide horizontalAngularJacobianB, - out Vector3Wide verticalAngularJacobianA, out Vector3Wide verticalAngularJacobianB) - { - //Both of the motion constraints are velocity motors, like tangent friction. They don't actually have a position level goal. - //But if we did want to make such a position level goal, it could be expressed as: - //dot(basis.X, constrainedPointOnA - constrainedPointOnB) = 0 - //dot(basis.Y, constrainedPointOnA - constrainedPointOnB) <= 0 - //dot(basis.Z, constrainedPointOnA - constrainedPointOnB) = 0 - //Note that the Y axis, corresponding to the vertical motion constraint, is an inequality. It pulls toward the surface, but never pushes away. - //It also has a separate maximum force and acts on an independent axis; that's why we solve it as a separate constraint. - //To get a velocity constraint out of these position goals, differentiate with respect to time: - //d/dt(dot(basis.X, constrainedPointOnA - constrainedPointOnB)) = dot(basis.X, d/dt(constrainedPointOnA - constrainedPointOnB)) - // = dot(basis.X, a.LinearVelocity + a.AngularVelocity x offsetToConstrainedPointOnA - b.linearVelocity - b.AngularVelocity x offsetToConstrainedPointOnB) - //Throwing some algebra and identities at it: - //dot(basis.X, a.LinearVelocity) + dot(basis.X, a.AngularVelocity x offsetToConstrainedPointOnA) + dot(-basis.X, b.LinearVelocity) + dot(basis.X, offsetToConstrainedPointOnB x b.AngularVelocity) - //dot(basis.X, a.LinearVelocity) + dot(a.AngularVelocity, offsetToConstrainedPointOnA x basis.X) + dot(-basis.X, b.LinearVelocity) + dot(b.AngularVelocity, basis.X x offsetToConstrainedPointOnB) - //The (transpose) jacobian is the transform that pulls the body velocity into constraint space- - //and here, we can see that we have an axis being dotted with each component of the velocity. That's gives us the jacobian for that degree of freedom. - //The same form applies to all three axes of the basis, since they're all doing the same thing (just on different directions and with different force bounds). - //Note that we don't explicitly output linear jacobians- they are just the axes of the basis, and the linear jacobians of B are just the negated linear jacobians of A. - Matrix3x3Wide.CreateFromQuaternion(basisQuaternion, out basis); - Vector3Wide.CrossWithoutOverlap(offsetA, basis.X, out horizontalAngularJacobianA.X); - Vector3Wide.CrossWithoutOverlap(offsetA, basis.Y, out verticalAngularJacobianA); - Vector3Wide.CrossWithoutOverlap(offsetA, basis.Z, out horizontalAngularJacobianA.Y); - Vector3Wide.CrossWithoutOverlap(basis.X, offsetB, out horizontalAngularJacobianB.X); - Vector3Wide.CrossWithoutOverlap(basis.Y, offsetB, out verticalAngularJacobianB); - Vector3Wide.CrossWithoutOverlap(basis.Z, offsetB, out horizontalAngularJacobianB.Y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ApplyHorizontalImpulse(in Matrix3x3Wide basis, - in Matrix2x3Wide angularJacobianA, in Matrix2x3Wide angularJacobianB, in Vector2Wide constraintSpaceImpulse, - in BodyInertiaWide inertiaA, in BodyInertiaWide inertiaB, - ref BodyVelocityWide velocityA, ref BodyVelocityWide velocityB) - { - //Transform the constraint space impulse into world space by using the jacobian and then apply each body's inverse inertia to get the velocity change. - Vector3Wide.Scale(basis.X, constraintSpaceImpulse.X, out var linearImpulseAX); - Vector3Wide.Scale(basis.Z, constraintSpaceImpulse.Y, out var linearImpulseAY); - Vector3Wide.Add(linearImpulseAX, linearImpulseAY, out var linearImpulseA); - Vector3Wide.Scale(linearImpulseA, inertiaA.InverseMass, out var linearChangeA); - Vector3Wide.Add(velocityA.Linear, linearChangeA, out velocityA.Linear); - Vector3Wide.Scale(linearImpulseA, inertiaB.InverseMass, out var negatedLinearChangeB); //Linear jacobians for B are just A's negated linear jacobians. - Vector3Wide.Subtract(velocityB.Linear, negatedLinearChangeB, out velocityB.Linear); - - Matrix2x3Wide.Transform(constraintSpaceImpulse, angularJacobianA, out var angularImpulseA); - Symmetric3x3Wide.TransformWithoutOverlap(angularImpulseA, inertiaA.InverseInertiaTensor, out var angularChangeA); - Vector3Wide.Add(velocityA.Angular, angularChangeA, out velocityA.Angular); - Matrix2x3Wide.Transform(constraintSpaceImpulse, angularJacobianB, out var angularImpulseB); - Symmetric3x3Wide.TransformWithoutOverlap(angularImpulseB, inertiaB.InverseInertiaTensor, out var angularChangeB); - Vector3Wide.Add(velocityB.Angular, angularChangeB, out velocityB.Angular); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ApplyVerticalImpulse(in Matrix3x3Wide basis, - in Vector3Wide angularJacobianA, in Vector3Wide angularJacobianB, in Vector constraintSpaceImpulse, - in BodyInertiaWide inertiaA, in BodyInertiaWide inertiaB, - ref BodyVelocityWide velocityA, ref BodyVelocityWide velocityB) - { - Vector3Wide.Scale(basis.Y, constraintSpaceImpulse, out var linearImpulseA); - Vector3Wide.Scale(linearImpulseA, inertiaA.InverseMass, out var linearChangeA); - Vector3Wide.Add(velocityA.Linear, linearChangeA, out velocityA.Linear); - Vector3Wide.Scale(linearImpulseA, inertiaB.InverseMass, out var negatedLinearChangeB); //Linear jacobians for B are just A's negated linear jacobians. - Vector3Wide.Subtract(velocityB.Linear, negatedLinearChangeB, out velocityB.Linear); - - Vector3Wide.Scale(angularJacobianA, constraintSpaceImpulse, out var angularImpulseA); - Symmetric3x3Wide.TransformWithoutOverlap(angularImpulseA, inertiaA.InverseInertiaTensor, out var angularChangeA); - Vector3Wide.Add(velocityA.Angular, angularChangeA, out velocityA.Angular); - Vector3Wide.Scale(angularJacobianB, constraintSpaceImpulse, out var angularImpulseB); - Symmetric3x3Wide.TransformWithoutOverlap(angularImpulseB, inertiaB.InverseInertiaTensor, out var angularChangeB); - Vector3Wide.Add(velocityB.Angular, angularChangeB, out velocityB.Angular); - } - - - public static void WarmStart(in Vector3Wide positionA, in QuaternionWide orientationA, in BodyInertiaWide inertiaA, in Vector3Wide positionB, in QuaternionWide orientationB, in BodyInertiaWide inertiaB, ref DynamicCharacterMotionPrestep prestep, ref CharacterMotionAccumulatedImpulse accumulatedImpulses, ref BodyVelocityWide velocityA, ref BodyVelocityWide velocityB) - { - ComputeJacobians(prestep.OffsetFromCharacter, prestep.OffsetFromSupport, prestep.SurfaceBasis, - out var basis, out var horizontalAngularJacobianA, out var horizontalAngularJacobianB, out var verticalAngularJacobianA, out var verticalAngularJacobianB); - ApplyHorizontalImpulse(basis, horizontalAngularJacobianA, horizontalAngularJacobianB, accumulatedImpulses.Horizontal, inertiaA, inertiaB, ref velocityA, ref velocityB); - ApplyVerticalImpulse(basis, verticalAngularJacobianA, verticalAngularJacobianB, accumulatedImpulses.Vertical, inertiaA, inertiaB, ref velocityA, ref velocityB); - } - - public static void Solve(in Vector3Wide positionA, in QuaternionWide orientationA, in BodyInertiaWide inertiaA, in Vector3Wide positionB, in QuaternionWide orientationB, in BodyInertiaWide inertiaB, float dt, float inverseDt, ref DynamicCharacterMotionPrestep prestep, ref CharacterMotionAccumulatedImpulse accumulatedImpulses, ref BodyVelocityWide velocityA, ref BodyVelocityWide velocityB) - { - //The motion constraint is split into two parts: the horizontal constraint, and the vertical constraint. - //The horizontal constraint acts almost exactly like the TangentFriction, but we'll duplicate some of the logic to keep this implementation self-contained. - ComputeJacobians(prestep.OffsetFromCharacter, prestep.OffsetFromSupport, prestep.SurfaceBasis, - out var basis, out var horizontalAngularJacobianA, out var horizontalAngularJacobianB, out var verticalAngularJacobianA, out var verticalAngularJacobianB); - - //Compute the velocity error by projecting the body velocity into constraint space using the transposed jacobian. - Vector2Wide horizontalLinearA; - Vector3Wide.Dot(basis.X, velocityA.Linear, out horizontalLinearA.X); - Vector3Wide.Dot(basis.Z, velocityA.Linear, out horizontalLinearA.Y); - Matrix2x3Wide.TransformByTransposeWithoutOverlap(velocityA.Angular, horizontalAngularJacobianA, out var horizontalAngularA); - Vector2Wide negatedHorizontalLinearB; - Vector3Wide.Dot(basis.X, velocityB.Linear, out negatedHorizontalLinearB.X); - Vector3Wide.Dot(basis.Z, velocityB.Linear, out negatedHorizontalLinearB.Y); - Matrix2x3Wide.TransformByTransposeWithoutOverlap(velocityB.Angular, horizontalAngularJacobianB, out var horizontalAngularB); - Vector2Wide.Add(horizontalAngularA, horizontalAngularB, out var horizontalAngular); - Vector2Wide.Subtract(horizontalLinearA, negatedHorizontalLinearB, out var horizontalLinear); - Vector2Wide.Add(horizontalAngular, horizontalLinear, out var horizontalVelocity); - - //I'll omit the details of where this comes from, but you can check out the other constraints or the sorta-tutorial Inequality1DOF constraint to explain the details, - //plus some other references. The idea is that we need a way to transform the constraint space velocity (that we get from transforming body velocities - //by the transpose jacobian) into a corrective impulse for the solver iterations. That corrective impulse is then used to update the velocities on each iteration execution. - //This transform is the 'effective mass', representing the mass felt by the constraint in its local space. - //In concept, this constraint is actually two separate constraints solved iteratively, so we have two separate such effective mass transforms. - Symmetric3x3Wide.MatrixSandwich(horizontalAngularJacobianA, inertiaA.InverseInertiaTensor, out var horizontalAngularContributionA); - Symmetric3x3Wide.MatrixSandwich(horizontalAngularJacobianB, inertiaB.InverseInertiaTensor, out var horizontalAngularContributionB); - Symmetric2x2Wide.Add(horizontalAngularContributionA, horizontalAngularContributionB, out var inverseHorizontalEffectiveMass); - //The linear jacobians are unit length vectors, so J * M^-1 * JT is just M^-1. - var linearContribution = inertiaA.InverseMass + inertiaB.InverseMass; - inverseHorizontalEffectiveMass.XX += linearContribution; - inverseHorizontalEffectiveMass.YY += linearContribution; - Symmetric2x2Wide.InvertWithoutOverlap(inverseHorizontalEffectiveMass, out var horizontalEffectiveMass); - - Vector2Wide horizontalConstraintSpaceVelocityChange; - horizontalConstraintSpaceVelocityChange.X = prestep.TargetVelocity.X - horizontalVelocity.X; - //The surface basis's Z axis points in the opposite direction to the view direction, so negate the target velocity along the Z axis to point it in the expected direction. - horizontalConstraintSpaceVelocityChange.Y = -prestep.TargetVelocity.Y - horizontalVelocity.Y; - Symmetric2x2Wide.TransformWithoutOverlap(horizontalConstraintSpaceVelocityChange, horizontalEffectiveMass, out var horizontalCorrectiveImpulse); - - //Limit the force applied by the horizontal motion constraint. Note that this clamps the *accumulated* impulse applied this time step, not just this one iterations' value. - var previousHorizontalAccumulatedImpulse = accumulatedImpulses.Horizontal; - Vector2Wide.Add(accumulatedImpulses.Horizontal, horizontalCorrectiveImpulse, out accumulatedImpulses.Horizontal); - Vector2Wide.Length(accumulatedImpulses.Horizontal, out var horizontalImpulseMagnitude); - //Note division by zero guard. - var dtWide = new Vector(dt); - var maximumHorizontalImpulse = prestep.MaximumHorizontalForce * dtWide; - var scale = Vector.Min(Vector.One, maximumHorizontalImpulse / Vector.Max(new Vector(1e-16f), horizontalImpulseMagnitude)); - Vector2Wide.Scale(accumulatedImpulses.Horizontal, scale, out accumulatedImpulses.Horizontal); - Vector2Wide.Subtract(accumulatedImpulses.Horizontal, previousHorizontalAccumulatedImpulse, out horizontalCorrectiveImpulse); - - ApplyHorizontalImpulse(basis, horizontalAngularJacobianA, horizontalAngularJacobianB, horizontalCorrectiveImpulse, inertiaA, inertiaB, ref velocityA, ref velocityB); - - //Same thing for the vertical constraint. - Vector3Wide.Dot(basis.Y, velocityA.Linear, out var verticalLinearA); - Vector3Wide.Dot(velocityA.Angular, verticalAngularJacobianA, out var verticalAngularA); - Vector3Wide.Dot(basis.Y, velocityB.Linear, out var negatedVerticalLinearB); - Vector3Wide.Dot(velocityB.Angular, verticalAngularJacobianB, out var verticalAngularB); - //If the character is deeply penetrating, the vertical motion constraint will allow some separating velocity- just enough for one frame of integration to reach zero depth. - var verticalBiasVelocity = Vector.Max(Vector.Zero, prestep.Depth * inverseDt); - - //The vertical constraint just targets zero velocity, but does not attempt to fight any velocity which would merely push the character out of penetration. - //Note that many characters will just have zero inverse inertia tensors to prevent them from rotating, so this could be optimized. - //We don't take advantage of this optimization for simplicity, and so that you could use this constraint unchanged in a simulation - //where the orientation is instead controlled by some other constraint or torque- imagine a game with gravity that points in different directions. - Symmetric3x3Wide.VectorSandwich(verticalAngularJacobianA, inertiaA.InverseInertiaTensor, out var verticalAngularContributionA); - Symmetric3x3Wide.VectorSandwich(verticalAngularJacobianB, inertiaB.InverseInertiaTensor, out var verticalAngularContributionB); - var inverseVerticalEffectiveMass = verticalAngularContributionA + verticalAngularContributionB + linearContribution; - var verticalCorrectiveImpulse = (verticalBiasVelocity - verticalLinearA + negatedVerticalLinearB - verticalAngularA - verticalAngularB) / inverseVerticalEffectiveMass; - - //Clamp the vertical constraint's impulse, but note that this is a bit different than above- the vertical constraint is not allowed to *push*, so there's an extra bound at zero. - var previousVerticalAccumulatedImpulse = accumulatedImpulses.Vertical; - var maximumVerticalImpulse = prestep.MaximumVerticalForce * dtWide; - accumulatedImpulses.Vertical = Vector.Min(Vector.Zero, Vector.Max(accumulatedImpulses.Vertical + verticalCorrectiveImpulse, -maximumVerticalImpulse)); - verticalCorrectiveImpulse = accumulatedImpulses.Vertical - previousVerticalAccumulatedImpulse; - - ApplyVerticalImpulse(basis, verticalAngularJacobianA, verticalAngularJacobianB, verticalCorrectiveImpulse, inertiaA, inertiaB, ref velocityA, ref velocityB); - } - - - public static bool RequiresIncrementalSubstepUpdates => true; - public static void IncrementallyUpdateForSubstep(in Vector dt, in BodyVelocityWide velocityA, in BodyVelocityWide velocityB, ref DynamicCharacterMotionPrestep prestep) - { - //Since collision detection doesn't run for every substep, we approximate the change in depth for the vertical motion constraint by integrating the velocity along the support normal. - //This is pretty subtle. If you disable it entirely (return false from "RequiresIncrementalSubstepUpdates" above), you might not even notice. - //If you disable the vertical motion constraint, then it can definitely be disabled. - - //Any movement of the character or its support along N results in a change in the vertical motion constraint's perception of depth. - //estimatedPenetrationDepthChange = dot(normal, velocityDtA.Linear + velocityDtA.Angular x contactOffsetA) - dot(normal, velocityDtB.Linear + velocityDtB.Angular x contactOffsetB) - Vector3Wide.CrossWithoutOverlap(velocityA.Angular, prestep.OffsetFromCharacter, out var wxra); - Vector3Wide.Add(wxra, velocityA.Linear, out var contactVelocityA); - - var normal = QuaternionWide.TransformUnitY(prestep.SurfaceBasis); - Vector3Wide.CrossWithoutOverlap(velocityB.Angular, prestep.OffsetFromSupport, out var wxrb); - Vector3Wide.Add(wxrb, velocityB.Linear, out var contactVelocityB); - Vector3Wide.Subtract(contactVelocityA, contactVelocityB, out var contactVelocityDifference); - Vector3Wide.Dot(normal, contactVelocityDifference, out var estimatedDepthChangeVelocity); - prestep.Depth -= estimatedDepthChangeVelocity * dt; - } -} - -//Each constraint type has its own 'type processor'- it acts as the outer loop that handles all the common logic across batches of constraints and invokes -//the per-constraint logic as needed. The CharacterMotionFunctions type provides the actual implementation. -public class DynamicCharacterMotionTypeProcessor : TwoBodyTypeProcessor -{ - /// - /// Simulation-wide unique id for the character motion constraint. Every type has needs a unique compile time id; this is a little bit annoying to guarantee given that there is no central - /// registry of all types that can exist (custom ones, like this one, can always be created), but having it be constant helps simplify and optimize its internal usage. - /// - public const int BatchTypeId = 51; -} diff --git a/Prowl.Runtime/Components/Physics/Types/Interpolation.cs b/Prowl.Runtime/Components/Physics/Types/Interpolation.cs deleted file mode 100644 index a58275fcb..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Interpolation.cs +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -namespace Prowl.Runtime; - -public enum InterpolationMode -{ - /// - /// No interpolation, the body will be moved on every physics update and left alone during normal updates - /// - None, - /// - /// The body will move from the previous physics pose to the current physics pose, - /// introducing one physics update of latency but should be very smooth - /// - Interpolated, - /// - /// The body will move from the current physics pose to a predicted one, - /// reducing the latency but introducing imprecise or jerky motion when the pose changes significantly - /// - Extrapolated -} diff --git a/Prowl.Runtime/Components/Physics/Types/PhysicsMaterial.cs b/Prowl.Runtime/Components/Physics/Types/PhysicsMaterial.cs deleted file mode 100644 index 937f43294..000000000 --- a/Prowl.Runtime/Components/Physics/Types/PhysicsMaterial.cs +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Constraints; - -namespace Prowl.Runtime; - -public struct PhysicsMaterial -{ - //__Narrow__Settings__ - public SpringSettings SpringSettings; - public float FrictionCoefficient; - public float MaximumRecoveryVelocity; - public bool IsTrigger; - - - public static bool AllowContactGeneration(PhysicsMaterial a, PhysicsMaterial b) - { - return true; - } - -} diff --git a/Prowl.Runtime/Components/Physics/Types/Raycast/HitInfo.cs b/Prowl.Runtime/Components/Physics/Types/Raycast/HitInfo.cs deleted file mode 100644 index 9c2d1ab28..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Raycast/HitInfo.cs +++ /dev/null @@ -1,34 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; - -namespace Prowl.Runtime.Raycast; - -/// -/// Information returned by the different simulation test methods in -/// -/// The position where the intersection occured -/// The direction of the surface hit -/// The distance along the ray where the hit occured -/// The container hit -public readonly record struct HitInfo : IComparable -{ - public Vector3 Point { get; init; } - public Vector3 Normal { get; init; } - public float Distance { get; init; } - public PhysicsBody Container { get; init; } - - public HitInfo(Vector3 point, Vector3 normal, float distance, PhysicsBody container) - { - Point = point; - Normal = normal; - Distance = distance; - Container = container; - } - - public int CompareTo(HitInfo other) - { - return Distance.CompareTo(other.Distance); - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Raycast/OverlapHandler.cs b/Prowl.Runtime/Components/Physics/Types/Raycast/OverlapHandler.cs deleted file mode 100644 index 41706f1c5..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Raycast/OverlapHandler.cs +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -using BepuPhysics; -using BepuPhysics.Collidables; - -namespace Prowl.Runtime.Raycast; - -internal struct OverlapCollectionHandler : ISweepHitHandler -{ - public LayerMask? LayerMask { get; set; } - private readonly ICollection _collection; - - public OverlapCollectionHandler(ICollection collection, LayerMask? layerMask) - { - LayerMask = layerMask; - _collection = collection; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable) - { - var result = Physics.GetContainer(collidable); - return LayerMask?.HasLayer(result.GameObject.layerIndex) ?? true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable, int childIndex) - { - return true; - } - - public void OnHit(ref float maximumT, float t, System.Numerics.Vector3 hitLocation, System.Numerics.Vector3 hitNormal, CollidableReference collidable) { } - - public void OnHitAtZeroT(ref float maximumT, CollidableReference collidable) - { - _collection.Add(Physics.GetContainer(collidable)); - } -} - -internal struct OverlapArrayHandler : ISweepHitHandler -{ - public LayerMask? LayerMask { get; set; } - private readonly PhysicsBody[] _collection; - - public int Count { get; set; } - - public OverlapArrayHandler(PhysicsBody[] collection, LayerMask? layerMask) - { - LayerMask = layerMask; - _collection = collection; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable) - { - var result = Physics.GetContainer(collidable); - return LayerMask?.HasLayer(result.GameObject.layerIndex) ?? true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable, int childIndex) - { - return true; - } - - public void OnHit(ref float maximumT, float t, System.Numerics.Vector3 hitLocation, System.Numerics.Vector3 hitNormal, CollidableReference collidable) { } - - public void OnHitAtZeroT(ref float maximumT, CollidableReference collidable) - { - if (Count >= _collection.Length) - return; - - _collection[Count++] = Physics.GetContainer(collidable); - - if (Count == _collection.Length) - maximumT = -1f; // We want to notify bepu that we don't care about any subsequent collision, not sure that works in the process breaking out early but whatever - } -} - -internal struct OverlapAnyHandler : ISweepHitHandler -{ - public LayerMask? LayerMask { get; set; } - public bool Any { get; set; } - - public OverlapAnyHandler(LayerMask? layerMask) - { - LayerMask = layerMask; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable) - { - var result = Physics.GetContainer(collidable); - return LayerMask?.HasLayer(result.GameObject.layerIndex) ?? true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable, int childIndex) - { - return true; - } - - public void OnHit(ref float maximumT, float t, System.Numerics.Vector3 hitLocation, System.Numerics.Vector3 hitNormal, CollidableReference collidable) { } - - public void OnHitAtZeroT(ref float maximumT, CollidableReference collidable) - { - Any = true; - maximumT = -1f; // Not sure that even works to let bepu know that it should not compute for more at all - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Raycast/RayHitHandler.cs b/Prowl.Runtime/Components/Physics/Types/Raycast/RayHitHandler.cs deleted file mode 100644 index 4729d0ff5..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Raycast/RayHitHandler.cs +++ /dev/null @@ -1,206 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -using BepuPhysics; -using BepuPhysics.Collidables; -using BepuPhysics.Trees; - -namespace Prowl.Runtime.Raycast; - -internal struct RayClosestHitHandler : IRayHitHandler, ISweepHitHandler -{ - public LayerMask? LayerMask { get; set; } - public HitInfo? HitInformation { get; set; } - - public RayClosestHitHandler(LayerMask? layerMask) - { - LayerMask = layerMask; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable) - { - var result = Physics.GetContainer(collidable); - return LayerMask?.HasLayer(result.GameObject.layerIndex) ?? true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable, int childIndex) - { - return true; - } - - public void OnRayHit(in RayData ray, ref float maximumT, float t, System.Numerics.Vector3 normal, CollidableReference collidable, int childIndex) - { - HitInformation = new(ray.Origin + ray.Direction * t, normal, t, Physics.GetContainer(collidable)); - maximumT = t; - } - - public void OnHit(ref float maximumT, float t, System.Numerics.Vector3 hitLocation, System.Numerics.Vector3 hitNormal, CollidableReference collidable) - { - HitInformation = new(hitLocation, hitNormal, t, Physics.GetContainer(collidable)); - maximumT = t; - } - - public void OnHitAtZeroT(ref float maximumT, CollidableReference collidable) - { - // Right now just ignore the hit; - // We can't just set info to invalid data, it'll be confusing for users, - // but we might need to find a way to notify that the shape at its resting pose is already intersecting. - } -} - -internal struct RayHitsCollectionHandler : IRayHitHandler, ISweepHitHandler -{ - public LayerMask? LayerMask { get; set; } - private readonly ICollection _collection; - - public RayHitsCollectionHandler(ICollection collection, LayerMask? layerMask) - { - LayerMask = layerMask; - _collection = collection; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable) - { - var result = Physics.GetContainer(collidable); - return LayerMask?.HasLayer(result.GameObject.layerIndex) ?? true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable, int childIndex) - { - return true; - } - - public void OnRayHit(in RayData ray, ref float maximumT, float t, System.Numerics.Vector3 normal, CollidableReference collidable, int childIndex) - { - _collection.Add(new(ray.Origin + ray.Direction * t, normal, t, Physics.GetContainer(collidable))); - } - - public void OnHit(ref float maximumT, float t, System.Numerics.Vector3 hitLocation, System.Numerics.Vector3 hitNormal, CollidableReference collidable) - { - _collection.Add(new(hitLocation, hitNormal, t, Physics.GetContainer(collidable))); - } - - public void OnHitAtZeroT(ref float maximumT, CollidableReference collidable) - { - // Right now just ignore the hit; - // We can't just set info to invalid data, it'll be confusing for users, - // but we might need to find a way to notify that the shape at its resting pose is already intersecting. - } -} - -internal struct RayHitsArrayHandler : IRayHitHandler, ISweepHitHandler -{ - private readonly HitInfo[] _array; - - public LayerMask? LayerMask { get; set; } - public int Count { get; set; } - public float StoredMax { get; set; } - public int IndexOfMax { get; set; } - - public RayHitsArrayHandler(HitInfo[] array, LayerMask? layerMask) - { - LayerMask = layerMask; - _array = array; - StoredMax = float.NegativeInfinity; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable) - { - var result = Physics.GetContainer(collidable); - return LayerMask?.HasLayer(result.GameObject.layerIndex) ?? true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AllowTest(CollidableReference collidable, int childIndex) - { - return true; - } - - - public void OnRayHit(in RayData ray, ref float maximumT, float t, System.Numerics.Vector3 normal, CollidableReference collidable, int childIndex) - { - if (Count < _array.Length) - { - if (t > StoredMax) - { - StoredMax = t; - IndexOfMax = Count; - } - - _array[Count++] = new(ray.Origin + ray.Direction * t, normal, t, Physics.GetContainer(collidable)); - - if (Count == _array.Length) // Once the array is filled up, ignore all hits that occur further away than the furthest hit in the array - maximumT = StoredMax; - } - else - { - Debug.Assert(t > StoredMax, "maximumT should have prevented this hit from being returned, if this is hit it means that we need to change the above into an 'else if (distance < StoredMax)'"); - - _array[IndexOfMax] = new(ray.Origin + ray.Direction * t, normal, t, Physics.GetContainer(collidable)); - - // Re-scan to find the new max now that the last one was replaced - StoredMax = float.NegativeInfinity; - for (int i = 0; i < _array.Length; i++) - { - if (_array[i].Distance > StoredMax) - { - StoredMax = _array[i].Distance; - IndexOfMax = i; - } - } - - maximumT = StoredMax; - } - } - - public void OnHit(ref float maximumT, float t, System.Numerics.Vector3 hitLocation, System.Numerics.Vector3 normal, CollidableReference collidable) - { - if (Count < _array.Length) - { - if (t > StoredMax) - { - StoredMax = t; - IndexOfMax = Count; - } - - _array[Count++] = new(hitLocation, normal, t, Physics.GetContainer(collidable)); - - if (Count == _array.Length) // Once the array is filled up, ignore all hits that occur further away than the furthest hit in the array - maximumT = StoredMax; - } - else - { - Debug.Assert(t > StoredMax, "maximumT should have prevented this hit from being returned, if this is hit it means that we need to change the above into an 'else if (distance < StoredMax)'"); - - _array[IndexOfMax] = new(hitLocation, normal, t, Physics.GetContainer(collidable)); - - // Re-scan to find the new max now that the last one was replaced - StoredMax = float.NegativeInfinity; - for (int i = 0; i < _array.Length; i++) - { - if (_array[i].Distance > StoredMax) - { - StoredMax = _array[i].Distance; - IndexOfMax = i; - } - } - - maximumT = StoredMax; - } - } - - public void OnHitAtZeroT(ref float maximumT, CollidableReference collidable) - { - // Right now just ignore the hit; - // We can't just set info to invalid data, it'll be confusing for users, - // but we might need to find a way to notify that the shape at its resting pose is already intersecting. - } -} diff --git a/Prowl.Runtime/Components/Physics/Types/Trigger.cs b/Prowl.Runtime/Components/Physics/Types/Trigger.cs deleted file mode 100644 index 78703172b..000000000 --- a/Prowl.Runtime/Components/Physics/Types/Trigger.cs +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using BepuPhysics.Collidables; - -using Prowl.Runtime.Contacts; - -namespace Prowl.Runtime; - -public delegate void TriggerDelegate(PhysicsBody @this, PhysicsBody other); - -/// -/// A contact event handler without collision response, which runs delegates on enter and exit -/// -public class Trigger : IContactEventHandler -{ - public bool NoContactResponse => true; - public event TriggerDelegate? OnEnter, OnLeave; - - void IContactEventHandler.OnStartedTouching(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int contactIndex) - { - OnEnter?.Invoke(Physics.GetContainer(eventSource), Physics.GetContainer(other)); - } - void IContactEventHandler.OnStoppedTouching(CollidableReference eventSource, CollidableReference other, ref TManifold contactManifold, int contactIndex) - { - OnLeave?.Invoke(Physics.GetContainer(eventSource), Physics.GetContainer(other)); - } -} diff --git a/Prowl.Runtime/Physics.cs b/Prowl.Runtime/Physics.cs deleted file mode 100644 index 4b9cd8434..000000000 --- a/Prowl.Runtime/Physics.cs +++ /dev/null @@ -1,308 +0,0 @@ -// This file is part of the Prowl Game Engine -// Licensed under the MIT License. See the LICENSE file in the project root for details. - -using System; -using System.Collections.Generic; - -using BepuPhysics; -using BepuPhysics.Collidables; - -using BepuUtilities; -using BepuUtilities.Memory; - -using Prowl.Runtime.Contacts; -using Prowl.Runtime.Controller; -using Prowl.Runtime.Raycast; -using Prowl.Runtime.SceneManagement; -using Prowl.Runtime.Utils; - -namespace Prowl.Runtime; - -// Bepu Implementation based on: https://github.com/Nicogo1705/Stride.BepuPhysics - -[FilePath("PhysicsSettings.projsetting", FilePathAttribute.Location.Setting)] -public class PhysicsSetting : ScriptableSingleton -{ - public Vector3 Gravity = new Vector3(0, -9.81f, 0); - public int Iterations = 8; - public int Substep = 1; - public int TargetFrameRate = 50; - public bool UseMultithreading = true; - public bool EnhancedDeterminism = false; - public bool AutoSyncTransforms = true; - -} - - -public static class Physics -{ - public static bool IsReady => isInitialized && Application.IsPlaying; - - public static Simulation? Sim { get; private set; } - public static BufferPool? Pool { get; private set; } - public static ThreadDispatcher? Dispatcher { get; private set; } - - public static CharacterControllersManager? Characters { get; private set; } - - private static double timer = 0; - - - private static bool isInitialized = false; - - internal static CollidableProperty CollidableMaterials { get; private set; } - internal static ContactEventsManager ContactEvents { get; private set; } - - internal static List Bodies { get; } = new(); - internal static List Statics { get; } = new(); - - public static PhysicsBody GetContainer(CollidableReference collidable) - { - if (collidable.Mobility == CollidableMobility.Static) - { - return GetContainer(collidable.StaticHandle); - } - else - { - return GetContainer(collidable.BodyHandle); - } - return null; - } - - public static Rigidbody GetContainer(BodyHandle handle) - { - return Bodies[handle.Value]; - } - - public static Staticbody GetContainer(StaticHandle handle) - { - return Statics[handle.Value]; - } - - public static void Initialize() - { - if (isInitialized) - return; - - //Any IThreadDispatcher implementation can be used for multithreading. Here, we use the BepuUtilities.ThreadDispatcher implementation. - Dispatcher = new ThreadDispatcher(Environment.ProcessorCount); - Pool = new BufferPool(); - Characters = new CharacterControllersManager(Pool); - CollidableMaterials = new CollidableProperty(); - ContactEvents = new ContactEventsManager(Dispatcher, Pool); - - var narrow = new BepuNarrowPhaseCallbacks() { CollidableMaterials = CollidableMaterials, ContactEvents = ContactEvents }; - var pose = new BepuPoseIntegratorCallbacks(); - pose.Gravity = PhysicsSetting.Instance.Gravity; - var desc = new SolveDescription(PhysicsSetting.Instance.Iterations, PhysicsSetting.Instance.Substep); - Sim = Simulation.Create(Pool, narrow, pose, desc); - Sim.Deterministic = PhysicsSetting.Instance.EnhancedDeterminism; - - CollidableMaterials.Initialize(Sim); - ContactEvents.Initialize(); - - isInitialized = true; - } - - public static void Update() - { - if (!isInitialized) - return; - - timer += Time.deltaTime; - int count = 0; - while (timer >= Time.fixedDeltaTime && count++ < 10) - { - SceneManager.PhysicsUpdate(); - if (PhysicsSetting.Instance.UseMultithreading) - Sim.Timestep((float)Time.fixedDeltaTime, Dispatcher); - else - Sim.Timestep((float)Time.fixedDeltaTime); - timer -= Time.fixedDeltaTime; - ContactEvents.Flush(); //Fire event handler stuff. - - foreach (var body in Bodies) - { - if (body == null) continue; - - if (PhysicsSetting.Instance.AutoSyncTransforms) - body.SyncTransform(); - - body.PreviousPose = body.CurrentPose; - if (body.BodyReference is { } bRef) - body.CurrentPose = bRef.Pose; - } - - foreach (var body in Statics) - { - if (body == null) continue; - - if (PhysicsSetting.Instance.AutoSyncTransforms) - body.SyncTransform(); - - body.PreviousPose = body.CurrentPose; - if (body.StaticReference is { } sRef) - body.CurrentPose = sRef.Pose; - } - } - - InterpolateTransforms(); - } - - private static void InterpolateTransforms() - { - // Find the interpolation factor, a value [0,1] which represents the ratio of the current time relative to the previous and the next physics step, - // a value of 0.5 means that we're halfway to the next physics update, just have to wait for the same amount of time. - var interpolationFactor = (float)(timer / Time.fixedDeltaTime); - interpolationFactor = MathF.Min(interpolationFactor, 1f); - foreach (var body in Bodies) - { - if (body == null) continue; - - if (body.InterpolationMode == InterpolationMode.Extrapolated) - interpolationFactor += 1f; - - var interpolatedPosition = Vector3.Lerp(body.PreviousPose.Position, body.CurrentPose.Position, interpolationFactor); - // We may be able to get away with just a Lerp instead of Slerp, not sure if it needs to be normalized though at which point it may not be that much faster - var interpolatedRotation = Quaternion.Slerp(body.PreviousPose.Orientation, body.CurrentPose.Orientation, interpolationFactor); - - var prevVersion = body.Transform.version; - body.Transform.rotation = interpolatedRotation; - body.Transform.position = interpolatedPosition - Vector3.Transform(body.CenterOfMass, interpolatedRotation); - // Physics doesnt (for the time being, may change) update the transform version - body.Transform.version = prevVersion; - } - } - - public static void Dispose() - { - if (!isInitialized) - return; - - CollidableMaterials.Dispose(); - ContactEvents.Dispose(); - Bodies.Clear(); - Statics.Clear(); - - Characters.Dispose(); - Characters = null; - Sim.Dispose(); - Sim = null; - Dispatcher.Dispose(); - Dispatcher = null; - Pool.Clear(); - Pool = null; - - isInitialized = false; - } - - #region Public API - - /// - /// Finds the closest intersection between this ray and shapes in the simulation. - /// - /// True when the given ray intersects with a shape, false otherwise - public static bool RayCast(in Vector3 origin, in Vector3 dir, float maxDistance, out HitInfo result, LayerMask? layerMask = null) - { - var handler = new RayClosestHitHandler(layerMask); - Sim.RayCast(origin, dir, maxDistance, ref handler); - if (handler.HitInformation.HasValue) - { - result = handler.HitInformation.Value; - return true; - } - - result = default; - return false; - } - - /// - /// Collect intersections between the given ray and shapes in this simulation. Hits are NOT sorted. - /// - public static void RaycastPenetrating(in Vector3 origin, in Vector3 dir, float maxDistance, HitInfo[] buffer, out Span hits, LayerMask? collisionMask = null) - { - var handler = new RayHitsArrayHandler(buffer, collisionMask); - Sim.RayCast(origin, dir, maxDistance, ref handler); - hits = new(buffer, 0, handler.Count); - } - - /// - /// Collect intersections between the given ray and shapes in this simulation. Hits are NOT sorted. - /// - public static void RaycastPenetrating(in Vector3 origin, in Vector3 dir, float maxDistance, ICollection collection, LayerMask? collisionMask = null) - { - var handler = new RayHitsCollectionHandler(collection, collisionMask); - Sim.RayCast(origin, dir, maxDistance, ref handler); - } - - /// - /// Finds the closest contact between and other shapes in the simulation when thrown in direction. - /// - /// True when the given ray intersects with a shape, false otherwise - public static bool SweepCast(in TShape shape, in RigidPose pose, in BodyVelocity velocity, float maxDistance, out HitInfo result, LayerMask? collisionMask = null) where TShape : unmanaged, IConvexShape //== collider "RayCast" - { - var handler = new RayClosestHitHandler(collisionMask); - Sim.Sweep(shape, pose, velocity, maxDistance, Pool, ref handler); - if (handler.HitInformation.HasValue) - { - result = handler.HitInformation.Value; - return true; - } - - result = default; - return false; - } - - /// - /// Finds contacts between and other shapes in the simulation when thrown in direction. - /// - /// True when the given ray intersects with a shape, false otherwise - public static void SweepCastPenetrating(in TShape shape, in RigidPose pose, in BodyVelocity velocity, float maxDistance, HitInfo[] buffer, out Span contacts, LayerMask? collisionMask = null) where TShape : unmanaged, IConvexShape //== collider "RayCast" - { - var handler = new RayHitsArrayHandler(buffer, collisionMask); - Sim.Sweep(shape, pose, velocity, maxDistance, Pool, ref handler); - contacts = new(buffer, 0, handler.Count); - } - - /// - /// Finds contacts between and other shapes in the simulation when thrown in direction. - /// - /// True when the given ray intersects with a shape, false otherwise - public static void SweepCastPenetrating(in TShape shape, in RigidPose pose, in BodyVelocity velocity, float maxDistance, ICollection collection, LayerMask? collisionMask = null) where TShape : unmanaged, IConvexShape //== collider "RayCast" - { - var handler = new RayHitsCollectionHandler(collection, collisionMask); - Sim.Sweep(shape, pose, velocity, maxDistance, Pool, ref handler); - } - - /// - /// Returns true when this shape overlaps with any physics object in this simulation - /// - /// True when the given shape overlaps with any physics object in the simulation - public static bool Overlap(in TShape shape, in RigidPose pose, LayerMask? collisionMask = null) where TShape : unmanaged, IConvexShape - { - var handler = new OverlapAnyHandler(collisionMask); - Sim.Sweep(shape, pose, default, 0f, Pool, ref handler); - return handler.Any; - } - - /// - /// Fills with any physics object in the simulation that overlaps with this shape - /// - public static void Overlap(in TShape shape, in RigidPose pose, PhysicsBody[] buffer, out Span overlaps, LayerMask? collisionMask = null) where TShape : unmanaged, IConvexShape - { - var handler = new OverlapArrayHandler(buffer, collisionMask); - Sim.Sweep(shape, pose, default, 0f, Pool, ref handler); - overlaps = new(buffer, 0, handler.Count); - } - - /// - /// Fills with any physics object in the simulation that overlaps with this shape - /// - public static void Overlap(in TShape shape, in RigidPose pose, ICollection collection, LayerMask? collisionMask = null) where TShape : unmanaged, IConvexShape - { - var handler = new OverlapCollectionHandler(collection, collisionMask); - Sim.Sweep(shape, pose, default, 0f, Pool, ref handler); - } - - #endregion - -} diff --git a/Prowl.Runtime/Prowl.Runtime.csproj b/Prowl.Runtime/Prowl.Runtime.csproj index 0c44b9b42..786f3f1f6 100644 --- a/Prowl.Runtime/Prowl.Runtime.csproj +++ b/Prowl.Runtime/Prowl.Runtime.csproj @@ -63,8 +63,6 @@ - - diff --git a/Prowl.Runtime/SceneManager.cs b/Prowl.Runtime/SceneManager.cs index ea9bd36b7..42ea08f30 100644 --- a/Prowl.Runtime/SceneManager.cs +++ b/Prowl.Runtime/SceneManager.cs @@ -100,8 +100,6 @@ public static void Clear() for (int i = 0; i < toRemove.Count; i++) _gameObjects.Remove(toRemove[i]); - Physics.Dispose(); - Physics.Initialize(); MainScene = new(); } @@ -113,9 +111,6 @@ public static void Update() if (_gameObjects[i].enabledInHierarchy) _gameObjects[i].PreUpdate(); - if (Application.IsPlaying) - Physics.Update(); - ForeachComponent((x) => { diff --git a/Prowl.Runtime/Time.cs b/Prowl.Runtime/Time.cs index 8007c6c7c..046051c85 100644 --- a/Prowl.Runtime/Time.cs +++ b/Prowl.Runtime/Time.cs @@ -59,7 +59,6 @@ public static class Time public static double deltaTime => CurrentTime.deltaTime; public static float deltaTimeF => (float)deltaTime; - public static double fixedDeltaTime => 1.0 / (PhysicsSetting.Instance?.TargetFrameRate ?? 50); public static double time => CurrentTime.time; public static double smoothUnscaledDeltaTime => CurrentTime.smoothUnscaledDeltaTime;