I’m trying to make a quick script so that I can see Vectrocity VectorLine objects in the editor regardless of being in play mode or not. The reason for this instead of the the included LineMaker is that LineMaker is intended for 3d or somewhat complex meshes to be “vectorized.” I just need to be able to set a few points in a vector line and see the shape immediately in the editor, and then be able to further modify that shape at runtime.
This means I need to be able to create a VectorLine object in edit mode and if switching to play mode, the same VectorLine should still be referenced in the vectrocity object creation script of sorts. So far I tried something along the lines of this:
using UnityEngine;
using Vectrosity;
[ExecuteInEditMode]
public class VectrocityObject : MonoBehaviour {
public float LineWidth = 3f;
public Material Material;
public Vector3[] SegmentPoints;
private VectorLine _vObject = null;
void Awake() {
if (_vObject == null) {
Vector3[] defaultPoints = new Vector3[2];
defaultPoints[0] = new Vector3(0f, 0f, 0f);
defaultPoints[1] = new Vector3(10f, 0f, 0f);
_vObject = new VectorLine(this.gameObject.name, defaultPoints, Material, LineWidth, LineType.Continuous, Joins.Weld);
_vObject.AddNormals();
_vObject.layer = this.gameObject.layer;
_vObject.vectorObject.transform.parent = transform;
}
_vObject.Draw3D();
}
void Update () {
if ((Material as Material) != null && Material != _vObject.material) {
_vObject.material = Material;
}
if ((SegmentPoints as Vector3[]) != null && SegmentPoints.Length >= 2) {
_vObject.Resize(SegmentPoints.Length);
_vObject.points3 = SegmentPoints;
_vObject.Draw3D();
}
}
}
(yes I know, my Update is super inefficient; I should be using a proper Editor class,etc… not the point here
)
The key thing here is that the private field _vObject
is set back to null every time I switch between play/edit modes. So if (_vObject == null)
always evaluates true and a new VectorLine is created every single time.
My initial thought was to just check on awake whether the LineVector object was reachable as a child, but while I can reach the child (a GameObject
), I can’t really fetch the VectorLine
out of it since it’s not really a Component
or GameObject
or any Unity type.
Any ideas as to how to solve this?
I’m not sure it’s really possible to make VectorLines in edit mode and have them persist. What I’d probably do is something like the LineMaker script, but you could use Debug.DrawLine to simulate the VectorLine in the editor, and save out the data so that it can be converted to a VectorLine at runtime.
I ended up coming with an OK solution without Debug.DrawLine which actually persists the VectorLine parameters I’m interested in and rebuild the VectorLine at either runtime or edit time, though it does use the actual VectorLine in both cases.
A VectorLine container class of sorts:
using UnityEngine;
using System.Collections.Generic;
using Vectrosity;
[ExecuteInEditMode]
public class VectrocityObject : MonoBehaviour {
public float LineWidth = 3f;
public Material Material;
public List<Vector3> SegmentPoints;
public VectorLine vectorLine;
void Awake() {
Transform oldVectorLine = transform.Find("Vector " + this.gameObject.name) as Transform;
if (oldVectorLine != null) {
DestroyImmediate(oldVectorLine.gameObject);
}
if (SegmentPoints as List<Vector3> == null) {
SegmentPoints = new List<Vector3>();
SegmentPoints.Add(Vector3.zero);
SegmentPoints.Add(Vector3.zero);
}
vectorLine = new VectorLine(this.gameObject.name, SegmentPoints.ToArray(), Material, LineWidth, LineType.Continuous, Joins.Weld);
Material = vectorLine.material;
vectorLine.AddNormals();
vectorLine.layer = this.gameObject.layer;
vectorLine.vectorObject.transform.parent = transform;
vectorLine.vectorObject.transform.localPosition = Vector3.zero;
vectorLine.Draw3D();
}
public void updateVectorLineParameters() {
if (vectorLine.points3.Length != SegmentPoints.Count) {
vectorLine.Resize(SegmentPoints.Count);
}
vectorLine.points3 = SegmentPoints.ToArray();
if (vectorLine.lineWidth != LineWidth) {
vectorLine.lineWidth = LineWidth;
}
if (vectorLine.material != Material) {
vectorLine.material = Material;
}
vectorLine.Draw3D();
}
}
And a somewhat “Friendly” custom editor for the inspector:
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(VectrocityObject))]
public class VectrocityObjectEditor : Editor {
public override void OnInspectorGUI() {
VectrocityObject vectrocityObject = (VectrocityObject)target;
vectrocityObject.LineWidth = EditorGUILayout.FloatField("Line Width", vectrocityObject.LineWidth);
vectrocityObject.Material = EditorGUILayout.ObjectField("Material", vectrocityObject.Material, typeof(Material)) as Material;
int newNumberOfSegmentPoints = vectrocityObject.SegmentPoints.Count;
newNumberOfSegmentPoints = EditorGUILayout.IntField("Number of Segments", newNumberOfSegmentPoints - 1) + 1;
for (int i = 0; i < vectrocityObject.SegmentPoints.Count; i++) {
vectrocityObject.SegmentPoints _= EditorGUILayout.Vector3Field("pos", vectrocityObject.SegmentPoints*);*_
* }*
* if (GUI.changed) {*
* if (vectrocityObject.SegmentPoints.Count < newNumberOfSegmentPoints) {*
* for (int i = 0; i < newNumberOfSegmentPoints - vectrocityObject.SegmentPoints.Count; i++) {*
* vectrocityObject.SegmentPoints.Add(Vector3.zero);*
* }*
* }*
* else if (vectrocityObject.SegmentPoints.Count > newNumberOfSegmentPoints) {*
* vectrocityObject.SegmentPoints.RemoveRange(newNumberOfSegmentPoints, vectrocityObject.SegmentPoints.Count - newNumberOfSegmentPoints);*
* }*
* vectrocityObject.updateVectorLineParameters(); *
* EditorUtility.SetDirty(vectrocityObject); *
* }*
* }*
}
Gets the job done.