I'm trying to toggle. When I click on the toggle (if it is on I mean checked), it closes some gameobject, if I click on the toggle (if it is off I mean unchecked) it opens some gameobject but I don't know which function unity
toggle.onselect?
toggle.onValuesChanged? or others which one
public GameObject controlledObject;
public NamesGet nameController;
public Text text;
public Button button;
public Toggle toggle;
private bool deneme;
public void FixedUpdate()
{
text.text = controlledObject.name;
if(?????????)
{
controlledObject.SetActive(!controlledObject.activeSelf);
}
}
I would use something like this :
toggle.onValueChanged.AddListener((value) =>
{
MyListener(value);
});//Do this in Start() for example
public void MyListener(bool value)
{
if(value)
{
//do the stuff when the toggle is on
}else {
//do the stuff when the toggle is off
}
}
New
instead using OnValueChanged why not use EventTrigger - Pointer Click so it will only be called Once.
same as adding Listener via script but its more quick and handy.
Related
This question already has answers here:
Impossible value in lambda expression
(2 answers)
Closed 19 days ago.
I have a list of Buttons that get activated after certain conditions are met. I then add a listener to each button to call a function when clicked. That function then needs to be able to get the text off the button that was clicked. This is what I've tried but it returns an out of range error, I think because it calls the function once clicked, and at that point the variable i is maxed out.
public List<GameObject> ButtonList = new List<GameObject>();
void Start() {
for (int i = 0; i < ButtonList.Count; i++) {
ButtonList[i].SetActive(true);
ButtonList[i].GetComponent<Button>().onClick.AddListener(() => {GetButtonText(ButtonList[i]); });
}
}
public void GetButtonText(GameObject SelectedButton) {
Debug.Log(SelectedButton.GetComponentInChildren<TMP_Text>().text)
}
I thought about creating game objects for each button and assigning them in the inspector, but the number of buttons in the list is likely to fluctuate, so it needs to remain dynamic. Additionally, because the game object this script is attached to is a prefab, I can't set up the listeners in the inspector either.
First of all I would suggest to make it list of Button and not a GameObjects you still will be able to access GameObject without call GetComponent each time.
This think happened because it use the last value of i:
you need to redo it like that:
public List<GameObject> ButtonList = new List<GameObject>();
void Start() {
for (int i = 0; i < ButtonList.Count; i++) {
var button = ButtonList[i];
button.SetActive(true);
button.GetComponent<Button>().onClick.AddListener(() => {GetButtonText(button); });
}
}
public void GetButtonText(GameObject SelectedButton) {
Debug.Log(SelectedButton.GetComponentInChildren<TMP_Text>().text)
}
Base And I rater suggest to create a class to wrap the buttons
public class MyButton : MonoBehaviour
{
public event Action<int> OnClick;
[SerializeField] private Button button;
[SerializeField] private Text text;
private int id = -1;
private void Awake()
{
button.onClick.AddListener(Click);
}
private void Click()
{
OnClick?.Invoke(id);
}
public void Init(int index)
{
id = index;
}
public void SetText(string message)
{
text.text = message;
}
}
I'm trying to use Unity's UI system .
What I want is that I have a button #1 as a card image and I have button 2 as a spade image. First I will click spade image and it's indicator will turn on. After that I will click the card image to make the Spade Icon image disappear. I managed to get variables from script to another script but whatever I do the first click of the Spade Button, the indicator lights up and spadeselected bool changes in the inspector. While spadeselected is true, the first click of the Card image doesn't do a thing. After clicking twice and so on everything works fine. What could cause this problem?
My main script for card button:
public class main : MonoBehaviour
{
private bool ace = false;
spadestatement _spadestatement;
public GameObject spadebutton;
public GameObject spade_icon;
private void Awake()
{
_spadestatement = spadebutton.GetComponent<spadestatement>();
}
private void Start()
{
gameObject.GetComponent<Button>().onClick.AddListener(turnoff);
}
private void turnoff()
{
ace ^= true;
if (_spadestatement.spadeselected == true)
{
spade_icon.SetActive(ace);
}
}
}
My spadestatement script for spade button:
public class spadestatement : MonoBehaviour
{
public bool spadeselected;
public GameObject indicator;
void Start()
{
gameObject.GetComponent<Button>().onClick.AddListener(select);
}
public void select()
{
spadeselected ^= true;
indicator.SetActive(spadeselected);
}
}
And here is a picture to make it more understandable:
When spadeselected is true, the first time you call turnoff() :
private void turnoff()
{
ace ^= true; //first time : after the assignment, ace is true
if (_spadestatement.spadeselected == true)
{
spade_icon.SetActive(ace); // since ace is true, set spade_icon active
}
}
The second time you call turnoff(), ace become false, thus spade_icon is deactive.
If you want to turn on/off the spade_icon, maybe try this one:
private void turnoff()
{
ace ^= true; //first time : after the assignment, ace is true
if (_spadestatement.spadeselected == true)
{
spade_icon.SetActive(!ace); // since ace is true, set spade_icon deactive
}
}
Or, if you don't want to bind the active/deactive behaviour of spade_icon with ace, you can:
private void turnoff()
{
if (_spadestatement.spadeselected == true)
{
spade_icon.SetActive(!spade_icon.activeSelf);
}
}
as I stated above, I need help with my c# code which I'm using in unity to make a 3D game.
When I click on an object it should change color and if there was previously another object selected, I need it to be deselected automatically.
I already wrote a code which is supposed to at least help me select(change a material color) but it isn't working.
I am checking if the left mouse button is pressed down and using raycast to check if there is something under a cursor. Also wrote a Selection class with 2 methods(Select/deselect) that are supposed to change color of an object.
I'll be thankful if you can help me.
Here's the code with mouse click:
public class ClickSelect : MonoBehaviour
{
private void Update()
{
Click();
}
public void Click()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Selectable selectable = hit.collider.gameObject.GetComponent<Selectable>();
if (selectable)
{
hit.collider.gameObject.GetComponent<Selectable>().Select();
}
}
}
}
}
And this is code of a selection class:
public class Selectable : MonoBehaviour
{
public void Select()
{
GetComponent<Renderer>().material.color = Color.yellow;
}
public void Deselect()
{
GetComponent<Renderer>().material.color = Color.gray;
}
}
First you should check if there is a Collider on the Selectable. If not add one. Because you are asking for a Ray that hits a collider and if there's no Collider it will return always null
then this
Selectable selectable = hit.collider.gameObject.GetComponent<Selectable>();
if (selectable)
{
hit.collider.gameObject.GetComponent<Selectable>().Select();
}
is complete Nonsense
why you get the Selectable in First Place and then the Selectable again?
And you don't need a Collider on it to detect the Transform so you can remove the hit.collider to hit.gameObject or better is hit.transform (Because u don't need the whole GameObject)
hit.collider.gameObject.TryGetComponent(out Selectable selectable);
//hit.transform.TryGetComponent(out Selectable selectable)
if(selectable != null)
{
selectable.Select();
}
Then instead of
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Try
Ray ray = Camera.main.ViewportPointToRay(Input.mousePosition);
hope it helps you, if so, feel free to mark it as solved and correct Answer.
To expand a bit on this answer, once you get the raycast itself to work properly, you want to store the current selection so you can fire deselect where necessary.
I would keep this information in the Selectable class itself like e.g.
public class Selectable : MonoBehaviour
{
// Stores the current selection and can only be modified by this class
private static Selectable _currentSelection;
// Public read-only accessor if needed
public static Selectable CurrentSelection => _currentSelection;
// Deselcts if current selection and resets the selection
public static void ClearSelection()
{
// if there is a current selection -> deselect it
if(_currentSelection) _currentSelection.Deselect();
// "forget" the reference
_currentSelection = null;
}
// In general rather cache reused references
[SerializeField] private Renderer _renderer;
// Optional accessor
public bool IsSelected => _currentSelection == this;
private void Awake ()
{
// if not referenced yet get it ONCE on runtime
if(!_renderer) _renderer = GetComponent<Renderer>();
// I would also ensure the default state initially
Deselect();
}
public void Select()
{
// if this is already the selected object -> nothing to do
if(_currentSelection == this) return;
// otherwise first clear any existing selection
ClearSelection();
// set your color
_renderer.material.color = Color.yellow;
// and store yourself as the current selection
_currentSelection = this;
}
public void Deselect()
{
// set your color
_renderer.material.color = Color.gray;
// if this is the current selection forget the reference
// usually this should always be the case anyway
if(_currentSelection == this)
{
_currentSelection = null;
}
}
}
and then
public class ClickSelect : MonoBehaviour
{
// in general Camera.main is expensive -> rather store he reference and reuse it
// Already reference this via the Inspector if possible
[SerializeField] private Camera _mainCamera;
private void Awake ()
{
// as fallback get it ONCE on runtime
if(!_mainCamera) _mainCamera = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
var ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit))
{
// Is what you clicked on a selectable?
if (hit.transform.TryGetComponent<Selectable>(out var selectable))
{
// Internally already handles deselection of current selected and skips if already selected this
selectable.Select();
}
// Optional: Deselect the current selection if you click on something else
else
{
Selectable.ClearSelection();
}
}
// Optional: Deselect the current selection if you click on nothing
else
{
Selectable.ClearSelection();
}
}
}
}
I have got displayed cards in a scene, they are gameobjects with this script:
public class CardClick : MonoBehaviour
{
DeckBuildManager deckManager;
// Start is called before the first frame update
void Start()
{
deckManager = FindObjectOfType<DeckBuildManager>();
}
// Update is called once per frame
public void AddToDeck()
{
if (deckManager.DeckCards.Count <= 9)
{
if (!deckManager.DeckCards.ContainsValue(this.gameObject.GetComponent<CardValues>().dataCard.cardName))
{
deckManager.DeckCards.Add(this.gameObject.GetComponent<CardValues>().dataCard, this.gameObject.GetComponent<CardValues>().dataCard.cardName);
}
}
}
}
Cards got a button component which use the AddToDeck function when clicked but there are impossible to click.
What can i do to click them?
I use panel to display those cards so its impossible to delete the panel in case it was the error.
resolv
public void ClickOnCard()
{
if (deckManager.DeckCards.Count <= 9)
{
if (!deckManager.DeckCards.ContainsValue(this.gameObject.GetComponent<CardValues>().dataCard.cardName))
{
deckManager.DeckCards.Add(this.gameObject.GetComponent<CardValues>().dataCard, this.gameObject.GetComponent<CardValues>().dataCard.cardName);
}
}
}
Ill try to explain my issue. I need to do for my school project simple 2D escape room. I've got most of the scripts ready, when I click an item he add to the inventory list, and then I can see it on my inventory bar. The problem is , I want that the buttons of the UI Bar inventory, to know after I click the item , to know what item I've been clicking on. the way I did worked half way because he always give the key item. Ive got State Machine Interface. that inheritance to 2 more scripts (that open or close the other interactive stuff (door drawer). got KeyItems script and Interactable Script and UImanager - Singleton.
is there to it in a generic way?
this is the PlayerCast Script that I add the items I click on to the inventory, thought the button need to be here
public enum item {none , paperclip , key }
public class PlayerCast : MonoBehaviour
{
public Camera cam;
public List<item> inventory;
public item activeItem;
private void Start()
{
inventory = new List<item>();
}
// Update is called once per frame
void Update()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.CompareTag("Interact"))
{
Interactable interactable = hit.collider.gameObject.GetComponent<Interactable>();
interactable.CLickMe(activeItem);
}
else if(hit.collider.CompareTag("Key"))
{
KeyItems hitItem = hit.collider.gameObject.GetComponent<KeyItems>();
hitItem.PickMeUp();
}
}
}
}
public void ButtonSelect() //this is the generic button im trying to do
{
this.activeItem = item.key;
Debug.Log("Clicked");
}
You need event.
public enum ItemTypes { None , Paperclip , Key }
[DisallowMultipleComponent]
public class Foo : MonoBehaviour {
// Action its void delegate
public event System.Action<ItemTypes> Selected;
public ItemTypes ActiveItem { get; private set; }; // property
public void ButtonSelect () {
ActiveItem = ItemTypes.Key;
Selected?.Invoke(ActiveItem); // invoke event
}
}
[DisallowMultipleComponent]
public class YourUIBar : MonoBehaviour {
[SerializeField] private Foo _foo; // link on inspector
private void OnEnable () {
ItemChange(Foo.ActiveItem); // setup current
Foo.Selected += ItemChange; // subscribe to event
}
private void OnDisable () {
Foo.Selected -= ItemChange;
}
private void ItemChange (ItemTypes item) {
// your code
}
}