Hi,
I have a scene which I want to use with many levels. I want to initialise an instance of the level class with different parameters including an array of game objects. I want to eventually randomly pick one of these game objects to use at a time. First, is this a good design pattern to use with unity?
I am having problems when creating the array, I can’t use the ‘new’’ keyword with monobehaviour etc. Can anybody give me any ideas how i should design this?
in your description of using arrays of gameobjects, you speak nothing about monobehaviours. What does this have to do with not being able to use “new” keyword with monobehaviour?
Your question is vague, all over the place, and generally incoherent.
Please rephrase your question in a manner that we can understand. Then we can help you.
Each level should be initialised with a number of objects, each object has a class script attached to it which holds variables such as ‘name’ and ‘position’ and methods such as ‘explode’. The only difference between these game objects will be the name and position, when the object is created.
I wanted to initialize 4-5 of these objects and store them in an array, so that they can be accessed one-by-one at a certain point in the level.
I don’t want to create a new scene for each level, as pretty much the only difference would be the name and position of the current level objects.
Can you give me an idea of the best way to do this in unity? I am from a C++ and C sharp background, but have never used unity, and I’m probably still getting used to the relationships between scripts, prefabs game objects etc.
you’d have prefabs of the objects that would get placed in your level (if the number of level objects is static, and you just change the names and position you could also just stick them in the level and call ‘Find’ at the beginning to get all of them).
You now need a startup script. Best option would be to have a gameobject in your scene that has a script on it called ‘startup’.
In that script you figure out which level you’re on (how ever you decide to inform the scene of that).
Based on the level you’d then create (or find if they all exist in the scene already), put into an array or list, and set the values you need.
Thanks, but I don’t want the all objects to be instantiated when the level starts.
Only one of the objects should be in the scene at a time. Also I want to allow each object to be destroyed and instantiated again later in the level.
The object has a monobehaviour class script attached to it, so can’t be put into a array/list without instantiating? Using FindObjectsOfType would require all the objects to be instantiated first? Is this correct?
GameObjects need to exist in the world in order to reference them. It’s not really clear what you’re trying to achieve here - but you could create prefabs and put them in your Resources folder then load them at runtime depending on which “level” you’re using.
Split the script into 2 classes. The new one only contains the ‘position’, ‘name’, ‘sound’ etc of the object.
This new class won’t inherit from monobehaviour so I can put it into an array using ‘new’ for each of the possible values.
When a new object needs to be instantiated, a random instance of this class from the array is attached to the new object using AddComponent(). This should allow the objects to vary the ‘position’, ‘name’, etc variables.
Similar to the following pseudocode:
//enemyData is the new class
enemyArray = new EnemyData[5];
EnemyArray[0] = new EnemyData { position = ..., name = ..., etc }
EnemyArray[1] = new EnemyData { position = ..., name = ..., etc }
etc...
void CreateNewEnemy()
{
newEnemyData = enemyArray[Random.Range(0,4);
GameObject newEnemy = Instantiate(enemyObject, newEnemyData.position) as GameObject;
newEnemy.GetComponent("EnemyData") = newEnemyData;
}
A class needs to inherit from UnityEngine.Component in order to work with Get/Remove/AddComponent.
You would have to make a third class that is a MonoBehaviour and wraps your EnemyData class in order to follow that pattern.
However - I ask again why you can’t just place the objects in the world, deactivate them, and then choose a random one to activate. It really feels like you’re over-thinking.
lordofduct had a valid solution. One that I’ve actually used in the past. You create a script lordofduct calls it startup I call it my LevelManager but they’re the same thing. This will be the script that actually manages the array of prefab references and turns them into actual game objects.
In your manager / start up object :
Make an array of gameobject that points to all the prefabs you might use in any level. These aren’t instantiated, just referenced in the array.
You leave these uninitialized in script as you’ll be dragging prefab references from the inspector to fill the array. Assuming you had two NPCEnemies available for any level your simply drag NPCEnemies 1 2’s prefab onto the PossiblePrefabs entry in the inspector to add a reference to that array.
During play you would then determine what monster needs to be created some how, that you’ve written that chooses these things how ever you see fit. To create the monster you would then use the Instantiate method. Using the returned GameObject you can then call make any necessary GetComponent calls to locate script instances of the new object to change scripted variables if the prefab default isn’t appropriate. Here is where you set things like hit points, color, damage what ever… stuff that scales with the level so that say lvl 20 enemies are tougher and stronger than level 1 enemies but still using the same prefab. Once this GameObject is instantiated you are free to destroy it at any time. That covers the prefab management side.
To differentiate levels you might choose to store data about a specific level in a class container which doesn’t need to derive from monobehaviour as it’s just a data holder (similar to a C struct). You can then store a collection of these level class containers in an array. This would be used for stuff like where enemies spawn from on any specific level or how strong enemies are on this level. Storing levels this way allows you to add / change values and settings right from the inspector.
Here I use UnityScript not because it’s better but because I’m more familiar with it off the top of my head. Keep in mind that I have I not run any of this code through unity so there’s likely to be syntax errors but the logic should be sound.
LevelController.js
public var PossibleEnemyPrefabs : GameObejct[];
public var levels : LevelSettings[];
public class LevelSettings
{
public var enemyhealth : int;
public var enemySpawnSpots : Vector3[];
}
function CreateEnemy (enemyId : int, level : int)
{
var newlyCreateedEnemy : GameObject = Instantiate(PossibleEnemyPrefabs[enemyId],ChoseSpawnPoint(level),Quaternion.Identity);
newlyCreateedEnemy.GetComponent(EnemyHealthScript).hitpoints = levels[level].enemyhealth;
}
function ChoseSpawnPoint ( level : int) :Vector3
{
var someRansomSpawnSpot : int = Random.Range (0,levels.Length);
return levels[level].enemySpawnSpots[someRansomSpawnSpot];
}