Instantiating a list of gameobjects in Unity C# - c#

How can I instantiate a list of GameObject in Unity3D using c#?
I fill the list with prefabs manually in inspector window.
Below is the code I've written in Deck.cs, but I get "Object reference is not set to an instance of an object". If you have a solution with an array, that will be appreciated as well.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
namespace Assets
{
class Deck:MonoBehaviour
{
public List<GameObject> deck;
public void Fill()
{
GameObject c1 = Instantiate(deck[0]);
GameObject c2 = Instantiate(deck[1]);
GameObject c3 = Instantiate(deck[2]);
GameObject c4 = Instantiate(deck[3]);
GameObject c5 = Instantiate(deck[4]);
GameObject c6 = Instantiate(deck[5]);
}
}
}
I also tried doing it with an array and I get 'The object you want to instantiate is null'
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
namespace Assets
{
class Deck:MonoBehaviour
{
public GameObject card1;
public GameObject card2;
public GameObject card3;
public GameObject card4;
public GameObject card5;
public GameObject card6;
public GameObject[] deck;
public void Start ()
{
deck = new GameObject[5];
GameObject c1 = Instantiate(card1) as GameObject;
GameObject c2 = Instantiate(card2) as GameObject;
GameObject c3 = Instantiate(card3) as GameObject;
GameObject c4 = Instantiate(card4) as GameObject;
GameObject c5 = Instantiate(card5) as GameObject;
GameObject c6 = Instantiate(card6) as GameObject;
}
}
}

Well considering your comments and that the first script your provided works perfectly without any error (as it should: there's no reason it should return an error), I feel like you are very new to Unity.
Therefore I'd recommend you to look to the Unity tutorials before anything else (they are quite well made and will help you understand the basics of the engine). You can find the Roll-a-ball tutorial here.
About your question:
1- In the first script, the Fill() method isn't called anywhere, you have to do something like this:
private void Start()
{
Fill();
}
2- This Start() method comes from the MonoBehaviour parent class (as well as the Update() method which is called every frame) and is called once at the beginning of the scene. Look to this chart to understand how unity flow is made.
3- Using a List<GameObject> or a GameObject[] all depends on your situation: if the size of the collection is going to change, go for a list. Otherwise array is advised.
4- Considering your script my guess is it should look like this:
namespace Assets
{
class Deck : MonoBehaviour
{
[SerializeField]
private GameObject[] deck;
private GameObject[] instanciatedObjects;
private void Start()
{
Fill();
}
public void Fill()
{
instanciatedObjects = new GameObject[deck.Length];
for (int i = 0; i < deck.Lenght; i++)
{
instanciatedObjects[i] = Instanciate(deck[i]) as GameObject;
}
}
}
}
You can of course still use lists if needed :)
EDIT:
If you want to use a list you simply have to:
change private GameObject[] instanciatedObjects; to private List<GameObject> instanciatedObjects;
replace instanciatedObjects = new GameObject[deck.Length]; by instanciatedObjects = new List<GameObject>();
replace instanciatedObjects[i] = Instanciated(deck[i]) as GameObject; by instanciateObjects.Add(Instanciated(deck[i]) as GameObject);
Hope this helps,

Use foreach to loop over your List with prefabs, like this:
public List<GameObject> Deck = new List<GameObject>(); // im assuming Deck is your list with prefabs?
public List<GameObject> CreatedCards = new List<GameObject>();
void Start()
{
Fill();
}
public void Fill()
{
foreach(GameObject _go in Deck)
{
GameObject _newCard = (GameObject)Instantiate(_go);
CreatedCards.Add(_newCard);
}
}
Also it's a good habit to name your lists with capital letter.

Related

Unity Says There is No Namespace called "Player"

I am trying make an infinite level generator that gets level parts I give to it and mix's them up to make infinite long an unique levels for me. but the problem is that When I Typed [SerializeField] private Player player; it said No namespace called "Player" which is odd because There are other code's were Player player is used and it works.Maybe I am just dumb but anyway here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LevelGenerator : MonoBehaviour {
private const float PLAYER_DISTANCE_SPAWN_LEVEL_PART = 200f;
[SerializeField] private Transform levelPart_Start;
[SerializeField] private List<Transform> levelPartList;
[SerializeField] private Player player;
private Vector3 lastEndPosition;
private void Awake() {
lastEndPosition = levelPart_Start.Find("EndPosition").position;
int startingSpawnLevelParts = 5;
for (int i = 0; i < startingSpawnLevelParts; i++) {
SpawnLevelPart();
}
}
private void Update() {
if (Vector3.Distance(player.GetPosition(), lastEndPosition) < PLAYER_DISTANCE_SPAWN_LEVEL_PART) {
SpawnLevelPart();
}
}
private void SpawnLevelPart() {
Transform chosenLevelPart = levelPartList[Random.Range(0, levelPartList.Count)];
Transform lastLevelPartTransform = SpawnLevelPart(chosenLevelPart, lastEndPosition);
lastEndPosition = lastLevelPartTransform.Find("EndPosition").position;
}
private Transform SpawnLevelPart(Transform levelPart, Vector3 spawnPosition) {
Transform levelPartTransform = Instantiate(levelPart, spawnPosition, Quaternion.identity);
return levelPartTransform;
}
}
I have tried to make in into a game object but then I got even more errors
No namespace called "Player"
It makes me think that the problem is in the Using.
In some parts of your code it accepts it because you are using it or it is in the same namespace.
Assuming it is called like this, try adding the using as follows
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Player; (it can change but should be like this)

C# errror "CS0116: A namespace cannot directly contain members such as fields or methods"

I get an error, Assets\scripts\Skins.cs(9,12): error CS0116: A namespace cannot directly contain members such as fields or methods on the Internet they write what it means incorrectly placed brackets, but I don’t see any errors
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public GameObject choise1;
public GameObject choise2;
public GameObject choise3;
public int skin = 1;
public class Skins : MonoBehaviour {
void Choise () {
if (Input.GetMouseDown(choise1)){
choise2.SetActive (false);
}
}
}
GameObject and that int skin need to be under Skins class, like Choise
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Skins : MonoBehaviour {
public GameObject choise1;
public GameObject choise2;
public GameObject choise3;
public int skin = 1;
void Choise () {
if (Input.GetMouseDown(choise1)){
choise2.SetActive (false);
}
}
}
If you still have some problems here, because I don't know what are u trying to do with that choiseX, maybe you need to create them.
I mean, maybe u are trying to write something like this
void Choise () {
var GameObject choise1 = new GameObject();
var GameObject choise2 = new GameObject();
var GameObject choise3 = new GameObject();
int skin = 1;
if (Input.GetMouseDown(choise1)){
choise2.SetActive (false);
}
}

Unity3D Shooter: Using tags to switch level after killing all enemies

I am new to Unity and was trying, after some suggestions, to use tags to know the number of enemies i have in each level and move to the next scene right after eliminating all enemies. This is the script i use on enemy gameobjects. I've also tagged each of them with the "enemy" tag in unity inspector but it still doesn't work when i run the game. After killing all the enemies, it didn´t change to next scene (Success!). Any ideas on what I'm doing wrong? Any other suggestions?
Thanks a lot for the help.
Enemies Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BadguyScript : MonoBehaviour
{
public GameObject[] enemies;
public int maxHealth;
public int curHealth;
private Animator myAnimator;
private bool isDead;
[SerializeField]
private float DespawnTime = 2.5f;
[SerializeField]
private string DeathAnimHash = "isDead";
void Start()
{
myAnimator = GetComponent<Animator>();
myAnimator.enabled =true;
myAnimator.SetBool (DeathAnimHash ,isDead);
maxHealth = 1;
curHealth = maxHealth;
}
void Update()
{
if (curHealth < 1)
{
isDead = true;
myAnimator.SetBool (DeathAnimHash ,isDead);
Destroy(gameObject,DespawnTime);
}
enemies = GameObject.FindGameObjectsWithTag("enemy"); // Checks if enemies are available with tag "Enemy".
if (enemies.Length == 0)
{
SceneManager.LoadScene("SucessScene"); // Load the scene with name "SucessScene"
}
}
void OnTriggerEnter2D(Collider2D col)
{
if (isDead)
return;
if (col.tag == "bullet")
{
curHealth -= 1;
Destroy(col.gameObject);
}
}
}
I would create a script holder gameobject for this and put a GameManager script inside it. And inside GameManager.cs which should be a singleton class you can have a property like this:
int _enemyNumber;
public int EnemyNumber{
get{
return _enemyNumber;
}
set{
_enemyNumber = value;
}
}
And when you need to change these values, use some functions you will create inside this game controller such as:
public void DecreaseEnemyCount(){
//do the logic here
}
public void SetEnemyCount(){
//do the logic here
}
Also you can find information about creating a singleton class here
You create a list with all enemies, its a good practice, cause you'll gain performance. But you're verifing if enemies.Lenght == 0, what will never occur, because before you are adding the gameObject in the list enemies = GameObject.FindGameObjectsWithTag("enemy");
In the start method, you can search for all enemies and add then in your array, and in the update or onTriggerEnter you remove it from your array and validate the array lenght. I think it'll be more easy.
Instead of adding the script to a new gameManager script attached to an empty game object cause now once all enemies are killed the script will not be in work but if added to an empty gameobject it will be working always.

Unity Engine - Instantiate a prefab by collision

I have a GameObject called Player.
Attached to Player there is a script component called Player ( same )
Inside the Player's script, I have a field called _weaponPrefab ( GameObject type )
In the Inspector, I can easily drag & drop any prefabs from my Prefab folder, inside the _weaponPrefab variable.
All good so far. What I want to archive is: to be able to add my Prefabs based on a Collision2D. So if my Player collides with a Prefab, let's say a Sword, the prefab of that sword will be automatically attached and insert into the _weaponPrefab field inside the Player script.
Below my Player script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField] private float _speed = 5.0f;
[SerializeField] private float _fireRate = 0.2f;
private bool _canFire = true;
[SerializeField] private GameObject _weaponPrefab; <- to populate runtime
// Use this for initialization
void Start ()
{
transform.position = Vector3.zero;
}
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown(KeyCode.Space) && _canFire)
StartCoroutine(Shoot());
}
void OnTriggerEnter2D(Collider2D other)
{
//here i don't know how to continue.
}
public IEnumerator Shoot()
{
_canFire = false;
Instantiate(_weaponPrefab, transform.position + new Vector3(0, 1, 0), Quaternion.identity);
yield return new WaitForSeconds(_fireRate);
_canFire = true;
}
}
Edit: i just wrote a comment of where i don't know how to proceed.
There are many ways to accomplish what you desire.
My suggestion may be out of your comfort zone at first, but it will provide you with most flexibility and eventually easy of programming/ designing/ maintaining your game (in my opinion).
First make a scriptable object (what is a scriptable object and how do i use it?)
using UnityEngine;
using System.Collections;
using UnityEditor;
public class Item
{
[CreateAssetMenu(menuName = "new Item")]
public static void CreateMyAsset()
{
public GameObject prefab;
// you can add other variables here aswell, like cost, durability etc.
}
}
Create a new item (in Unity, Assets/new Item)
Then create a monobehaviour script which can hold the item. In your case let's name it "Pickup".
public class Pickup : MonoBehaviour
{
public Item item;
}
Finally in your player script, change your on TriggerEnter to:
void OnTriggerEnter2D(Collider2D other)
{
if(other.GetComponentInChildren<Pickup>())
{
var item = other.GetComponentInChildren<Pickup>().item;
_weaponPrefab = item.prefab;
}
}
When you instantiate a GameObject you need to pass basically 3 parameters (However not all of them are mandatory, check):
The prefab
The position
The rotation
Let's assume you have a placeholder in the hand or in the back of your character, to keep there the weapon once collected. This placeholder can be an empty gameobject (no prefab attached, but will have a transform.position component)
Now let's assume you have a list of weapons in the scene with their prefab and with a different tag each. Then you can do something like this:
GameObject weapon;
GameObject placeholder;
public Transform sword;
public Transform bow;
...
void OnTriggerEnter2D(Collider2D other)
{
//You can use a switch/case instead
if(other.gameObject.tag == "sword"){
Instantiate(sword, placeholder.transform.position, Quaternion.identity);
}else if(other.gameObject.tag == "bow"){
Instantiate(bow, placeholder.transform.position, Quaternion.identity);
}...
}
What I'll do is load the prefabs first in a Dictionary<string, GameObject> from the resources folder.
First I populate the dictionary with all the weapon prefabs in the Start method with the tag of the object as a key. Then in the OnTriggerEnter2D I check if the tag is in the dictionary then I instantiate it from there.
Take a look at the code :
private Dictionary<string, GameObject> prefabs;
// Use this for initialization
void Start () {
var sword = (GameObject) Resources.Load("Weapons/sword", typeof(GameObject));
prefabs.Add("sword", sword);
// Add other prefabs
};
void OnTriggerEnter2D(Collider2D other)
{
if (prefabs.ContainsKey(other.tag))
Instantiate(prefabs[other.tag]);
}
NOTE : your prefabs needs to be in the folder Assets/Resources/Weapons because I used Resources.Load("Weapons/sword", typeof(GameObject));

How i use array of vector3 to list in inspector all vector3 in list?

In the top of script:
public Vector3[] positionsList;
List<Vector3> positions = new List<Vector3>();
In Update: I'm updating the List but i also want to update the array so i can watch the vector3 positions in the inspector while the game is running.
var position = GenerateRandomPositions(objects[0]);
if (!positions.Contains(position))
{
positions.Add(position);
}
Simply make the List public, the inspector can handle it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ListInInspectorTest : MonoBehaviour {
public List<Vector3> superawesomeListOfVector3s;
void Update () {
if(superawesomeListOfVector3s.Count < 10) {
superawesomeListOfVector3s.Add(Random.insideUnitSphere);
}
}
}
If it is important that the variable is private or protected to other code. you could add the [SerializeField] tag above the variable that you want to see in the inspector. source (https://unity3d.com/learn/tutorials/topics/tips/show-private-variables-inspector)

Categories