spawn gameobject from array - c#

I'm having some trouble spawning a random asteroid from an array within a for loop.
The array is working now, however (I assume this is in the for loop somewhere) it wont alternate between the different game objects. whichever object spawns first, spawns every time, but each time you load the game it spawns a different one every time.
How do I get it to chose a new random object from the array after every spawn instance?
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public GameObject[] asteroids;
public Vector3 spawnValues;
public int asteroidCount;
public float spawnWait;
public float startWait;
public float waveWait;
void Start () {
StartCoroutine (spawnWaves ());
}
IEnumerator spawnWaves () {
GameObject asteroid = asteroids[Random.Range(0, asteroids.Length)];
while (asteroidCount > 0) {
for (int i = 0; i < asteroidCount; i++) {
Vector3 spawnPosition = new Vector3 (spawnValues.x, Random.Range (-spawnValues.y, spawnValues.y), spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (asteroid, spawnPosition, spawnRotation);
yield return new WaitForSeconds (spawnWait);
}
}
}
}

you select the object to spawn outside the loop
GameObject asteroid = asteroids[Random.Range(0, asteroids.Length)];
needs to be here
while (asteroidCount > 0) {
for (int i = 0; i < asteroidCount; i++) {
GameObject asteroid = asteroids[Random.Range(0, asteroids.Length)];

Related

Checking collisions in near objects for random object spawning in Unity 5

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.

Infinite runner has bumps. How do I smooth it?

I have a script that spawns my ground prefabs infinitely. The only problem is that occasionally there is a "bump" for the player to hit at the boundary of a new ground prefab.
It seems like one prefab is slightly higher than the previous one and when the player hits that small bump they go flying. How do I fix this?
I might just make the player a game object instead of a rigidbody and animate it instead of using actual physics.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GroundManager : MonoBehaviour
{
//oH is object height
public GameObject[] ground;
public GameObject[] obstacles;
private Transform playerTransform;
private float spawnZ = 0.0f;
private float spawnO = 0.0f;
public float oH;
private float tileLength = 40.0f;
private float oLength = 36.0f;
private int tilesOnScreen = 8;
void Start()
{
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
for (int i = 0; i < tilesOnScreen; i++)
{
SpawnTile();
SpawnObstacle();
}
}
// Player must be tagged "Player"
void Update()
{
if (playerTransform.position.z > (spawnZ - tilesOnScreen * tileLength))
{
SpawnTile();
SpawnObstacle();
}
}
private void SpawnTile(int prefabIndex = -1)
{
GameObject go;
go = Instantiate(ground[0]) as GameObject;
go.transform.SetParent(transform);
go.transform.position = Vector3.forward * spawnZ;
spawnZ += tileLength;
}
private void SpawnObstacle()
{
GameObject go;
go = Instantiate(obstacles[Random.Range(0, obstacles.Length)]) as GameObject;
go.transform.SetParent(transform);
go.transform.position = new Vector3(0, oH, 1 * spawnO);
spawnO += oLength;
}
}
This code works to infinitely spawn the ground objects but has the bumps that I described. Just one bump is enough to screw up the whole game.

Unity3d scripting error c# IndexOutOfRangeException: Array index is out of range

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.

Spawning game object unity (C#)

I writing simple runner game.
I have game object (quad).
I want it to generate.
I wrote spawnscript:
using UnityEngine;
using System.Collections;
public class SpawnScript : MonoBehaviour {
public GameObject[] obj;
//public GameObject obj;
public float spawnMin = 1f;
public float spawnMax = 2f;
// Use this for initialization
void Start () {
Spawn();
}
void Spawn()
{
//for (int i = 0; i < 10; i++)
// Instantiate(obj, new Vector3(i * 2.0f, 0, 0), Quaternion.identity);
Instantiate(obj[Random.Range(0, obj.GetLength(0))], transform.position, Quaternion.identity);
Invoke("Spawn", Random.Range(spawnMin, spawnMax));
}
}
But my quad spawning one time.I need it to spawn multiple times.
Where is my problem?
Use InvokeRepeating instead of Invoke in start event:
// Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
InvokeRepeating("Spawn", 3, 3);
If you do InvokeRepeating("Function", 1.0f, 1.0f), it will call Function one second after the InvokeRepeating call and then every one second thereafter.
Hence, you can control the spawn timings.
Update
As asked in comments:
You can also cancel InvokeRepeating any time by calling below code. More information here.
CancelInvoke("Spawn");
There is no problem with code. All GameObjects instantiated same position so you can use code below:
public float spawnDistanceFactor = 2f; //Value is your choice. You can change it.
void Spawn()
{
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
Instantiate(obj, spawnPos, Quaternion.identity);
startPosX+=spawnDistanceFactor;
}
}
It is only moves positions on X axis you can move it x,y,z.
Also
You can use Random function for moving spawn position
public float randomMin = 2f;
public float randomMax = 4f;
void Spawn()
{
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
Instantiate(obj, spawnPos, Quaternion.identity);
float randomX = Random.Range(randomMin,randomMax);
startPosX+=randomX;
}
}
You can do a lot of things.
For destroying prefabs you can add Destroy script to object (You should create prefab with script) Like:
void DestroyObject(){
Destroy(this.gameObject);
}
or use list to hold pointers to the GameObjects. Like:
using System.Collections.Generic; // For list
private List<GameObject> objectList;
public float randomMin = 2f;
public float randomMax = 4f;
void Start(){
objectList = new List<GameObject>();
Spawn();
}
void Spawn()
{
objectList.Clear(); ///For multiple spawn purpose dont dublicate items.
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
GameObject newObject = Instantiate(obj, spawnPos, Quaternion.identity) as GameObject;
objectList.Add(newObject);
float randomX = Random.Range(randomMin,randomMax);
startPosX+=randomX;
}
}
void DestroyObject(){
for(int i=0;i<objectList.Count;i++){
Destroy(objectList[i]);
}
}

How to spawn enemy at random intervals?

I am using EnemyScript to move the enemy towards the player and killing the player, but I'm unable to spawn it randomly in code. I am currently spawning it directly through screen by placing the prefab on the scene.
Here is my EnemyScript
using UnityEngine;
using System.Collections;
public class EnemyScript : MonoBehaviour {
public Transform target;
public float speed = 2f;
void Update ()
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
void OnTriggerEnter2D(Collider2D otherCollider)
{
PlayerControl shot = otherCollider.gameObject.GetComponent<PlayerControl>();
if (shot != null)
{
Destroy(shot.gameObject);
}
}
}
you could use something similar to this:
public GameObject myObj;
void Start ()
{
enemy = GameObject.Find("enemy");
InvokeRepeating("SpawnEnemy", 1.6F, 1F);
}
public void SpawnEnemy()
{
Vector3 position = new Vector3(Random.Range(35.0F, 40.0F), Random.Range(-4F, 2F), 0);
Instantiate(myObj, position, Quaternion.identity);
}
in the InvokeRepeating call you could possibly add the random range there also instead of a timed instantiate. This example is just a snippet of some prototype code i did a while ago, it may not suit your needs directly but hopefully will give you a general idea on what to do.
EDIT: to make sense, put this into a blank object somewhere in your scene, dont attach this to the actual enemy.
i programmed it like this.
public GameObject enemyPrefab;
public float numEnemies;
public float xMin = 20F;
public float xMax = 85F;
public float yMin = 3.5F;
public float yMax = -4.5F;
void Start () {
for (int i=0; i< numEnemies; i++) {
Vector3 newPos = new Vector3(Random.Range(xMin,xMax),Random.Range(yMin,yMax),0);
GameObject enemy = Instantiate(enemyPrefab,newPos,Quaternion.identity) as GameObject;
}
}
This will spawn a random number of enemies, at random locations, after random periods of time, all adjustable in the Inspector.
public float minTime = 1;
public float maxTime = 3;
public int minSpawn = 1;
public int maxSpawn = 4;
public Bounds spawnArea; //set these bounds in the inspector
public GameObject enemyPrefab;
private spawnTimer = 0;
Vector3 randomWithinBounds(Bounds r) {
return new Vector3(
Random.Range(r.min.x, r.max.x),
Random.Range(r.min.y, r.max.y),
Random.Range(r.min.z, r.max.z));
}
void Update() {
spawnTimer -= Time.deltaTime;
if(spawnTimer <= 0) {
spawnTimer += Random.Range(minTime, maxTime);
int randomSpawnCount = Random.Range(minSpawn, maxSpawn);
for(int i = 0; i < randomSpawnCount; i++) {
Instantiate(transform.transformPoint(enemyPrefab), randomWithinBounds(spawnArea), Quaternion.identity);
}
}
}
//bonus: this will show you the spawn area in the editor
void OnDrawGizmos() {
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = Color.yellow;
Gizmos.drawWireCube(spawnArea.center, spawnArea.size);
}
People on here seem to like using coroutines for time delays, but I personally prefer to track my own timers in Update() to maximize control and predictability.

Categories

Resources