Combining prefabs into one game object before calling Instantiation

I want to write a class that puts a bunch of GameObject prefabs (walls, floors, windows, furniture, etc) into a random house-shaped Game Object and return that object to the caller. Once the caller has this single GameObject, it can Instantiate() it into being.

I know I can use this code:

SomeHousePiece.transform.parent = ParentObject.transform;

to join objects together, but since I’m trying to put this all together BEFORE Instantiation, I get this error:

Setting the parent of a transform which resides in a prefab is disabled to prevent data corruption.

I’ve read that this is because I need to call Instantiate() on all these components before I can group them under a single parent, but I really want to avoid calling Instantiate() in the House builder class. I want that class to be purely a thing that generates a Game Object for later use.

Is this possible? I have an impression that I’m fighting against the “Unity way” of doing things, but as a long-time C# developer, there are habits (like separating construction logic from display logic) that are hard to break.

Should I just call Instantiate() from within my Builder class and be done with it?

I prefer keeping prefabs as invariants, so even if you could change the parent, it seems like a bad idea.

One thing you could do is create fake prefabs. Instantiate will gladly copy prefabs or existing gameObjects. So HouseMaker could Instantiate, position, child… everything, but into an object at -999 set to inactive. Then could return that as the “prefab.” And, to repeat, later code will gladly Instantiate that.

Or, a more programmery way, and more what you’re asking for, have the HouseMaker create and return a HouseBlueprint, which would be used to Instantiate the house. Your main program will never call Instantiate. Instead, it will call Transform H1 = housePattern1.spawn();

HouseBlueprint might look something like:

class HouseBlueprint {
  Transform myPrefab;
  Vector3 myLocalPos, myLocalRotation, myLocalScale;
  HouseBluePrint[] Children;

  // recursively instantiates, hooks up, positions all PFs that make me: 
  Transform spawn() { return _spawn(null); }

  Transform _spawn(Transform myParent) {
    Transform T = Instantiate(myPrefab, 0 ,0);
    if(myParent!=null) {
      T.parent = myParent;
      T.localPosition = ...
    }
    ...
    foreach(HouseBlueprint b2 in Children)
      _spawn(b2, T);
    return T;
  }

Can think of it as a standard recursive data structure, with an eval() function. The root should probably always be a “positioning” empty, which also solves the problem deciding the parent if you just have 4 walls. I use this trick – I think it really is the correct solution, but it is very Computer Sciencey.