Hello folks,
I come once more asking for guidance, I am currently working on extending the editor with a basic mesh processing tool to create procedural walls, but in the attempt of moving some vertices, I found out that the way I was using an Editor script was probably wrong, and all the code I wrote until then worked “by accident”.
The situation is the following: I have a GameObject with a WallsHandler component attached. The WallsHandler is used to handle (what a surprise) a particular mesh I have generated with another component. All the work done by WallsHandler is actually done by its Editor script called WallsHandlerEditor, as the script is only meant to be used in editor mode. This Editor script has several features, including the possibility of cutting a window inside the associated mesh, users can click any triangle on the mesh, and if some parameters are validated, it creates the actual window “hole” and attach a collider to its position. This collider is stored inside an array of BoxCollider. When the user hits one of those colliders, a button is displayed on top of the window, and if the button is clicked, an EditorWindow called fixtureWindow is displayed. Here’s a screen of the result:
So far so good, what is really bothering me is the actual process of editing the window. Every modification I do inside this fixtureWindowis is successfully applied to my WallsHandlerEditor and its associated mesh, but the boolean value I was using to check whether the window is open or not is reset. When this boolean is equal to true, I also draw a Handler to freely move the window along its normals (as you can see from the picture above). What I really cannot understand is why, just after any change is made (both if i move the handler or inside the fixtureWindow) the boolean control value is turned to false and the handler disappears. My code has NO WAY to reset that value, and I literally have no idea why this is happening. What makes it even more strange is that even if the value is turned to false, the EditorWindow can still edit the mesh…
This is part of WallsHandlerEditor code:
[InitializeOnLoad]
[CustomEditor(typeof(WallsHandler))]
public class WallsHandlerEditor : Editor {
public bool hasSomethingToDisplay = false;
public bool fixtureEditMode = false;
public Vector3 showCenter = new Vector3();
public int index = -1;
WallsHandler _target;
void OnEnable(){
// Debug.Log("INSERT HELP TOOLBOX FOR FIXING THE PLANE TRANSFORM");
_target = (WallsHandler)target;
}
void OnSceneGUI(){
if(fixtureEditMode){
Debug.Log("works");
Handles.color = Color.yellow;
// ONCE I GET THE RIGHT NORMALS, I CAN JUST GRAB THE WINDOW ONE IN THIS DIRECTION
Vector3 a = _target.fixtures[index].face1Window[0];
Vector3 b = _target.fixtures[index].face1Window[3];
Vector3 c = _target.fixtures[index].face2Window[2];
Vector3 side1 = b - a;
Vector3 side2 = c - a;
Vector3 perp = Vector3.Cross(side1, side2);
EditorGUI.BeginChangeCheck();
Vector3 lookTarget = Handles.Slider(showCenter, perp);
if (EditorGUI.EndChangeCheck())
{
float distn = Vector3.Distance(showCenter, lookTarget);
float movDistance = System.Convert.ToSingle(System.Math.Round(distn,4));
//NEED TO FIND THE LEFT AND RIGHT EMPTY SPACES AT FIRST
//index IS THE CURRENT fixtures INDEX
fixture curFixture = _target.fixtures[index];
int leftCompanion1 = findAdjacentFace(curFixture.face1[1], curFixture.face1[3]);
Mesh m = _target.gameObject.GetComponent<MeshFilter>().sharedMesh;
int leftCompanion2 = findCompanionIndex( leftCompanion1, m);
int rightCompanion1 = findAdjacentFace(curFixture.face1[0], curFixture.face1[2]);
int rightCompanion2 = findCompanionIndex( rightCompanion1, m);
Vector3[] side1Verts = getOrderedVertices(leftCompanion1, leftCompanion2, _target.gameObject.GetComponent<MeshFilter>().sharedMesh);
Vector3[] side2Verts = getOrderedVertices(rightCompanion1, rightCompanion2, _target.gameObject.GetComponent<MeshFilter>().sharedMesh);
//calculate difference between current and new width, check if there's enough space, and in case, apply
// CURRENT WINDOW WIDTH + OFFSET, MANAGE IN A DIFFERENT WAY THE OFFSET
Vector3 midPoint = Vector3.Lerp(curFixture.face1[0], curFixture.face1[1], 0.5f); // GETTING THE CENTRAL POINT OF THE WINDOWS. USING THE TOP ONES, IT IS IRRELEVANT
float availableLeftSpace;
float availableRightSpace;
//AVAILABLE SPACE IS CALCULATED ON ONLY ONE SIDE, AS IT IS ALWAYS GRANTED TO BE EVEN
if(side1Verts[0] == curFixture.face1[1]){
float distance = Vector3.Distance(curFixture.face1[1], side1Verts[1]);
availableLeftSpace = System.Convert.ToSingle(System.Math.Round(distance,4));
} else {
float distance = Vector3.Distance(curFixture.face1[1], side1Verts[0]);
availableLeftSpace = System.Convert.ToSingle(System.Math.Round(distance,4));
}
if(side2Verts[1] == curFixture.face1[0]){
float distance = Vector3.Distance(curFixture.face1[0], side2Verts[0]);
availableRightSpace = System.Convert.ToSingle(System.Math.Round(distance,4));
} else {
float distance = Vector3.Distance(curFixture.face1[0], side2Verts[1]);
availableRightSpace = System.Convert.ToSingle(System.Math.Round(distance,4));
}
//TRUE IS MOVING LEFT, FALSE IS MOVING RIGHT
bool moveDirection = true;
if(moveDirection){
if(availableLeftSpace-movDistance >= 0.2f){
DestroyImmediate(_target.gameObject.GetComponent<MeshCollider>());
Mesh locMesh = _target.transform.GetComponent<MeshFilter>().sharedMesh;
Vector3[] oldVerts = locMesh.vertices;
Vector3[] newVerts = new Vector3[oldVerts.Length];
//I COULD RETRIEVE THE INDEXES AT THE BEGINNING AND NOT SEARCH FOR THEM EVERY TIME
// ALSO, THERE IS NO POINT IN MOVING TOWARDS SIDEVERTS,
// I COULD SIMPLY MOVE AWAY OR CLSOER TO THE OPPOSITE WINDOW VERTEX
for(int i = 0; i < oldVerts.Length;i++){
// EXTERNAL VERTS LEFT SIDE
if(oldVerts[i] == curFixture.face1[1]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1[0], -movDistance);
} else if(oldVerts[i] == curFixture.face1[3]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1[2], -movDistance);
} else if(oldVerts[i] == curFixture.face2[0]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2[1], -movDistance);
} else if(oldVerts[i] == curFixture.face2[2]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2[3], -movDistance);
}
// INTERNAL VERTS LEFT SIDE
else if(oldVerts[i] == curFixture.face1Window[1]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1Window[3], -movDistance);
} else if(oldVerts[i] == curFixture.face1Window[2]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1Window[0], -movDistance);
} else if(oldVerts[i] == curFixture.face2Window[0]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2Window[2], -movDistance);
} else if(oldVerts[i] == curFixture.face2Window[3]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2Window[1], -movDistance);
}
// EXTERNAL VERTS RIGHT SIDE
else if(oldVerts[i] == curFixture.face1[0]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1[1], -movDistance);
} else if(oldVerts[i] == curFixture.face1[2]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1[3], -movDistance);
} else if(oldVerts[i] == curFixture.face2[1]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2[0], -movDistance);
} else if(oldVerts[i] == curFixture.face2[3]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2[2], -movDistance);
}
// INTERNAL VERTS RIGHT SIDE
else if(oldVerts[i] == curFixture.face1Window[0]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1Window[2], -movDistance);
} else if(oldVerts[i] == curFixture.face1Window[3]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face1Window[1], -movDistance);
} else if(oldVerts[i] == curFixture.face2Window[1]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2Window[3], -movDistance);
} else if(oldVerts[i] == curFixture.face2Window[2]){
newVerts[i] = Vector3.MoveTowards(oldVerts[i], curFixture.face2Window[0], -movDistance);
}
//IT'S A COMMON VERTEX
else {
newVerts[i] = oldVerts[i];
}
}
_target.transform.GetComponent<MeshFilter>().sharedMesh.vertices = newVerts;
_target.gameObject.AddComponent<MeshCollider>();
Debug.Log("here");
}
}
}
}
}
and this is the fixtureWindow code:
using UnityEngine;
using UnityEditor;
public class fixtureWindow : EditorWindow {
WallsHandlerEditor editor;
fixture currentFixture;
public float width;
public float height;
public float heightfromGround;
public float borderDistance = 0.2f; //MINIMUM DISTANCE OF NODES FROM THE CANVAS
public void Init(WallsHandlerEditor e, fixture fixt){
editor = e;
currentFixture = fixt;
height = fixt.face1Window[2].y - fixt.face1Window[1].y;
heightfromGround = currentFixture.face1Window[1].y;
width = Vector3.Distance(fixt.face1Window[1], fixt.face1Window[3]);
}
void OnDestroy(){
Debug.Log("Destroy");
editor.exitEditMode();
}
void OnGUI(){
EditorGUI.BeginChangeCheck();
width = EditorGUILayout.FloatField("Width", width);
if(EditorGUI.EndChangeCheck()){
editor.checkNewWidth(width);
}
EditorGUI.BeginChangeCheck();
height = EditorGUILayout.FloatField("Height", height);
if(EditorGUI.EndChangeCheck()){
editor.checkNewWindowHeight(height, borderDistance);
heightfromGround = currentFixture.face1Window[1].y;
this.Repaint();
}
//CHECKING WHETHER THE HEIGHT FROM GROUND WAS CHANGED OR NOT
EditorGUI.BeginChangeCheck();
heightfromGround = EditorGUILayout.FloatField("Height from Ground", heightfromGround);
if (EditorGUI.EndChangeCheck()){
if(heightfromGround < borderDistance){
heightfromGround = borderDistance;
}
float maxHeight = currentFixture.face1[0].y - borderDistance - (currentFixture.face1Window[0].y - currentFixture.face1Window[1].y);
if(heightfromGround > (maxHeight)){
heightfromGround = (maxHeight);
}
editor.checkNewHeightFromGround(heightfromGround);
}
if (GUILayout.Button("Delete window")){
Debug.Log("TODO");
}
}
}
Ignoring the heavily not optimized code, what could be possibly causing the problem? I tried to debug OnEnable and it is not called, what is changing that value? Why fixtureWindow keeps track of the editor but the editor bool control is reset?