C#:
public class Block : MonoBehaviour {
private int color;
}
public class BlueBlock : Block {
void Awake () {
color = 1;
}
// more BlueBlock specific functions here
}
public class RedBlock : Block {
void Awake () {
color = 2;
}
// more RedBlock specific functions here
}
A block is a simple cube turned into a prefab. But how do I derive from this cube so that when I have a blueblock and a redblock that I can say:
blocks[0] = myBlueBlock;
blocks[1] = myRedBlock;
I can not derive prefabs from each other right? In XNA I always used to create some class like BaseProjectile and then create new classes that derive from that called Laser or Missile or EscapePod or whatever and I can put all of them in a single BaseProjectile array. And I can just spawn them into the level and treat them all as BaseProjectiles.
I mean, the problem is that I have to create 3 prefabs (one for each block). And to unity they are not the same so I canât treat them as âBaseBlocksâ so to say.
I donât really want to use a single class and then use enums/symbols with large switch-statements to decide if it is a concrete cube or a metal cube? etc. They are very much alike. But they just have slightly different functions.
And if it matters, I instantiate them like this:
Instantiate(Resources.Load("Block"), .....
I could just add a variable to it called blockType and just assign a new instance of a BlueBlock or a RedBlock to it perhaps somehow? But it seems like a dirty solution.
You need to ditch your way of thinking with polymorphism (as it relates to GameObjects) and start thinking in terms of object composition.
In your coloured block example, thereâs no reason to create the two extra behaviours at all. Simply set the colour in the editor for the red block prefab and the blue block prefab and both of them can be thought of as blocks. If each block needs a specific behaviour, create two different behaviours and attach them to each prefab as necessary (say one block bounces and the other spins like a top).
3 Likes
So instead of inheritance, in Unity we mainly create small scripts and assign them to the prefabs? So something like: Composition over inheritance - Wikipedia ?
Which would probably translate to something like the code below (dirty code)?
public enum BlockType { Base, Blue, Red, Flying }
public class Block : MonoBehaviour {
/// <summary>
/// Adds the a behavior script to the block
/// </summary>
void SetType(BlockType type)
{
switch (type)
{
case BlockType.Base:
return;
case BlockType.Blue:
GetComponent<GameObject>().AddComponent<MyBlueBehaviorScript>();
case BlockType.Red:
GetComponent<GameObject>().AddComponent<MyRedBehaviorScript>();
case BlockType.Flying:
GetComponent<GameObject>().AddComponent<MyFlyingBehaviorScript>();
}
}
}
And then:
spawnedBlock = Instantiate(Resources.Load("Block"), ..... as GameObject;
spawnedBlock.GetComponent<Block>().settype(BlockType.BlueBlock) // get block script and then set it's type so it can attach the proper behaviour script.
This is quiet dirty though⌠The switch-statement is not necessary (Iâm sure) and it may not fire the behaviourâs script Awake() & Start() and such.
So the Block-prefab would need a constructor-parameter and assign the behaviour-script when the prefab is constructed (or cloned). Unity does not seem to really support this⌠So Iâm probably doing something wrong. Because I only find weird workarounds like: Instantiate GameObject with parameters - Questions & Answers - Unity Discussions to add paramters to the gameobject constructors in Unity. But this could still bug in theory if your script also uses the constructor perhaps.
Is there a super simple example somewhere of like an item or projectile or etc. for Unity to do this properly? I still donât really know how to do this properly. Is there no tutorial about this? Because just about any project needs this.
Ditch that Switch statement. What GroZZleR meant is literary just make two block prefabs in the editor, with both a Block script that defines all that makes a block a block (in your case the color) and then create and attach specific behavior scripts in the editor. There is no need to use a Switch statement for that.
1 Like
Ooooh⌠So:
- I make, letâs say, 2 block prefabs.
- I make one block-script (with the color property) and attach it to each prefab (in the editor).
- I create 2 behavior-scripts and attach each script to the corresponding prefab (in the editor).
- Upon game-start I run some for-loop and instantiate a 1000 blocks, randomizing between blue and red ones. I just change the first parameter of the Instantiate() method to spawn the proper block.
- Then I just get the return-value of âInstantiate(âŚ) as GameObjectâ and put those in an 2D array of GameObjects? And then if I ever need a block at a specific index I just call: myBlockArray[x, y].GetComponent().CallSomeMethod()
Or I could make an array of Block and retrieve the Block-script from the Instantiate:
MyBlockArray[index] = (Instantiate(âŚ) as GameObject).GetComponent(). I suppose that this comes down to what I need the array for.
Is that the proper way to do this in Unity? I suppose that GetComponent<>() does not consume a lot of resources.
But if I ever change the size of one prefab, I have to do so for each prefab (if I want them to have the same size)? Because prefabs can not derive from another prefab unless I use some kind of plugin I believe.
Though I do not expect to have 1000 different blocks, pickups or projectile prefabs so it wonât be a problem I guess.
Well, if you want to randomly spawn two (or more) types of block, just create a list of some type in a spawn script:
[SerializeField]
private List<GameObject> _tiles;
Then you can just add any blocks to the list that you want to be able to spawn, if you want to limit it to only gameObjects of type block, that do a List. To randomly switch between those blocks, just add something like:GameObject tile = _tiles[Random.Range(0, _tiles.Count)]; And then just instantiate them with: Instantiate(tile, position, rotation);
Doing it this way, you donât need to change the type of bock yourself, but the game will just pick a block out of the available ones and instantiate it in whatever position and rotation you pass in.
The result could be:
Also, you can still use a base class for object, and you can even add that class to a prefab, but indeed you can not directly inherit a prefab GameObject.
And yes, you can just add those GameObjects to a 2D array after Instantiating, although I donât see the merit of doing that directly, then again, I donât know what type of game you are making so it might have merit to keep an array around. GetComponent<>() is indeed the normal way to do it in Unity.
1 Like
Okay thanks. I just wanted to be sure that I implement my basics the proper way :).