Răsfoiți Sursa

Added base Joint type to C#
Making sure everything compiles and runs after many untested physics related additions/changes

BearishSun 9 ani în urmă
părinte
comite
02d748de78
34 a modificat fișierele cu 677 adăugiri și 37 ștergeri
  1. 1 1
      BansheeCore/Include/BsCorePrerequisites.h
  2. 3 3
      BansheeCore/Include/BsFJoint.h
  3. 2 0
      MBansheeEngine/MBansheeEngine.csproj
  4. 3 1
      MBansheeEngine/Physics/BoxCollider.cs
  5. 3 1
      MBansheeEngine/Physics/CapsuleCollider.cs
  6. 1 1
      MBansheeEngine/Physics/CharacterController.cs
  7. 329 2
      MBansheeEngine/Physics/Joint.cs
  8. 5 3
      MBansheeEngine/Physics/MeshCollider.cs
  9. 0 1
      MBansheeEngine/Physics/NativeCharacterController.cs
  10. 90 0
      MBansheeEngine/Physics/NativeJoint.cs
  11. 0 1
      MBansheeEngine/Physics/NativeRigidbody.cs
  12. 14 0
      MBansheeEngine/Physics/Physics.cs
  13. 5 3
      MBansheeEngine/Physics/PlaneCollider.cs
  14. 10 1
      MBansheeEngine/Physics/Rigidbody.cs
  15. 3 1
      MBansheeEngine/Physics/SphereCollider.cs
  16. 1 0
      SBansheeEngine/Include/BsScriptBoxCollider.h
  17. 1 0
      SBansheeEngine/Include/BsScriptCapsuleCollider.h
  18. 2 1
      SBansheeEngine/Include/BsScriptCharacterController.h
  19. 2 0
      SBansheeEngine/Include/BsScriptCollider.h
  20. 2 2
      SBansheeEngine/Include/BsScriptCollisionData.h
  21. 1 1
      SBansheeEngine/Include/BsScriptControllerCollision.h
  22. 78 0
      SBansheeEngine/Include/BsScriptJoint.h
  23. 6 6
      SBansheeEngine/Include/BsScriptJointCommon.h
  24. 2 0
      SBansheeEngine/Include/BsScriptMeshCollider.h
  25. 1 1
      SBansheeEngine/Include/BsScriptPhysicsQueryHit.h
  26. 2 0
      SBansheeEngine/Include/BsScriptPlaneCollider.h
  27. 2 1
      SBansheeEngine/Include/BsScriptRigidbody.h
  28. 2 0
      SBansheeEngine/Include/BsScriptSphereCollider.h
  29. 2 0
      SBansheeEngine/SBansheeEngine.vcxproj
  30. 6 0
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  31. 2 2
      SBansheeEngine/Source/BsScriptCharacterController.cpp
  32. 3 3
      SBansheeEngine/Source/BsScriptCollider.cpp
  33. 1 1
      SBansheeEngine/Source/BsScriptCollisionData.cpp
  34. 92 0
      SBansheeEngine/Source/BsScriptJoint.cpp

+ 1 - 1
BansheeCore/Include/BsCorePrerequisites.h

@@ -290,7 +290,7 @@ namespace BansheeEngine
 	class StringTable;
 	class PhysicsMaterial;
 	class PhysicsMesh;
-	class CollisionData;
+	struct CollisionData;
 	// Scene
 	class SceneObject;
 	class Component;

+ 3 - 3
BansheeCore/Include/BsFJoint.h

@@ -32,13 +32,13 @@ namespace BansheeEngine
 		/** Sets a body managed by the joint. One of the bodies must be movable (i.e. non-kinematic). */
 		virtual void setBody(JointBody body, Rigidbody* value) = 0;
 
-		/** Returns the position of a body relative to the joint. */
+		/** Returns the position relative to the body, at which the body is anchored to the joint. */
 		virtual Vector3 getPosition(JointBody body) const = 0;
 
-		/** Returns the rotation of a body relative to the joint. */
+		/** Returns the rotation relative to the body, at which the body is anchored to the joint. */
 		virtual Quaternion getRotation(JointBody body) const = 0;
 
-		/** Sets the position and rotation of a body relative to the joint. */
+		/** Sets the position and rotation relative to the body, at which the body is anchored to the joint.  */
 		virtual void setTransform(JointBody body, const Vector3& position, const Quaternion& rotation) = 0;
 
 		/** 

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -119,10 +119,12 @@
     <Compile Include="Physics\NativeCapsuleCollider.cs" />
     <Compile Include="Physics\NativeCharacterController.cs" />
     <Compile Include="Physics\NativeCollider.cs" />
+    <Compile Include="Physics\NativeJoint.cs" />
     <Compile Include="Physics\NativeMeshCollider.cs" />
     <Compile Include="Physics\NativePlaneCollider.cs" />
     <Compile Include="Physics\NativeRigidbody.cs" />
     <Compile Include="Physics\NativeSphereCollider.cs" />
+    <Compile Include="Physics\Physics.cs" />
     <Compile Include="Physics\PhysicsMaterial.cs" />
     <Compile Include="Physics\PhysicsMesh.cs" />
     <Compile Include="Physics\PhysicsCommon.cs" />

+ 3 - 1
MBansheeEngine/Physics/BoxCollider.cs

@@ -1,4 +1,6 @@
-namespace BansheeEngine
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
 {
     /// <summary>
     /// Collider with box geometry.

+ 3 - 1
MBansheeEngine/Physics/CapsuleCollider.cs

@@ -1,4 +1,6 @@
-namespace BansheeEngine
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
 {
     /// <summary>
     /// Collider with capsule geometry.

+ 1 - 1
MBansheeEngine/Physics/CharacterController.cs

@@ -10,7 +10,7 @@ namespace BansheeEngine
     /// of the standard physics model to handle various issues with manually moving kinematic objects.Uses a capsule to
     /// represent the character's bounds. 
     /// </summary>
-    public class CharacterController : Component
+    public sealed class CharacterController : Component
     {
         internal NativeCharacterController native;
 

+ 329 - 2
MBansheeEngine/Physics/Joint.cs

@@ -1,12 +1,339 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+using System;
 using System.Runtime.InteropServices;
 
 namespace BansheeEngine
 {
-    public class Joint : Component
+    /// <summary>
+    /// Base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (e.g. a door 
+    /// hinge). One of the bodies in the joint must always be movable (i.e. non-kinematic).
+    /// </summary>
+    public abstract class Joint : Component
     {
-        // TODO
+        internal NativeJoint native;
+
+        [SerializeField]
+        internal SerializableData serializableData = new SerializableData();
+
+        /// <summary>
+        /// Triggered when the joint's break force or torque is exceeded.
+        /// </summary>
+        public event Action OnJointBreak;
+
+        /// <summary>
+        /// Maximum force the joint can apply before breaking. Broken joints no longer participate in physics simulation.
+        /// </summary>
+        public float BreakForce
+        {
+            get { return serializableData.breakForce; }
+            set
+            {
+                if (serializableData.breakForce == value)
+                    return;
+
+                serializableData.breakForce = value;
+
+                if (native != null)
+                    native.BreakForce = value;
+            }
+        }
+
+        /// <summary>
+        /// Sets the maximum force the joint can apply before breaking. Broken joints no longer participate in physics
+        /// simulation.
+        /// </summary>
+        public float BreakTorque
+        {
+            get { return serializableData.breakTorque; }
+            set
+            {
+                if (serializableData.breakTorque == value)
+                    return;
+
+                serializableData.breakTorque = value;
+
+                if (native != null)
+                    native.BreakTorque = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether collisions between the two bodies managed by the joint are enabled.
+        /// </summary>
+        public bool EnableCollision
+        {
+            get { return serializableData.enableCollision; }
+            set
+            {
+                if (serializableData.enableCollision == value)
+                    return;
+
+                serializableData.enableCollision = value;
+
+                if (native != null)
+                    native.EnableCollision = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns one of the bodies managed by the joint.
+        /// </summary>
+        /// <param name="body">Which of the rigidbodies to return.</param>
+        /// <returns>Rigidbody managed by the joint, or null if none.</returns>
+        public Rigidbody GetRigidbody(JointBody body)
+        {
+            return serializableData.bodies[(int) body];
+        }
+
+        /// <summary>
+        /// Sets a body managed by the joint. One of the bodies must be movable (i.e. non-kinematic).
+        /// </summary>
+        /// <param name="body">Which of the rigidbodies to set.</param>
+        /// <param name="rigidbody">Rigidbody to managed by the joint, or null. If one of the bodies is null the other
+        ///                         one will be anchored globally to the position/rotation set by <see cref="SetPosition"/>
+        ///                         and <see cref="SetRotation"/>.</param>
+        public void SetRigidbody(JointBody body, Rigidbody rigidbody)
+        {
+            if (serializableData.bodies[(int)body] == rigidbody)
+                return;
+
+            if (serializableData.bodies[(int)body] != null)
+                serializableData.bodies[(int)body].SetJoint(null);
+
+            serializableData.bodies[(int)body] = rigidbody;
+
+            if (rigidbody != null)
+                serializableData.bodies[(int)body].SetJoint(this);
+
+            if (native != null)
+            {
+                native.SetRigidbody(body, rigidbody);
+                UpdateTransform(body);
+            }
+        }
+
+        /// <summary>
+        /// Returns the position at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body to retrieve position for.</param>
+        /// <returns>Position relative to the body.</returns>
+        public Vector3 GetPosition(JointBody body)
+        {
+            return serializableData.positions[(int)body];
+        }
+
+        /// <summary>
+        /// Sets the position at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body set the position for.</param>
+        /// <param name="position">Position relative to the body.</param>
+        public void SetPosition(JointBody body, Vector3 position)
+        {
+            if (serializableData.positions[(int)body] == position)
+                return;
+
+            serializableData.positions[(int) body] = position;
+
+            if (native != null)
+                UpdateTransform(body);
+        }
+
+        /// <summary>
+        /// Returns the rotation at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body to retrieve rotation for.</param>
+        /// <returns>Rotation relative to the body.</returns>
+        public Quaternion GetRotation(JointBody body)
+        {
+            return serializableData.rotations[(int)body];
+        }
+
+        /// <summary>
+        /// Sets the rotation at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body set the rotation for.</param>
+        /// <param name="rotation">Rotation relative to the body.</param>
+        public void SetRotation(JointBody body, Quaternion rotation)
+        {
+            if (serializableData.rotations[(int)body] == rotation)
+                return;
+
+            serializableData.rotations[(int)body] = rotation;
+
+            if (native != null)
+                UpdateTransform(body);
+        }
+
+        /// <summary>
+        /// Triggered when the joint breaks.
+        /// </summary>
+        internal void DoOnJointBreak()
+        {
+            if (OnJointBreak != null)
+                OnJointBreak();
+        }
+
+        /// <summary>
+        /// Notifies the joint that one of the attached rigidbodies moved and that its transform needs updating.
+        /// </summary>
+        /// <param name="body">Rigidbody that moved.</param>
+	    internal void NotifyRigidbodyMoved(Rigidbody body)
+	    {
+		    // If physics update is in progress do nothing, as its the joint itself that's probably moving the body
+		    if (Physics.IsUpdateInProgress)
+			    return;
+
+		    if (serializableData.bodies[0] == body)
+			    UpdateTransform(JointBody.A);
+		    else if (serializableData.bodies[1] == body)
+			    UpdateTransform(JointBody.B);
+	    }
+
+        /// <summary>
+        /// Creates the internal representation of the Joint for use by the component.
+        /// </summary>
+        /// <returns>New native joint object.</returns>
+        internal abstract NativeJoint CreateNative();
+
+        private void OnInitialize()
+        {
+            NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
+        }
+
+        private void OnReset()
+        {
+            RestoreNative();
+        }
+
+        private void OnEnable()
+        {
+            if (native == null)
+                RestoreNative();
+        }
+
+        private void OnDisable()
+        {
+            DestroyNative();
+        }
+
+        private void OnDestroy()
+        {
+            if (serializableData.bodies[0] != null)
+                serializableData.bodies[0].SetJoint(null);
+
+            if (serializableData.bodies[1] != null)
+                serializableData.bodies[1].SetJoint(null);
+
+            DestroyNative();
+        }
+
+        private void OnTransformChanged(TransformChangedFlags flags)
+        {
+            if (!SceneObject.Active)
+                return;
+
+            // We're ignoring this during physics update because it would cause problems if the joint itself was moved by physics
+            // Note: This isn't particularily correct because if the joint is being moved by physics but the rigidbodies
+            // themselves are not parented to the joint, the transform will need updating. However I'm leaving it up to the
+            // user to ensure rigidbodies are always parented to the joint in such a case (It's an unlikely situation that
+            // I can't think of an use for - joint transform will almost always be set as an initialization step and not a 
+            // physics response).
+            if (Physics.IsUpdateInProgress)
+                return;
+
+            UpdateTransform(JointBody.A);
+            UpdateTransform(JointBody.B);
+        }
+
+        /// <summary>
+        /// Creates the internal representation of the Joint and restores the values saved by the Component.
+        /// </summary>
+        private void RestoreNative()
+	    {
+            native = CreateNative();
+
+            // Note: Merge into one call to avoid many virtual function calls
+            Rigidbody[] bodies = new Rigidbody[2];
+
+		    if (serializableData.bodies[0] != null)
+			    bodies[0] = serializableData.bodies[0];
+		    else
+			    bodies[0] = null;
+
+		    if (serializableData.bodies[1] != null)
+			    bodies[1] = serializableData.bodies[1];
+		    else
+			    bodies[1] = null;
+
+		    native.SetRigidbody(JointBody.A, bodies[0]);
+		    native.SetRigidbody(JointBody.B, bodies[1]);
+		    native.BreakForce = serializableData.breakForce;
+            native.BreakTorque = serializableData.breakTorque;
+            native.EnableCollision = serializableData.enableCollision;
+		    native.BreakTorque = serializableData.breakTorque;
+            native.EnableCollision = serializableData.enableCollision;
+
+		    UpdateTransform(JointBody.A);
+		    UpdateTransform(JointBody.B);
+	    }
+
+        /// <summary>
+        /// Destroys the internal joint representation.
+        /// </summary>
+        private void DestroyNative()
+	    {
+	        if (native != null)
+	        {
+	            native.Destroy();
+                native = null;
+	        }
+	    }
+
+        /// <summary>
+        /// Updates the local transform for the specified body attached to the joint.
+        /// </summary>
+        /// <param name="body">Body to update.</param>
+	    private void UpdateTransform(JointBody body)
+	    {
+		    Vector3 localPos;
+		    Quaternion localRot;
+
+		    localPos = serializableData.positions[(int)body];
+		    localRot = serializableData.rotations[(int)body];
+
+		    // Transform to world space of the related body
+		    Rigidbody rigidbody = serializableData.bodies[(int)body];
+		    if (rigidbody != null)
+		    {
+			    localRot = rigidbody.SceneObject.Rotation * localRot;
+			    localPos = localRot.Rotate(localPos) + rigidbody.SceneObject.Position;
+		    }
+
+		    // Transform to space local to the joint
+		    Quaternion invRotation = SceneObject.Rotation.Inverse;
+
+		    localPos = invRotation.Rotate(localPos - SceneObject.Position);
+		    localRot = invRotation * localRot;
+
+		    native.SetPosition(body, localPos);
+            native.SetRotation(body, localRot);
+	    }
+
+        /// <summary>
+        /// Holds all data the joint component needs to persist through serialization.
+        /// </summary>
+        [SerializeObject]
+        internal class SerializableData
+        {
+            public Rigidbody[] bodies = new Rigidbody[2];
+            public Vector3[] positions = new Vector3[2];
+            public Quaternion[] rotations = new Quaternion[2];
+            public float breakForce = float.MaxValue;
+            public float breakTorque = float.MaxValue;
+            public bool enableCollision = false;
+        }
     }
 
     /// <summary>

+ 5 - 3
MBansheeEngine/Physics/MeshCollider.cs

@@ -1,4 +1,6 @@
-namespace BansheeEngine
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
 {
     /// <summary>
     /// A collider represented by an arbitrary mesh.
@@ -47,10 +49,10 @@
         }
 
         /// <inheritdoc/>
-        protected override bool IsValidParent(Rigidbody parent) 
+        protected internal override bool IsValidParent(Rigidbody parent) 
 	    {
 		    // Triangle mesh colliders cannot be used for non-kinematic rigidbodies
-		    return mesh == null|| mesh.MeshType == PhysicsMeshType.Convex || parent.IsKinematic;
+		    return mesh == null|| mesh.MeshType == PhysicsMeshType.Convex || parent.Kinematic;
         }
 
     /// <summary>

+ 0 - 1
MBansheeEngine/Physics/NativeCharacterController.cs

@@ -1,6 +1,5 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-
 using System;
 using System.Runtime.CompilerServices;
 

+ 90 - 0
MBansheeEngine/Physics/NativeJoint.cs

@@ -0,0 +1,90 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Wrapper around the native Joint class.
+    /// <see cref="Joint"/>
+    /// </summary>
+    internal class NativeJoint : ScriptObject
+    {
+        private Joint component;
+
+        /// <summary>
+        /// Component that owns the native joint object.
+        /// </summary>
+        public Joint Component
+        {
+            get { return component; }
+            set { component = value; }
+        }
+
+        public float BreakForce
+        {
+            set { Internal_SetBreakForce(mCachedPtr, value); }
+        }
+
+        public float BreakTorque
+        {
+            set { Internal_SetBreakTorque(mCachedPtr, value); }
+        }
+
+        public bool EnableCollision
+        {
+            set { Internal_SetEnableCollision(mCachedPtr, value); }
+        }
+
+        public void SetRigidbody(JointBody body, Rigidbody rigidbody)
+        {
+            IntPtr rigidbodyPtr = IntPtr.Zero;
+            if (rigidbody != null)
+                rigidbodyPtr = rigidbody.native.GetCachedPtr();
+
+            Internal_SetBody(mCachedPtr, body, rigidbodyPtr);
+        }
+
+        public void SetPosition(JointBody body, Vector3 position)
+        {
+            Internal_SetPosition(mCachedPtr, body, ref position);
+        }
+
+        public void SetRotation(JointBody body, Quaternion rotation)
+        {
+            Internal_SetRotation(mCachedPtr, body, ref rotation);
+        }
+        
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        private void Internal_DoOnJointBreak()
+        {
+            Component.DoOnJointBreak();
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBody(IntPtr thisPtr, JointBody body, IntPtr rigidbody);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPosition(IntPtr thisPtr, JointBody body, ref Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRotation(IntPtr thisPtr, JointBody body, ref Quaternion rotation);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBreakForce(IntPtr thisPtr, float force);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBreakTorque(IntPtr thisPtr, float torque);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetEnableCollision(IntPtr thisPtr, bool value);
+    }
+}

+ 0 - 1
MBansheeEngine/Physics/NativeRigidbody.cs

@@ -1,6 +1,5 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-
 using System;
 using System.Runtime.CompilerServices;
 

+ 14 - 0
MBansheeEngine/Physics/Physics.cs

@@ -0,0 +1,14 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
+{
+    public static class Physics
+    {
+        public static bool IsUpdateInProgress
+        {
+            get { return false; /* TODO */ }
+        }
+
+        // TODO
+    }
+}

+ 5 - 3
MBansheeEngine/Physics/PlaneCollider.cs

@@ -1,4 +1,6 @@
-namespace BansheeEngine
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
 {
     /// <summary>
     /// Collider with plane geometry.
@@ -50,10 +52,10 @@
         }
 
         /// <inheritdoc/>
-        protected override bool IsValidParent(Rigidbody parent)
+        protected internal override bool IsValidParent(Rigidbody parent)
     	{
 		    // Planes cannot be added to non-kinematic rigidbodies
-		    return parent.IsKinematic;
+		    return parent.Kinematic;
         }
 
         /// <summary>

+ 10 - 1
MBansheeEngine/Physics/Rigidbody.cs

@@ -14,7 +14,7 @@ namespace BansheeEngine
     /// rigidbody to be valid. Colliders that are on the same scene object as the rigidbody, or on child scene objects
     /// are automatically considered as part of the rigidbody.
     /// </summary>
-    public class Rigidbody : Component
+    public sealed class Rigidbody : Component
     {
         internal NativeRigidbody native;
         private List<Collider> children = new List<Collider>();
@@ -450,6 +450,15 @@ namespace BansheeEngine
                 OnCollisionEnd(data);
         }
 
+        /// <summary>
+        /// Sets that joint that this rigidbody is attached to. Allows the rigidbody to notify the joint when it moves.
+        /// </summary>
+        /// <param name="joint">Joint the rigidbody is attached to, or null if none.</param>
+        internal void SetJoint(Joint joint)
+        {
+            parentJoint = joint;
+        }
+
         /// <summary>
         /// Recalculates rigidbody's mass, inertia tensors and center of mass depending on the currently set child 
         /// colliders. This should be called whenever relevant child collider properties change(like mass or shape).

+ 3 - 1
MBansheeEngine/Physics/SphereCollider.cs

@@ -1,4 +1,6 @@
-namespace BansheeEngine
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
 {
     /// <summary>
     /// Collider with sphere geometry.

+ 1 - 0
SBansheeEngine/Include/BsScriptBoxCollider.h

@@ -10,6 +10,7 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for BoxCollider. */
 	class BS_SCR_BE_EXPORT ScriptBoxCollider : public TScriptCollider<ScriptBoxCollider>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeBoxCollider")
 	private:
 		ScriptBoxCollider(MonoObject* instance, const SPtr<Collider>& collider);

+ 1 - 0
SBansheeEngine/Include/BsScriptCapsuleCollider.h

@@ -10,6 +10,7 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for CapsuleCollider. */
 	class BS_SCR_BE_EXPORT ScriptCapsuleCollider : public TScriptCollider<ScriptCapsuleCollider>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeCapsuleCollider")
 	private:
 		ScriptCapsuleCollider(MonoObject* instance, const SPtr<Collider>& collider);

+ 2 - 1
SBansheeEngine/Include/BsScriptCharacterController.h

@@ -12,8 +12,9 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for CharacterController. */
 	class BS_SCR_BE_EXPORT ScriptCharacterController : public ScriptObject<ScriptCharacterController>
 	{
-		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeCharacterController")
 	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeCharacterController")
+
 		/** Returns the native CharacterController object. */
 		CharacterController* getCharController() const { return mCharacterController.get(); }
 

+ 2 - 0
SBansheeEngine/Include/BsScriptCollider.h

@@ -49,7 +49,9 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for Collider. */
 	class BS_SCR_BE_EXPORT ScriptCollider : public TScriptCollider<ScriptCollider>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeCollider")
+
 	private:
 		friend class ScriptColliderBase;
 

+ 2 - 2
SBansheeEngine/Include/BsScriptCollisionData.h

@@ -19,9 +19,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with CollisionData structure. */
 	class BS_SCR_BE_EXPORT ScriptCollisionDataHelper : public ScriptObject<ScriptCollisionDataHelper>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "ScriptCollisionData")
 
-	public:
 		/** Converts native collision data to its managed counterpart. */
 		static ScriptCollisionData create(const CollisionData& data);
 
@@ -38,9 +38,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with ContactPoint structure. */
 	class BS_SCR_BE_EXPORT ScriptContactPointHelper : public ScriptObject<ScriptContactPointHelper>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "ContactPoint")
 
-	public:
 		/** Unboxes a boxed managed ContactPoint struct and returns the native version of the structure. */
 		static ContactPoint unbox(MonoObject* obj);
 

+ 1 - 1
SBansheeEngine/Include/BsScriptControllerCollision.h

@@ -23,9 +23,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with ControllerCollision structure. */
 	class BS_SCR_BE_EXPORT ScriptControllerCollisionHelper : public ScriptObject<ScriptControllerCollisionHelper>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "ScriptControllerCollision")
 
-	public:
 		/** Converts native collision data to its managed counterpart. */
 		static ScriptControllerCollision create(const ControllerColliderCollision& data);
 

+ 78 - 0
SBansheeEngine/Include/BsScriptJoint.h

@@ -0,0 +1,78 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsJoint.h"
+
+namespace BansheeEngine
+{
+	class ScriptJoint;
+
+	/** Base class for all Joint interop objects. */
+	class BS_SCR_BE_EXPORT ScriptJointBase : public ScriptObjectBase
+	{
+	public:
+		/** Returns the native Joint object. */
+		virtual Joint* getJoint() const { return mJoint.get(); };
+	protected:
+		friend ScriptJoint;
+
+		ScriptJointBase(MonoObject* instance);
+		virtual ~ScriptJointBase() {}
+
+		/** Initializes the interop object with a native joint. Must be called right after construction. */
+		void initialize(const SPtr<Joint>& joint);
+
+		/** Destroys the internal joint object. */
+		void destroyJoint();
+
+		SPtr<Joint> mJoint;
+	};
+
+	/** A more specialized version of ScriptObject that allows the constructor to set the native joint. */
+	template <class Type>
+	class TScriptJoint : public ScriptObject<Type, ScriptJointBase>
+	{
+	public:
+		virtual ~TScriptJoint() {}
+
+	protected:
+		TScriptJoint(MonoObject* instance, const SPtr<Joint>& joint)
+			:ScriptObject(instance)
+		{
+			initialize(joint);
+		}
+	};
+
+	/** Interop class between C++ & CLR for Joint. */
+	class BS_SCR_BE_EXPORT ScriptJoint : public TScriptJoint<ScriptJoint>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeJoint")
+
+	private:
+		friend class ScriptJointBase;
+
+		ScriptJoint(MonoObject* instance);
+
+		/** Triggered the joint breaks. */
+		static void onJointBreak(MonoObject* instance);
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_Destroy(ScriptJointBase* thisPtr);
+		static void internal_SetBody(ScriptJointBase* thisPtr, JointBody body, ScriptRigidbody* value);
+		static void internal_SetPosition(ScriptJointBase* thisPtr, JointBody body, Vector3* position);
+		static void internal_SetRotation(ScriptJointBase* thisPtr, JointBody body, Quaternion* rotation);
+		static void internal_SetBreakForce(ScriptJointBase* thisPtr, float force);
+		static void internal_SetBreakTorque(ScriptJointBase* thisPtr, float torque);
+		static void internal_SetEnableCollision(ScriptJointBase* thisPtr, bool value);
+
+		typedef void(__stdcall *OnJointBreakThunkDef) (MonoObject*, MonoException**);
+
+		static OnJointBreakThunkDef onJointBreakThunk;
+	};
+}

+ 6 - 6
SBansheeEngine/Include/BsScriptJointCommon.h

@@ -13,9 +13,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with D6Joint::Drive structure. */
 	class BS_SCR_BE_EXPORT ScriptD6JointDrive : public ScriptObject<ScriptD6JointDrive>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "D6JointDrive")
 
-	public:
 		/** Converts managed limit to its native counterpart. */
 		static D6Joint::Drive convert(MonoObject* object);
 
@@ -33,9 +33,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with HingeJoint::Drive structure. */
 	class BS_SCR_BE_EXPORT ScriptHingeJointDrive : public ScriptObject<ScriptHingeJointDrive>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "HingeJointDrive")
 
-	public:
 		/** Converts managed limit to its native counterpart. */
 		static HingeJoint::Drive convert(MonoObject* object);
 
@@ -53,9 +53,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with LimitLinearRange structure. */
 	class BS_SCR_BE_EXPORT ScriptLimitLinearRange : public ScriptObject<ScriptLimitLinearRange>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "LimitLinearRange")
 
-	public:
 		/** Converts managed limit to its native counterpart. */
 		static LimitLinearRange convert(MonoObject* object);
 
@@ -73,9 +73,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with LimitLinear structure. */
 	class BS_SCR_BE_EXPORT ScriptLimitLinear : public ScriptObject<ScriptLimitLinear>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "LimitLinear")
 
-	public:
 		/** Converts managed limit to its native counterpart. */
 		static LimitLinear convert(MonoObject* object);
 
@@ -93,9 +93,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with LimitAngularRange structure. */
 	class BS_SCR_BE_EXPORT ScriptLimitAngularRange : public ScriptObject<ScriptLimitAngularRange>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "LimitAngularRange")
 
-	public:
 		/** Converts managed limit to its native counterpart. */
 		static LimitAngularRange convert(MonoObject* object);
 
@@ -113,9 +113,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with LimitConeRange structure. */
 	class BS_SCR_BE_EXPORT ScriptLimitConeRange : public ScriptObject<ScriptLimitConeRange>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "LimitConeRange")
 
-	public:
 		/** Converts managed limit to its native counterpart. */
 		static LimitConeRange convert(MonoObject* object);
 

+ 2 - 0
SBansheeEngine/Include/BsScriptMeshCollider.h

@@ -10,7 +10,9 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for MeshCollider. */
 	class BS_SCR_BE_EXPORT ScriptMeshCollider : public TScriptCollider<ScriptMeshCollider>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeMeshCollider")
+
 	private:
 		ScriptMeshCollider(MonoObject* instance, const SPtr<Collider>& collider);
 

+ 1 - 1
SBansheeEngine/Include/BsScriptPhysicsQueryHit.h

@@ -22,9 +22,9 @@ namespace BansheeEngine
 	/** Helper class for dealing with PhysicsQueryHit structure. */
 	class BS_SCR_BE_EXPORT ScriptPhysicsQueryHitHelper : public ScriptObject<ScriptPhysicsQueryHitHelper>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "ScriptPhysicsQueryHit")
 
-	public:
 		/** Converts native physics query hit to its managed counterpart. */
 		static ScriptPhysicsQueryHit create(const PhysicsQueryHit& data);
 

+ 2 - 0
SBansheeEngine/Include/BsScriptPlaneCollider.h

@@ -10,7 +10,9 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for PlaneCollider. */
 	class BS_SCR_BE_EXPORT ScriptPlaneCollider : public TScriptCollider<ScriptPlaneCollider>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativePlaneCollider")
+
 	private:
 		ScriptPlaneCollider(MonoObject* instance, const SPtr<Collider>& collider);
 

+ 2 - 1
SBansheeEngine/Include/BsScriptRigidbody.h

@@ -11,8 +11,9 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for Rigidbody. */
 	class BS_SCR_BE_EXPORT ScriptRigidbody : public ScriptObject<ScriptRigidbody>
 	{
-		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeRigidbody")
 	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeRigidbody")
+
 		/** Returns the native Rigidbody object. */
 		Rigidbody* getRigidbody() const { return mRigidbody.get(); }
 

+ 2 - 0
SBansheeEngine/Include/BsScriptSphereCollider.h

@@ -10,7 +10,9 @@ namespace BansheeEngine
 	/** Interop class between C++ & CLR for SphereCollider. */
 	class BS_SCR_BE_EXPORT ScriptSphereCollider : public TScriptCollider<ScriptSphereCollider>
 	{
+	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeSphereCollider")
+
 	private:
 		ScriptSphereCollider(MonoObject* instance, const SPtr<Collider>& collider);
 

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -317,6 +317,7 @@
     <ClInclude Include="Include\BsScriptHString.h" />
     <ClInclude Include="Include\BsScriptInput.h" />
     <ClInclude Include="Include\BsScriptInputConfiguration.h" />
+    <ClInclude Include="Include\BsScriptJoint.h" />
     <ClInclude Include="Include\BsScriptJointCommon.h" />
     <ClInclude Include="Include\BsScriptLight.h" />
     <ClInclude Include="Include\BsScriptLogEntry.h" />
@@ -431,6 +432,7 @@
     <ClCompile Include="Source\BsScriptGUIInputBox.cpp" />
     <ClCompile Include="Source\BsScriptInput.cpp" />
     <ClCompile Include="Source\BsScriptInputConfiguration.cpp" />
+    <ClCompile Include="Source\BsScriptJoint.cpp" />
     <ClCompile Include="Source\BsScriptJointCommon.cpp" />
     <ClCompile Include="Source\BsScriptLight.cpp" />
     <ClCompile Include="Source\BsScriptLogEntry.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -410,6 +410,9 @@
     <ClInclude Include="Include\BsScriptCharacterController.h">
       <Filter>Header Files\Physics</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptJoint.h">
+      <Filter>Header Files\Physics</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -757,5 +760,8 @@
     <ClCompile Include="Source\BsScriptCharacterController.cpp">
       <Filter>Source Files\Physics</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptJoint.cpp">
+      <Filter>Source Files\Physics</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 2 - 2
SBansheeEngine/Source/BsScriptCharacterController.cpp

@@ -44,13 +44,13 @@ namespace BansheeEngine
 	void ScriptCharacterController::onColliderHit(MonoObject* instance, const ControllerColliderCollision& collisionData)
 	{
 		ScriptControllerCollision scriptCollisionData = ScriptControllerCollisionHelper::create(collisionData);
-		MonoUtil::invokeThunk(onColliderHit, instance, &scriptCollisionData);
+		MonoUtil::invokeThunk(onColliderHitThunk, instance, &scriptCollisionData);
 	}
 
 	void ScriptCharacterController::onControllerHit(MonoObject* instance, const ControllerControllerCollision& collisionData)
 	{
 		ScriptControllerCollision scriptCollisionData = ScriptControllerCollisionHelper::create(collisionData);
-		MonoUtil::invokeThunk(onControllerHit, instance, &scriptCollisionData);
+		MonoUtil::invokeThunk(onControllerHitThunk, instance, &scriptCollisionData);
 	}
 
 	void ScriptCharacterController::internal_CreateInstance(MonoObject* instance, CHAR_CONTROLLER_DESC* initData)

+ 3 - 3
SBansheeEngine/Source/BsScriptCollider.cpp

@@ -29,9 +29,9 @@ namespace BansheeEngine
 		mCollider = collider;
 
 		MonoObject* instance = getManagedInstance();
-		collider->onCollisionBegin.connect(std::bind(&Collider::onCollisionBegin, instance, _1));
-		collider->onCollisionStay.connect(std::bind(&Collider::onCollisionStay, instance, _1));
-		collider->onCollisionEnd.connect(std::bind(&Collider::onCollisionEnd, instance, _1));
+		collider->onCollisionBegin.connect(std::bind(&ScriptCollider::onCollisionBegin, instance, _1));
+		collider->onCollisionStay.connect(std::bind(&ScriptCollider::onCollisionStay, instance, _1));
+		collider->onCollisionEnd.connect(std::bind(&ScriptCollider::onCollisionEnd, instance, _1));
 	}
 
 	void ScriptColliderBase::destroyCollider()

+ 1 - 1
SBansheeEngine/Source/BsScriptCollisionData.cpp

@@ -30,7 +30,7 @@ namespace BansheeEngine
 			output.colliderB = nullptr;
 
 		UINT32 numContactPoints = (UINT32)data.contactPoints.size();
-		ScriptArray contactPoints = ScriptArray::create<ContactPoint>(numContactPoints);
+		ScriptArray contactPoints = ScriptArray::create<ScriptContactPointHelper>(numContactPoints);
 		for (UINT32 i = 0; i < numContactPoints; i++)
 			contactPoints.set(i, ScriptContactPointHelper::box(data.contactPoints[i]));
 

+ 92 - 0
SBansheeEngine/Source/BsScriptJoint.cpp

@@ -0,0 +1,92 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsScriptJoint.h"
+#include "BsMonoUtil.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsScriptRigidbody.h"
+
+namespace BansheeEngine
+{
+	ScriptJoint::OnJointBreakThunkDef ScriptJoint::onJointBreakThunk = nullptr;
+
+	ScriptJointBase::ScriptJointBase(MonoObject* instance)
+		:ScriptObjectBase(instance)
+	{ }
+
+	void ScriptJointBase::initialize(const SPtr<Joint>& joint)
+	{
+		mJoint = joint;
+
+		MonoObject* instance = getManagedInstance();
+		joint->onJointBreak.connect(std::bind(&ScriptJoint::onJointBreak, instance));
+	}
+
+	void ScriptJointBase::destroyJoint()
+	{
+		mJoint = nullptr;
+	}
+
+	ScriptJoint::ScriptJoint(MonoObject* instance)
+		:TScriptJoint(instance, nullptr)
+	{ }
+
+	void ScriptJoint::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_Destroy", &ScriptJoint::internal_Destroy);
+		metaData.scriptClass->addInternalCall("Internal_SetBody", &ScriptJoint::internal_SetBody);
+		metaData.scriptClass->addInternalCall("Internal_SetPosition", &ScriptJoint::internal_SetPosition);
+		metaData.scriptClass->addInternalCall("Internal_SetRotation", &ScriptJoint::internal_SetRotation);
+		metaData.scriptClass->addInternalCall("Internal_SetBreakForce", &ScriptJoint::internal_SetBreakForce);
+		metaData.scriptClass->addInternalCall("Internal_SetBreakTorque", &ScriptJoint::internal_SetBreakTorque);
+		metaData.scriptClass->addInternalCall("Internal_SetEnableCollision", &ScriptJoint::internal_SetEnableCollision);
+
+		onJointBreakThunk = (OnJointBreakThunkDef)metaData.scriptClass->getMethod("Internal_DoOnJointBreak")->getThunk();
+	}
+
+	void ScriptJoint::onJointBreak(MonoObject* instance)
+	{
+		MonoUtil::invokeThunk(onJointBreakThunk, instance);
+	}
+
+	void ScriptJoint::internal_Destroy(ScriptJointBase* thisPtr)
+	{
+		thisPtr->destroyJoint();
+	}
+
+	void ScriptJoint::internal_SetBody(ScriptJointBase* thisPtr, JointBody body, ScriptRigidbody* value)
+	{
+		Rigidbody* rigidbody = nullptr;
+		if (value != nullptr)
+			rigidbody = value->getRigidbody();
+
+		thisPtr->mJoint->setBody(body, rigidbody);
+	}
+
+	void ScriptJoint::internal_SetPosition(ScriptJointBase* thisPtr, JointBody body, Vector3* position)
+	{
+		Quaternion rotation = thisPtr->mJoint->getRotation(body);
+		thisPtr->mJoint->setTransform(body, *position, rotation);
+	}
+
+	void ScriptJoint::internal_SetRotation(ScriptJointBase* thisPtr, JointBody body, Quaternion* rotation)
+	{
+		Vector3 position = thisPtr->mJoint->getPosition(body);
+		thisPtr->mJoint->setTransform(body, position, *rotation);
+	}
+
+	void ScriptJoint::internal_SetBreakForce(ScriptJointBase* thisPtr, float force)
+	{
+		thisPtr->mJoint->setBreakForce(force);
+	}
+
+	void ScriptJoint::internal_SetBreakTorque(ScriptJointBase* thisPtr, float torque)
+	{
+		thisPtr->mJoint->setBreakTorque(torque);
+	}
+
+	void ScriptJoint::internal_SetEnableCollision(ScriptJointBase* thisPtr, bool value)
+	{
+		thisPtr->mJoint->setEnableCollision(value);
+	}
+}