How to assign GameObjects to Prefabs?

My goal is to have a random model of “car” spawn with a random “bad part”(like a broken door) and when you press E, the bad part will dissapear, and a good part will spawn.

This is what I’ve done to try to accomplish.
In the scene, I will have spawn a random prefab out of two choices, that move to a certain location. I’m calling these cars,

Then, within those cars(prefabs) there are 2 more prefabs for each of them. I’m calling them parts. One of the parts will get randomly spawned and follow the car’s movement.

Now, I need these parts to have it’s own script. And the function is, when you walk into a trigger box, text will appear and you can press E to destory the part spawned and then spawn another prefab in it’s place.

However, every time I try to assign GameObjects from the scene or prefabs, the part’s clone will be missing those values. Is there a way to fix this? Or a better method than sticking all these prefabs inside other prefabs?

Here is the script for spawning cars
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class CarSpawnScript : MonoBehaviour
{
public GameObject[ ] carPrefabs;
public float speed = 7;
public Transform waypoint;
private GameObject carInstance;
private void Start()
{
int prefabCount = carPrefabs.Length;
int index = Random.Range(0, prefabCount);
GameObject prefab = carPrefabs[index];
carInstance = Instantiate(prefab, transform.position, Quaternion.identity);
}
private void Update()
{
Vector3 currentPosition = carInstance.transform.position;
Vector3 newPos = Vector3.MoveTowards(currentPosition, waypoint.position, speed * Time.deltaTime);
carInstance.transform.position = newPos;
}
}

This is the script for destroying a prefab and spawning another. Currently does not work
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DoorFixScript : MonoBehaviour
{
public GameObject gooddoor;
public GameObject baddoor;
public Canvas EPromptCanvas;
public GameObject player;
public GameObject tool;
void Start()
{
EPromptCanvas.enabled = false;
}
private void OnTriggerEnter(Collider Player)
{
if (Player.tag == “Player”)
{
Debug.Log(“Player near box”);
}
EPromptCanvas.enabled = true;
}
private void Update()
{
if (EPromptCanvas.enabled == true)
{
if (Input.GetKeyDown(KeyCode.E))
{
if (player.transform.position == tool.transform.position)
{
Destroy(baddoor);
Instantiate(gooddoor, transform.position, Quaternion.identity);
}
}
}
}
}

These are the prefabs for the first “car”
9138544--1269382--upload_2023-7-11_1-9-30.png
These are the prefabs for the second “car”
9138544--1269385--upload_2023-7-11_1-9-57.png
All of the “parts” have a hierarchy like this. BadDoor1Origin is just an empty, so the origin of the obejcts can be the same as it’s transform.parent, the car, while the actual part spawn a little offset from the spawn point. This is probabaly also really stupid.
9138544--1269388--upload_2023-7-11_1-10-29.png
This is what the scene looks like.


(i have a player and freelook camera but that’s irrelevant)
The empty that is the car’s spawn and “waypoint” are also in the scene.

Please could you use the code element (“insert code”) when posting source code.

sorry, if this makes it any easier this is the code in code format

Here is the script for spawning cars

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class CarSpawnScript : MonoBehaviour
{
public GameObject[] carPrefabs;

public float speed = 7;

public Transform waypoint;

private GameObject carInstance;

private void Start()
{
int prefabCount = carPrefabs.Length;
int index = Random.Range(0, prefabCount);

GameObject prefab = carPrefabs[index];
carInstance = Instantiate(prefab, transform.position, Quaternion.identity);
}

private void Update()
{
Vector3 currentPosition = carInstance.transform.position;
Vector3 newPos = Vector3.MoveTowards(currentPosition, waypoint.position, speed * Time.deltaTime);
carInstance.transform.position = newPos;
}
}

This is the script for destroying a prefab and spawning another. Currently does not work

This is the script for destroying a prefab and spawning another. Currently does not work
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DoorFixScript : MonoBehaviour
{

public GameObject gooddoor;

public GameObject baddoor;

public Canvas EPromptCanvas;
public GameObject player;
public GameObject tool;

void Start()
{
EPromptCanvas.enabled = false;
}

private void OnTriggerEnter(Collider Player)
{
if (Player.tag == "Player")
{
Debug.Log("Player near box");
}
EPromptCanvas.enabled = true;
}

private void Update()
{
if (EPromptCanvas.enabled == true)
{
if (Input.GetKeyDown(KeyCode.E))
{
if (player.transform.position == tool.transform.position)
{
Destroy(baddoor);
Instantiate(gooddoor, transform.position, Quaternion.identity);
}
}
}
}
}

I would add some debugging code to see if player and tool position are equal at any time. Maybe, calculating the distance between them, and compare against a threshold, might work better.

When you call Instantiate(GameObject obj), obj can be either an instance in the scene, or a prefab. In both cases, a new GameObject will be created which is a clone of obj. It will have the exact same hierarchy and the exact same scripts and values, as in the original.

In your case, you have two preconfigured cars, and I suggest you create 2 separate prefabs because these are predetermined static configurations. Then just add those scripts and configuration into the prefab. They will be there when you instantiate the prefab.

There’s also something called prefab variants.

To instantiate your prefab, you need an object reference to it. The standard way to do this is to add public GameObject fields to your MonoBehaviour script, such as public GameObject SimpleCarPrefab;. Then in your Editor you drag your car prefab file to this field, and it will be available in the script at runtime.