I am trying to automatically list all declared variables on my class. I am working on a pooling script, so for each gameobject I have a prefab, an array, an array size and a pool size. (they all follow naming standards, prefab name + "array" for array and etc).
private GameObject _PlayerLaserPrefab;
private GameObject[] _PlayerLaserPrefabArray;
private int _PlayerLaserPrefabPoolsize = 30;
private Queue<Transform> _PlayerLaserPrefabQueue = new Queue<Transform>();
private void Initiate_PlayerLaserPrefabPool()
{
_PlayerLaserPrefabArray = new GameObject[_PlayerLaserPrefabPoolsize];
for (int i = 0; i < _PlayerLaserPrefabPoolsize; i++)
{
_
PlayerLaserPrefabArray[i] = Instantiate(_PlayerLaserPrefab,Vector3.zero,
Quaternion.identity) as GameObject;
Transform Obj=PlayerLaserPrefabArray[i].GetComponent<Transform>();
ObjTransform1.parent = transform;
_PlayerLaserPrefabQueue.Enqueue(ObjTransform1);
_PlayerLaserPrefabArray[i].SetActive(false);
}
}
this code has to be repeated for all game´s objects so I am looking for a method to dynamically generate these funcions and variables based on the object´s name.
//pseudo code would be:
foreach (gameobject in list)
create array
create queue
initiate pool
Generate spawn function
Related
I am new to Unity as I am new to C#. I'm making a 2D endless runner, but I ran into some problems when I try to destroy the instantiated prefabs(level parts). I tried a few ways that I found online, but these methods destroyed the prefab that was instantiated latest(for example if I instantiated 10 level parts, only the 10th was destroyed). I'm looking for something that destroys the earliest instantiated prefabs.
Thanks for your help! Have a good one :)
The code I have:
public class LevelGenerator : MonoBehaviour{
private const float distance_to_spawn = 100f;
[SerializeField]private List<Transform> LevelPartList;
[SerializeField]private Transform LevelPart0;
[SerializeField]private GameObject player;
private Vector3 lastEndingBlock;
private Vector3 distance = new Vector3(5,3,0);
private Transform lastLevelPartTransform;
// the starting point of the spawning process
private void Awake()
{
lastEndingBlock = LevelPart0.Find("ending_block").position;
}
// calling the spawning function, so it's infinite
private void Update()
{
if(Vector3.Distance(player.transform.position,lastEndingBlock) < distance_to_spawn)
{
SpawnLevelPart();
}
}
// choose randomly out of the prefabs(level parts)
private void SpawnLevelPart()
{
Transform chosenLevelPart = LevelPartList[Random.Range(0,LevelPartList.Count)];
lastLevelPartTransform= SpawnLevelPart(chosenLevelPart,lastEndingBlock - distance);
lastEndingBlock = lastLevelPartTransform.Find("ending_block").position;
}
// the function used to spawn new level parts
private Transform SpawnLevelPart(Transform LevelPart,Vector3 spawnPosition)
{
Transform levelPartTransform = Instantiate(LevelPart,spawnPosition,Quaternion.identity);
return levelPartTransform;
}
}
Intead of keeping the spare private Transform lastLevelPartTransform; I would keep the, in a Queue like so:
private Queue<Transform> transformsToDestroy = new Queue<Transform>();
// choose randomly out of the prefabs(level parts)
private void SpawnLevelPart()
{
Transform chosenLevelPart = LevelPartList[Random.Range(0,LevelPartList.Count)];
gosToDestroy.Enqueue(SpawnLevelPart(chosenLevelPart,lastEndingBlock - distance));
lastEndingBlock = lastLevelPartTransform.Find("ending_block").position;
}
So that wherever you need, you can Destroy(transformsToDestroy.Dequeue().gameObject)
Hello Gergő Starosta! If you want to delete objects that you instantiating before, you can basically collect all instantiated objects under one parent object.
private Transform SpawnLevelPart(Transform LevelPart,Vector3 spawnPosition)
{
Transform levelPartTransform = Instantiate(LevelPart,spawnPosition,Quaternion.identity);
levelPartTransform.parent = parentObject.transform;
return levelPartTransform;
}
After that, you can use this:
Destroy(parentObject.GetChild[ChildNumber])
I want an array of game objects, each game object has a simple script to move it. I want a controlling script to be able to trigger the remote script by referencing the array coordinates / game object at that point.
I am missing something basic in referencing a "global" variable - so apologies in advance. I have spent several hours now reading and trying things out.
Example questions like here Accessing a variable from another script C#
or
https://answers.unity.com/questions/42843/referencing-non-static-variables-from-another-scri.html
I believe the array should be static as there is only one set of data, however I don't care if it isnt
CreateGrid.cs
public class CreateGrid : MonoBehaviour
{
public static GameObject[,] gridArray = new GameObject[5, 5];
public GameObject gridSpace;
// Start is called before the first frame update
void Start()
{
GenerateGrid();
}
void GenerateGrid()
{
for (int x = 0; x < 5; x++)
{
for (int z = 0; z < 5; z++)
{
gridArray[x, z] = Instantiate(gridSpace, new Vector3(x, 0, z), Quaternion.identity) as GameObject;
}
}
// test grid works
// gridArray[2, 2].transform.Translate(0.0f, 3.0f, 0.0f);
}
}
test code
public class Pulse : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
for (int x = 0; x < 5; x++)
{
CreateGrid.gridArray[x, 3].GetComponent<MoveObject>().StartBounce(5.0f);
}
}
}
The grid of objects works.
However the test code errors with Object reference not set to an instance of an object from the line
CreateGrid.gridArray[x, 3].GetComponent().StartBounce(5.0f);
specifically CreateGrid.gridArray
Given that I seem to be really struggling with a concept, please explain clearly.
Thanks
Unless you don't clearly define otherwise, you don't know when the Start method of two MonoBehaviours will run.
In your case, the Pulse's Start method is called before CreateGrid's.
To fix your problem, I advise you to call CreateGrid's Generate method inside the Awake method of the class.
I often use this method to initialize members of the class not relying on other classes instances and use the Start method to initialize members needing other instances to be self-initialized.
using System;
using UnityEngine;
using System.Collections;
using UnityStandardAssets.Characters.ThirdPerson;
public class Multiple_objects : MonoBehaviour {
public GameObject prefab;
public GameObject[] gos;
public int NumberOfObjects;
private ThirdPersonCharacter[] thirdPersonCharacter;
private Animator[] _animator;
private int count = 0;
void Awake()
{
Vector3 v3 = prefab.transform.position;
_animator = new Animator[NumberOfObjects];
gos = new GameObject[NumberOfObjects];
for(int i = 0; i < gos.Length; i++)
{
count = count + 2;
GameObject clone = (GameObject)Instantiate(prefab, Vector3.zero, Quaternion.identity);
gos [i] = clone;
gos [i].transform.position = new Vector3 (v3.x - count, v3.y, v3.z);
_animator [i] = gos[i].GetComponent<Animator> ();
Math.Round(Random
When i type point after the Random like: Random.
I have only Equals and ReferenceEquals
And if i create a variable of Random for example:
Random _random;
Then i type _random.
I get more propeties but not Range.
You are using both the UnityEngine and System namespace. Both of these namespaces contain a Random class, so Visual Studio/Unity doesn't know which one you want to use. To specify which random you want to use, you would simply do this:
UnityEngine.Random.Range(0.0f, 5.0f);
Write UnityEngine.Random.Range
You have to clarify the namespace.
Unless you want the .net Random ( in that case look at the other answer)
Why the property Range not exist in Random class in unity?
Random _random;
_random.Rand...
Range is a static function in the Random class. You don't need to create instance of the class to use static functions inside then. You call static functions directly.
This should do it: Random.Range(0f,3f);
If you are getting the Random' is an ambiguous reference betweenSystem.Random' and UnityEngine.Random' error then that's because you haveusing System;`(which you did in your code) and therefore you must use the full namespace to access Unity random function.
UnityEngine.Random.Range(0f, 3f);
I'm Getting a error when i try to instantiate in the manager class. saying
Error CS1061: Type UnityEngine.Object' does not contain a definition forGetComponent' and no extension method GetComponent' of typeUnityEngine.Object' could be found. Are you missing an assembly reference? (CS1061) (Assembly-CSharp)
Add this to your Obstacle class:
void Start()
{
manager = GameObject.FindWithTag("ObstacleManager").GetComponent<ObstacleManager>();
}
The tag obviously has to be the tag of the gameobject the manager is attached to.
Also: Always start class names with a capital letter (I did that in the snippet, keep that in mind, you will get an error right know with that).
Maybe you want to actually change your spawning a bit though. Have two lists, one for free spawnpoints and one for occupied. When you destroy an obstacle, pass the position to the spawning function to move the position to the free list.
Edit:
Another option to create the reference is to set it in your ObstacleManager on spawning. You need to grab a reference to the instantiated obstacle for this. I believe this should work without actually grabbing the obstacle gameobject, but you could do that too.
Obstacle obs = ((GameObject)Instantiate(TypeOfObstacles[j], pointsAvailiable[pointsIndex].position, Quaternion.identity)).GetComponent<Obstacle>();
obs.SetManagerReference(this);
And in Obstacle add
public void SetManagerReference(ObstacleManager obsManager)
{
manager = obsManager;
}
For the free position you can do something like this:
// in Obstacle.cs
public void OnMouseDown()
{
manager.SpawnNewObstacle(transform.position); // you might be able to actually pass the transform, but I'm not sure if it will get destroyed before used in the other function
Destroy(gameObject);
}
In the Manager:
public int noOfObsacles;
public float[] xPercent;
public GameObject[] TypeOfObstacles;
float y;
// to keep track of which spawn points are free and which aren't use these lists
private List<Transform> freePositions;
private List<Transform> occupiedPositions;
private void Start()
{
freePositions = new List<Transform>(spawnPoints);
occupiedPositions = new List<Transform>();
SpawnObstacles();
}
private void SpawnObstacles()
{
// just use this for initial obstacles
// call Spawn as often as needed
for(int i = 0; i < noOfObstacles; i++)
{
Spawn();
}
}
// you call this function from the obstacle that gets destroyed
public void SpawnNewObstacle(Vector3 freePos)
{
// find the spawnpoint in the occupied points
// and move it to the free ones since the obstacle got destroyed
for(int i = 0; i < occupiedPositions.Count; i++)
{
if(occupiedPositions[i].position == freePos)
{
freePositions.Add(occupiedPositions[i]);
occupiedPositions.RemoveAt(i);
break;
}
}
// and call Spawn
Spawn();
}
private void Spawn()
{
y = Random.value;
int pointsIndex = Random.Range (0, freePositions.Count);
for (int j =0; j<xPercent.Length; j++)
{
if ( y < xPercent[j])
{
// these 4 lines are essential for the spawning
Obstacle obs = ((GameObject)Instantiate(TypeOfObstacles[j], freePositions[pointsIndex], Quaternion.identity).GetComponent<Obstacle>();
obs.SetManagerReference(this);
occupiedPositions.Add(freePositions[pointsIndex]);
freePositions.RemoveAt(pointsIndex);
break;
}
}
}
had a bracket issue! my bad
obstacle obs = ((GameObject)Instantiate(TypeOfObstacles[j], freePositions[pointsIndex].position, Quaternion.identity)).GetComponent();
I have a gameObject 'gm' which has a script. That script has a reference to Transform parentFoo, and needs to access a non-static, public int 'x', which exists and is defined in a script attached as a component to multiple children 'bar', which are all children of parentFoo. I'm then trying to throw all these ints into a list, but the issue is with actually getting them. What's the simplest way to get this done?
The following code demonstrates what I'm trying to get done, but it doesn't work at all.
//defined in UnityEditor:
public Transform fooParent;
void blah () {
List<int> list = new List<int>();
for (int i = 0; i < fooParent.childCount; i++) {
Transform tempChild = Players.GetChild(i);
list.Add (tempChild.x);
}
}
Any theoretical discussion on why and how your answer works is more than welcome :D ("teach a man how to fish...")
EDIT: specifying title, copied text to stackoverflow; removed link from Unity Answers b.c. question was fully addressed here
New Code:
public Transform fooParent;
public void blah () {
List<int> list = new List<int>();
for (int i = 0; i < fooParent.childCount; i++) {
Transform tempChild = fooParent.GetChild(i);
list.Add (tempChild.gameObject.GetComponent<ScriptName>().x);
}
}
This is because .GetChild returns a transform so from there you must use .gameObject to get the GameObject that that transform is attached to. From there you can access the components attached to that gameobject (Scripts, Transforms, etc...) by using .GetComponent<>() where inside the <> brackets you input the name of the component (in this case the script) you want to access. Now in control of the script you can access its variables by using .variableName. Lastly the void blah should be public void blah. Unless of course you want it to be a private or static method.