how GetComponentInChildren in unity - c#

I have a problem:
How to assign [] status to rend[]
public GameObject[] Obj;
private bool[] Status;
private MeshRenderer[] rend;
private void Start ()
{
for (int i = 0; i < Obj.Length; i++)
{
rend[i] = GetComponentInChildren<MeshRenderer>();
Status[i] = rend[i];
}
}

Accorting to Object.bool you can try this way:
public GameObject[] Obj ;
private bool[] Status;
private MeshRenderer[] rend;
void Start () {
for (int i = 0; i < Obj.Length; i++)
{
rend[i] = Obj[i].GetComponentInChildren<MeshRenderer>();
Status[i] = rend[i] != null;
}
}

Your question is very unclear so I can just guess what you are trying to archieve:
I'ld say you want to find the first MeshRenderer under your GameObjects in Obj and get an array Status saying whether they are enabled or not.
You are currently allways searching for MeshRenderer in the GameObject this script is attached to instead of looking in the Obj GameObjects. You have to get it using
Obj[i].GetComponentInChildren<MeshRenderer>();
you probably don't initailize your arrays -> you cannot just assign values using Status[i] = and rend[i] = if the arrays were never initialized using new. You can either do that in start once you have the size of Obj
public GameObject[] Obj;
private bool[] Status;
private MeshRenderer[] rend;
private void start()
{
Status = new bool[Obj.Length];
rend = new MeshRenderer[Obj.Length];
// ...
}
but I would prefer using a List<bool> and List<MeshRenderer> instead so you can simply add and remove values later (while an array has a fixed length).
Finally I guess you want to know whether the component MeshRenderer is enabled so you can assign rend[i].enabled
all together
something like
public GameObject[] Obj ;
// Using List here you can already initialize it here
// which would be possible using an array
private List<bool> Status = new List<bool>();
private List<MeshRenderer> rend = new List<MeshRenderer>();
private void Start(){
for (int i = 0; i < Obj.Length; i++)
{
rend.Add(Obj[i].GetComponentInChildren<MeshRenderer>());
bool existsAndEnabled = rend[i] != null && rend[i].enabled;
Status.Add(existsAndEnabled);
}
}
Note that it is still possible that for one of the GameObjects in Obj there is no MeshRenderer found so I say Status shall also be false if there was none.

Related

How i can optimizating my code in Unity3D

I try optimizating my games, how i can optimizating my random generator?
PS: Game have occulison culling, dynamic batching, no rich text, GPU Instancing, LOD Groups on best population object (Berries, Logs, Leaves on tree, stick).
using static System.Random;
using UnityEngine;
public class StickGenerator : MonoBehaviour
{
[Header("Игровые объекты")] // game objects
public GameObject Object;
[Header("Лимит строений")] // is builded?
private bool objectBuilded = false;
[Header("Количество")] // how much
public int what;
[Header("Максимум блоков для рендера")] // max X and Z for render
public int maxRangeX;
public int maxRangeZ;
[Header("Рандомные координаты")] // random coordinations
private int randomPosX;
private int randomPosZ;
private void Start() // generation
{
if(objectBuilded == false)
{
System.Random randomPos = new System.Random();
for (int i = 0; i <= what; i++)
{
randomPosX = randomPos.Next(1, maxRangeX);
randomPosZ = randomPos.Next(1, maxRangeZ);
Instantiate(Object, new Vector3(randomPosX, 0.56f, randomPosZ), Quaternion.identity);
}
objectBuilded = true;
}
}
}
Try debugging with the profiler to see what kind of spikes you are getting, that way you can now where to optimize first.

UI Button reference not visible in the inspector

I declared my Button[] public so i can reference it from my inspector
but it does not appear in my inspector. Please help!!!
I tried restarting the C# as well as re-importing everything in unity....
public rocket rocket;
public Button[] levelButtons;
void Start()
{
for(int i=1 ; i<levelButtons.Length ; i++)
{
// if(i + 1 > rocket.level)
levelButtons[i].SetEnabled(false);
}
}
Button actually is GameObject include Component Button. And you should init size for Array you want to create before using it. I had edited code for example:
//Your array
public GameObject[] levelButtons;
//Object to attach Button
public GameObject panelShow;
//Size for Array
public int sizeArrayButton = 5;
void Awake()
{
//Init size for Array
levelButtons = new GameObject[sizeArrayButton];
for (int i = 0; i < levelButtons.Length; i++)
{
//Create new Object and random for position of Gameobject
GameObject button = new GameObject();
button.transform.parent = panelShow.transform;
button.AddComponent<RectTransform>();
button.AddComponent<Button>();
button.transform.position = new Vector3(Random.Range(100, 50), Random.Range(100, 26), Random.Range(-25, 26));
button.AddComponent<Image>();
button.GetComponent<Button>().onClick.AddListener(() => { Debug.Log($"Button: +{i}+ was clicked"});
levelButtons[i] = button;
}
}
And in Unity, you also make it by using List and Prefabs.
so the issue is solved...so basically what i did was just update my unity version and then it allowed me to use UnityEngine.UI and the issue is now fixed...
Thank you everyone for your time...much apppreciated

Using same Boolean with multiple objects in Unity 2D

I have four game objects with the same script and the same bool, when one of them get hit by ray the bool state is true, but the function will not start because the other three game objects is set to false.
What I tried:
the code works fine with the last object being instantiated
if I disabled the script on the first object and re-enabled it again the function works fine on this object only
public bool selected;
void Start(){
selected = false;
}
void Update(){
showRange ();
}
public void showRange(){
if (selected == true) {
for (int i = 0; i < tileRange.Count; i++) {
tileRange [i].GetComponent<SpriteRenderer> ().enabled = true;
}
} else {
for (int i = 0; i < tileRange.Count; i++) {
tileRange [i].GetComponent<SpriteRenderer> ().enabled = false;
}
}
}
Simply use a static variable: What is the use of static variable in C#? When to use it? Why can't I declare the static variable inside method?
You would have:
public static bool selected;
Try using gamemanager.
public static gamemanager Instance;
public bool selected;
private void Awake()
{
Instance = this;
}
Your gamemanager can have a public bool variable "selected".
New start method:
void Start() {
gamemanager.Instance.selected = false;
}
New showRange function
public void showRange(){
if (gamemanager.Instance.selected) {
for (int i = 0; i < tileRange.Count; i++) {
tileRange [i].GetComponent<SpriteRenderer> ().enabled = true;
}
} else {
for (int i = 0; i < tileRange.Count; i++) {
tileRange [i].GetComponent<SpriteRenderer> ().enabled = false;
}
}
}
I am sure this code can be improved. Let me know if it helps.
The problem isn't in the selected bool, but it's in showRange() method. If the ray hit one object it will be selected and the other three will remain unselected ((that's because I use a list that stores the last hitted object, then the code works only for the object inside this list))
showRange() will not work with the selected object, because the method want all the four object to be selected, then it works (stupid method, I was unable to sleep because of it).
I managed to fix showRange() problem, using a new script that turns off all game objects script component and turns on the selected one script, this will make showRange() method unable to check the bool state of the other three objects.
For (Guilherme, misher and Josep) thank you for your help, I really appreciate it, but as it is shown above the problem wasn't in the Boolean.
For (Muhammad Farhan Aqeel) I believe your code should work, but I didn't manage to get it work maybe because I'm still new to programming.

System.Array.IndexOf returns -1

I put a screenshot that will tell you everything.
private Transform[] hiddenObjects;
void Start()
{
leftImageRandom = new Randomizer(0, LeftImageSequence.transform.childCount - 1, true);
DoStart();
}
private void DoStart()
{
leftImageIndex = leftImageRandom.getRandom();
LeftImageSequence.setCurrentChildIndex(leftImageIndex);
RightImageSequence.setCurrentChildIndex(leftImageIndex);
//take hidden objects and put them in an array
hiddenObjects = RightImageSequence.CurrentChild.transform.GetChild(0).transform.GetComponentsInChildren<Transform>();
for(int i=1;i<hiddenObjects.Length;i++)
hiddenObjects[i].gameObject.GetOrAddComponent<MouseEventSystem>().MouseEvent += ClickedHiddenObject;
Debug.Log(hiddenObjects.Length);
}
private void ClickedHiddenObject(GameObject target, MouseEventType type)
{
if (type == MouseEventType.CLICK && CanClick)
{
int targetIndex = System.Array.IndexOf(hiddenObjects, target.gameObject);
Debug.Log(targetIndex);
hiddenObjects[targetIndex].GetComponent<SpriteRenderer>().DOFade(1f, 0.3f).SetEase(Ease.Linear);
}
}
I have a targetIndex that needs to return the index of the object I clicked on. Each object contains the PoligonCollider2D component. The problem is that it always returns -1 to any object. What's the problem, what am I doing wrong?
From your code:
private Transform[] hiddenObjects;
...
System.Array.IndexOf(hiddenObjects, target.gameObject)
hiddenObjects is an array of Transform, but target.gameObject is a GameObject (actually target is already a GameObject, so this is redundant): the types don't match, so indeed a GameObject is never gonna be equal to a Transform.
Instead try:
System.Array.IndexOf(hiddenObjects, target.transform)

How to show 3D text notification/toast

Is there any simple way to show text notification in front of the camera (while in the game) and make it follow the camera while the player is moving?
We are creating a game where the player can give commands with voice, and when the command is recognized, some text notification must be shown (like toast notifications in Android).
I know about text meshes and that we can put it in front of the camera and show/hide it, but we need it to be done programmatically.
I ended up with creating a class which generates toast on fly.
Code is something like this (initial version, needs small re-factorizations):
using UnityEngine;
public class ToastText3D : MonoBehaviour
{
public static ToastText3D Instance { get; private set; }
private static bool isShowingTextMessage;
private static GameObject textMeshGameObject;
// Preventing instantiation of class by making constructor protoected (or private)
protected ToastText3D() { }
private void Awake()
{
// Check if instance already exists
if (Instance == null)
// if not, set instance to this
Instance = this;
else if (Instance != this)
// Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
Destroy(gameObject);
// Sets this to not be destroyed when reloading scene
DontDestroyOnLoad(gameObject);
}
private void Update()
{
if (!isShowingTextMessage)
return;
var headPosition = Camera.main.transform.position;
var gazeDirection = Camera.main.transform.forward;
float distanceFromCamera = 2; // TODO: Move this to const
Vector3 desiredPosition = headPosition + gazeDirection * distanceFromCamera;
textMeshGameObject.transform.position = desiredPosition;
// Rotate the object to face the user.
Quaternion toQuat = Camera.main.transform.localRotation;
toQuat.x = 0;
toQuat.z = 0;
textMeshGameObject.transform.rotation = toQuat;
}
// Returns current text mesh or creates new one if there is no
private TextMesh getCurrentTextMesh()
{
if (!textMeshGameObject)
textMeshGameObject = new GameObject();
TextMesh curTextMesh = textMeshGameObject.GetComponent(typeof(TextMesh)) as TextMesh;
if (!curTextMesh)
{
// TODO: Make constants
curTextMesh = textMeshGameObject.AddComponent(typeof(TextMesh)) as TextMesh;
MeshRenderer meshRenderer = textMeshGameObject.GetComponent(typeof(MeshRenderer)) as MeshRenderer;
meshRenderer.enabled = true;
curTextMesh.anchor = TextAnchor.MiddleCenter;
curTextMesh.alignment = TextAlignment.Center;
curTextMesh.fontStyle = FontStyle.Bold;
curTextMesh.fontSize = 20;
curTextMesh.transform.localScale = new Vector3(0.02f, 0.02f, 0.02f);
}
return curTextMesh;
}
public void Show3DTextToast(string textToShow, int timeout = 5)
{
if (timeout < 0 || textToShow == "")
return;
TextMesh curTextMesh = getCurrentTextMesh();
curTextMesh.text = textToShow;
textMeshGameObject.SetActive(true);
isShowingTextMessage = true;
// Canceling message hiding invokation if there was any
CancelInvoke("Hide3DTextToast"); // TODO: Move function name to const
// Hiding text if there is any timeout
if (timeout != 0)
Invoke("Hide3DTextToast", timeout);
}
public void Hide3DTextToast()
{
textMeshGameObject.SetActive(false);
isShowingTextMessage = false;
}
}
Now all we need is to call function Show3DTextToast by passing him text and interval.
Example:
ToastText3D.Instance.Show3DTextToast("Text Message", 10);

Categories

Resources