i have a problem with my unity code and i can't get it why it doesn't work. I am kinda new to unity, just starting to learn it. I have 4 prefabs with different name in the project tree, and i want a prefab to spawn every second, but i want it to be randomized without using "if"'s, so i tried to save the prefabs names in an array and then Instantiate the GameObject that has the same name with the value of the array. When i run my script in Unity it says that the object i want to instantiate is null, i tried to find an answer on the web, but i found nothing. Can you help me?
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawnnoif : MonoBehaviour
{
public GameObject cub;
public GameObject capsula;
public GameObject cilindru;
public GameObject sfera;
public int x;
public GameObject paleta;
public float delta;
public string[] a = { "cub", "capsula", "cilindru", "sfera" };
void Start()
{
Vector3 position = new Vector3(UnityEngine.Random.Range(-1.88f, 2.1f), 1, UnityEngine.Random.Range(-7.81f, -3.1f));
x = UnityEngine.Random.Range(0, 3);
Instantiate(GameObject.Find(a[x]), position, Quaternion.identity);
}
IEnumerator Spawn()
{
while (true)
{
Vector3 position = new Vector3(UnityEngine.Random.Range(-1.88f, 2.1f), 1, UnityEngine.Random.Range(-7.81f, -3.1f));
x = UnityEngine.Random.Range(0, 3);
Instantiate(GameObject.Find(a[x]), position, Quaternion.identity);
yield return new WaitForSeconds(1.0f);
}
}
}
Please don't use Find for this! It is extremely expensive! And unreliable!
This function only returns active GameObjects. If no GameObject with name can be found, null is returned.
Especially since it looks like you want to use this for prefabs that only exist in the Assets and not in the Scene this will always return null as it only finds objects from the Scene.
Rather use an array like
public GameObject[] Prefabs;
reference your objects here and simply do
Vector3 position = new Vector3(Random.Range(-1.88f, 2.1f), Random.Range(-7.81f, -3.1f));
Instantiate(Prefabs[Random.Range(0, Prefabs.Length)], position, Quaternion.identity);
To your IEnuemrator ... well, you never start this as a Coroutine so it is simply never running.
You can do it directly in Start using StartCoroutine
private void Start()
{
StartCoroutine(Spawn());
}
private IEnumerator Spawn()
{
while (true)
{
Vector3 position = new Vector3(Random.Range(-1.88f, 2.1f), Random.Range(-7.81f, -3.1f));
Instantiate(Prefabs[Random.Range(0, Prefabs.Length)], position, Quaternion.identity);
yield return new WaitForSeconds(1.0f);
}
}
actually you could even directly use
private IEnumerator Start()
{
while (true)
{
Vector3 position = new Vector3(Random.Range(-1.88f, 2.1f), Random.Range(-7.81f, -3.1f));
Instantiate(Prefabs[Random.Range(0, Prefabs.Length)], position, Quaternion.identity);
yield return new WaitForSeconds(1.0f);
}
}
If Start is declared as IEnumerator Unity automatically runs it as a Coroutine.
Or in such a simple case you could even use InvokeRepeating like
private void Start()
{
// second parameter is the initial delay
// last parameter the repeat interval
InvokeRepeating(nameof(Spawn), 0, 1.0f);
}
private void Spawn()
{
Vector3 position = new Vector3(Random.Range(-1.88f, 2.1f), Random.Range(-7.81f, -3.1f));
Instantiate(Prefabs[Random.Range(0, Prefabs.Length)], position, Quaternion.identity);
}
You could use an array of GameObjects (the prefabs) and assign them in the editor. Then you can assign as many prefabs as you want in the Inspector and spawn them randomly:
public class Spawnnoif : MonoBehaviour
{
public GameObject[] prefabs;
public int x;
public GameObject paleta;
public float delta;
void Start()
{
Vector3 position = new Vector3(UnityEngine.Random.Range(-1.88f, 2.1f), 1, UnityEngine.Random.Range(-7.81f, -3.1f));
x = UnityEngine.Random.Range(0, prefabs.Length);
Instantiate(prefabs[x], position, Quaternion.identity);
}
...
}
Related
For Unity (Lastest Version & C#)
How do I make an object fall from the sky at random places (random x but fixed y) in a 2D game
How do I delete them when they get off-screen and create a timing between objects falling
Whenever I run the program it randomly creates object but keeps naming them this: myObj, myObj(Clone), myObj(Clone)(Clone), myObj(Clone)(Clone)(Clone) every time a new object is instantiated. More importantly the instantiate part keeps running, spawning a bunch of objects and not deleting them.
Also, I just don't get how to delete the objects as soon as they get out of from the camera. Do I have to create a different script for it or smthn?
public class RandomObjectsFalling : MonoBehaviour
{
public GameObject obj;
public float timebeforedie = 1f;
void Start()
{
StartCoroutine(SpawnBlocks());
}
IEnumerator SpawnBlocks()
{
while(x <= 1)
{
float randomPosition = Random.Range(-10f, 10f);
GameObject clone = (GameObject)Instantiate(prefab, new Vector3(randomPosition, 8, 0), Quaternion.identity); //problem is this keeps getting called creating a whole bunch of objects but they don't get destroyed
yield return new WaitForSeconds(timebeforedie);
Destroy(clone);
}
}
}
Use this code to Spawn Your Obj
public GameObject prefab;
public bool startSpawning;
public float spawnDelay;
private float _currentSpawnDelay;
private void Start()
{
_currentSpawnDelay = spawnDelay;
}
private void Update()
{
if (startSpawning)
{
_currentSpawnDelay -= Time.deltaTime;
if (_currentSpawnDelay < 0)
{
_currentSpawnDelay = spawnDelay;
var randomPosition = Random.Range(-10f, 10f);
Instantiate(prefab, new Vector3(randomPosition, 8, 0), Quaternion.identity);
}
}
}
And This To Destroy Them But This Code Need To be Attach On Obj You That you want to Spawn
private void Update()
{
if (gameObject.transform.position.x < -20)
{
Destroy(gameObject);
}
}
Attach The Destroy Code to your Obj Prefab
I have almost finished my first game in Unity, which is a simple maze with characters collecting different coins. As it was a hassle to manually put all the different coins in the terrain, I decided to try and make a random generator for the coins.
The script is largely working, but the problem is that it's spawning objects most of the time inside walls. So I tried to add rigid bodies to coins, but this is messing with the coins position as the coins have a script for rotation. I also have the coins collision triggered because they perform a certain action when colliding with the character.
So after some research I saw that I need to check in my generator script for a near object collision and somehow change the spawn position of the coin if it's true. I'm trying to figure out how I can do that. My script is attached to my terrain and it looks like this:
using System.Collections;
using CustomArrayExtensions;
using UnityEngine;
public class ObjectSpawner : MonoBehaviour
{
[SerializeField] public GameObject[] letters;
GameObject selectedObject;
private int amount = 0;
public int limit;
void Start()
{
StartCoroutine(SpawnObjects());
}
IEnumerator SpawnObjects()
{
selectedObject = letters.GetRandom();
while (amount < limit)
{
Instantiate(selectedObject, new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f)), Quaternion.identity);
yield return new WaitForSeconds(5.0f);
amount++;
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == "Fox_Main")
{
Debug.Log("Collision Detected");
}
}
}
So i tried both answers and they didn't help me.Coins and other objects is still spawning close/inside the walls.My boxes have box collider and rigidbody with all positions/rotations locked(i need it that way so that i can destroy it later without moving it with the character),walls have box collider.So i tried to modify your solutions following Unity Documentation.I failed too.Here is what i have done so far.
See here
using System.Collections;
using UnityEngine;
public class RandomCrates : MonoBehaviour
{
public GameObject[] crates;
private GameObject selectedCrate;
public int limit = 0;
public float x, y, z;
public float forX_From,forX_To,forZ_From,forZ_To;
private int mask = 1 << 7;
void Start()
{
StartCoroutine(SpawnObjects());
}
IEnumerator SpawnObjects()
{
for (int i = 0; i < crates.Length; i++)
{
for (int j = 0; j < limit; j++)
{
Vector3 freePos = GetFreePosition();
Instantiate(crates[i], freePos, Quaternion.identity);
yield return new WaitForSeconds(0.0f);
}
}
}
Vector3 GetFreePosition()
{
Vector3 position;
Collider[] collisions = new Collider[1];
do
{
position = new Vector3(Random.Range(forX_From, forX_To), 10.0f, Random.Range(forZ_From, forZ_To));
} while (Physics.OverlapBoxNonAlloc(position, new Vector3(x, y, z), collisions, Quaternion.identity, mask) > 0);
return position;
}
}
Unity provides a simple way to detect collisions in specific position with Physics.OverlapSphere:
public class ObjectSpawner : MonoBehaviour
{
[SerializeField] public GameObject[] letters;
GameObject selectedObject;
private int amount = 0;
public int limit;
private float radius = 2f; //Radius of object to spawn
void Start()
{
StartCoroutine(SpawnObjects());
}
IEnumerator SpawnObjects()
{
selectedObject = letters[Random.Range(0, letters.Length)];
while (amount < limit)
{
Vector3 spawnPos = new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f));
//Check collisions
if (DetectCollisions(spawnPos) > 0)
continue;
Instantiate(selectedObject, spawnPos, Quaternion.identity);
yield return new WaitForSeconds(5.0f);
amount++;
}
}
private int DetectCollisions(Vector3 pos)
{
Collider[] hitColliders = Physics.OverlapSphere(pos, radius);
return hitColliders.Length;
}
}
In this way, if there is a collision in spawn position, the coin will not be spawned.
There are different ways of approaching this problem and given more information one could come up with a smarter approach. However, to provide you with a simple solution to your problem: You could just pick random positions until you find a "free spot".
Assuming your coins to have a size of 1, you could do something like:
IEnumerator SpawnObjects()
{
selectedObject = letters.GetRandom();
while(amount < limit)
{
Vector3 freePos = GetFreePosition();
Instantiate(selectedObject, freePos), Quaternion.identity);
yield return new WaitForSeconds(5.0f);
amount++;
}
}
Vector3 GetFreePosition()
{
Vector3 position;
Collider[] collisions = new Collider[1];
do
{
position = new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f));
}
while(Physics.OverlapSphereNonAlloc(position, 1f, collisions) > 0);
return position;
}
Please note that Physics.OverlapSphereNonAlloc() can also accept a LayerMask for filtering collisions based on layers. You might want to look into this, to prevent detecting collision with your terrain, which may well keep the do-while loop from exiting and freeze Unity.
im working at a infinit runner game and i want to add objectpooling to the platforms, but i got 2 errors:
Assets\PlatformGenerator.cs(37,26): error CS1501: No overload for method 'SpawnObject' takes 1 arguments
Assets\ObjectPool.cs(36,16): error CS0165: Use of unassigned local variable 'ToReturn'
Here is the platform generator script:
{
public GameObject ThePlatform;
public Transform GenerationPoint;
public float DistanceBetween;
private float PlatFormWidth;
public float DistanceBetweenMin;
public float DistanceBetweenMax;
public ObjectPool PlatformPool;
// Start is called before the first frame update
void Start()
{
PlatFormWidth = ThePlatform.GetComponent<BoxCollider2D>().size.x;
}
// Update is called once per frame
void Update()
{
if(transform.position.x < GenerationPoint.position.x)
{
DistanceBetween = Random.Range(DistanceBetweenMin, DistanceBetweenMax);
transform.position = new Vector3(transform.position.x + PlatFormWidth + DistanceBetween,
transform.position.y, transform.position.z);
//Instantiate(ThePlatform, transform.position, transform.rotation);
PlatformPool.SpawnObject(ThePlatform, transform.position, transform.rotation);
}
}
}
Here is the ObjectPooler script:
{
public GameObject ObjectToPool;
public List<GameObject> ThePool = new List<GameObject>();
public int StartAmount;
// Start is called before the first frame update
void Start()
{
for(int i = 0; i < StartAmount; i++)
{
ThePool.Add(Instantiate(ObjectToPool));
ThePool[i].SetActive(false);
ThePool[i].transform.parent = transform;
}
}
// Update is called once per frame
void Update()
{
}
public GameObject SpawnObject(Vector3 Position)
{
GameObject ToReturn;
ToReturn = ThePool[0];
ThePool.RemoveAt(0);
ToReturn.transform.position = Position;
ToReturn.SetActive(true);
return ToReturn;
}
}
hope you can help me because im new at programming and don't now hot fix things like this and if you see other things i should improve it would be very nice if you tell it me.
In the Object Pooler script you put the following function public GameObject SpawnObject(Vector3 Position) which takes only one argument for position. But in the platform generator you are calling the function with three arguments PlatformPool.SpawnObject(ThePlatform, transform.position, transform.rotation). So, replace the PlatformPool.SpawnObject(ThePlatform, transform.position, transform.rotation) in the platform generator script with PlatformPool.SpawnObject(transform.position);.
First error, your method is only asking for one argument. You are passing 3. (Vector3 just represents the x,y,z points of a transform or a gameObject.) If you wanna dynamically pass a Vector3 object, you can do something like this
Vector3 v = new Vector3 (0,0,0);
then you pass it on to your method SpawnObject(v);
For the second error, make sure ThePool list is not empty and you are assigning them properly, because you are assigning it to ToReturn.
Logging helps a lot, try to debug something like this
Debug.LogError(ThePool == null);
or check it's length
Debug.LogError(ThePool.Length);
if it is, try to add a condition so that you don't get an error
if(ToReturn != null)
// ....
I am newbie to Unity. In my project i have instantiates a ball in the player position. From the Player Position the ball should go to random position 40 to 90 degrees. if the player is in 0,0,0 position. the target should be 10,0,0.
I have done the code. But it is not perfect. I have done something wrong.
randomly it should set the target.
public class Movetowards3: MonoBehaviour {
// Use this for initialization
GameObject go;
public GameObject prefab;
public GameObject Target;
public GameObject endPos1;
public Vector3 endpos2;
float speed = 5f;
public bool s=false;
public GameObject player;
public bool s2=false;
void Start () {
go = Instantiate(prefab, player.transform.localPosition, Quaternion.identity);
}
// Update is called once per frame
void Update () {
player=GameObject.FindGameObjectWithTag("Player");
if(s==true)
{
go = Instantiate(prefab, player.transform.localPosition, Quaternion.identity);
endpos2 =new Vector3(player.transform.position.x+10f,player.transform.position.y,player.transform.position.z);
s=false;
}
if(go.transform.position != endpos2)
{
Vector3 newPos = Vector3.MoveTowards(go.transform.localPosition, endpos2,speed * Time.deltaTime);
go.transform.position = newPos;
}
}
}
I have incremented the value of x, but i think it is not correct.
At its core your code is correct, however the issue is that endpos does not have the chance to instantiate.
I think this is your issue:
Here:
public bool s=false;
You set s to false and you never change it later. This becomes a problem here:
if(s==true)
{
go = Instantiate(prefab, player.transform.localPosition, Quaternion.identity);
endpos2 =new Vector3(player.transform.position.x+10f,player.transform.position.y,player.transform.position.z);
s=false;
}
And, you need these to instantiate to start what you do in the next if statement:
if(go.transform.position != endpos2)
{
Vector3 newPos = Vector3.MoveTowards(go.transform.localPosition, endpos2,speed * Time.deltaTime);
go.transform.position = newPos;
}
So I would recommend that you either make public bool s=true;
Or add and else statement to the first if statement.
Also just a side comment, you instantiate go twice, I don't know if thats intentional but they are doing the same thing.
This is my spawning script belowwritten in c# The script should create objects randomly in the scene.
The issue is that I'm getting this error at runtime.
IndexOutOfRangeException: Array index is out of range.
CreateEasterEggs.MakeThingToSpawn () (at Assets/CreateEasterEggs.cs:52)
CreateEasterEggs.Update () (at Assets/CreateEasterEggs.cs:28)
Not sure what I have done wrong, thinking its something to do with the game object?
Thank you.
using UnityEngine;
using System.Collections;
public class CreateEasterEggs : MonoBehaviour
{
public float secondsBetweenSpawning = 0.1f;
public float xMinRange = -25.0f;
public float xMaxRange = 25.0f;
public float yMinRange = -5.0f;
public float yMaxRange = 0.0f;
public float zMinRange = -25.0f;
public float zMaxRange = 25.0f;
public GameObject[] spawnObjects; // what prefabs to spawn
private float nextSpawnTime;
void Start ()
{
// determine when to spawn the next object
nextSpawnTime = Time.time+secondsBetweenSpawning;
}
void Update ()
{
// if time to spawn a new game object
if (Time.time >= nextSpawnTime) {
// Spawn the game object through function below
MakeThingToSpawn ();
// determine the next time to spawn the object
nextSpawnTime = Time.time+secondsBetweenSpawning;
}
}
void MakeThingToSpawn ()
{
//Start the vector at an invalid position
Vector3 spawnPosition = new Vector3(0, 0, 0);
//while we are not in the right range, continually regenerate the position
while ((spawnPosition.z < 4 && spawnPosition.z > -4) || (spawnPosition.x < 4 && spawnPosition.x > -4))
{
spawnPosition.x = Random.Range (xMinRange, xMaxRange);
spawnPosition.y = Random.Range (yMinRange, yMaxRange);
spawnPosition.z = Random.Range (zMinRange, zMaxRange);
}
// determine which object to spawn
int objectToSpawn = Random.Range (0, spawnObjects.Length);
// actually spawn the game object
GameObject spawnedObject = Instantiate (spawnObjects [objectToSpawn], spawnPosition, transform.rotation) as GameObject;
// make the parent the spawner so hierarchy doesn't get super messy
spawnedObject.transform.parent = gameObject.transform;
}
}
IndexOutOfRange means that you tried to access to an element of an array that doesn't exist.
In your case as you are doing it with Random.Range (0, spawnObjects.Length); Then the only possible case is that your array is empty.
Try to Debug.Log(spawnObjects.Length): before the Instantiate and you will see that in fact your array of gameobjects is empty as It will return 0.