I'm stuck on this one. I have two buttons that are each associated with a respective pop-up that I would like to show when the buttons are clicked and then hide when the buttons are clicked again and so on. I know I need to invert the boolean using '!' but I'm not exactly sure how to implement it in my code below. What is the correct way that my PaletteState function should be written? Thanks!
using UnityEngine ;
using System.Collections ;
using UnityEngine.UI ;
public class ShowHidePalettes : MonoBehaviour
{
public Button changeColorButton ;
public GameObject colorPalette ;
public Button brushSizeButton ;
public GameObject brushSizePalette ;
void Awake ()
{
changeColorButton.onClick.AddListener (() => PaletteState (colorPalette, true)) ;
brushSizeButton.onClick.AddListener (() => PaletteState (brushSizePalette, true)) ;
}
void Start ()
{
PaletteState (colorPalette, false) ;
PaletteState (brushSizePalette, false) ;
}
public void PaletteState (GameObject _palette, bool _visible)
{
_visible = !_visible ;
if (_visible == true)
{
_palette.SetActive (true) ;
} else
{
_palette.SetActive (false) ;
}
}
}
You need two boolean variables for each Button since each Button control two different UI/popup. You flip the respective boolean variable when the Button is clicked with the '!'. You can then pass in the boolean variable to the SetActive function.
Also, you need a way to determine which Button is pressed. You can use two different functions for that but using one and passing the Button instance is better.
You should also remove listener with RemoveListener in the OnDisable function since you subscribed to one.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class ShowHidePalettes : MonoBehaviour
{
public Button changeColorButton;
public GameObject colorPalette;
bool showColorPalette = false;
public Button brushSizeButton;
public GameObject brushSizePalette;
bool showSizeButton = false;
void Start()
{
colorPalette.SetActive(false);
brushSizePalette.SetActive(false);
}
void buttonCallBack(Button buttonClicked)
{
//Change Color Palette Button clicked
if (buttonClicked == changeColorButton)
{
showColorPalette = !showColorPalette;//Flip
colorPalette.SetActive(showColorPalette);
}
//Change Brush Size Button Button clicked
if (buttonClicked == brushSizeButton)
{
showSizeButton = !showSizeButton;//Flip
brushSizePalette.SetActive(showSizeButton);
}
}
void OnEnable()
{
changeColorButton.onClick.AddListener(() => buttonCallBack(changeColorButton));
brushSizeButton.onClick.AddListener(() => buttonCallBack(brushSizeButton));
}
void OnDisable()
{
changeColorButton.onClick.RemoveListener(() => buttonCallBack(changeColorButton));
brushSizeButton.onClick.RemoveListener(() => buttonCallBack(brushSizeButton));
}
}
Try this:
Remove the bool _visible parameter from PaletteState method.
Then alternate GameObject state by itself.
public void PaletteState (GameObject _palette)
{
_palette.SetActive (!palette.activeSelf) ;
}
Your code should be something like this :
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class ShowHidePalettes : MonoBehaviour
{
public Button changeColorButton;
public GameObject colorPalette;
public Button brushSizeButton;
public GameObject brushSizePalette;
private bool colorPalleteVisibility = false;
private bool brushSizePalleteVisibility = false;
public void PaletteState(PaleteType type)
{
if (type == PaleteType.ColorPalette)
{
colorPalleteVisibility = !colorPalleteVisibility;
colorPalette.SetActive(colorPalleteVisibility);
}
else if (type == PaleteType.BrushSizePalette)
{
brushSizePalleteVisibility = !brushSizePalleteVisibility;
colorPalette.SetActive(brushSizePalleteVisibility);
}
}
}
public enum PaleteType
{
ColorPalette, BrushSizePalette
}
Related
So I have two scripts one to press a button which changes between two objects, and what I want to do is be able to switch out the second avatar with others when I hit e when near another object. the scripts are working, but I have no clue how to get it to switch
here are the trigger script and the switch script
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwitchCharacterScript : MonoBehaviour
{
private const string ButtonName = "E";
// references to controlled game objects
public GameObject avatar1, avatar2;
// variable contains which avatar is on and active
int whichAvatarIsOn = 1;
// Use this for initialization
void Start()
{
// anable first avatar and disable another one
avatar1.gameObject.SetActive(true);
avatar2.gameObject.SetActive(false);
}
// public method to switch avatars by pressing the UI button
public void SwitchAvatar()
{
// processing whichAvatarIsOn variable
switch (whichAvatarIsOn)
{
// if the first avatar is on
case 1:
// then the second avatar is on now
whichAvatarIsOn = 2;
// disable the first one and enable the second one
avatar1.gameObject.SetActive(false);
avatar2.gameObject.SetActive(true);
break;
// if the second avatar is on
case 2:
// then the first avatar is on now
whichAvatarIsOn = 1;
// disable the second one and enable the first one
avatar1.gameObject.SetActive(true);
avatar2.gameObject.SetActive(false);
break;
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftAlt))
{
SwitchAvatar();
}
}
}
`
`
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
public class Trigger : MonoBehaviour
{
public SwitchCharacterScript player;
[SerializeField] private bool triggerActive = false;
public GameObject GameObject;
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
triggerActive = true;
}
}
void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
triggerActive = false;
}
}
private void Update()
{
if (triggerActive && Input.GetKeyDown(KeyCode.E))
{
SomeCoolAction();
}
}
public void SomeCoolAction()
{
}
}
`
In the somecoolaction is where I don't know what to do to be able to switch them; if you could not tell, I am new at this both coding and using StackOverflow.
I could not find anything on how to do something similar, or I did not know what to search for and could not find if anyone had a way to do it or a video or something.
Instead of bools I would rather store the actual reference:
public class Trigger : MonoBehaviour
{
private SwitchCharacterScript player;
void OnTriggerEnter2D(Collider2D other)
{
if (other.TryGetComponent<SwitchCharacterScript>(out var switchCharacer))
{
player = switcCharacter;
}
}
void OnTriggerExit2D(Collider2D other)
{
if (player.gameObject == other.gameObject)
{
player = null;
}
}
private void Update()
{
if (player && Input.GetKeyDown(KeyCode.E))
{
player.SwitchAvatar();
}
}
}
In general to be a bit more dynamic I would rather use an array for the characters and do e.g.
public class SwitchCharacterScript : MonoBehaviour
{
// references to controlled game objects
public GameObject[] avatars;
// variable contains which avatar is on and active
private int whichAvatarIsOn = -1;
// Use this for initialization
private void Start()
{
foreach(var avatar in avatars)
{
avatar.SetActive(false);
}
SwitchAvatar();
}
// public method to switch avatars by pressing the UI button
public void SwitchAvatar()
{
if(whichAvatarIsOn > 0 && whichAvatarIsOn < avatars.Length)
{
avatars[whichAvatarIsOn].SetActive(false);
}
whichAvatarIsOn = (whichAvatarIsOn + 1) % avatars.Length;
avatars[whichAvatarIsOn].SetActive(true);
}
}
So I'm new to C# I somewhat know Python I couldn't understand how functions work I tried doing something like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisiondetectorleft : MonoBehaviour
{
public class Triggerdetecting()
{
public void OnTriggerStay(Collider other)
{
if (other.attachedRigidbody)
other.attachedRigidbody.AddForce((Vector3.up * 10);
}
}
void FixedUpdate()
{
if (Input.GetKeyDown("space"))
{
//I'm so lost
Triggerdetecting objTriggerdetecting = new Triggerdetecting();
}
}
}
I'm trying to create some sort of hitbox by detecting trigger if a button pressed and meets the condition make the object more faster. I tried few ways to call function non of them worked. Thank you for your time. If you unable to understand what I meant you can ask me I'll try to explain in other ways.
Want something like this:
def detection():
if OnTriggerStay == True:
moveobject up
if Input.GetKeyDown("space")) == True:
detection()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisiondetectorleft : MonoBehaviour
{
//create bool to set it true or false while inside the object
private bool _canHit;
private void Update()
{
if (_canHit)
{
if (Input.GetKeyDown(KeyCode.A))
{
_canHit = false;
//task
}
}
}
//set _canHit true if object enters trigger
private void OnTriggerEnter(Collider other)
{
if (other.attachedRigidbody)
_canHit = true;
}
//set _canHit false if object exits trigger
private void OnTriggerExit(Collider other)
{
if (other.attachedRigidbody)
_canHit = false;
}
}
I was able to detect and log while true but I didn't figured how to react to object that triggers
I would go the same route as you did in your answer attempt.
The last bit missing in order to b able to actually use the according object is simple: Instead of a bool rather directly store the object
public class collisiondetectorleft : MonoBehaviour
{
private Collider _currenTarget;
private void Update()
{
if (_currenTarget && Input.GetKeyDown(KeyCode.A))
{
Debug.Log($"I am interacting with {_currentTarget}");
_currenTarget = null;
}
}
private void OnTriggerEnter(Collider other)
{
if (!other.attachedRigidbody) return;
_currenTarget = other;
}
private void OnTriggerExit(Collider other)
{
if (other != _currenTarget) return;
_currenTarget = null;
}
}
Within my, if function, the Input.GetKey("t") command does not work.
The Restart method is called when I remove the contents from the if function and place them outside.
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
bool gameHasEnded = false;
public float restartDelay = 2f;
public GameObject LevelFailedUI;
public GameObject LevelCompleteUI;
public void CompleteLevel ()
{
if (LevelFailedUI == true)
{
LevelCompleteUI.SetActive(true);
}
}
public void EndGame ()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
LevelFailedUI.SetActive(true);
if (Input.GetKey("t")) //nothing happens when "t" is pressed.
{
Invoke("Restart", restartDelay);
}
}
}
void Restart ()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
LevelFailedUI.SetActive(false);
}
}
It won't work because unity has to be inside the function and also hasn't reached the check before reaching the if statement and you press the button during one frame which is basically impossible. You have to check for input constantly that is why it is done inside the Update function.
void Update() {
if (Input.GetKey(KeyCode.T) && gameHasEnded) {
Invoke("Restart", restartDelay);
}
}
public void EndGame() {
if (gameHasEnded == false) {
gameHasEnded = true;
LevelFailedUI.SetActive(true);
}
}
I am making a small platform game and in that, I made a scene where you can change the colour of your player. I made 3 buttons that change the colour when you click on them. I also made two code files, but they are not working. I see no errors in the console either.
P.S the colour changing code and buttons are on a different scene than the game object.
This is the code for the buttons that change the colour:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColourManager : MonoBehaviour
{
public static int colour;
public void DefaultBlue()
{
colour = 0;
}
public void Green()
{
colour = 1;
}
public void Red()
{
colour = 2;
}
}
This is the code on the game object itself:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColourTarget : MonoBehaviour
{
void Start()
{
rend = GetComponent<Renderer>();
rend.sharedMaterial = materials[0];
rend.enabled = true;
}
private Renderer rend;
public int lcolour = ColourManager.colour;
public Material[] materials;
private void Update()
{
if (lcolour == 0)
{
rend.sharedMaterial = materials[0];
}
if (lcolour == 1)
{
rend.sharedMaterial = materials[1];
}
if (lcolour == 2)
{
rend.sharedMaterial = materials[2];
}
}
}
Note that changing sharedMaterial might not be what you want to do here.
If you want to modify the material of a renderer use material instead.
so rather use material. Especially once e.g. a color was changed and you are dealing with instanced materials, afterwards changing the shared material has no effect at all.
Then do not do this in Update! It is very redundant and inefficient setting this every frame!
Finally note that this
public int lcolour = ColourManager.colour;
is only assigned ONCE the moment this object is initialized and then never changed anymore ... int is a VALUE type, not a reference!
I would rather use and event and make your target listen to any changes.
So your code might look like
public class ColourManager : MonoBehaviour
{
public static int colour;
// we will invoke this event everytime the color index is changed
// and directly pass the according new index in
public static event Action<int> OnColourIndexChanged;
public void DefaultBlue()
{
colour = 0;
// The ? is a null check and only
// calls Invoke if there is at least one listener to this event
OnColourIndexChanged?.Invoke(colour);
}
public void Green()
{
colour = 1;
OnColourIndexChanged?.Invoke(colour);
}
public void Red()
{
colour = 2;
OnColourIndexChanged?.Invoke(colour);
}
}
and then
public class ColourTarget : MonoBehaviour
{
[SerializeField] private Renderer _renderer;
public Material[] materials;
private void Awake()
{
if(!_renderer) _renderer = GetComponent<Renderer>();
_renderer.enabled = true;
// Add a callback to the event
// Removing it first is save also if it wasn't added so far
// This just makes sure it is always added only exactly once
ColourManager.OnColourIndexChanged -= UpdateMaterial;
ColourManager.OnColourIndexChanged += UpdateMaterial;
// do the first update now with the current state
UpdateMaterial(ColourManager.colour);
}
// Now this is called only when the value is changed in the manager
// script and once at the beginning with the initial state
private void UpdateMaterial(int index)
{
// check for validity
if(index < 0 || index >= materials.Length) return;
_renderer.material = materials[index];
}
private void OnDestroy()
{
// Always make sure to clean up listeners once not needed anymore
// otherwise you get NullReferencExceptions
ColourManager.OnColourIndexChanged -= UpdateMaterial;
}
}
I have four buttons using the same prefab and holding 4 text elements from an array out of which only one is assigned bool value to true. I am trying to access that true element when any of false element is clicked. i want to highlight true element when the false element is clicked. can anyone please help me to achieve this functionality?
using simpleobjectpool
taking reference from unity quiz game tutorial
Thanks
Answer Button Script
public class AnswerButton : MonoBehaviour
{
public Text answerText;
private AnswerData answerData;
private GameController gameController;
private bool isCorrect;
void Start()
{
gameController = FindObjectOfType<GameController>();
}
public void Setup(AnswerData data)
{
answerData = data;
answerText.text = answerData.answerText;
}
public void HandleClick()
{
gameController.AnswerButtonClicked(answerData.isCorrect);
{
if (answerData.isCorrect)
{
}
if (!answerData.isCorrect)
{
}
}
Answer Data Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class AnswerData
{
public string answerText;
public bool isCorrect;
}
QuestionData Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class QuestionData
{
public string questionText;
public AnswerData[] answers;
}
Game Controller Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;
public class GameController : MonoBehaviour
{
public Text questionText;
public Text scoreDisplayText;
public SimpleObjectPool answerButtonObjectPool;
public Transform answerButtonParent;
public GameObject questionPanel;
public GameObject roundOverPanel;
public GameObject levelsPanel;
private DataController dataController;
private RoundData currentRoundData;
private bool isRoundActive;
private float timeBeetweenQuestions = 3.0f;
private List<GameObject> answerButtonGameObjects = new List<GameObject>();
private QuestionData[] questionPool;
private int questionIndex;
private int qNumber = 0;
private List<int> questionIndexesChosen = new List<int>();
public int playerScore = 0;
public int totalQuestions;
private static int pointAddedForCorrectAnswer;
public AudioSource answerButtonClicked;
public AudioSource wrongAnswerClicked;
void Start ()
{
dataController = FindObjectOfType<DataController>();
currentRoundData = dataController.GetCurrentRoundData();
questionPool = currentRoundData.questions;
playerScore = 0;
questionIndex = 0;
scoreDisplayText.text = "Score: " + playerScore.ToString();
isRoundActive = true;
ShowQuestion();
}
private void ShowQuestion()
{
RemoveAnswerButtons();
QuestionData questionData = questionPool[questionIndex];
questionText.text = questionData.questionText;
for (int i = 0; i < questionData.answers.Length; i++)
{
GameObject answerButtonGameObject =
answerButtonObjectPool.GetObject();
answerButtonGameObjects.Add(answerButtonGameObject);
answerButtonGameObject.transform.SetParent(answerButtonParent);
AnswerButton answerButton =
answerButtonGameObject.GetComponent<AnswerButton>();
AnswerButton.Setup(questionData.answers[i]);
}
}
private void RemoveAnswerButtons()
{
while (answerButtonGameObjects.Count > 0)
{
answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
answerButtonGameObjects.RemoveAt(0);
}
}
IEnumerator TransitionToNextQuestion()
{
yield return new WaitForSeconds(timeBeetweenQuestions);
ShowQuestion();
}
IEnumerator WaitForFewSeconds()
{
yield return new WaitForSeconds(timeBeetweenQuestions);
EndRound();
}
IEnumerator ReturnCorrectButtonColor()
{
Debug.Log("im correct");
GetComponent<Button>().image.color = Color.green;
yield return new WaitForSeconds(seconds: 2.9f);
GetComponent<Button>().image.color = Color.white;
}
IEnumerator ReturnWrongButtonColor()
{
Debug.Log("im wrong");
GetComponent<Button>().image.color = Color.red;
yield return new WaitForSeconds(seconds: 2.9f);
GetComponent<Button>().image.color = Color.white;
}
public void AnswerButtonClicked (bool isCorrect)
{
if (isCorrect)
{
playerScore += currentRoundData.pointAddedForCorrectAnswer;
scoreDisplayText.text = "Score: " + playerScore.ToString();
//play coorect answer sound
answerButtonClicked.Play();
StartCoroutine(ReturnCorrectButtonColor());
}
if (!isCorrect)
{
//play wrong answer sound
answerButtonClicked = wrongAnswerClicked;
answerButtonClicked.Play();
StartCoroutine(ReturnWrongButtonColor());
// buttons = GameObject.FindGameObjectsWithTag("Answer");
// {
// foreach (GameObject button in buttons)
// {
// if (button.GetComponent<AnswerButton>
//().answerData.isCorrect)
// {
// button.GetComponent<AnswerButton>
// ().StartCoroutine(ReturnCorrectButtonColor());
// }
// }
//}
}
if (qNumber < questionPool.Length - 1) /
{
qNumber++;
StartCoroutine(TransitionToNextQuestion());
}
else
{
StartCoroutine(WaitForFewSeconds());
}
}
public void EndRound()
{
isRoundActive = false;
questionPanel.SetActive(false);
roundOverPanel.SetActive(true);
}
//on button click return to main menu
public void ReturnToMenu ()
{
SceneManager.LoadScene("MenuScreen");
}
}
In order to highlight both Wrong (the clicked one) and the Right buttons you need to have access to both buttons. This means that you can't do highlighting from HandleClick method of your Answer Button Script, as it only has access to itself, e.g. to the Wrong button.
The good thing is that this method notifies GameController that the button has been clicked. GameController knows about all the buttons, so it can easily highlight both buttons.
So, instead of launching your highlight subroutines from Answer Button's HandleClick, you should do this from GameController's AnswerButtonClicked: identify both the Right button and the clicked button there and launch appropriate subroutines for them.
Update:
For instance, your ReturnCorrectButtonColor would look like:
IEnumerator ReturnCorrectButtonColor( GameObject button )
{
Debug.Log("im correct");
button.GetComponent<Button>().image.color = Color.green;
yield return new WaitForSeconds(seconds: 2.9f);
button.GetComponent<Button>().image.color = Color.white;
}
so in AnswerButtonClicked you identify which button to highlight as a correct answer button and pass it as a paramter to this method:
StartCoroutine(ReturnCorrectButtonColor(correctButton));