- Home /
Spawned Objects not appearing
Hello so i'm trying to make a tower defense game, i have the movement from http://forum.unity3d.com/threads/54678-A-Waypoint-Script-Explained-in-Super-Detail! which works a treat with one object. However i'm trying to spawn more then one object, the below code spawns clones of a enemy prefab i've made. However only 1 clone appears and moves in unity. (the waypoint script is attached to a in game object, and the spawn is attached to a separate in game object)
public GameObject spawnedObject;
int totalCreatures = 18;
int liveCreatures = 0;
float WaveTimeSetup = 20;
float waveTime;
// Use this for initialization
void Start () {
spawn();
}
// Update is called once per frame
void Update () {
}
void spawn(){
for (int i = 0; i < 10; i++)
Instantiate(spawnedObject , transform.position, Quaternion.identity);
}
}
Answer by ATMEthan · Feb 18, 2013 at 07:48 PM
Your code should look something like this:
using UnityEngine;
using System.Collections;
public class HelpingNoobs : MonoBehaviour {
//prefab of the enemy to make
public GameObject enemyPrefab;
//used when we instantiate an new enemy
private GameObject spawnedObject;
//a reference of all the spawned objects
private List<GameObject> spawnedObjects;
//total number of creatures in a level
private int totalCreatures = 18;
//number of alive creatures
private int liveCreatures = 0;
// Use this for initialization
void Start () {
//at the start we spawn/initializes all of the enemies for the level
spawn();
}
void Spawn() {
//here we instantiate and save the reference to the enemies in a list
spawnedObjects = new List<GameObject>();
for(int index = 0; index <= totalCreatures; index++) {
spawnedObject = Instantiate(enemyPrefab , transform.position, Quaternion.identity);
spawnedObjects.Add(spawnedObject);
liveCreatures++;
}
}
// Update is called once per frame
void Update () {
//in every update we update the list of enemies and mkae them move/die
foreach(GameObject enemy in spawnedObjects) {
//here is where you put your
//logic to update and move your enemies
enemy.move();
if(enemy.Health <= 0)
enemy.KillMe();
}
}
}
Please don't take offense to the class name.
So, when you level starts this script will execute the start method. This is when we want to spawn the enemies and position them. Then in the update you'll update every enemy so they will move along the path you supplied. One thing this script does NOT take into account is a staggerness for you enemies. IE most likely all of these enemies will be placed on top of each other since their initial position is the same for each enemy. So, this may explain why you only see one enemy(they are all on top of each other). So to account for this you'll have to add like a 50pixel offset so each enemy is 50 pixels behind the enemy in front of it.
And it goes without saying you'll have to provide your own logic for the enemy.$$anonymous$$ove() and enemy.$$anonymous$$ill$$anonymous$$e() methods. Those should probably be in their own script that is attached to the enemy prefab.
thankyou for the help.
I'm getting this error though
error CS0246: The type or namespace name `List`1' could not be found. Are you missing a using directive or an assembly reference?
You are missing a using statement at the top. If you right click on the List keyword, you should get an option that says resolve -> using system.collections.generic; or alternatively if you don't see that just type using system.collections.generic with the other using statements
Okay thankyou, i got a few more errors but i felt bad for just copying your code. So i'm back using the code below. It spawns A object now, that moves ect. I'm running into difficulty in figuring out how to space the objects from one another, so they don't spawn on top of another.
public GameObject spawnedObject;
int totalCreatures = 20;
int liveCreatures = 0;
public GameObject maxCreatures;
float WaveTimeSetup = 20;
float waveTime;
public Transform[] spawnedObjects;
// Use this for initialization
void Start () {
liveCreatures=0;
}
// Update is called once per frame
void Update () {
if(liveCreatures==0)
{
spawn();
}
}
void spawn(){
for (int i = 0; i < 5; i++)
{
Instantiate( spawnedObject, transform.position, Quaternion.identity);
liveCreatures++;
}
}
}
Ok, this isn't too hard. When you do your Instantiate, you are always using the position 'transform.position.' So, let's say that Vector value is (0,0,0). All of your enemies are spawning at the position (0(x),0(y),0(z)). So what we have to do is make it so the next enemy spawns behind him. (I assume you are doing this in 2D and that you are using the x-axis as horizontal points and y-axis as vertical points, the standard cartesian plane). So, there are many ways to increment the position I'll show you two ways:
//here is 1 way
//let's save the position in a new variable so we can make changes to it without changing the original position
Vector3 spawnPosition = transform.position;
// this will be our offset, so if the first enemy spawns at (0,0,0) the next will spawn at (50,0,0)
float spawnPositionOffset = 50;
void Spawn() {
for (int i = 0; i < 5; i++)
{
// this makes and enemy at position (0,0,0) in the first iteration, the 2nd iteration will spawn an enemy at (50,0,0), the 3rd at (100,0,0) etc..
Instantiate(spawnedObject, spawnPosition, Quaternion.identity);
liveCreatures++;
//here we increment our spawn position by 50 units in the positive direction but we keep the same y and x value so they spawn in a line
spawnPosition = new Vector3((spawnPosition.x + spawnPositionOffset), spawnPosition.y, spawnPosition.x);
}
}
//here is a 2nd way
Vector3 spawnPosition = transform.position;
float spawnPositionOffset = 50;
void Spawn() {
for (int i = 0; i < 5; i++)
{
Instantiate(spawnedObject, spawnPosition, Quaternion.identity);
liveCreatures++;
incrementSpawnPosition();
}
}
void incrementSpawnPosition() {
spawnPosition = new Vector3((spawnPosition.x + spawnPositionOffset), spawnPosition.y, spawnPosition.x);
}
Now, as you might notice these two ways are basically the same thing. Although we put the logic to increment the position in its own method ins$$anonymous$$d of doing it in the for loop in the spawn method. Now, this gives us the ability to change the increment logic without cluttering the spawn method. So, for example if you wanted to make 3 by 3 rows of enemies, obviously the code supplied doesn't work since it only offsets the next enemy on the x-axis. So, all you have to do n ow is change the incrementSpawnPosition() and nothing changes in the spawn() method. This is just a good practice so methods like spawn() aren't cluttered with other logic. If you didn't do it this way and you started making more complicated spawn position the for loop would start to get bulky and cluttered which make code readability much worse. So, for something simple you wouldn't need to make the increment method but on more complicate things you might want to so your code stays cleaner looking (As a good programmer tip, methods should only handle/do one thing)
Answer by Grz · Feb 18, 2013 at 07:22 PM
from the looks of the code, it would appear that you spawn 10 objects, but all at the same position. Check your hierarchy view and see if there are 10 objets in there, it might just look like 1 in the game view.
hey thanks, yea 10 items appear in the hierarchy. However only 2 objects are actually spawning in game and moving with the waypoint script attached.
Answer by froYo · Feb 18, 2013 at 06:53 PM
Hey, your for loop should look like this:
for(int i = 0; i < 10; i++)
{
Instantiate(spawnedObject , transform.position, Quaternion.identity);
}
as your for loop was missing the {}
Hope this helps :)
Hey man thanks for that, however only 2 objects are spawning ins$$anonymous$$d of 10 =(, also if i set it up like below, it just keep spawning and spawning, not sure how to set a limit on it.
void Start () {
liveCreatures=0;
}
// Update is called once per frame
void Update () {
if(liveCreatures==0)
{
spawn();
}
}
void spawn(){
for (int i = 0; i < 5; i++)
{
Instantiate( spawnedObject, transform.position, Quaternion.identity);
}
}
}
for loops don't require a block (delimited with {}). A single statement is also acceptable. But I HIGHLY suggest always using braces!
I don't see that liveCreatures is ever being changed. If it isn't incremented, then you should get 5 new objects spawned EVERY FRA$$anonymous$$$$anonymous$$
@greg1992: You aren't incrementing livecreatures so its always going to be zero and Spawn() is always going to be called on Update()
Although froYo's comment about the missing {} is valid. Statements that use {} but only have 1 line of execution do not need the {} So to clarify look at these examples:
//this is the same
for (int i = 0; i < 5; i++)
{
Instantiate( spawnedObject, transform.position, Quaternion.identity);
}
//as this
for (int i = 0; i < 5; i++)
Instantiate( spawnedObject, transform.position, Quaternion.identity);
//this is not the same
for (int i = 0; i < 5; i++)
{
Instantiate( spawnedObject, transform.position, Quaternion.identity);
doSomethingElse(); //this will execute in the for loop
}
//as this
for (int i = 0; i < 5; i++)
Instantiate( spawnedObject, transform.position, Quaternion.identity);
doSomethingElse(); //this line is NOT executed in the for loop
//it will be executed after the for loop`
It's more of a personal preference at this point. Although, I agree with froYo and that you should have the { } b/c you never know when you'll want to add another line. I hope this didn't confuse you!
okay thanks, is there a way to set a limit on the amount of times something is spawned?