// Method called to serialize a Spline Settings object public void GetObjectData(System.Object obj, SerializationInfo info, StreamingContext context) { SplineSettings settings = (SplineSettings)obj; info.AddValue("name", settings.name); }
//Generates a mesh along a spline. The mesh is defined in the settings at index i private void GenerateMesh(Transform splineParent, SplineSettings settings, int spline, int i) { GeneratedMesh meshSettings = settings.generated[i]; string name = meshSettings.name; if (name.Length == 0) { name = string.Concat("Generated Mesh ", i.ToString("D2")); } name = string.Concat(i.ToString("D2"), "-", name); Transform newGenerated = splineParent.Find(name); //Create a new GameObject if there is none in the current scene if (newGenerated == null) { newGenerated = new GameObject().transform; newGenerated.parent = splineParent; newGenerated.localPosition = Vector3.zero; newGenerated.localRotation = Quaternion.identity; newGenerated.localScale = Vector3.one; newGenerated.name = name; newGenerated.gameObject.AddComponent <MeshFilter>(); newGenerated.gameObject.AddComponent <MeshRenderer>(); } //Update mesh and material newGenerated.GetComponent <MeshFilter>().mesh = meshSettings.Generate(splines[spline]); newGenerated.GetComponent <MeshRenderer>().material = meshSettings.material; }
//Initialize from file public static void Init(SplineSettings _settings) { SplineSettingsEditorWindow window = (SplineSettingsEditorWindow)EditorWindow.GetWindow(typeof(SplineSettingsEditorWindow)); window.minSize = new Vector2(600, 300); window.viewIndex = -1; settings = _settings; }
public void SetSettings(SplineSettings _settings) { settings = _settings; assetIsActive = new bool[settings.generated.Count + settings.placers.Count]; for (int i = 0; i < assetIsActive.Length; i++) { assetIsActive[i] = true; } }
//Open a new SplineSettings asset private void OpenSplineSettings() { string absPath = EditorUtility.OpenFilePanel("Select Spline Settings", "Assets/", "asset"); if (absPath.StartsWith(Application.dataPath)) { string relPath = absPath.Substring(Application.dataPath.Length - "Assets".Length); settings = AssetDatabase.LoadAssetAtPath(relPath, typeof(SplineSettings)) as SplineSettings; } }
// inspector for SplineSettings only shows a list of assetnames public override void OnInspectorGUI() { SplineSettings settings = target as SplineSettings; string[] assets = settings.GetAssetNames(); foreach (string asset in assets) { GUILayout.Label(asset); } }
private void DrawSplineInspector() { if (activeSpline >= 0) { GUILayout.Label("Spline:"); EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); string name = EditorGUILayout.TextField("Name", component.GetSplineName(activeSpline)); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(component, "Change spline name"); EditorUtility.SetDirty(component); component.SetSplineName(activeSpline, name); } EditorGUI.BeginChangeCheck(); SplineSettings settings = (SplineSettings)EditorGUILayout.ObjectField("Settings", component.GetSplineSettings(activeSpline), typeof(SplineSettings), true); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(component, "Change spline settings"); EditorUtility.SetDirty(component); component.SetSplineSettings(activeSpline, settings); } EditorGUI.indentLevel--; EditorGUILayout.Space(); if (settings != null) { GUILayout.Label("Active assets:"); EditorGUI.indentLevel++; bool[] ActiveAssets = component.GetActiveAssets(activeSpline); EditorGUI.BeginChangeCheck(); for (int i = 0; i < settings.generated.Count; i++) { ActiveAssets[i] = EditorGUILayout.Toggle(settings.generated[i].name, ActiveAssets[i]); } for (int i = 0; i < settings.placers.Count; i++) { ActiveAssets[i + settings.generated.Count] = EditorGUILayout.Toggle(settings.placers[i].name, ActiveAssets[i + settings.generated.Count]); } if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(component, "Change active assets"); EditorUtility.SetDirty(component); component.SetActiveAssets(activeSpline, ActiveAssets); ResetGeneratedContent(); } EditorGUI.indentLevel--; EditorGUILayout.Space(); } } }
//Constructor using position and index in component public Spline(Vector3 position, int index) { points = new List <ControlPoint> { new ControlPoint(position, Vector3.forward), new ControlPoint(position + Vector3.forward, Vector3.forward) }; ResetArcLengthTable(); name = string.Concat("Spline_", index.ToString("D2")); settings = null; assetIsActive = null; }
private static int tableSize = 100; //Precision value for the table //Constructor public Spline() { points = new List <ControlPoint> { new ControlPoint(Vector3.forward, Vector3.forward), new ControlPoint(Vector3.forward * 2, Vector3.forward) }; ResetArcLengthTable(); name = string.Concat("Spline"); settings = null; assetIsActive = null; }
//Update each spline that uses a given SplineSettings public void UpdateSpline(SplineSettings settings) { for (int i = 0; i < splineCount; i++) { if (splines[i].GetSettings() == settings) { SetSplineSettings(i, settings); UpdateSpline(i); } } }
public static bool OnOpenAsset(int instanceID, int line) { SplineSettings settings = Selection.activeObject as SplineSettings; if (settings != null) { SplineSettingsEditorWindow.Init(settings); // Open editor window return(true); //catch open file } return(false); // let unity open the file }
// Method called to deserialize a Spline Settings object public System.Object SetObjectData(System.Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { SplineSettings settings = (SplineSettings)obj; string name = (string)info.GetString("name"); string[] assets = AssetDatabase.FindAssets(string.Concat(name, " t:SplineSettings")); if (assets.Length > 0) { settings = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(assets[0]), typeof(SplineSettings)) as SplineSettings; obj = settings; } return(obj); // Formatters ignore this return value //Seems to have been fixed! }
//Generates all procedural obejcts for a spline private void ApplySettings(int index) { Transform splineParent = transform.Find(GetSplineName(index)); SplineSettings settings = GetSplineSettings(index); if (splineParent == null) { splineParent = AddGeneratedBranch(index); } if (settings.assetCount < splineParent.childCount) { foreach (Transform child in splineParent) { string childName = child.name.Split('-')[1]; string[] assetNames = settings.GetAssetNames(); bool activeAsset = false; for (int i = 0; i < assetNames.Length; i++) { if (childName == assetNames[i]) { activeAsset = true; } } if (!activeAsset) { DestroyImmediate(child.gameObject); Resources.UnloadUnusedAssets(); } } } for (int i = 0; i < settings.generated.Count; i++) { if (splines[index].assetIsActive[i]) { GenerateMesh(splineParent, settings, index, i); } } for (int i = 0; i < settings.placers.Count; i++) { if (splines[index].assetIsActive[settings.generated.Count + i] && settings.placers[i].objectReference != null) { PlaceObjects(splineParent, settings, index, i); } } }
private void OnGUI() { EditorGUI.BeginChangeCheck(); EditorGUILayout.Space(); //Draw top bar with name and open & close buttons GUILayout.BeginHorizontal(); string name = "No asset selected"; if (settings != null) { name = settings.name; } GUILayout.Label(name); if (GUILayout.Button("Open", GUILayout.Width(100f))) { OpenSplineSettings(); } if (GUILayout.Button("Close", GUILayout.Width(100f))) { settings = null; } GUILayout.EndHorizontal(); EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); //Draw editor if a settings asset is selected if (settings != null) { GUILayout.BeginHorizontal(); //Left panel scrollposition = EditorGUILayout.BeginScrollView(scrollposition, false, true, GUILayout.Width(position.width / 2), GUILayout.Height(position.height - 30)); string[] names = settings.GetAssetNames(); //Generated meshes list GUILayout.Label("Generated meshes:"); for (int i = 0; i < settings.generated.Count; i++) { string assetName = ""; try { assetName = names[i]; } catch (IndexOutOfRangeException) { //Cloning a asset can take longer then one GUI frame. In this case the amount of names given by GetAssetNames is less then the amount of assets. //This problem fixes itselve in the next frame. } EditorGUILayout.BeginHorizontal(); GUILayout.Label(assetName, GUILayout.Width(position.width / 2 - 215)); if (GUILayout.Button("Edit", GUILayout.Width(60))) { viewIndex = i; GUIUtility.keyboardControl = 0; } if (GUILayout.Button("Clone", GUILayout.Width(60))) { settings.CloneGeneratedMesh(i); viewIndex = i + 1; GUIUtility.keyboardControl = 0; } if (GUILayout.Button("Remove", GUILayout.Width(60))) { settings.generated.RemoveAt(i); viewIndex = -1; GUIUtility.keyboardControl = 0; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.BeginHorizontal(); GUILayout.Label("", GUILayout.Width(position.width / 2 - 87)); if (GUILayout.Button("Add", GUILayout.Width(60))) { settings.AddGeneratedMesh(); viewIndex = settings.generated.Count - 1; GUIUtility.keyboardControl = 0; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); //Object placers list GUILayout.Label("Object Placers:"); for (int i = settings.generated.Count; i < names.Length; i++) { EditorGUILayout.BeginHorizontal(); GUILayout.Label(names[i], GUILayout.Width(position.width / 2 - 215)); if (GUILayout.Button("Edit", GUILayout.Width(60))) { viewIndex = i; GUIUtility.keyboardControl = 0; } if (GUILayout.Button("Clone", GUILayout.Width(60))) { settings.CloneObjectPlacer(i - settings.generated.Count); viewIndex = i + 1; GUIUtility.keyboardControl = 0; } if (GUILayout.Button("Remove", GUILayout.Width(60))) { settings.placers.RemoveAt(i - settings.generated.Count); viewIndex = -1; GUIUtility.keyboardControl = 0; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.BeginHorizontal(); GUILayout.Label("", GUILayout.Width(position.width / 2 - 87)); if (GUILayout.Button("Add", GUILayout.Width(60))) { settings.AddObjectPlacer(); viewIndex = settings.assetCount - 1; GUIUtility.keyboardControl = 0; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.EndScrollView(); //Right panel GUILayout.BeginVertical(); if (viewIndex >= 0 && viewIndex < settings.assetCount) { if (viewIndex < settings.generated.Count) { DrawGeneratedMeshSettings(settings.generated[viewIndex]); } else { DrawObjectPlacerSettings(settings.placers[viewIndex - settings.generated.Count]); } } GUILayout.EndVertical(); GUILayout.EndHorizontal(); } if (EditorGUI.EndChangeCheck()) { if (settings) { EditorUtility.SetDirty(settings); SplineComponent[] components = FindObjectsOfType <SplineComponent>(); foreach (SplineComponent component in components) { component.UpdateSpline(settings); } } } }
//Places objects along a spline. The object is defined in the settings at index i private void PlaceObjects(Transform splineParent, SplineSettings settings, int spline, int i) { ObjectPlacer objectSettings = settings.placers[i]; string name = objectSettings.name; if (name.Length == 0) { name = objectSettings.objectReference.name; } name = string.Concat((settings.generated.Count + i).ToString("D2"), "-", name); //Get branch transform for current object, or create one if it does not exist Transform objectParent = null; foreach (Transform parent in splineParent) { if (parent.name == name) { objectParent = parent; } } if (objectParent == null) { objectParent = new GameObject().transform; objectParent.parent = splineParent; objectParent.localPosition = Vector3.zero; objectParent.localRotation = Quaternion.identity; objectParent.localScale = Vector3.one; objectParent.name = name; } int child = 0; Vector3 lastPosition = Vector3.one * float.MaxValue; //Loop along the length of the spline for (float j = objectSettings.offset; j < splines[spline].GetArcLength() - objectSettings.offset; j += objectSettings.distance) { //Get the transform of the child, or create one if it does not exist Transform newObject; if (objectParent.childCount > child) { newObject = objectParent.GetChild(child); } else { newObject = (Transform)PrefabUtility.InstantiatePrefab(objectSettings.objectReference); newObject.parent = objectParent; newObject.gameObject.hideFlags = HideFlags.DontSaveInEditor; } //Calculate the position of this child Vector3 forward = splines[spline].GetDirection(j).normalized; Vector3 up = splines[spline].GetUp(j).normalized; Vector3 right = Vector3.Cross(forward, up).normalized; Vector3 position = splines[spline].GetPoint(j) + right * objectSettings.position.x + up * objectSettings.position.y; //When type is set to global distance, the position needs to be recalculated if (objectSettings.type == offsetType.globalDistance) { if (lastPosition.x < float.MaxValue) { //To fix the distance, it gets devided by the distance it had using the arcDistance calculation float realDistance = (lastPosition - position).magnitude; j += objectSettings.distance / realDistance; forward = splines[spline].GetDirection(j).normalized; up = splines[spline].GetUp(j).normalized; right = Vector3.Cross(forward, up).normalized; position = splines[spline].GetPoint(j) + right * objectSettings.position.x + up * objectSettings.position.y; } lastPosition = position; } //Calculate rotation Vector3 splineRotation = Spline.GetEulerAngles(up, forward); if (!objectSettings.constraints[0]) { splineRotation.x = 0; } if (!objectSettings.constraints[1]) { splineRotation.y = 0; } if (!objectSettings.constraints[2]) { splineRotation.z = 0; } Quaternion rotation = Quaternion.Euler(splineRotation) * Quaternion.Euler(objectSettings.rotation); //Calculate scale Vector3 scale = objectSettings.objectReference.localScale; scale.Scale(objectSettings.scale); newObject.position = transform.TransformPoint(position); newObject.rotation = transform.rotation * rotation; newObject.localScale = scale; child++; } // Loop through all remaining children and delete them if they are no longer on the spline while (objectParent.childCount > child) { DestroyImmediate(objectParent.GetChild(child).gameObject); } }
public void SetSplineSettings(int index, SplineSettings settings) { splines[index].SetSettings(settings); UpdateSpline(index); }