Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
ai.fluctio.fluctio-sim / Core / Components / Prefabs / Primitives / Base / PrimitivePhysicsProperties.cs
Size: Mime:
using Fluctio.FluctioSim.Common.Configuration;
using Fluctio.FluctioSim.Core.Components.Base;
using Fluctio.FluctioSim.Core.Components.MujocoGeom;
using Mujoco;
using UnityEngine;
using PhysicsMaterial = Fluctio.FluctioSim.Core.Components.PhysicsMaterials.PhysicsMaterial;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Fluctio.FluctioSim.Core.Components.Prefabs.Primitives.Base
{
	[ExecuteInEditMode]
	[RequireComponent(typeof(MujocoStructure))]
	[AddComponentMenu(Config.PrefixedName+"/Physics/Geom Settings/Physics Properties", Config.ComponentMenuOrder + 60)]
	[DisallowMultipleComponent]
	public sealed class PrimitivePhysicsProperties : EditorComponent
	{
		[Tooltip("Multiplier applied to the global gravity configured in Unity project settings\n1 = normal gravity\n0 = no gravity\n-1 = inversed gravity")]
		[SerializeField] public float gravityMultiplier = 1;
		
		[SerializeField] public MassDefinitionType massDefinitionType = MassDefinitionType.Density;
		[SerializeField] public PhysicsMaterial physicsMaterial;
		[SerializeField] public float density = 1000;
		[SerializeField] public float mass = 10;

		private MjBody _bodyComponent;
		private MjGeom _geomComponent;

		protected override void Initialize()
		{
			base.Initialize();
			var structure = GetComponent<MujocoStructure>();
			_bodyComponent = structure.BodyComponent;
			_geomComponent = structure.GeomComponent;
		}

		private void ToGeom()
		{
			switch (massDefinitionType)
			{
				case MassDefinitionType.Density:
					_geomComponent.Mass = 0;
					_geomComponent.Density = density;
					break;
				case MassDefinitionType.Material:
					density = physicsMaterial.density;
					goto case MassDefinitionType.Density;
				case MassDefinitionType.Mass:
					_geomComponent.Mass = mass;
					break;
				default:
					Debug.LogError($"Wrong value for {nameof(massDefinitionType)}: {massDefinitionType}");
					massDefinitionType = MassDefinitionType.Density;
					break;
			}
		}

		private void FromGeom()
		{
			if (_geomComponent.Mass != 0)
			{
				massDefinitionType = MassDefinitionType.Mass;
				mass = _geomComponent.Mass;
				return;
			}
			if (massDefinitionType == MassDefinitionType.Mass)
			{
				massDefinitionType = MassDefinitionType.Density;
			}
			// ReSharper disable once CompareOfFloatsByEqualityOperator
			if (_geomComponent.Density != density)
			{
				massDefinitionType = MassDefinitionType.Density;
				density = _geomComponent.Density;
			}
		}

		private void ConstrainValues()
		{
			density = Mathf.Max(density, Config.MinFloat);
			mass = Mathf.Max(mass, Config.MinFloat);
			physicsMaterial ??= PhysicsMaterial.Default;
		}

		public override void OnSelfChanged()
		{
			base.OnSelfChanged();
			ConstrainValues();
			_bodyComponent.GravityCompensation = 1 - gravityMultiplier;
			ToGeom();
		}

		public override void OnOtherChanged()
		{
			base.OnOtherChanged();
			gravityMultiplier = 1 - _bodyComponent.GravityCompensation;
			FromGeom();
		}
	}

	public enum MassDefinitionType
	{
		Density,
		Material,
		Mass,
	}

	#if UNITY_EDITOR
	[CustomEditor(typeof(PrimitivePhysicsProperties), true)]
	[CanEditMultipleObjects]
	public class PrimitivePhysicsPropertiesEditor : EditorComponentEditor
	{
		// ReSharper disable once InconsistentNaming
		private new PrimitivePhysicsProperties target => (PrimitivePhysicsProperties)base.target;

		public override void OnInspectorGUI()
		{
			serializedObject.Update();
			
			var gravityMultiplierProperty = serializedObject.FindProperty("gravityMultiplier");
			EditorGUILayout.PropertyField(gravityMultiplierProperty);
			
			var massDefinitionTypeProperty = serializedObject.FindProperty("massDefinitionType");
			EditorGUILayout.PropertyField(massDefinitionTypeProperty);
			
			// TODO: show all three fields and recalculate all of them when one changes
			var densityProperty = serializedObject.FindProperty("density");
			var physicsMaterialProperty = serializedObject.FindProperty("physicsMaterial");
			var massProperty = serializedObject.FindProperty("mass");
			if (!massDefinitionTypeProperty.hasMultipleDifferentValues)
			{
				switch (target.massDefinitionType)
				{
					case MassDefinitionType.Density:
						EditorGUILayout.PropertyField(densityProperty);
						break;
					case MassDefinitionType.Material:
						EditorGUILayout.PropertyField(physicsMaterialProperty);
						GUI.enabled = false;
						EditorGUILayout.PropertyField(densityProperty);
						GUI.enabled = true;
						break;
					case MassDefinitionType.Mass:
						EditorGUILayout.PropertyField(massProperty);
						break;
					default:
						// ReSharper disable once Unity.PerformanceCriticalCodeInvocation
						Debug.LogError(
							$"Wrong value for {nameof(target.massDefinitionType)}: {target.massDefinitionType}");
						target.massDefinitionType = MassDefinitionType.Density;
						break;
				}
			}

			serializedObject.ApplyModifiedProperties();
		}
	}
	#endif
}