Repository URL to install this package:
Version:
1.0.0 ▾
|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Fluctio.FluctioSim.Common.Configuration;
using Fluctio.FluctioSim.Core.Components.Base;
using Fluctio.FluctioSim.Core.Components.MujocoGeom;
using Fluctio.FluctioSim.Core.MujocoExtensions;
using Fluctio.FluctioSim.Core.MujocoExtensions.MujocoDataProxy;
using Fluctio.FluctioSim.Utils.General;
using JetBrains.Annotations;
using Mujoco;
using UnityEngine;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using Fluctio.FluctioSim.Common.Icons;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.ShortcutManagement;
#endif
namespace Fluctio.FluctioSim.Core.Components.Prefabs.Primitives.Base
{
[RequireComponent(typeof(MujocoStructure))]
[AddComponentMenu(Config.PrefixedName+"/Physics/Joint", Config.ComponentMenuOrder + 10)]
public class PrimitiveJoint : InternalsEditorComponent
{
[SerializeField]
public JointType jointType = JointType.Free;
private JointType _previousJointType = JointType.None;
[field: SerializeField, HideInInspector]
public GameObject JointObject { get; private set; }
[field: SerializeField, HideInInspector]
[CanBeNull]
public MjBaseJoint JointComponent { get; private set; }
public ComponentData Data { get; private set; }
public T GetJointComponent<T>() where T: MjBaseJoint
{
if (JointComponent == null)
{
throw new InvalidOperationException("Requested joint is null");
}
if (JointComponent is not T typedJointComponent)
{
throw new InvalidCastException($"Tried to get joint of type {typeof(T).Name}, but it is actually {JointComponent.GetType().Name}");
}
return typedJointComponent;
}
public override void InitializePrefab()
{
var parent = transform.parent;
var parentBody = (parent != null) ? parent.GetComponentInParent<MjBody>(true) : null;
if (jointType == JointType.Free && parentBody != null)
{
jointType = JointType.None;
}
}
protected override void InitializeOnce()
{
base.InitializeOnce();
JointObject = new GameObject("Joint");
JointObject.transform.SetParent(transform);
JointObject.transform.localPosition = Vector3.zero;
AddJoint();
}
protected override IEnumerable<GameObject> GetInternalObjects() => new[] {JointObject};
protected override IEnumerable<Object> GetCreatedInternals() => new[] {JointObject};
protected override void Initialize()
{
base.Initialize();
_previousJointType = jointType;
Data = JointComponent.GetData();
}
public override void OnSelfChanged()
{
base.OnSelfChanged();
if (jointType == _previousJointType)
{
return;
}
EditorStubs.DelayIfEditMode(() =>
{
DeleteJoint();
AddJoint();
});
}
private void AddJoint()
{
var jointComponentType = jointType switch
{
JointType.Free => typeof(MjFreeJoint),
JointType.None => null,
JointType.Hinge => typeof(MjHingeJoint),
JointType.Ball => typeof(MjBallJoint),
JointType.Slide => typeof(MjSlideJoint),
_ => throw new InvalidEnumArgumentException(
nameof(jointType),
(int)jointType,
jointType.GetType())
};
if (jointComponentType == null)
{
return;
}
JointComponent = JointObject.AddComponent(jointComponentType) as MjBaseJoint;
Data = JointComponent.GetData();
_previousJointType = jointType;
}
private void DeleteJoint()
{
EditorStubs.Destroy(JointComponent);
JointComponent = null;
Data = null;
_previousJointType = JointType.None;
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (!Selection.gameObjects.Contains(gameObject)) {
// exclude children
return;
}
if (JointComponent == null || !JointComponent.isActiveAndEnabled)
{
return;
}
Gizmos.DrawWireSphere(JointComponent.transform.position, 0.5f);
Handles.Label(JointComponent.transform.position, $"{jointType.ToString()} joint");
}
#endif
}
public enum JointType
{
Free,
None,
Hinge,
Ball,
Slide,
}
#if UNITY_EDITOR
[EditorTool("Joints Tool", typeof(PrimitiveJoint))]
internal class PrimitiveJointTool : EditorTool
{
private GUIContent _iconContent;
public override GUIContent toolbarIcon => _iconContent;
private void OnEnable()
{
_iconContent = new GUIContent
{
image = DefinedIcons.ComponentJoint,
text = "Joints Tool",
tooltip = "(J) Selecting this tool shows position/rotation handles for joints",
};
}
[Shortcut("Activate Joints Tool", typeof(SceneView), KeyCode.J)]
static void PlatformToolShortcut()
{
ToolManager.SetActiveTool<PrimitiveJointTool>();
}
public override void OnToolGUI(EditorWindow window)
{
ForEachJoint((joint, internalJoint) =>
{
PositionHandle(internalJoint);
RotationHandle(internalJoint);
});
}
private void ForEachJoint(Action<PrimitiveJoint, MjBaseJoint> action)
{
foreach (var obj in targets)
{
var joint = obj as PrimitiveJoint;
if (joint == null)
{
return;
}
var internalJoint = joint.JointComponent;
if (internalJoint == null)
{
return;
}
if (!internalJoint.isActiveAndEnabled)
{
return;
}
action(joint, internalJoint);
}
}
private void PositionHandle(MjBaseJoint internalJoint)
{
using var changeScope = new EditorGUI.ChangeCheckScope();
var newPosition = Handles.PositionHandle(internalJoint.transform.position, internalJoint.transform.rotation);
if (changeScope.changed)
{
Undo.RecordObject(internalJoint.transform, "Move joint");
internalJoint.transform.position = newPosition;
}
}
private void RotationHandle(MjBaseJoint internalJoint)
{
using var changeScope = new EditorGUI.ChangeCheckScope();
var newRotation = Handles.RotationHandle(internalJoint.transform.rotation, internalJoint.transform.position);
if (changeScope.changed)
{
Undo.RecordObject(internalJoint.transform, "Rotate joint");
internalJoint.transform.rotation = newRotation;
}
}
}
#endif
}