How do I dynamically generate scenes?

All the tutorials seem to involve attaching scripts to manually placed game objects, forcing a particular starting state for the scene.

I am interested in programmatically generating the world and placing the assets. I might use the graphical editor to experiment, but it is of paramount importance that I understand:

  • Where start-up code is configured (i.e. code that happens before the default scene is loaded)
  • How to spawn objects
  • Best practices for game architecture

I don’t want to create levels myself in the editor. I’d like to have an abstraction of the game environment and then ‘build’ the world from that. For example, I can’t see how I’d randomly generate a world.

Based on the price tag and impressive examples such as Kerbal, I’m certain that a rich and powerful development environment hides beneath the beginner’s drag ‘n’ drop experience.

Start-up config: You can use the Awake and Start functions in your script to start every method or config you need before the player can play the game. Spawn objects its simple that you think just use Instantiate(object, position, rotation) and boom! it will spawn. Also see: Instantiate

About the best pratices for game architecture see this link it will be useful for you: StackOverFlow Arch Question

Well, your idea is honorable but goes against the whole engine principle. Unity is trying to make your work easier. by adding visual aspect and more drag and drop than code.

What you are looking for is more of Conventional DirectX approach where you code it all from A to Z (and still DirectX is an API so uít has some helpers).

But well.

You can have a game manager object. Unfortunately, this one has to be added to an object. From there, you can start creating your scene in the Awake or Start method, Awake is run on creation of the object, Start is run once before the first Update, in your case they both run one after the other and won’t make big difference.

So you could have:

GameObject objectA = (GameObject)Resources.Load(path,typeof(GameObject)); 
GameObject obj = (GameObject)Instantiate(objectA, position, rotation);
obj.AddComponent<ComponentName>();

this will fetch a prefab in the resources folder see here:

Then you instantiate a clone of that prefab see here:

Note the cast on each step as C# requires it.

Then AddComponent is the method that adds script by code. This is equivalent of dropping scripts onto an object.

That is already a beginning. If you need more go ahead.

I have understood that you have come from another environment (like server side) or another engine. There is a unity3d way to do the things, and if you don’t understand and try to do it different you will be fighting against the wall.

To work better you need truly understand about Scene, Prefabs and Component based development. I said truly because they are not what appear to be. You can see a scene like a Configuration set of code that is executed when load, could be a nice scene like 3dmax, or a simple bunch of script that compute stuff before send to game scene. For example, in kerbal. Probably the ingame is a single scene, empty, without planets or ships, but a lot of prefabs with every rules configured and reference for assets.

You will become very angry sometimes. But when you take the gotchas, it is a great way to work. Expecially when you use the full power of Editor

Unity - Scripting API: Editor.

There is some nice things here how to organize your project and use prefabs:

How to instantiate dynamically:

Building a scene entirely in code is a good way to get one’s head around scripting.

In the Unity Editor create an empty scene and delete it’s default camera. Add an empty game object. Add the following script to that empty game object.

using UnityEngine;
using System.Collections;


/// <summary>
///  Create a scene from scratch
/// </summary>
public class SceneFromScratch : MonoBehaviour {

	// Use this for initialization
	void Start () {

        // create a camera
        GameObject cam = new GameObject();
        cam.name = "Generated Camera";
        cam.transform.parent = this.gameObject.transform;
        cam.AddComponent<Camera>();
        cam.transform.position = new Vector3(2.5f, 2, -3);
        cam.transform.localEulerAngles = new Vector3(20, 325, 5);
        
        // create a light
        GameObject lightGameObject = new GameObject("Generated Light");
        lightGameObject.transform.parent = this.gameObject.transform;
        lightGameObject.AddComponent<Light>();
        lightGameObject.light.color = Color.white;
        lightGameObject.transform.position = new Vector3(-0.8f, 1.3f, -1.4f);
        
        // create a generic cube
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.name = "Generated Cube";
        cube.transform.parent = this.gameObject.transform;

        // create a custom square
        GameObject g = GetSquareGameObject("Generated Square");
        g.transform.parent = this.gameObject.transform;
        g.transform.localScale = new Vector3(2, 2, 2);
        
	}
	
	// Update is called once per frame
	void Update () {
	
	}


    GameObject GetSquareGameObject(string name)
    {
        GameObject g;
       
        g = new GameObject(name);
        g.AddComponent<MeshFilter>();
        g.AddComponent<MeshRenderer>();

        // assign a mesh
        g.GetComponent<MeshFilter>().mesh = GetSquareMesh(); 

        // modify material (and shader)
        g.renderer.material.color = Color.red;

        Shader shader = Shader.Find("Diffuse");
        g.renderer.material.shader = shader;
        

        return g;
    }

    Mesh GetSquareMesh()
    {
        Vector3[] newVertices = new Vector3[4];
        Vector3[] newNormals = new Vector3[4];
        Vector2[] newUV = new Vector2[4];
        int[] newTriangles = new int[6];

        Mesh mesh = new Mesh();

        // vertices
        newVertices[0] = new Vector3(0, 0, 0);
        newVertices[1] = new Vector3(0, 1, 0);
        newVertices[2] = new Vector3(1, 0, 0);
        newVertices[3] = new Vector3(1, 1, 0);

        // normals
        newNormals[0] = -Vector3.forward;
        newNormals[1] = -Vector3.forward;
        newNormals[2] = -Vector3.forward;
        newNormals[3] = -Vector3.forward;
        
        // uv
        newUV[0] = new Vector2(0, 0);
        newUV[1] = new Vector2(0, 1);
        newUV[2] = new Vector2(1, 0);
        newUV[3] = new Vector2(1, 1);

        // triangles

        // first triangle
        newTriangles[0] = 0;
        newTriangles[1] = 1;
        newTriangles[2] = 2;

        // second triangle
        newTriangles[3] = 1;
        newTriangles[4] = 3;
        newTriangles[5] = 2;

        // assign to mesh
        mesh.vertices = newVertices;
        mesh.uv = newUV;
        mesh.normals = newNormals;
        mesh.triangles = newTriangles;
       
        return mesh;
    }
}

You can write an Editor script, which becomes selectable in the toolbar, which will do the initial boot up for you: ie. when selected it will create a new empty scene, delete the default camera, add a root game object, and attach your scene generating script to it, and play the result.

Make sure you save any current scene before selecting this Editor script in the toolbar.

Editor script (goes into Editor folder):

using UnityEngine;
using UnityEditor;
using System.Collections;

public class EditorTest : EditorWindow
{
    bool isCreated = false;

    [MenuItem("Window/Scene From Scratch")]
    public static void ShowWindow()
    {
        EditorWindow.GetWindow(typeof(EditorTest));
    }

    void OnGUI()
    {
        if (!isCreated)
        {
            if ( EditorApplication.isPlaying == true )
            {
                EditorApplication.isPlaying = false;
            }
 
            EditorApplication.NewScene();
            GameObject c = GameObject.Find("Main Camera");
            if(c != null)
                DestroyImmediate(c);

            GameObject g = new GameObject("Scene From Scratch");
            g.AddComponent<SceneFromScratch>(); // a scene generating script

            EditorApplication.isPlaying = true;

            isCreated = true;

            EditorWindow.GetWindow(typeof(EditorTest)).Close();
        }
    }
}

And the scene generating script (referenced by above):

using UnityEngine;
using System.Collections;


/// <summary>
///  Create a scene from scratch
/// </summary>
public class SceneFromScratch : MonoBehaviour {

	// Use this for initialization
	void Start () {

        // create a camera
        GameObject cam = new GameObject();
        cam.name = "Generated Camera";
        cam.transform.parent = this.gameObject.transform;
        cam.AddComponent<Camera>();
        cam.transform.position = new Vector3(2.5f, 2, -3);
        cam.transform.localEulerAngles = new Vector3(20, 325, 5);
        
        // create a light
        GameObject lightGameObject = new GameObject("Generated Light");
        lightGameObject.transform.parent = this.gameObject.transform;
        lightGameObject.AddComponent<Light>();
        lightGameObject.light.color = Color.white;
        lightGameObject.transform.position = new Vector3(-0.8f, 1.3f, -1.4f);
        
        // create a generic cube
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.name = "Generated Cube";
        cube.transform.parent = this.gameObject.transform;

        // create a custom square
        GameObject g = GetSquareGameObject("Generated Square");
        g.transform.parent = this.gameObject.transform;
        g.transform.localScale = new Vector3(2, 2, 2);
        
	}
	
	// Update is called once per frame
	void Update () {
	
	}


    GameObject GetSquareGameObject(string name)
    {
        GameObject g;
       
        g = new GameObject(name);
        g.AddComponent<MeshFilter>();
        g.AddComponent<MeshRenderer>();

        // assign a mesh
        g.GetComponent<MeshFilter>().mesh = GetSquareMesh(); 

        // modify material (and shader)
        g.renderer.material.color = Color.red;

        Shader shader = Shader.Find("Diffuse");
        g.renderer.material.shader = shader;
        

        return g;
    }

    Mesh GetSquareMesh()
    {
        Vector3[] newVertices = new Vector3[4];
        Vector3[] newNormals = new Vector3[4];
        Vector2[] newUV = new Vector2[4];
        int[] newTriangles = new int[6];

        Mesh mesh = new Mesh();

        // vertices
        newVertices[0] = new Vector3(0, 0, 0);
        newVertices[1] = new Vector3(0, 1, 0);
        newVertices[2] = new Vector3(1, 0, 0);
        newVertices[3] = new Vector3(1, 1, 0);

        // normals
        newNormals[0] = -Vector3.forward;
        newNormals[1] = -Vector3.forward;
        newNormals[2] = -Vector3.forward;
        newNormals[3] = -Vector3.forward;
        
        // uv
        newUV[0] = new Vector2(0, 0);
        newUV[1] = new Vector2(0, 1);
        newUV[2] = new Vector2(1, 0);
        newUV[3] = new Vector2(1, 1);

        // triangles

        // first triangle
        newTriangles[0] = 0;
        newTriangles[1] = 1;
        newTriangles[2] = 2;

        // second triangle
        newTriangles[3] = 1;
        newTriangles[4] = 3;
        newTriangles[5] = 2;

        // assign to mesh
        mesh.vertices = newVertices;
        mesh.uv = newUV;
        mesh.normals = newNormals;
        mesh.triangles = newTriangles;
       
        return mesh;
    }
}