How to recycle random prefabs that spawn from a specific point.

Hello everyone! Thank you in advance for taking the time to help with my question. Long story short I am working on a 2d game. In the game I have cars spawning from both ends of the screen from a “spawn point” empty prefab. The cars would go to the opposite end of the screen where they would enter the trigger of another “end point” prefab and become destroyed. However on mobile devices, constant instantiating and destroying isn’t good so I am cleaning up my code.

I was working on a way to recycle my car prefabs. What I was expecting my code to do is:
Game Manager Script- Boolean check to see if any cars have spawned. If no cars have spawned, pick a random number either 0, or 1. Each number is a case referring to a different car prefab which subsequently gets placed at the “spawn point” and a shared-between-multiple-scripts boolean is set to true.

public class GameManager : MonoBehaviour {
	CarSpawner Script;
	public Transform RightSpawnPoint;
	public bool TruckSpawned;
	public bool SilverCarSpawned;
	public bool CarSpawned;
	private GameObject TruckR;
	private GameObject SilverCarR;

// Use this for initialization
void Start () {
	//CarSpawned = true;
	TruckR = GameObject.Find ("TruckR2");
	SilverCarR = GameObject.Find ("SilverCarR2");
	RightSpawnPoint = GameObject.Find ("spawnPointRight").transform;
	Script = GameObject.Find ("DestroyPoint1").GetComponent<CarSpawner> ();
	Invoke ("CreateCarsRight", (Random.Range(0,1)));

}

// Update is called once per frame
void Update () {
	TruckSpawned = Script.TruckOnScreen;
	SilverCarSpawned = Script.SilverCarOnScreen;

	if (TruckSpawned == false && SilverCarSpawned == false) {
		CarSpawned = false;
	}

	if (TruckSpawned == true || SilverCarSpawned == true) {
		CarSpawned = true;
	}

}

void CreateCarsRight () {
	float delay = Random.Range (2, 6);
	int CarR_Num = Random.Range (0, 2);
	if (CarSpawned == false) {
		switch (CarR_Num) {
		case 0: TruckR.transform.position = new Vector3(RightSpawnPoint.position.x, RightSpawnPoint.position.y, transform.position.z);
			TruckSpawned = true;
			break;
		case 1: SilverCarR.transform.position = new Vector3(RightSpawnPoint.position.x, RightSpawnPoint.position.y, transform.position.z);
			SilverCarSpawned = true;
			break;
		}
	}
	Invoke ("CreateCarsRight", delay);
}

}

Car Controller Script- This script is attached to both vehicle prefabs. It has booleans for each vehicle. if both are false, then the car stops moving. if either are true, then the car can move.

public class RightCarController : MonoBehaviour {

WheelJoint2D[] WheelJoints;
private int Speed = 1000;
JointMotor2D Motor;
public bool TruckVisible;
public bool SilverCarVisible;
public Transform FrontWheel;
public Transform RearWheel;
private int Torque = 10000;
GameManager Script;
Rigidbody2D[] Rigidbodies;

// Use this for initialization
void Start () {
	Script = GameObject.Find ("GameEngine").GetComponent<GameManager> ();

}

// Update is called once per frame
void Update () {
	TruckVisible = Script.TruckSpawned;
	SilverCarVisible = Script.SilverCarSpawned;

	if (TruckVisible == false || SilverCarVisible == false) {
		Rigidbodies[0].isKinematic = true;
		Rigidbodies[1].isKinematic = true;
		Rigidbodies[2].isKinematic = true;
		WheelJoints[0].useMotor = false;
		WheelJoints[1].useMotor = false;
		Rigidbodies[0].isKinematic = false;
		Rigidbodies[1].isKinematic = false;
		Rigidbodies[2].isKinematic = false;
	}

	if (TruckVisible == true || SilverCarVisible == true) {
		WheelJoints[0].useMotor = true;
		WheelJoints[1].useMotor = true;

	}
}

void Awake () {
	WheelJoints = GetComponentsInChildren<WheelJoint2D> ();
	Rigidbodies = GetComponentsInChildren<Rigidbody2D> ();
	Motor.motorSpeed = Speed;
	Motor.maxMotorTorque = Torque;
	WheelJoints[0].motor = Motor;
	WheelJoints [1].motor = Motor;
}

}

End Point Script- This script is attached to the end point. I have the on trigger enter 2d here because the cars won’t interact with the end point from their end, I believe, since the end point is kinematic. When a gameobject with a tag “car” comes into its trigger, its supposed to set the shared booleans to false.

public class EndPoint : MonoBehaviour {

public bool TruckOnScreen;
public bool SilverCarOnScreen;
RightCarController Script;
// Use this for initialization
void Start () {
	Script = GameObject.Find ("TruckR2").GetComponent<RightCarController> ();

}

// Update is called once per frame
void Update () {
	TruckOnScreen = Script.TruckVisible;
	SilverCarOnScreen = Script.SilverCarVisible;

}

void OnTriggerEnter2D(Collider2D other) {
	if (other.gameObject.tag == "Car")
		TruckOnScreen = false;
		SilverCarOnScreen = false;
}

}

What actually happens, is that the vehicles get set to the spawn point and that is it. If I manually set one of the cars to true, both start rolling. Additionally, both seem to ignore being set to false from the end point and being set to the transform of the spawn point when false.

When testing one car and everything separately, everything seemed to work. Putting everything together, and adding an additional car seem to break it. It seems to me, that there is something wrong with the way my booleans are set up. Any help is greatly appreciated!.

Hi, i suggest you try a different approach on what your trying to implement. Here’s what comes to my mind, first try to implement a object pooling script that will handle spawning and returning of cars.

Here’s a sample object pooling code i made, attach this script to the same game object your car spawner is attached, set up objectPoolData after. Add a reference to this script to your car spawner and let your car spawner handle Spawning and Returning of objects.

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

public class SampleObjectPoolingScript : MonoBehaviour {

	[System.Serializable]
	public class ObjectPoolData {
		public string key = "";
		public Transform objectTransform = null;
		public int initialSpawnCount = 5;
	}

	public ObjectPoolData[] objectPoolData;
	public Vector3 inActiveObjectPosition = Vector3.zero;

	private Dictionary<string, List<Transform>> activeObjects = null;
	
	private Dictionary<string, List<Transform>> inActiveObjects = null;

	private Dictionary <string, Transform> prefabDictionary = null;

	private Transform myTransform = null;

	public Transform SpawnObject (string key, Vector3 position) {
		if (inActiveObjects.ContainsKey (key)) {
			List<Transform> objectList = inActiveObjects[key];
			Transform t = null;
			if (objectList.Count > 0) {
				t = objectList[0];
				objectList.Remove (t);
				t.parent = null;
				t.position = position;
				t.gameObject.SetActive (true);
			} else {
				t = Instantiate (prefabDictionary[key], position, Quaternion.identity) as Transform;
			}
			activeObjects[key].Add (t);
			return t;
		}
		return null;
	}
	
	public void ReturnObject (string key, Transform t) {
		if (!activeObjects.ContainsKey (key)) { return; }
		DisableObject (t);
		activeObjects [key].Remove (t);
		inActiveObjects [key].Add (t);
	}

	void Start () {
		myTransform = transform;
		InitializeObjectPool ();
	}

	private void InitializeObjectPool () {
		foreach (ObjectPoolData data in objectPoolData) {
			List<Transform> objectList = new List<Transform> ();
			for (int i = 0; i < data.initialSpawnCount; i++) {
				Transform t = Instantiate (data.objectTransform, inActiveObjectPosition, Quaternion.identity) as Transform;
				DisableObject (t);
				objectList.Add (t);
			}
			string poolKey = data.key.Equals ("") ? data.objectTransform.name : data.key;
			if (!inActiveObjects.ContainsKey (poolKey)) {
				inActiveObjects.Add (poolKey, objectList);
				activeObjects.Add (poolKey, new List<Transform> ());
				prefabDictionary.Add (poolKey, data.objectTransform);
			}
		}                                     
	}
	
	private void DisableObject (Transform t) {
		t.gameObject.SetActive (false);
		t.parent = myTransform;
		t.position = inActiveObjectPosition;
	}
}

Add this SampleVehicleHook script i made to each of your vehicle prefab:

using UnityEngine;
using System.Collections;

public class SampleVehicleHook : MonoBehaviour {

	public delegate void CarReachedEndPointHook (Transform t);
	public CarReachedEndPointHook OnCarReachedEndPointHook;
	
	void OnTriggerEnter2D(Collider2D other) {
		if (OnCarReachedEndPointHook != null) {
			OnCarReachedEndPointHook (transform);
		}
	}
}

Here is a SampleCarSpawner script i made as an example of how to use those 2 previous scripts above:

using UnityEngine;
using System.Collections;

public class SampleVehicleSpawner : MonoBehaviour {
	
	public SampleObjectPoolingScript objectPoolingManager;
	
	public string carKey = "Car";
	
	public void SampleSpawnACar () {
		Transform t = objectPoolingManager.SpawnObject (carKey, Vector3.zero);
		var vehicleHook = t.GetComponent<SampleVehicleHook> ();
		vehicleHook.OnCarReachedEndPointHook = HandleOnCarReachedEndPointHook;
	}
	
	void HandleOnCarReachedEndPointHook (Transform t) {
		objectPoolingManager.ReturnObject (carKey, t);
	}
}

Hope this helps :slight_smile: PS. Wasn’t able to test those scripts i just created them