- Home /
Is there a way to find a Vectrocity VectorLine object at runtime from a script?
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?
Answer by saldavonschwartz · May 21, 2013 at 02:59 AM
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[i] = EditorGUILayout.Vector3Field("pos", vectrocityObject.SegmentPoints[i]);
}
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.
Answer by Eric5h5 · May 20, 2013 at 09:30 PM
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.
Thanks for the answer! I'll give that a try and I'll look into the Line$$anonymous$$aker script too (I know about it from the docs, but haven't tried it yet). What I'm not 100% clear on is, so when creating a LineVector, the whole Vectrocity machinery creates a GameObject with a $$anonymous$$eshFilter and $$anonymous$$eshRenderer Components. These do persist between runs if created in edit mode. It's just the VectorLine which doesn't. Is this because LineVector is not serializable? I'm fairly new to Unity, so I'm still trying to figure out what makes an object persist or not, regardless of C#.
VectorLine is indeed not serializable. I don't know if it could be made so, since it depends on some things set up at runtime.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Initialising List array for use in a custom Editor 1 Answer
Illuminating a 3D object's edges OnMouseOver (script in c#)? 1 Answer
Flip over an object (smooth transition) 3 Answers