How to create a menu on click of GameObject? (Unity) - c#

I want to be able to hover over a GameObject (agent) and on either right or left click, create a floating menu similar to the windows right click menu. I have tried using a combination of OnGUI() and OnMouseOver() but I either don't get the behaviour I need or get nothing at all. Here is what I have so far:
private void OnMouseOver()
{
mouseOver = true;
mousePos = Input.mousePosition;
}
private void OnMouseExit()
{
mouseOver = false;
}
private void OnGUI()
{
if (mouseOver && Input.GetMouseButtonDown(0))
{
GUI.Box(new Rect(mousePos.x, mousePos.y, 200f, 100f), "this is a test");
}
}
mouseOver and mousePos are initialy set to false.

Input.GetMouseButtonDown() only executes for a single frame so the GUI.Box is being drawn but only for a single frame.
To fix this Input.GetMouseButton() can be used instead as it executes for as long as the button is pressed.

What I do is create my desired menu in a Canvas, add an animator controller and an animation and put it outside of the camera view (the animation moves the menu inside the camera view), finally add a bool condition trigger to hide or show the menu
Then i just attach a click function into a button to fire the animation when somebody clicks it
public class ShowMenu : MonoBehaviour
{
public Animator ObjectBtnAnimations;
public void HideObjControls()
{
if (ObjectBtnAnimations.GetBool("hide"))
{
ObjectBtnAnimations.SetBool("hide", false);
}
else
{
ObjectBtnAnimations.SetBool("hide", true);
}
}
}

Related

How to create a pie menu in Unity 3D for switching weapons?

Long story short, I'm trying to create a UI panel where you hold and drag your mouse wheel button and select the option you want (while holding that button). So it is a pop-up menu that is triggered when you press the mouse wheel button. When you release the button, there are 2 possible situations:
You didn't move your cursor to a valid position. The pop-up menu is closed.
You moved your cursor to a valid position. You triggered an option from this pop-up menu.
To give you an example, the weapon switch system in, say, Tomb Raider does this similarly. It looks like a roulette, you hold the button then move your cursor to a certain location that "belongs" to, say, shotgun. Then you release the button, the menu is closed and now you are equiped with a shotgun.
Right now, the pop-up panel kinda works. However it's not a hold-release mechanism but a click mechanism. You click the button once, then the menu pops up and stays there.
How do you do that in Unity3D?
Here is my script so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PosSelector : MonoBehaviour
{
Animator posSelectorAnimator;
public GameObject posSelector;
public Animator posButtonAnimator;
void Start ()
{
posSelectorAnimator = posSelector.GetComponent<Animator>();
}
void Update ()
{
if (Input.GetKeyDown(KeyCode.Mouse2))
{
Open();
}
if (Input.GetKeyUp(KeyCode.Mouse2))
{
Close();
}
}
void Open()
{
Vector3 mousePos = Input.mousePosition;
Debug.Log("Middle button is pressed.");
posSelector.transform.position = (mousePos);
posSelectorAnimator.SetBool("ButtonDown", true);
}
void Close()
{
if (posButtonAnimator.GetCurrentAnimatorStateInfo(0).IsName("Highlighted"))
{
Debug.Log("Position selected.");
Debug.Log(posButtonAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash);
}
else
{
Debug.Log("Input not found.");
Debug.Log(posButtonAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash);
}
}
}
First of all, what you are cresting is called a pie menu.
You could create a script for the buttons inside your pie menu. Then let that script inherit from MonoBehaviour, IPointerEnterHandler and IPointerExitHandler.
These interfaces force you to implement the following methods:
public void OnPointerEnter(PointerEventData eventData)
{
PosSelector.selectedObject = gameObject;
}
public void OnPointerExit(PointerEventData eventData)
{
PosSelector.selectedObject = null;
}
Now create a static field in your PosSelector script called selectedObject:
public static GameObject selectedObject;
Then in your Close() Method, you can use selectedObject as your output:
void Close()
{
//Close your menu here using the animator
//Return if nothing was selected
if(selectedObject == null)
return;
//Select a weapon or whatever you want to do with your output
}
Also, consider renaming your question to something like "how to create a pie menu in unity? " so that other people with the same question have an easier time finding this question

(Unity - C#) Problems with buttons triggering other events

I'm developing a 2D mobile game where the player should tap on the screen to go up. I just added a pause button recently and I've noticed that when I click the button it counts as a tap on the screen, so the player goes up. Basically, in the same exact moment that I press the pause button, the player jumps and then the game freezes while he is in mid-air. Is there a way I could make so the button wouldn't count as a tap?
Here's the part of the player script that makes him move:
if (Input.GetMouseButtonDown (0) && isDead == false && isKnifeDead == false && UiStartScript.uiInstance.firstClickUi == true) {
rb.velocity = Vector2.up * velocity;
}
Heres's the part of the UI script for the pause button:
public void PauseGame()
{
Time.timeScale = 0;
}
My EventSystem:
EventSystem
My Button:
Button
An easy with no code required is to remove the code about detecting tap on screen and instead place a button that covers the whole screen (invisible button).
That button event would trigger the screen movement.
You can add extra buttons on top and Unity will automatically discard the tap from any other button below.
This way you can start adding UI all over without checking in code which should be considered.
In U. I script add
public GameObject PlayerConrtollerScript;
In your U.I Script, under the class Pausgame()
Add this code.
GameObject.PlayerControllerScript.SetActive = false;
When unpaused you need to add to your script that has the
Time. timeScale =1;
Add this code.
GameObject.PlayerControllerScript.SetActive = true;
After you have added the code mentioned above. Don't forget to add the player game object from your hierarchy into the Inspector with the U. I script, the space will be available to add a game object when you scroll down to your U. I script.
That will stop your player from moving around during pause.
This is the approach that I been done. I create a cople of tricks using Event System and Canvas for take advantage of the Mouse Input, you don't need the use of Updates functions for do the basic gameplay.
Here's my example project: TapAndJump on Github
Check the GameObjects called "Click Panel" and "Pause Button" and
respective linked methods.
JumpWithTap.cs
using UnityEngine;
public class JumpWithTap : MonoBehaviour
{
[SerializeField] private UIHandler uiHandler;
[SerializeField] private float jumpPower = 5f;
private Rigidbody2D rb2D;
private int counter;
#region Class Logic
public void Jump()
{
rb2D.velocity = Vector2.up * jumpPower;
uiHandler.SetNumberToCounter(++counter);
}
#endregion
#region MonoBehaviour API
private void Awake()
{
rb2D = GetComponent<Rigidbody2D>();
}
#endregion
}
UIHandler.cs
using UnityEngine;
using UnityEngine.UI;
public class UIHandler : MonoBehaviour
{
[SerializeField] private Text counterText;
[SerializeField] private Text pauseText;
[SerializeField] private Image clickPanel;
private bool isPaused = false;
public bool IsPaused
{
get { return isPaused; }
set
{
pauseText.gameObject.SetActive(value);
isPaused = value;
}
}
#region Class Logic
public void SetNumberToCounter(int number) => counterText.text = number.ToString();
public void DisableClickPanel() => clickPanel.raycastTarget = !clickPanel.raycastTarget;
public void PauseGame()
{
IsPaused = !IsPaused;
DisableClickPanel();
// Time.timeScale = IsPaused == true ? 0 : 1; // If you want keep the Physics (ball fall) don't stop the time.
}
#endregion
}
I guided by your code example and so on; be free that modify and request any issue.

Changing the image of long clicked Sprite

I am trying to change the image of a sprite that's had a long click on it.
My below code works except in the LongPress method it changes the image of all sprites that have this script assigned as an inspector component. Additionally, the code triggers after long clicking anywhere onscreen, not isolating itself to just the sprites with the script assinged
OnMouseDownAsButton would solve a lot of the issues, however wrapping bits of my code in an OnMouseDownAsButton function to isolate the colliders seems to cancel out the update() method.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class LongClickButton : MonoBehaviour
{
public Sprite flagTexture;
public Sprite defaulttexture;
public float ClickDuration = 2;
public UnityEvent OnLongClick;
bool clicking = false;
float totalDownTime = 0;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
totalDownTime = 0;
clicking = true;
}
if (clicking && Input.GetMouseButton(0))
{
totalDownTime += Time.deltaTime;
if (totalDownTime >= ClickDuration)
{
clicking = false;
OnLongClick.Invoke();
}
}
if (clicking && Input.GetMouseButtonUp(0))
{
clicking = false;
}
}
public void LongPress()
{
if (GetComponent<SpriteRenderer>().sprite == flagTexture)
{
GetComponent<SpriteRenderer>().sprite = defaulttexture;
}
else if(GetComponent<SpriteRenderer>().sprite == defaulttexture)
GetComponent<SpriteRenderer>().sprite = flagTexture;
}
}
Try using OnMouseDown functions and OnMouseUpAsButton. Your current issue seems that the Input detects of a mouse down anywhere on screen, which causes all scripts to activate, which causes the changes.
void OnMouseDown() {
clicking = true
}
void OnMouseUpAsButton(){
clicking = false
}
void Update() {
if(clicking){
//your time stuff
}
}
You could add a EventTrigger component to the gameobject with the "OnPointerEnter" and "OnPointerExit" events to check if the mouse is on that object (Make OnPointerEnter call a function that sets a boolean to true and OnPointerExit to set that boolean to false).
What you could do is make your script implement interafaces IPointerEnterHandler, IPointerExitHandler found in namespace UnityEngine.EventSystems. Inside onPointerEnter and onPointerExit you could set a value of boolean variable.

How to make a function perform with a button input that was written for keyboard input?

I'm creating a game for iOS and I have some pre-written code to perform an action within my game when the R key or any anywhere on the screen is clicked. I'm wanting this action to only be performed when I click/tap a designated button in game and not just anywhere on the screen.
I've tried changing one of the inputs to Input.GetTouch() and also adding the script to an existing button.
using UnityEngine;
using DiceMaster;
public class Roller : MonoBehaviour
{
Spinner spinner;
Thrower thrower;
void Start()
{
spinner = GetComponent<Spinner>();
thrower = GetComponent<Thrower>();
if (spinner)
spinner.autoDestroy = false;
if (thrower)
thrower.autoDestroy = false;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.R) || Input.GetMouseButtonDown(0))
{
if (thrower) thrower.Trigger();
if (spinner) spinner.Trigger();
}
}
}
I want only the designated button in game to initiate the action (i.e tapping the button on an iPhone) but NOT when the screen is clicked anywhere else or if other buttons are pressed. What would be the best way to change it?

Playing animation on button click with a condition

I want to do menu animation. In the animator, its contain 2 animations. One is opening animation, the other is closing animation. I set the opening animation as default state and added condition between of them. The condition is a bool type parameter. I drag the script which controls they behaviours and animator component on gameobject, but when the opening animation plays and player clicks the play button the parameter turns into true but it doesn't play.
Animator canvasAnim;
public Button lvlSelector;
Button lvlSelector_A;
// Use this for initialization
void Start () {
canvasAnim = GetComponent<Animator>();
lvlSelector_A = lvlSelector.GetComponent<Button>();
lvlSelector_A.onClick.AddListener(LevelSelector);
}
IEnumerator SlideLevelSelectMenu()
{
yield return new WaitForSeconds(1f);
SceneManager.LoadScene("LevelSelectMenu");
}
void LevelSelector()
{
canvasAnim.SetBool("clickedclose", true);
StartCoroutine(SlideLevelSelectMenu());
}
Animator:
Gameobject:
This problem occurs because of your Animator. You should call Animator on Canvas game object (Not on Menu Manager). Just change your script to this:
void Start () {
canvasAnim = GameObject.Find("Canvas").GetComponent<Animator>();
...
}
I hope it helps you.

Categories

Resources