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.
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
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;
}
}