diff options
3 files changed, 164 insertions, 0 deletions
diff --git a/JamHelper/Assets/JamHelper/JamUtils/Physics.meta b/JamHelper/Assets/JamHelper/JamUtils/Physics.meta new file mode 100644 index 0000000..d5b0db8 --- /dev/null +++ b/JamHelper/Assets/JamHelper/JamUtils/Physics.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee37b26dd339f8746a27ed8efe0e1f1f +folderAsset: yes +DefaultImporter: +  externalObjects: {} +  userData:  +  assetBundleName:  +  assetBundleVariant:  diff --git a/JamHelper/Assets/JamHelper/JamUtils/Physics/PhysicsHelper.cs b/JamHelper/Assets/JamHelper/JamUtils/Physics/PhysicsHelper.cs new file mode 100644 index 0000000..7cd1e5a --- /dev/null +++ b/JamHelper/Assets/JamHelper/JamUtils/Physics/PhysicsHelper.cs @@ -0,0 +1,145 @@ +//#define PHYSICS_EXTENSION + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +// 参考 +// * https://www.youtube.com/watch?v=BNiAt0HnC5M&ab_channel=DitzelGames + +namespace JamUtils.Physics +{ + +	public static class PhysicsHelper +	{ +		public const int VERSION_CODE = 1; + +		/// <summary> +		/// 施加一定大小的力,使速度达到targetVelocity +		/// </summary> +		/// <param name="rigidbody"></param> +		/// <param name="velocity"></param> +		/// <param name="mode"></param> +#if PHYSICS_EXTENSION +		public static Vector3 AddForceToReachVelocity(this Rigidbody rigidbody, Vector3 targetVelocity, float force = 1, ForceMode mode = ForceMode.Force) +#else +		public static Vector3 AddForceToReachVelocity(Rigidbody rigidbody, Vector3 targetVelocity, float force = 1, ForceMode mode = ForceMode.Force) +#endif +		{ +			if (targetVelocity.magnitude == 0) +			{ +				return Vector3.zero; +			} + +			Vector3 velocity = targetVelocity + targetVelocity.normalized * 0.2f * rigidbody.drag; + +			//force = 1 => need 1 s to reach velocity (if mass is 1) => force can be max 1 / Time.fixedDeltaTime +			force = Mathf.Clamp(force, -rigidbody.mass / Time.fixedDeltaTime, rigidbody.mass / Time.fixedDeltaTime); + +			//dot product is a projection from rhs to lhs with a length of result / lhs.magnitude https://www.youtube.com/watch?v=h0NJK4mEIJU +			if (rigidbody.velocity.magnitude == 0) +			{ +				rigidbody.AddForce(velocity * force, mode); +				return velocity * force; +			} +			else +			{ +				var velocityProjectedToTarget = (velocity.normalized * Vector3.Dot(velocity, rigidbody.velocity) / velocity.magnitude); +				rigidbody.AddForce((velocity - velocityProjectedToTarget) * force, mode); +				return (velocity - velocityProjectedToTarget) * force; +			} +		} + +		/// <summary> +		/// 施加一定大小的力矩,使角速度达到目标值 +		/// </summary> +		/// <param name="rigidbody"></param> +		/// <param name="rotation"></param> +		/// <param name="rps"></param> +		/// <param name="force"></param> +#if PHYSICS_EXTENSION +		public static void ApplyTorqueToReachRPS(this Rigidbody rigidbody, Quaternion rotation, float rps, float force = 1) +#else +		public static void ApplyTorqueToReachRPS(Rigidbody rigidbody, Quaternion rotation, float rps, float force = 1) +#endif +		{ +			var radPerSecond = rps * 2 * Mathf.PI + rigidbody.angularDrag * 20; + +			float angleInDegrees; +			Vector3 rotationAxis; +			rotation.ToAngleAxis(out angleInDegrees, out rotationAxis); + +			if (force == 0 || rotationAxis == Vector3.zero) +				return; + +			rigidbody.maxAngularVelocity = Mathf.Max(rigidbody.maxAngularVelocity, radPerSecond); + +			force = Mathf.Clamp(force, -rigidbody.mass * 2 * Mathf.PI / Time.fixedDeltaTime, rigidbody.mass * 2 * Mathf.PI / Time.fixedDeltaTime); + +			var currentSpeed = Vector3.Project(rigidbody.angularVelocity, rotationAxis).magnitude; + +			rigidbody.AddTorque(rotationAxis * (radPerSecond - currentSpeed) * force); +		} + +		public static Vector3 QuaternionToAngularVelocity(Quaternion rotation) +		{ +			float angleInDegrees; +			Vector3 rotationAxis; +			rotation.ToAngleAxis(out angleInDegrees, out rotationAxis); + +			return rotationAxis * angleInDegrees * Mathf.Deg2Rad; +		} + +		public static Quaternion AngularVelocityToQuaternion(Vector3 angularVelocity) +		{ +			var rotationAxis = (angularVelocity * Mathf.Rad2Deg).normalized; +			float angleInDegrees = (angularVelocity * Mathf.Rad2Deg).magnitude; + +			return Quaternion.AngleAxis(angleInDegrees, rotationAxis); +		} + +		public static Vector3 GetNormal(Vector3[] points) +		{ +			//https://www.ilikebigbits.com/2015_03_04_plane_from_points.html +			if (points.Length < 3) +				return Vector3.up; + +			var center = GetCenter(points); + +			float xx = 0f, xy = 0f, xz = 0f, yy = 0f, yz = 0f, zz = 0f; + +			for (int i = 0; i < points.Length; i++) +			{ +				var r = points[i] - center; +				xx += r.x * r.x; +				xy += r.x * r.y; +				xz += r.x * r.z; +				yy += r.y * r.y; +				yz += r.y * r.z; +				zz += r.z * r.z; +			} + +			var det_x = yy * zz - yz * yz; +			var det_y = xx * zz - xz * xz; +			var det_z = xx * yy - xy * xy; + +			if (det_x > det_y && det_x > det_z) +				return new Vector3(det_x, xz * yz - xy * zz, xy * yz - xz * yy).normalized; +			if (det_y > det_z) +				return new Vector3(xz * yz - xy * zz, det_y, xy * xz - yz * xx).normalized; +			else +				return new Vector3(xy * yz - xz * yy, xy * xz - yz * xx, det_z).normalized; + +		} + +		public static Vector3 GetCenter(Vector3[] points) +		{ +			var center = Vector3.zero; +			for (int i = 0; i < points.Length; i++) +				center += points[i] / points.Length; +			return center; +		} + + +	} +} diff --git a/JamHelper/Assets/JamHelper/JamUtils/Physics/PhysicsHelper.cs.meta b/JamHelper/Assets/JamHelper/JamUtils/Physics/PhysicsHelper.cs.meta new file mode 100644 index 0000000..be3b5e6 --- /dev/null +++ b/JamHelper/Assets/JamHelper/JamUtils/Physics/PhysicsHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 074e0715a475fe84a9a2de82d2f7f3e0 +MonoImporter: +  externalObjects: {} +  serializedVersion: 2 +  defaultReferences: [] +  executionOrder: 0 +  icon: {instanceID: 0} +  userData:  +  assetBundleName:  +  assetBundleVariant:   | 
