I'm making an application with Augmented Reality using ArToolkit.
It's very simple.
I show some elements accord the toggle stage. Example, I've 3 elements
When I run, one element is displayed. If I click in first toggle this element hide and the next element show. When I click in second toggle the previous element hide and the next is show.
In another words, when I run only the first element (Cube) is displayed. When I click in first toggle, each element (cube, esphere, cilinder) is show:
Step 1:
Step 2:
Step 3:
This is my hierarchy:
Inside ArControlador are the markers. Inside Canvas are the toggles.
But, actually I build this project in rude way, getting each element with GameObject.Find. I want get the GameObjects in in elegance way, clean code and it can be scaleable.
I want get the GameObjects in an automated way, so if I have 3, 5, 10 or 20 elements the code will run perfectly.
I think in some possibilities like Array of GameObjects, List of GameObjects, create a GameObject father and get all childs like FindGameObjectsWithTag but I don't have successfull.
This is my code, it already works but in rude way, geting GameObject per GameObject and enable/disable the GameObjects with aux variable, see:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Linq;
using System.Collections.Generic;
using System;
using UnityEngine.SceneManagement;
public class AlternaEntreOsPassos : MonoBehaviour
{
private UnityEngine.UI.Toggle[] toggles;
public int aux = 0;
public GameObject marker1, marker2, marker3;
void Awake()
{
//Find manually the objects
marker1 = GameObject.Find("Marcador1");
marker2 = GameObject.Find("Marcador2");
marker3 = GameObject.Find("Marcador3");
}
void Start()
{
toggles = GetComponentsInChildren<UnityEngine.UI.Toggle>();
if (toggles.Length > 0)
{
//2nd and 3rd false for not be displayed yet...
marker2.SetActive(false);
marker3.SetActive(false);
for (int i = 0; i < toggles.Length; i++)
{
int closureIndex = i;
toggles[closureIndex].interactable = false;
toggles[closureIndex].onValueChanged.AddListener((isOn) =>
{
if (isOn == true)
{
aux++;
//Disabling the toggle that was clicked
toggles[closureIndex].interactable = false;
if (closureIndex < toggles.Length - 1)
{
//Activatin the next toggle
toggles[closureIndex + 1].interactable = true;
}
if (aux == 1)
{
//Desactivating the actual element and activating the next element
marker1.SetActive(false);
marker2.SetActive(true);
}
if (aux == 2)
{
//Desactivating the actual element and activating the next element
marker2.SetActive(false);
marker3.SetActive(true);
}
if (aux == 3)
{
marker3.SetActive(false);
}
}
}
);
}
toggles[0].interactable = true;
}
}
}
So, how I can get the GameObjects in intelligent way like the examples above (array, list, tag) or something else.
Loop over the transform hierarchy. You've already got your step1, step2, step3... objects assigned to a parent.
List<GameObject> steps = new List<GameObject>();
void Awake() {
GameObject parentObject = GameObject.Find("Steps");
for(int i = 0; i < parentObject.transform.childCount; i++) {
steps.Add(parentObject.transform.GetChild(i));
}
}
Related
The objects are being set to out of the canvas
The objective of setting them is to show the user inventory with only the items that the user have
It's setting them active normally, and in the order that the user got it, but in wrong positioning
No error messages were sent
Before setting the positions array, i checked what were the positions in the scene to put it right on the array
But the objects are setting in the wrong place
I put this debug logs to try to see the problem
But it says the positions that i set
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class Filters
: MonoBehaviour
{
[Header("Items")]
public GameObject doubleSpeed;
public GameObject doubleJump;
public GameObject superForce;
public GameObject noGravity;
public GameObject noHit;
public GameObject apple;
private GameObject[] items;
public int index = 0;
public float[] position = new float[6] { -125.8f, -78.6f, -24.1f, 23.1f, 80.69913f, 36.3375f };
private float x;
// Update is called once per frame
void Update()
{
Player player = FindObjectOfType<Player>();
Filter(doubleJump, player.doubleJumps);
Filter(doubleSpeed, player.doubleSpeeds);
Filter(superForce, player.superForces);
Filter(noGravity, player.noGravitys);
Filter(noHit, player.noHits);
Filter(apple, player.apples);
items = GameObject.FindGameObjectsWithTag("Have");
if(items.Length != 0)
{
for(int i = 0; i < items.Length; i++)
{
items[i].transform.position = new Vector3(position[i], 52.8f , 1f);
items[i].SetActive(true);
Debug.Log("Changed the position and set active new position:" + items[i].transform.position);
}
}
}
void Filter(GameObject item, int quantity)
{
if(quantity < 1)
{
item.SetActive(false);
Debug.Log("less than 1");
}
else
{
item.SetActive(true);
Debug.Log("set active");
item.tag = "Have";
Debug.Log("set the tag");
}
}
}
In general there is a difference between the localPosition - the position relative to the parent object and usually the one displayed in the Unity Inspector - and the absolute world space position you are setting in
items[i].transform.position = new Vector3(position[i], 52.8f , 1f);
Further there is an even bigger difference when dealing with a RectTransform. What you see and edit in the Inspector is the RectTransform.anchoredPosition which is relative to the parents RectTransform and additionally takes the Anchors and Pivot settings into account.
So try this instead
items[i].GetComponent<RectTransform>().anchoredPosition3D = new Vector3(position[i], 52.8f , 1f);
anchoredPosition3D is basically the same as anchoredPosition but additionally allows to set the delta in the Z axis
In general for your usecase I would recommend to use a HorizontalLayoutGroup and rather let the UI handle the placement itself. You would then simply use SetActive to hide and show items.
How could I make it so, for example, if only one thing is on it will move to the first slot, I think you know what I mean... So how could I make this?1
I thought about using arrays but I don't understand how.
This is my code currently, rn it just shows and hides but doesnt move them so there just a gap.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class UI : MonoBehaviour
{
public Text myText;
public GameObject Player;
public GameObject SugarIcon;
public GameObject DashIcon;
public GameObject JumpIcon;
public GameObject ShieldIcon;
private string dashreadystring;
private string doublejumpstring;
private string triplejumpstring;
private string shieldbuffstring;
private int iconamount = 0;
void Start()
{
GameObject Player = GameObject.Find("Player");
}
void Update()
{
PlayerScript PlayerScript = Player.GetComponent<PlayerScript>();
bool dashready = PlayerScript.canDash;
float sugarbuff = PlayerScript.sugarbuffactive;
int airJumpCount = PlayerScript.airJumpCount;
int airJumpCountMax = PlayerScript.airJumpCountMax;
bool canDoubleJump = PlayerScript.canDoubleJump;
bool shieldon = PlayerScript.shieldon;
float score = Player.transform.position.x;
// If Dash is ready, show icon, if not, hide it.
if (dashready == true)
{
DashIcon.GetComponent<Renderer>().enabled = true;
}
else
{
DashIcon.GetComponent<Renderer>().enabled = false;
}
// If Sugarbuff is active, show icon, if not, hide it.
if (sugarbuff == 1.5)
{
SugarIcon.GetComponent<Renderer>().enabled = true;
}
else
{
SugarIcon.GetComponent<Renderer>().enabled = false;
}
// If can jump,
if ((airJumpCount < airJumpCountMax) | ((canDoubleJump) && (sugarbuff == 1.5f)))
{
JumpIcon.GetComponent<Renderer>().enabled = true;
}
else
{
JumpIcon.GetComponent<Renderer>().enabled = false;
}
if (shieldon)
{
ShieldIcon.GetComponent<Renderer>().enabled = true;
}
else
{
ShieldIcon.GetComponent<Renderer>().enabled = false;
}
}
}
How could I make this? Thanks.
If your icons are children of a parent container that uses a HorizontalLayoutGroup component, it will automatically line up your icons horizontally (use VerticalLayoutGroup or GridLayoutGroup to autoalign in different patterns).
Then, if you disable the gameObject of the icons, they will disappear. The HorizontalLayoutGroup will rearrange the remaining icons in the way I think you want. When you reenable the icon, it will be reinserted into the horizontal layout.
Notes:
You are currently disabling the Renderer Component on the gameObject. This does make the object invisible, but it still exists and takes up space. Instead, disable the gameObject for the icon itself (SugarIcon.enabled = false). Hopefully the Icon objects are just images, and have no scripts/logic on them, but if so, you'll need to decouple that.
It looks like you're using GetComponent() calls many times every frame. Don't do this -- GetComponent() calls have a pretty big overhead. Instead, call it once, when you initialize your manager, and then cache the result. This will save a ton of processing.
// Call GetComponent() and cache the reference one time (when you initialize the objects).
Renderer sugarIconRenderer = SugarIcon.GetComponent<Renderer>();
// Call the cached reference every frame when you need it.
sugarIconRenderer.enabled = false;
I have 2 classes attached to 2 different GUIs, PlayerInfoGUI and DiplomacyGUI.
I am trying to have a method in PlayerInfoGUI create a list of buttons dynamically which, when clicked will then pull up DiplomacyGUI. (Both GUIs as well as the dynamic buttons have their own prefabs created)
My PlayerInfoGUI class dynamically populates a panel with buttons using the PopulatePlayerList method.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
public class PlayerInfoGUI : MonoBehaviour
{
public Image[] guiElements;
public GameObject playerInfoButtonPrefab, canvasParent;
public GameObject diplomacyMenu;
void Awake ()
{
PopulatePlayerList (GameEngine.competingPlayers);
}
void PopulatePlayerList (List<CompetingPlayer> players)
{
for (int i = 0; i < players.Count; i++) {
GameObject go = (GameObject)Instantiate
(playerInfoButtonPrefab);
Button playerInfoButton = go.GetComponent<UnityEngine.UI.Button>
();
CompetingPlayer receivingPlayer = players [i];
playerInfoButton.onClick.AddListener (() => handleDiplomacyMenu
(receivingPlayer));
go.transform.SetParent (canvasParent.transform, false);
}
}
public void handleDiplomacyMenu (CompetingPlayer receivingPlayer)
{
diplomacyMenu.SetActive (true);
}
}
The listener on the PlayerInfo Button is firing when clicked, but the diplomacyMenu GameObject is not showing up in the scene. Most of the research I have read says this should be a simple diplomacyMenu.SetActive(true), or a diplomacy.gameObject.SetActive(true), but this doesn't work.
I have confirmed that the code is being run, but the object cannot be seen.
Thank you in Advance!
PlayerInfoPrefab
PlayerInfoButtonPrefab
DiplomacyPrefab
You're using diplomacyMenu.gameObject when diplomacyMenu is already a game object, this might cause issues. Also make sure the prefab that is represented by diplomacyMenu has its children enabled. I think SetActive() just sets the top level parent to enabled, not any nested objects.
I'm trying to create a search interface similar to Facebook's. That is, you type in all or part of a name, and the matches are displayed in a list below.
I know how to extract the input from the InputField (SearchBar) but I don't know how to display the matching results in the panel below during runtime.
Create a new label/button for each match and append to... the panel?
What container should I use?
How do I actually "add/append"?
Any help would be much appreciated.
Here is my scene:
And here is my code:
using UnityEngine;
using UnityEngine.UI;
using System;
public class SearchScript : MonoBehaviour {
public InputField SearchBar;
public GameObject Panel;
public List<String> myList;
public void Start() {
myList = new List <String>();
myList.Add("Andre");
myList.Add("Angela");
myList.Add("Temi");
myList.Add("Tupac");
myList.Add("Graham");
myList.Add("Grandpa");
myList.Add("Michael");
myList.Add("Miguel");
SearchBar.onValueChanged.AddListener(delegate {ValueChangeCheck(myList); });
}
public void ValueChangeCheck(List<string> myList) {
string contents = SearchBar.text;
List<String> outList = new List <String> ();
for (int i = 0; i < myList.Count; i++) {
if (myList [i].Contains (contents)) {
outList.Add (myList [i]);
}
}
for (int i = 0; i < outList.Count; i++) {
>>HELP<<
}
}
}
This page in the Unity manual describes what you'll need to do in general terms. The first thing you'll want to do is (in the editor) make a blank button/label or whatever it is you want your final product to look like. For this example, I'm going to act like it's going to be a button. Once you've got the button looking the way you want, set the position to (0,0) and make it a prefab. Make a public field in your MonoBehaviour and drag the prefab into it in the editor. That will look like this:
public GameObject ButtonPrefab;
Next, in your loop, you'll need to instantiate each button, making sure that you parent the new object to your canvas (which is your SearchBar's parent, so we have an easy way to get at it). Then assign your text and shift it down and you'll be golden!
for (int i = 0; i < outList.Count; i++) {
var newButton = Instantiate(ButtonPrefab,SearchBar.transform.parent,false) as GameObject;
// This assumes you have a Text component in your prefab
newButton.GetComponent<Text>().text = outList[i];
// You'll just have to experiment to find the value that works for you here
newButton.transform.position += Vector2.down * 20 * (i + 1);
}
This code is C# and I'm using the Unity game engine.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class CollisionDetectionForQuest : MonoBehaviour {
public GameObject[] Garbages;
public GameObject[] GarbagesDummy;
public bool activateInactive;
//public GameObject[] Counter;
void Start(){
Garbages = GameObject.FindGameObjectsWithTag("Trash");
foreach (GameObject garb in Garbages) {
}
GarbagesDummy = GameObject.FindGameObjectsWithTag ("TrashDummy");
foreach(GameObject dummy in GarbagesDummy){
dummy.gameObject.SetActive (false);
}
}
void OnCollisionEnter(Collision obj){
if (obj.gameObject.CompareTag ("Trash")) {
obj.gameObject.SetActive (false);
activateInactive = true;
//in this line i want to activate my GarbageDummy 1 by 1 base on
//every Trash i put in my collider.
foreach(GameObject a in GarbagesDummy){
a.gameObject.SetActive (true);
}
}
So basically I want to activate the garbagedummy gameobject 1 by 1 on every trash I put on my collider. But I tried this and it doesn't work:
foreach(GameObject dummy in GarbageDummy){
for(int i = 0; i < GarbageDummy.Length; i++){
dummy.gameobject.setActive(true);
}
}
anyone help please.
Here is my screenshot:
If you would like to activate a single garbage dummy object (any of them in the array), then you don't want to use a loop there. Instead, keep track of which one you've activated up to as a field like this:
public int ActivatedDummyIndex; // Add this!
public GameObject[] Garbages;
public GameObject[] GarbagesDummy;
...
Then whenever a trash object is added, increase that number and use it as an index in your GarbagesDummy array:
void OnCollisionEnter(Collision obj){
if (obj.gameObject.CompareTag ("Trash")) {
obj.gameObject.SetActive (false);
activateInactive = true;
// Get the next dummy:
GameObject dummy = GarbagesDummy[ActivatedDummyIndex];
// Increase the index for next time:
ActivatedDummyIndex++;
// Activate that dummy:
dummy.SetActive(true);
}
}
This assumes that the number of dummy objects is the same as the number of trash objects. If you've got more trash objects and add them all, you'll eventually get an index out of range exception (as it would "run out" of dummy objects to use).
Whilst that should answer your question, it's worth mentioning that this isn't the typical approach. Rather than having a fixed number of hidden dummy objects and showing one when needed, you'd normally instance a new dummy object instead (using GameObject.Instantiate).