Custom editor help

I am creating a tool that will act as a sort of height map editor that can be used to create terrain fast for my game, I am currently creating each cell by hand in blender and between having to create the terrain and load each surrounding cell to match the seems I am just not getting very far at all.

I was trying to create a custom editor tool that would display dots or vertices at intervals of 1 creating an infinite grid, each vertices will be connected with visible lines both in rows and columns and each square on the grid will be split into triangles. each triangle needs to be able to display a number. each number will represent the height of the vertices so the position on the grid and the number displayed on the triangle will make up a 3d plot point, which needs to be able to be saved on a json file or in a similar manner, and there needs to be a generate button that generates a 3d terrain using this grid system.

I need to know first if this is possible and if it is I need help getting started.

I changed what I want since what I wanted I think is impossible to make work correctly. So here is what I got so far

I need help getting cells to spawn when they are supposed to, when you click new a window should pop up with 3 boxes asking for the cells name, x and y coordinates. I also want a shortcut set for creating a new cell. I want an error message to display if a cell already exists that way I cannot over lap. I want the default name for each of the cells to be wilderness and I want the x and y boxes to have the lowest positive number available inside them by default, I need help doing this as I have little knowledge of UI’s.

I also need help ironing out the syntax errors.

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class CellWindow : EditorWindow
{
    [MenuItem("Heightmap Creation/Editor")]
    public static void ToolBar()
    {
        CellWindow cellWindow = (CellWindow)GetWindow(typeof(CellWindow));
        cellWindow.Show();

        if (GUILayout.Button("Spawn Cell"))
        {
            Cell.add("cell",0,0);
        }
    }
}

public class Cell : MonoBehaviour
{
    Mesh cell = new Mesh();
    public string cellName = "cell";
    int cellSize = 256;

    public int xPosition = 0;
    public int yPosition = 0;

    List<Vector3> vertices = new List<Vector3>();

    public void add(cellName,xPosition,yPosition)
    {
        for(int x = 0; x <= cellSize; x++)
        {
            for (int z = 0; z <= cellSize; z++)
            {
                Vector3 point = new Vector3(x, 0, z);
                vertices.Add(point);
            }
        }

        cell.name = cellName + " (" + xPosition + (", ") + yPosition + (")");
        cell.SetVertices(vertices);
    }
}

If you have a grid of points to make triangles, you cant “display a number to represent the terrain height”, becuase the triangle can have 3 different heights at its vertex, so im not sure what you want for that
Plus, you’ve added a second post with more details which I haven’t worked into my code

Heres a basic interface that overlays a grid and lets you adjust heights with mouse clicks
The grid isn’t infinate, you’d probably have to use a dictionary to track what cells are modified and assume the rest are blank

//Assets/Editor/MapEdit.cs
using UnityEngine;
using UnityEditor;
using System.Collections;

public class MapEdit : EditorWindow {

    #region Init

    [MenuItem( "EDITORS/Tile Editor" )]
    static void Init () {
        MapEdit window = (MapEdit) EditorWindow.GetWindow( typeof( MapEdit ) );
        window.Show();
        window.position = new Rect( 20, 80, 300, 150 );
    }

    void OnFocus () {
        SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
        SceneView.onSceneGUIDelegate += this.OnSceneGUI;
    }

    void OnDestroy () {
        SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
    }

    #endregion

    #region Variables

    int[,] _heights;
    int[,] heights {
        get {
            if ( _heights == null ) {
                _heights = new int[sizeX, sizeZ];
            }
            return _heights;
        }
        set {
            _heights = value;
        }
    }

    float cellSize = 1f, heightStep = 0.25f;

    int sizeX = 21, sizeZ = 21;

    int drawSize;

    Plane worldPlane = new Plane( Vector3.up, Vector3.zero );

    float rayDistance;

    int mouseWorldPosXUnclamped, mouseWorldPosZUnclamped, mouseWorldPosX, mouseWorldPosZ;

    #endregion

    #region Scene Controls

    void OnSceneGUI ( SceneView sceneView ) {
        Event e = Event.current;
        Ray mouseRay = HandleUtility.GUIPointToWorldRay( e.mousePosition );

        if ( ScreenContainsMouse( e.mousePosition ) && worldPlane.GetSide( Camera.current.transform.position ) ) {
            if ( worldPlane.Raycast( mouseRay, out rayDistance ) ) {
                Vector3 mousePos = mouseRay.GetPoint( rayDistance );
                mouseWorldPosXUnclamped = Mathf.RoundToInt( mousePos.x / cellSize );
                mouseWorldPosZUnclamped = Mathf.RoundToInt( mousePos.z / cellSize );
                mouseWorldPosX = Mathf.Clamp( mouseWorldPosXUnclamped, 0, heights.GetLength( 0 ) - 1 );
                mouseWorldPosZ = Mathf.Clamp( mouseWorldPosZUnclamped, 0, heights.GetLength( 1 ) - 1 );

                for ( int x = mouseWorldPosX - drawSize; x < mouseWorldPosX + drawSize + 1; x++ ) {
                    for ( int z = mouseWorldPosZ - drawSize; z < mouseWorldPosZ + drawSize + 1; z++ ) {
                        if ( x < 0 || x > heights.GetLength( 0 ) - 1 || z < 0 || z > heights.GetLength( 1 ) - 1 )
                            continue;

                        Vector3 gridPos = new Vector3( x * cellSize, 0, z * cellSize );
                        Vector3 terrainPos = new Vector3( x * cellSize, heights[x, z] * heightStep + 1, z * cellSize );

                        Handles.Label( gridPos, "" + heights[x, z] );

                        Handles.color = Color.red;
                        Handles.DrawLine( gridPos, terrainPos );
                        Handles.color = Color.black;
                        if ( x < heights.GetLength( 0 ) - 1 && z < heights.GetLength( 1 ) - 1 && x < mouseWorldPosX + drawSize && z < mouseWorldPosZ + drawSize ) {
                            Vector3 terrainPosPlusX = new Vector3( ( x + 1 ) * cellSize, heights[x + 1, z] * heightStep + 1, z * cellSize );
                            Vector3 terrainPosPlusZ = new Vector3( x * cellSize, heights[x, z + 1] * heightStep + 1, ( z + 1 ) * cellSize );
                            Vector3 terrainPosPlusXZ = new Vector3( ( x + 1 ) * cellSize, heights[x + 1, z + 1] * heightStep + 1, ( z + 1 ) * cellSize );

                            Handles.DrawLine( terrainPos, terrainPosPlusX );
                            Handles.DrawLine( terrainPosPlusX, terrainPosPlusXZ );
                            Handles.DrawLine( terrainPosPlusXZ, terrainPosPlusZ );
                            Handles.DrawLine( terrainPosPlusZ, terrainPos );
                        }
                    }
                }

                if ( GridContainsMouse() ) {
                    Handles.color = Color.red;
                    Handles.DrawWireDisc( new Vector3( mouseWorldPosX * cellSize, 0, mouseWorldPosZ * cellSize ), Vector3.up, cellSize * 0.75f );
                    Handles.color = Color.green;
                    Handles.DrawWireDisc( new Vector3( mouseWorldPosX * cellSize, heights[mouseWorldPosX, mouseWorldPosZ] * heightStep, mouseWorldPosZ * cellSize ), Vector3.up, cellSize * 0.75f );
                }

                if ( e.type == EventType.MouseDown && e.button == 0 && GridContainsMouse() ) {
                    heights[mouseWorldPosX, mouseWorldPosZ]++;
                }

                if ( e.type == EventType.MouseDown && e.button == 1 && GridContainsMouse() ) {
                    heights[mouseWorldPosX, mouseWorldPosZ]--;
                }
            }
        }

        sceneView.Repaint();
    }

    #endregion

    #region GUI Controls

    void OnGUI () {
        cellSize = EditorGUILayout.FloatField( "Cell Size", cellSize );
        heightStep = EditorGUILayout.FloatField( "Cell Height Step", heightStep );
        sizeX = Mathf.Max( 1, EditorGUILayout.IntField( "Size X", sizeX ) );
        sizeZ = Mathf.Max( 1, EditorGUILayout.IntField( "Size Z", sizeZ ) );
        drawSize = Mathf.Clamp( EditorGUILayout.IntField( "Number Drawn", drawSize ), 1, Mathf.Min( sizeX, sizeZ ) / 2 );
    }

    #endregion

    #region Helper Functions

    bool ScreenContainsMouse ( Vector3 v ) {
        return v.x > 0 && v.x < Screen.width && v.y > 0 && v.y < Screen.height;
    }

    bool GridContainsMouse () {
        return mouseWorldPosXUnclamped > -1 && mouseWorldPosXUnclamped < heights.GetLength( 0 ) && mouseWorldPosZUnclamped > -1 && mouseWorldPosZUnclamped < heights.GetLength( 1 );
    }

    #endregion

}

here is a simple script to display 4 buttons.

using UnityEngine;
using UnityEditor;
public class MyWindow : EditorWindow
{

    // Add menu named "My Window" to the Window menu
    [MenuItem("Window/My Window")]
    static void Init()
    {
        MyWindow window = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow));
        window.Show();
    }

    void OnGUI()
    {
        GUILayout.Label("4 Buttons");
        GUILayout.Space(20);

        GUI.backgroundColor = Color.red;
        if (GUILayout.Button("Red Btn", GUILayout.Width(250), GUILayout.Height(30)))
        {

        }
        EditorGUILayout.BeginHorizontal();
        GUI.backgroundColor = Color.yellow;
        if (GUILayout.Button("Yellow Btn", GUILayout.Width(100), GUILayout.Height(30)))
        {

        }
        GUILayout.Space(46);
        GUI.backgroundColor = Color.green;
        if (GUILayout.Button("Green Btn", GUILayout.Width(100), GUILayout.Height(30)))
        {

        }
        EditorGUILayout.EndHorizontal();
        GUI.backgroundColor = Color.blue;
        if (GUILayout.Button("Blue Btn", GUILayout.Width(250), GUILayout.Height(30)))
        {

        }




    }
}

Here is what i come up with.
You need 9 points to build a single triangle. So you’re current script doesn’t tell me what points are part of what tri. and unity doesn’t allow for more 65k of points. cell size of 256 is over the max. Anyways.
These scripts should get started in making your own meshes. a lot of work is still needed.
My window in under “Make Triangles/Create” to bring up the buttons

2869923–210293–BuildTri.unitypackage (13 KB)

So you mean that the first post I made is possible? I scrapped that idea and restarted but that is still great news I would be very happy if you could help me get my first idea working, I will check out your code and see what I can come up with. I forgot to mention that the number would only display if all 3 points of the triangle were the same height.

I do not understand, why do I need 9 points to make a triangle? that does not make sense to me. I can decrease cell size to 128 by 128 but that is as low as I can go otherwise it just takes way too long to make 1 cell. I do understand that I did not tell unity what points to connect I will need a good way around that also.

if I can get my first idea working great if not I will also need a way of making it so that each cell borders the ones next to it without tearing and without any holes. But again I will take a look at both these scripts I just got home from work so I will get to that now.

Alright so from what hpjohn is saying what I wanted to do first he made it sound possible, though I do not know if he fully understands everything I was asking to do. I went ahead and fixed up my script a bit it needs alot of work but I think I could make it possible. I need help connecting all the vertices though.

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class CellWindow : EditorWindow
{
    public static string cellName = "Wilderness";
    public static int xPosition = 0;
    public static int yPosition = 0;

    [MenuItem("Heightmap Creation/Editor")]
    static void Init()
    {
        CellWindow cellWindow = (CellWindow)GetWindow(typeof(CellWindow));
        cellWindow.Show();
    }

    void OnGUI()
    {
        GUI.backgroundColor = Color.red;
        if (GUILayout.Button("Spawn Cell", GUILayout.Width(250), GUILayout.Height(30)))
        {
            Cell.add(cellName, xPosition, yPosition);
        }
    }
}

public static class Cell
{
    public static void add(string cellName,int xPosition,int yPosition)
    {
        //Declare Variables.
        Mesh cell = new Mesh();
        int cellSize = 65;

        List<Vector3> vertices = new List<Vector3>();

        //Plot points.
        for (int x = 0; x <= cellSize; x++)
        {
            for (int z = 0; z <= cellSize; z++)
            {
                Vector3 vertex = new Vector3(x, 0, z);
               
                //Addpoints.
                vertices.Add(vertex);
            }
        }

        //Foreach vertex connect other vertices.

        //Create the cell
        cell.name = cellName + " (" + xPosition + (", ") + yPosition + (")");
        cell.SetVertices(vertices);
    }
}

My bad, not 9 points. 3 points AKA verts. each vert needs a Verctor3, 3 Vector3s is 9 numbers.
There is no way around this. you have to tell unity how to build the triangles.

Yes the grid i wanted would be 2d, but there would be a height value and if all three verts had the same height it would be displayed on the triangle.

But if my custom heightmap window tool is not possible i need a whole new system entirely, the next best option would be a window with buttons and images,for brushes where i can edit the height if each cell individually but then i need a good way of adding cells to the scene and such.

Not sure what i am going to do at this point but i need to do something with my terrain as doing it by hand is just too slow.

3d modeling is the way to go. Build tiles not triangles. Then have a script place the tiles for you.

So build the flat cell in blender than have a script place that forme and a script edit that mesh? I was thinking of doing that if that is what you are suggesting.

your problem is two fold. you want to generate a mesh. Then you want to edit that mesh.
You need to figure out how to get the mesh. you can build it in blender, you can build it in unity via code. and if you truly want it to be infinite, then you have hole thing to figure out. I’m thinking of having you build smaller sections in blender then have unity place them when the player is close enough.
But with this you have to be able to tell unity where the edges are so that they line up… it kind of reminds me of how Never Winter Nights created there worlds.

Now see if that is the route i am going there is absolutely no point, the whole point of generating mesh then editing is is to speed up the process. Building a single seemless world like what i want is going to be massive and it will just take way too long in blender.

I am trying to create a faster alternative to my current method, the render cam already only renders objects in its area so that is not why i am doing this, the infinite thing is definately not worth it, i need it to end so that when you reach the end of the world you spawn at the other end of it. I also need to be able to punch holes in it for caves.