Accessing script component right after instantiation - c#

I have a script creating UI buttons in Unity. It creates instances of a prefab, which has also custom script components in it. I'd like to instantiate a new copy and immediately access values members/fields of the newly created object's scripts:
turretButtons.Add(Instantiate(buttonProto, gameObject.transform));
turretButtons[turretButtons.Count - 1].image.sprite = turretIcon;
turretButtons[turretButtons.Count - 1].GetComponent<DetailsWindowController>().turretDefinition = turretDef;
The first line creates the new instance, the second change the icon, both work perfectly. The third however, in which I try to access the DetailsWindowController script/class's turretDefinition public member throws "NullReferenceException: Object reference not set to an instance of an object". What am I missing?

The component you are looking for is probably not attached to exactly the same GameObject the Button component is attached to.
You should use GetComponentInChildren in order to always look for the component recursive downwards inside of the button's hierachy. Also note the true parameter which is required to find components on disabled children. This might be usefull in the case the button is spawned disabled.
var newButton = Instantiate(buttonProto, gameObject.transform);
newButton.image.sprite = turretIcon;
newButton.GetComponentInChildren<DetailsWindowController>(true).turretDefinition = turretDef;
turretButtons.Add(newButton);

Related

How can I get this to work : "WorkersText = GameObject.FindGameObjectWithTag("Workers");"

I have a text object in my game called WorkersText.
I am creating a save / load script for my game so the player can save and load their progress.
Originally I dragged the Text Object to the Object Inspector, but after the player loads the save point, it removes it from there. The same happened with general GameObjects, so I added a line to assign it in Start(). eg ObjectManager = GameObject.FindGameObjectWithTag("ObjectManager");
Now I need to do the same with my Text objects but it wont let me do WorkersText = GameObject.FindGameObjectWithTag("Workers");
I get the error that Cannot convert type 'UnityEngine.GameObject' to 'UnityEngine.UI.Text'
So I assume FindGameObjectWithTag is off the table. Is there any other way to refrence the Text via code? Sadly as mensioned before, I cannot simply drag the Text object into the Object Inspector.
You get GameObject as a result and obviously cannot assign it to the Text type variable. That is what error is about. Add GetComponent<Text>() to the object returned. If it has such a component - you will get your Text to assign.

Unity Button doesn’t accept function

I have this problem. I wrote a script with a method when interacting with which the player exits the game, but when I wanted to bind it to the button, and I realised that it didn’t work . In the OnClick() component, I attached my script, but for some reason the method is not attached.How can I attach my method?
Create an empty GameObject, attach your credits.cs to it then assign this gameobject to the OnClick(), then Credits > (Your method).
Make sure your method is public.

How to assign programmatically an Interactable Event in MRTK

I am creating a map in Unity3D to be displayed in Hololens 2. I am using MRTK to code interactable functionality.
Since the map contains a lot of independent countries, whose respond onClick may vary with time, I decided to add the required components programmatically. For example:
public Transform worlmap;
public Microsoft.MixedReality.Toolkit.UI.Theme mTheme;
public Microsoft.MixedReality.Toolkit.UI.States mStates;
List<Microsoft.MixedReality.Toolkit.UI.Theme> themes;
void Start()
{
themes = new List<Microsoft.MixedReality.Toolkit.UI.Theme>();
if (mTheme)
{
themes.Add(mTheme);
}
// Looping through all the countries in worldMap
foreach (Transform country in worldMap)
{
// Adding the 4 components which make a GameObject interactable in Hololens
country.gameObject.AddComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>();
country.gameObject.AddComponent<Microsoft.MixedReality.Toolkit.UI.PressableButton>();
country.gameObject.AddComponent<Microsoft.MixedReality.Toolkit.Input.NearInteractionTouchable>();
country.gameObject.AddComponent<MeshCollider>();
// Assigning State
country.gameObject.GetComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>().States = mStates;
// Assigning the Profiles (Will definine the colors based on the State)
Microsoft.MixedReality.Toolkit.UI.InteractableProfileItem mProfile = new Microsoft.MixedReality.Toolkit.UI.InteractableProfileItem();
mProfile.Themes = themes;
mProfile.Target = country.gameObject;
country.gameObject.GetComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>().Profiles.Add(mProfile);
// Assigning Events
// TODO
}
}
The part below is working, but I am not able to assign Events to the different countries in the same loop.
I can define these events in the Editor, for example:
But since it is a repetitive activity which may slightly change over time, I was trying to achieve the same programmatically inside the loop of the script above.
This is what I tried, but it is not working:
// Creating an Event
Microsoft.MixedReality.Toolkit.UI.InteractableEvent mEvent = new Microsoft.MixedReality.Toolkit.UI.InteractableEvent();
// Assigning the method to be executed during onClick
mEvent.Event.AddListener(country.gameObject.GetComponent<CountrySelected>().printName)
// Assigning the Event to Interactable
country.gameObject.GetComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>().InteractableEvents.Add(mEvent);
What is the correct way of adding programmatically Events to an Interactable in MRTK?
To assign OnClick Event for the Interactable component at the runtime, please try the following code:
this.GetComponent<Interactable>().OnClick.AddListener(MyFun1);
The Interactable component profile in the Unity Editor may not display the new method at the runtime, but it does work in the scene.

Enum Value Set in Editor Not Changing in Script

I am working on a project that requires around 30 buttons in a UI menu. Each of these buttons has a "Loader" script attached to it, and the overall scene has a GameManager object (which persists through scenes).
The GameManager holds an enum with a number of named states equal to the number of buttons.
The idea is I need to populate the next scene with specific content depending on the button pressed, so I thought to assign each of these buttons an enum value, and when clicked the Loader script will change the GameManager's enum to equal the button's value. This way I can avoid making 30+ scenes and instead change the single scene based on the state. When the next scene is loaded, it should determine what the current state is, and does stuff based on that.
The problem is, even though I am able to manually assign the enum value of each individual button in the editor, that doesn't seem to actually do anything. Here are my scripts (abbreviated for only the relevant methods), and sample output when clicking a button.
Here is my GameManager:
public class GameManager : MonoBehaviour {
//Used so MenuContent scene knows what random content to populate with
public enum MenuChosen
{
Tabs, Formal, Casual, Headwear, Accessories, Speakers, ComputerParts,
GameConsoles, MobilePhones, Furniture, Lighting, OfficeSupplies, Gadgets, Toys,
Summer, SchoolSupplies, ArtsCrafts, Checking, Savings, PayPal, OtherAccount, Visa,
MasterCard, AirMiles, OtherCards, Food, Retail, Digital, OtherCoupons,
PayTransaction, ScheduledPayments, LoanPayment, MobileRecharge
};
public MenuChosen chosen;
}
And here is my Loader class. It is attached to every button. In the editor, I selected four buttons, and manually changed their states to "Formal", "Casual", "Headwear", and "Accessories", via the drop-down list in the inspector for each of them.
The Loader class creates a reference to the GameManager object, and attempts to change its "chosen" enum variable to be equal to the value that was set in the inspector window (which is called "MenuOption" in the loader).
public class Loader : MonoBehaviour {
public GameManager gm;
public GameManager.MenuChosen MenuOption;
private void Start()
{
gm = GameObject.FindGameObjectWithTag("GameManager").GetComponent<GameManager>();
Debug.Log("Current Loader State: " + MenuOption);
}
public void LoadMenuContent()
{
Debug.Log("Button's State is: " + MenuOption);
gm.chosen = MenuOption;
SceneManager.LoadScene("MenuContent");
Debug.Log("Current state is: " + gm.chosen);
}
}
When I first run the game, the debug messages show that the buttons' enum values are indeed changed:
Current Loader State: Accessories
Current Loader State: Headwear
Current Loader State: Formal
Current Loader State: Casual
However, the logs printed in the LoadMenuContent() method show something different:
Button's State is: Tabs
Current state is: Tabs
So even though it shows that the buttons' MenuOption is properly changed, once it reaches LoadMenuContent(), which is called when the button is pressed, then somehow the state has changed back to the default state, "Tabs".
Any thoughts on why the enum might be changing?
I discovered what my issue was.
Due to the large quantity of buttons, I had resorted to copying and pasting them.
This meant that each button was identical, and had its own copy of the Loader script as a component. By doing this, I was able to change the individual values of the enum of each individual button in the inspector.
However, this also meant that each and every button, in the OnClick() method, were all still holding a reference to the original button that I had copied and pasted. So these buttons were independent, but they all referenced the same exact script from the same exact button, who's state had never been changed from the default.
In order to fix this, I had to go in and manually drag each button into its own OnClick() method as a reference to itself, so they were properly calling the correct function from their own individual Loader script.

Object selection in unity

I want to select a gameobject at run time in unity and move it using an UI button.
for example if there are three cubes in the scene i want to select one cube and one that I clicked will move once I click the UI button .
I have no idea how to pass the value of the selected object to the button click event.If some one can show it using a sample code it would be great.
You can set a tag on the object and then use the GameObject.FindGameObjectsWithTag() function to get that object.
Here is the documentation for the function: https://docs.unity3d.com/ScriptReference/GameObject.FindGameObjectsWithTag.html
Use this:
var obj = Selection.activeObject;
When working with objects that are primarily in a scene, it is strongly recommended to use below code instead:
var transform = Selection.activeTransform;
Refer to official doc here.

Categories

Resources