Well, I already know that Unity itself has the Sprite Swap function, for that, but I wanted it to click when I changed the image and returned the old one only when it closed the window that was opened, or if I clicked it again on the icon, I tried to several ways so I turned to a helpy
Video link:- https://youtu.be/-H7j3vdKl8A.
Visit github if u dont undertand it here.
https://github.com/NareshBisht/Unity-UI-Shop-Select-2-UI-object-at-same-time/blob/master/ButtonAnimationHold.cs
Thank you.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
//*************************Script to select one "Category(say Weapon)" UI Button till anathor category button(say Vehicles) is pressed.********************************//
/*
* Steps to be followed to make this script work
* Select All the Category Buttons (for example:- Suppose u r builiding a shop UI then Select all Category button Like Helics, Weapons -- refer to video link above;
* Now tag all these category button as same (say UI_CategoryButtons).
* Attach this script to all the UI_category button.
* the script will aotomatically add Button, Animator, Image component to the Ui Gameobjects.
* now select Animation in Transition tab.
* now press the Auto genrate Animation in Button component tab.
* now, set Transition from Animation to none in button Tab.
* Now, Do the above step for Sub category UI element too (for eg do for Apache, Tiger, f-22 etc which is the sub category of Helics --- refer video)
* open Animation window and Animate ur Ui elements.
* ur good to go now.
*/
[RequireComponent(typeof(Button))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(Image))]
public class ButtonAnimationHold : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
public float TransitionTime = 0.3f; //Time taken to transition from one animation state to anathor.
private Animator MyAnim; //reference to animator attacted to the UI gameObject.
private void Start()
{
MyAnim = GetComponent<Animator>();
PlayNoramlState(); //Playing normal state at beginning.
}
public void HighlightThisButton_UnhighlightRest() //called when button is pressed (Called by OnPointerClick() defined below)
{
string TagOfPressedButton = gameObject.tag; //the tag of the button pressed by user.
foreach (Button button in gameObject.GetComponentInParent<Transform>().root.gameObject.GetComponentsInChildren<Button>()) //searching the gameobject with tag as in TagOfPressedButton inside the canvas which contain all UI element.
{ //we search inside Canvas to improve perf.
if(button.gameObject.tag == TagOfPressedButton && button.gameObject != this.gameObject) //selecting gameobjects with same tag(tag of button which was pressed) execpt the one which was pressed and then playing normal state in all selected GO.
{
button.gameObject.GetComponent<ButtonAnimationHold>().PlayNoramlState(); //Playing normal state in all UI gameObject with same tag except the one which called it.
}
}
MyAnim.Play("Pressed"); //Playing Pressed state in the UI element that was pressed.
}
public void PlayNoramlState()
{
MyAnim.CrossFadeInFixedTime("Normal", TransitionTime); //smoothly transitioning to Normal state;
}
public void OnPointerEnter(PointerEventData eventData) //Called when pointer hover over the Ui elemnt;
{
if(MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Normal")) //Playing highlighted state only when it is in normal state and not when it is in Pressed state.
{
MyAnim.CrossFadeInFixedTime("Highlighted", TransitionTime); //smoothly transitioning to Highlighted state;
}
}
public void OnPointerExit(PointerEventData eventData)
{
if (MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Highlighted") || MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Normal")) //Playing Normal state only when it is in Highlighted state and not when it is in Pressed state
{
MyAnim.CrossFadeInFixedTime("Normal", TransitionTime); //smoothly transitioning to Normal state;
}
}
public void OnPointerClick(PointerEventData eventData) //called when button is pressed that is pointer down and pointer up both have to be done over button
{
HighlightThisButton_UnhighlightRest();
}
}
//video link
//https://youtu.be/-H7j3vdKl8A
Related
I'm sorry if my English is bad at first.
The button
This is the button I want to run the animation when pressed.
Animations
Sprites I want to change between these two states when pressing the button
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
public class Button : MonoBehaviour
{
private Animator animator;
public void SetTrigger(string Pressed) { }
Collider2D col;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
animator.SetFloat("Position", 0);
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
Vector2 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
if (touch.phase == TouchPhase.Began)
{
Collider2D touchedCollider = Physics2D.OverlapPoint(touchPosition);
if (col == touchedCollider)
{
animator.SetFloat("Position", 1);
}
}
}
}
}
This is how the code has been after the last attempt I have made, it has things that may not make sense because I have been mixing things while testing. I have tried it with floats, bools and triggers. With the bool it has worked halfway for me, if I touched the button it did not sink but if from unity I pressed the button manually changing the boolean to true, and after touching from the mobile screen it recognized the touch and returned the button to the original position. In all situations what did not work well was the touch control but I have revised the touch control code and I would say that it is fine.
Sorry if it is not understood well, I am new to unity and programming, also English is not my main language
Are you sure Button does not already have implementation for what you are trying to achieve? Check what options are available under "Transition" in Button inspector. You can pick between Color Tint, Sprite Swap or Animation there, I suppose it handles most of the cases and I've never seen anyone implemeting animations to button in custom way.
I'm making an upgrade button for a game I'm creating, obviously I want the upgrade to only be available once, how do I code that?
I looked around the internet and each person suggested trying the following:
Bouton.SetActive (false);
or something like that. However, this makes the button inactive during startup. I want it to be inactive or destroyed after just one click. the button in question must be a GameObject
Anyone know how to fix this?
Thank you in advance!
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class One_One_Click_to_Save_the_GameObject_Deactivate_If_scene_replay : MonoBehaviour
{
public GameObject Bouton;
void Start()
{
if (PlayerPrefs.HasKey("buttonState")) // if the button was saved in memory
{
if (PlayerPrefs.GetInt("buttonState") == 0) //if the value is 0
Bouton.SetActive (false); // make button disabled
}
else
{
PlayerPrefs.SetInt("buttonState", 1); // saving in memory that button is on
}
}
public void buttonCliked()
{
Bouton.SetActive(false); // making the button disabled
PlayerPrefs.SetInt("buttonState", 0); //saving in memory that button is off
}
}
First of all you do not have any code piece to reset the state of your button on PlayerPrefs.
You should go to Edit -> Clear All PlayerPrefs on Unity Editor to get rid of the previous saved states.
Then you will check if the player is already used the upgrade button which you did on start but you dont need the else statement because in default it will be already active on the scene so this should be enough
void Start()
{
if (PlayerPrefs.HasKey("buttonState")) // if the button was saved in memory
{
if (PlayerPrefs.GetInt("buttonState") == 0) //if the value is 0
Bouton.SetActive (false); // make button disabled
}
}
Alternatively you can use the PlayerPrefs.GetInt() method with a default parameter so you don't need to check if it has a key, like this
void Start()
{
if (PlayerPrefs.GetInt("buttonState",1) == 0) // This will return 1 if there is no key with the name "buttonState"
Bouton.SetActive (false);
}
And after you clicked the upgrade which you should be doing on your buttonCliked() method. You can set the buttonstate to zero and it will always disable it on start. If you want to reset the state you need to clear the player prefs again like we did it on first step
public void buttonCliked()
{
Bouton.SetActive(false); // making the button disabled
PlayerPrefs.SetInt("buttonState", 0); //saving in memory that button is off
}
But again alternatively you can disable the clicking function on the button rather than just disabling it on the menu. What you should do is create a Button reference rather than a gameobject (or get the button component on the gameobject) and set it's interactable field to false. Which makes the button not clickable but still be seen on the screen.
You can use public Button Bouton; rather than public GameObject Bouton;and instead of using Bouton.SetActive (false); you can now call Bouton.interactable = false;
I'm trying to divide the screen to 2 and use them as 2 different buttons (L,R) in Unity. But for the ones who are playing first time, I want to show the buttons' text and image to teach them what they do, and after that I want to disable buttons' image and text, they will be still interactable but invisible.
First time screen
How can I ?
Way easier and more reliable than what you did would simply be do add something like this to your Button:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
[DisallowMultipleComponent]
public class HintsController : MonoBehaviour
{
private Image _image;
private Text _text;
private float _originalAlpha;
// optional to control if Hints should be enabled on starting the App
public bool enableAtStart;
private void Awake()
{
// GetComponentInChildren finds the component on this object or any
// child of this object recursively
// (true) : make sure you also find the components if this or the child objects
// are currently disabled
// On this way you don't even have to rely on that the Image is on the
// Button GameObject or below in the hierachy
_image = GetComponentInChildren<Image>(true);
_text = GetComponentInChildren<Text>(true);
if(_image)
{
_originalAlpha = _image.color.a;
}
// optional to controll if Hints should be enabled on starting the App
ShowHints(enableAtStart);
}
public void ShowHints(bool isVisible)
{
// Skip if no Image found
if (_image)
{
var color = _image.color;
color.a = isVisible ? _originalAlpha : 0;
_image.color = color;
}
// Skip if no Text found
if (_text)
{
_text.enabled = isVisible;
}
}
}
Then from any other script, you simply can do e.g.
// TODO somehow get the reference either to the button GameObject or the Button component
var button;
button.GetComponent<HintsController>().ShowHints(false);
To disable hints.
I used button.image.enabled = bool valuefor image component and button.transform.GetChild(0).gameObject.SetActive(bool value) for the text.
i would suggest just making an empty for each button in the scene view, name them left and right. drag you button images(sprites) onte the scene and size them to fill the camera with proper positioning. apply boxCollider2D to both of the parent game objects(the empties you created and named left and right.) then you will need some light scripting.
pseudo-wise i would say:
you will use:
void OnMouseDown(){
//button touched
}
to see if the button is pressed.
when your tutorial is over you will set the image and text invisible with the code you mentioned above or something similar. this script goes on each button.
I have a chunk of code similar to this:
GameObject prefab; // Gets set when GUI button is clicked
void Update(){
if(Input.GetMouseButtonUp(0) && prefab){
Instantiate(prefab, /* At mouse position on ground */);
prefab = null;
}
}
Here is the code when I click the button:
public void SetBuilding(GameObject building){
prefab = building;
Destroy(ghostBuildingObject);
ghostBuildingObject = Instantiate(building);
if (ghostBuildingObject) {
// Set the alpha to half
Color c = ghostBuildingObject.GetComponent<MeshRenderer>().material.color;
c.a = 0.5f;
ghostBuildingObject.GetComponent<MeshRenderer>().material.color = c;
// Disable Components
ghostBuildingObject.GetComponent<Collider>().isTrigger = true;
Destroy(ghostBuildingObject.GetComponent<NavMeshObstacle>());
Destroy(ghostBuildingObject.GetComponent<Building>());
ghostBuilding = ghostBuildingObject.AddComponent<GhostBuilding>();
ghostBuildingObject.layer = LayerMask.NameToLayer("Ghost");
ghostBuildingObject.name = "Ghost Building";
}
}
Basically what it does is creates an object where I click on the ground object. What happens is when I click on a button it still creates the game object. How can I stop it from creating a gameObject when I click on a GUI Button?
Was in the process of typing this before you put your own answer. I still decided to put my answer because what you did in your answer is so wrong and unnecessary. You are allocating memory multiple times per frame, in the code in your answer only to detect a click...
I am using a Button (UnityEngine.GUI.Button)
I am using the unity5 GUI elements
You shouldn't be using that to begin with. Some people suggests you should use a raycast but the problem of a ray passing through a UI will still remain.
What you need is the a Button from UnityEngine.UI.Button not UnityEngine.GUI.Button. You have to change your whole program to use UI from UnityEngine.UI.
To create your button, you go to GameObject->UI->Button. That should create Canvas and other components required to get Button to work. Here are Unity UI tutorials.
Basically what it does is creates an object where I click on the
ground object.
You can detect a button click by implementing IPointerClickHandler and overriding the OnPointerClick function.
Attach the script below to the ground you want to detect the click.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Click : MonoBehaviour, IPointerClickHandler
{
void Start()
{
Camera.main.gameObject.AddComponent<PhysicsRaycaster>();
}
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Clicked!");
}
}
For your Button, you can just subscribe to to Buttons using the Button.onClick.AddListener(() => functionName());. Below is a full code for detecting clicks on 3 buttons. The good thing about this is that only one click will be detected. Clicks will not go through other GameObjects and you are NOT allocating memory each frame just to detect a button click.
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour
{
public Button button1;
public Button button2;
public Button button3;
void OnEnable()
{
//Register Button Events
button1.onClick.AddListener(() => buttonCallBack(button1));
button2.onClick.AddListener(() => buttonCallBack(button2));
button3.onClick.AddListener(() => buttonCallBack(button3));
}
private void buttonCallBack(Button buttonPressed)
{
if (buttonPressed == button1)
{
//Your code for button 1
//Call your SetBuilding(GameObject building) function for any button
SetBuilding(someGameOBject);
}
if (buttonPressed == button2)
{
//Your code for button 2
}
if (buttonPressed == button3)
{
//Your code for button 3
}
}
void OnDisable()
{
//Un-Register Button Events
button1.onClick.RemoveAllListeners();
button2.onClick.RemoveAllListeners();
button3.onClick.RemoveAllListeners();
}
}
I don't know if i clearly understand but you are Instantiating on the button and at the click:
ghostBuildingObject = Instantiate(building);
and
Instantiate(prefab, /* At mouse position on ground */);
so it's normal for it to be created 2 times
Have you tried with:
if(Input.GetMouseButtonUp(0) && prefab != null){
Instantiate(prefab, /* At mouse position on ground */);
prefab = null;
}
Using Pointer Events seems to fix the issue:
void Update(){
// Get pointer events
var pointer = new PointerEventData(EventSystem.current);
pointer.position = Input.mousePosition;
// Test the raycast
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointer, raycastResults);
// Check if anything was cast
if(Input.GetMouseButtonUp(0) && raycastResults.Count == 0 && prefab){
Instantiate(prefab, /* At mouse position on ground */);
prefab = null;
}
}
I have recently been making the UI for a game I am creating and have run into a problem.
I have been trying to find a way in the new Unity 4.6 for the user to be able to click on a player card and have it select the player they clicked on.
public void Panel1Click()
{
GameManager.Player1Select ();
}
This is the way I am doing it at the moment, calling this when the player clicks on Panel 1, there are also 3 more for each of them.
I have been researching different methods on how to find the object the player clicks the execute the correct selecting code.
if (GameObject.Find ("Panel 1"))
{
print ("Click Panel 1");
GameManager.Player1Select();
}
This is one of the methods I tried, however nothing gets called. (Because it just checks if the object exists/is true? I think).
All these methods are linked to the EventSystem component on the panels.
Is there a more efficient way of condensing all the functions and just checking which panel the player clicks on?
You can add a collider to the game object (sprite), and then in the OnMouseDown function to test if it is clicked.
Select the card --> Add a box collider to it --> Add a MonoBehaviour script and attach to the card --> In the script, add function:
bool bClicked = false;
void OnMouseDown()
{
Debug.Log(gameObject.name + " is clicked");
bClicked = true;
}
You can actually have one parameter for your click handler. Supported types are: int, float, string and object reference. So you can define your handler like this:
public void SelectCharacter(int character) {
GameManager.PlayerSelect(character)
}
Then just set the parameter in the event trigger.
Create a script and put it on the object(Panel) you want to interact with, then try this code. In this example it finds the parent panel and sets it to inactive
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class CloseInventory : MonoBehaviour, IPointerDownHandler
{
GameObject inventoryPanel;
// Use this for initialization
void Start()
{
inventoryPanel = GameObject.Find("Inventory Panel");
}
public void OnPointerDown(PointerEventData eventData)
{
//SET WHAT TO DO HERE
inventoryPanel.SetActive(false);
}
}