public override void OnInspectorGUI() { GUI.changed = false; GravityEngine gravityEngine = (GravityEngine)target; float massScale = gravityEngine.massScale; float timeScale = gravityEngine.timeScale; float lengthScale = gravityEngine.lengthScale; float physToWorldFactor = gravityEngine.physToWorldFactor; bool optimizeMassless = gravityEngine.optimizeMassless; bool detectNbodies = gravityEngine.detectNbodies; bool evolveAtStart = gravityEngine.evolveAtStart; bool scaling = gravityEngine.editorShowScale; bool showAdvanced = gravityEngine.editorShowAdvanced; bool showTrajectory = gravityEngine.editorShowTrajectory; bool cmFoldout = gravityEngine.editorCMfoldout; bool mapToScene = gravityEngine.mapToScene; bool trajectoryPrediction = gravityEngine.trajectoryPrediction; float trajectoryTime = gravityEngine.trajectoryTime; GameObject trajCanvas = gravityEngine.trajectoryCanvas; GameObject markerParent = gravityEngine.markerParent; float computeFactor = gravityEngine.trajectoryComputeFactor; int stepsPerFrame = gravityEngine.stepsPerFrame; int particleStepsPerFrame = gravityEngine.particleStepsPerFrame; GravityEngine.Algorithm algorithm = GravityEngine.Algorithm.LEAPFROG; ForceChooser.Forces force = ForceChooser.Forces.Gravity; GravityScaler.Units units = GravityScaler.Units.DIMENSIONLESS; EditorGUIUtility.labelWidth = 200; mapToScene = EditorGUILayout.Toggle(new GUIContent("Use Transform to Reposition", mapTip), mapToScene); EditorGUIUtility.labelWidth = 150; // SCALING scaling = EditorGUILayout.Foldout(scaling, "Scaling"); if (scaling) { units = (GravityScaler.Units)EditorGUILayout.EnumPopup(new GUIContent("Units", unitsTip), gravityEngine.units); EditorGUILayout.LabelField("Scaling values change when <ENTER> ispressed."); switch (units) { case GravityScaler.Units.DIMENSIONLESS: // only have mass scale in DL case EditorGUILayout.LabelField("Use mass scale to control scene speed."); EditorGUILayout.LabelField("(More massive = faster)"); massScale = EditorGUILayout.DelayedFloatField(new GUIContent("Mass Scale", mTip), gravityEngine.massScale); break; case GravityScaler.Units.SI: // no mass scale is controlled by time exclusivly EditorGUILayout.LabelField("m/kg/sec."); // meters per Unity unit in the case of meters lengthScale = EditorGUILayout.DelayedFloatField(new GUIContent("Unity unit per m", timeTip), gravityEngine.lengthScale); timeScale = EditorGUILayout.DelayedFloatField(new GUIContent("Game sec. per sec.", timeTip), gravityEngine.timeScale); break; case GravityScaler.Units.ORBITAL: EditorGUILayout.LabelField("km/1E24 kg/hr"); // Express in km per Unity unit km/U lengthScale = EditorGUILayout.DelayedFloatField(new GUIContent("Unity unit per km", timeTip), gravityEngine.lengthScale); timeScale = EditorGUILayout.DelayedFloatField(new GUIContent("Game sec. per hour", timeTip), gravityEngine.timeScale); break; case GravityScaler.Units.SOLAR: EditorGUILayout.LabelField("AU/1E24 kg/year"); lengthScale = EditorGUILayout.DelayedFloatField(new GUIContent("Unity unit per AU", timeTip), gravityEngine.lengthScale); timeScale = EditorGUILayout.DelayedFloatField(new GUIContent("Game Sec per year", timeTip), gravityEngine.timeScale); break; } } // TRAJECTORY PREDICTION showTrajectory = EditorGUILayout.Foldout(showTrajectory, "Trajectory Prediction"); if (showTrajectory) { trajectoryPrediction = EditorGUILayout.Toggle(new GUIContent("Trajectory Prediction", trajTip), trajectoryPrediction); trajectoryTime = EditorGUILayout.FloatField(new GUIContent("Trajectory Time", trajTimeTip), trajectoryTime); computeFactor = EditorGUILayout.FloatField(new GUIContent("Re-computes per frame)", trajResetTip), computeFactor); trajCanvas = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Canvas for Text (optional)", trajCanvasTip), trajCanvas, typeof(GameObject), true); markerParent = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Time Marker Parent (optional)", markerTip), markerParent, typeof(GameObject), true); } // ADVANCED showAdvanced = EditorGUILayout.Foldout(showAdvanced, "Advanced"); if (showAdvanced) { algorithm = (GravityEngine.Algorithm)EditorGUILayout.EnumPopup(new GUIContent("Algorithm", algoTip), gravityEngine.algorithm); // Force selection is tangled with choice of integrator and scale - so needs to be here force = (ForceChooser.Forces)EditorGUILayout.EnumPopup(new GUIContent("Force", forceTip), gravityEngine.force); if (force == ForceChooser.Forces.Custom) { IForceDelegate force_delegate = gravityEngine.GetComponent <IForceDelegate>(); if (force_delegate == null) { EditorGUILayout.LabelField(" Attach a Force Delegate to this object.", EditorStyles.boldLabel); } else { EditorGUILayout.LabelField(" Force delegate: " + force_delegate.GetType()); } } if (force != ForceChooser.Forces.Gravity) { EditorGUILayout.LabelField(" Note: Orbit predictors assume Newtonian gravity"); EditorGUILayout.LabelField(" They are not accurate for other forces."); } optimizeMassless = EditorGUILayout.Toggle(new GUIContent("Optimize Massless Bodies", mlessTip), gravityEngine.optimizeMassless); detectNbodies = EditorGUILayout.Toggle(new GUIContent("Automatically Add NBody objects", autoAddTip), gravityEngine.detectNbodies); evolveAtStart = EditorGUILayout.Toggle(new GUIContent("Evolve at Start", autoStartTip), gravityEngine.evolveAtStart); physToWorldFactor = EditorGUILayout.FloatField(new GUIContent("Physics to World Scale", phyWTip), gravityEngine.physToWorldFactor); EditorGUILayout.LabelField("Steps per frame:"); stepsPerFrame = EditorGUILayout.IntField(new GUIContent(" Massive Bodies", stepTip), stepsPerFrame); particleStepsPerFrame = EditorGUILayout.IntField(new GUIContent(" Particles", pstepTip), particleStepsPerFrame); } // Switch bodies list on/off based on option if (!gravityEngine.detectNbodies) { // use native Inspector look & feel for bodies object EditorGUILayout.LabelField("Control Nbody in following gameObjects (and children)", EditorStyles.boldLabel); SerializedProperty bodiesProp = serializedObject.FindProperty("bodies"); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(bodiesProp, true); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); } } else { EditorGUILayout.LabelField("NBody objects will be detected automatically", EditorStyles.boldLabel); } // Show the CM and the velocity of the CM cmFoldout = EditorGUILayout.Foldout(cmFoldout, "Center of Mass Info"); if (cmFoldout) { EditorGUILayout.LabelField("Center of Mass:" + gravityEngine.GetWorldCenterOfMass()); EditorGUILayout.LabelField("CM Velocity:" + gravityEngine.GetWorldCenterOfMassVelocity()); } // Checking the Event type lets us update after Undo and Redo commands. // A redo updates _lengthScale but does not run the setter if (Event.current.type == EventType.ExecuteCommand && Event.current.commandName == "UndoRedoPerformed") { // explicitly re-set so setter code will run. gravityEngine.lengthScale = lengthScale; } if (GUI.changed) { Undo.RecordObject(gravityEngine, "GE Change"); gravityEngine.mapToScene = mapToScene; gravityEngine.timeScale = timeScale; gravityEngine.massScale = massScale; // This runs a setter in GE that will do a rescale of the scene if necessary gravityEngine.lengthScale = lengthScale; gravityEngine.units = units; gravityEngine.physToWorldFactor = physToWorldFactor; gravityEngine.optimizeMassless = optimizeMassless; gravityEngine.detectNbodies = detectNbodies; gravityEngine.editorShowTrajectory = showTrajectory; gravityEngine.trajectoryPrediction = trajectoryPrediction; gravityEngine.trajectoryTime = trajectoryTime; gravityEngine.trajectoryCanvas = trajCanvas; gravityEngine.markerParent = markerParent; gravityEngine.trajectoryComputeFactor = computeFactor; gravityEngine.algorithm = algorithm; gravityEngine.force = force; gravityEngine.evolveAtStart = evolveAtStart; gravityEngine.editorShowScale = scaling; gravityEngine.editorShowAdvanced = showAdvanced; gravityEngine.editorCMfoldout = cmFoldout; gravityEngine.stepsPerFrame = stepsPerFrame; gravityEngine.particleStepsPerFrame = particleStepsPerFrame; EditorUtility.SetDirty(gravityEngine); } }