Unity - Input.GetMouseButtonDown - c#

I created a script where by clicking on the smartphone display, an object was activated. I used Input.GetMouseButtonDown(0) to check if a tap was made on the display. The script works fine, but I have a problem: if I insert a button in the scene, clicking on the button I receive both the click of the button and that of the Input.GetMouseButtonDown function. How could I "divide" the two touches?
// Example
void Update()
{
if (Input.GetMouseButtonDown(0))
myObject.SetActive(true);
}
public void PauseButton()
{
// Open Pause Panel
}
I was thinking of deleting "Input.GetMouseButtonDown (0)" and using an invisible button and resizing it on the portion of the display I needed.

Add Tag to your UI button like: "UI"
Below function tells whether a click was Over a UI object tagged with a UI tag, so you can check in your screen tap function if you should fire your event or not
public static class InputHandler
{
public const string CompareTagForUIElements = "UI";
public static bool IsPointerOverUIObject(int touchId)
{
var eventDataCurrentPosition = new PointerEventData(EventSystem.current);
// I'm using touch since you are talking about smartphones,
// if you still need click use Input.mousePosition
eventDataCurrentPosition.position = new Vector2(GetTouch(touchId).position.x, GetTouch(touchId).position.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
for (int i = 0; i < results.Count; i++)
{
if (results[i].gameObject.CompareTag(CompareTagForUIElements))
return true;
}
return false;
}
}
So rather than
public void ITappedOnScreen()
{
if(Input.GetMouseButtonDown(0))
Debug.Log("Screen tapped");
}
use
public void ITappedOnScreen()
{
if(Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Begin &&
!InputHandler.IsPointerOverUIObject(0))
Debug.Log("Screen tapped");
}

Related

Area2D only becomes invisible when clicked on the edges. (c#)

I have created a pause screen Area2D for my game, in any case the player goes AFK. I wrote a code so whenever the key P is pressed it appears and everything pauses, and if it is clicked it disappears and everything goes back to normal. I wrote a code, but it didn't work
I tried this:
public override void _PhysicsProcess(float delta)
{
// Makes the pause screen visible when P is pressed
if (Input.IsActionPressed("Pause"))
{
Visible = true;
}
}
public override void _Ready()
{
}
public void _on_PauseScreen_mouse_entered()
{
if (Input.IsActionPressed("click"))
{
Visible = false;
}
}
But it only works when clicked on the edges, I know that's how collisions are but how do I make it so when anywhere the sprite is pressed, it disappears?
The problem in your code should be, that you are just checking if the action is pressed, when the mouse entered the area.
If you move the mouse to the middle of the area and click then, your event was already fired.
Create a variable to track, if the mouse is currently in the area by using entered and exit signals and use that to determine if something should happen when you click:
bool bMouseEntered = false
public override void _PhysicsProcess(float delta)
{
// Makes the pause screen visible when P is pressed
if (Input.IsActionPressed("Pause"))
{
Visible = true;
}
if (Input.IsActionPressed("click") && bMouseEntered)
{
Visible = false;
}
}
public override void _Ready()
{
}
public void _on_PauseScreen_mouse_entered()
{
bMouseEntered = true;
}
public void _on_PauseScreen_mouse_exited()
{
bMouseEntered = false;
}
I want it so if it is pressed anywhere on the pause screen, it dissapears.
That is probably the simplest case. And the easier way to do it is to put the check in _physics_process, where the other check is:
public override void _PhysicsProcess(float delta)
{
// Makes the pause screen visible when P is pressed
if (Input.IsActionPressed("Pause"))
{
Visible = true;
}
if (Input.IsActionPressed("click"))
{
Visible = false;
}
}
So it has nothing to do with collision or the mouse. It is just checking for the action regardless of where or how it happens.
We can argue that using _input or _unhandled_input is better, in particular if timing is critical, but I don't expect it to be an issue in this case.
Addendum:
I want it so when it is pressed anywhere ON THE PAUSE SCREEN. it disappears. it doesn't cover the full screen.
At the time of writing Bugfish already has a working solution. I'll give you an alternative.
Since you are using an Area2D it must have the property input_pickable, when it is set to true (which is the default) it allows to "pick" the Area2D with the mouse. And you would get this interaction in the input_event signal or overwriting _input_event. Which would look like this:
void _InputEvent(Viewport viewport, InputEvent ev, int shapeIdx)
{
var btn = ev as InputEventMouseButton;
if(btn != null && ev.ButtonIndex == ButtonList.Left && ev.Pressed)
{
Visible = false;
}
}

Enable & Disable Button On your Turn

I am trying to configure this type of game where I have 6 players connected to the same room. On game start, the Master Client (first player turn) starts where the UI button should be enabled only to him and it should be disabled to all other players and after the first player click the button it will get disabled and for the 2nd player alone it should be enabled and so on to all other players.
So i have this idea where a loop should iterate through the list of players when a button is clicked by the first or master client then getNext() that is the next player as per the actor number. The problem is how do i put in code?
I was also recommended to use Custom properties but it has been a huge problem to me since i don't understand them. Watched some of the tutorials and also some documentation but I seem not to understand.
I am currently not using photonview component.
let me just write a short code of what i mean;
public class GameManager : MonoBehaviourPunCallbacks
{
private ExitGames.Client.Photon.Hashtable _myCustomProperties = new ExitGames.Client.Photon.Hashtable();
private void Start()
{
//onstart the master client should only be the one t view the button and click it
//his name should be displayed when it his turn
if (PhotonNetwork.IsMasterClient)
{
Player_Name.text = PhotonNetwork.MasterClient.NickName + " " + "it's your turn";
button.SetActive(true);
}
}
//onclcik the Button
public void TurnButton()
{
for(int i = 0; i<PhotonNetwork.Playerlist.length; i++)
{
//so every click of the button a loop should iterate and check the player if is the next to see the button and click it
//a name should also be displayed on his turn as per his nickname
}
}
}
There is no need for custom player properties here.
I would rather use room properties for that
public class GameManager : MonoBehaviourPunCallbacks
{
private const string ACTIVE_PLAYER_KEY = "ActivePlayer";
private const string ACTIVE_ME_FORMAT = "{0}, you it's your turn!!";
private const string ACTIVE_OTHER_FORMAT = "Please wait, it's {0}'s turn ...";
private Room room;
[SerializeField] private Button button;
[SerializeField] private Text Player_Name;
#region MonoBehaviourPunCallbacks
private void Awake()
{
button.onClick.AddListener(TurnButton):
button.gameObject.SetActive(false);
Player_Name.text = "Connecting ...";
// Store the current room
room = PhotonNetwork.CurrentRoom;
if (PhotonNetwork.IsMasterClient)
{
// As master go active since usually this means you are the first player in this room
// Get your own ID
var myId = PhotonNetwork.LocalPlayer.ActorNumber;
// and se it to active
SetActivePlayer(myId);
}
else
{
// Otherwise fetch the active player from the room properties
OnRoomPropertiesUpdate(room.CustomProperties);
}
}
// listen to changed room properties - this is always called if someone used "SetCustomProperties" for this room
// This is basically the RECEIVER and counter part to SetActivePlayer below
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
// Maybe another property was changed but not the one we are interested in
if(!propertiesThatChanged.TryGetValue(ACTIVE_PLAYER_KEY, out var newActiveID)) return;
// if we got a value but it's not an int something is wrong in general
if(!(newActiveID is int newActvieIDValue))
{
Debug.LogError("For some reason \"ACTIVE_PLAYER_KEY\" is not an int!?");
return;
}
// otherwise apply the ID
ApplyActivePlayer(newActvieIDValue);
}
// Optional but might be important (?)
// In the rare case that the currently active player suddenly leaves for whatever reason
// as the master client you might want to handle this and go to the next player then
//public override void OnPlayerLeftRoom (Player otherPlayer)
//{
// if(!PhotonNetwork.IsMasterClient) return;
//
// if(!propertiesThatChanged.TryGetValue(ACTIVE_PLAYER_KEY, out var currentActiveID) && currentActiveID is int currentActiveIDValue) return;
//
// if(currentActiveIDValue != otherPlayer.ActorNumber) return;
//
// var nextPlayer = Player.GetNextFor(currentActiveIDValue);
// var nextPlayerID = nextPlayer.ActorNumber;
// SetActivePlayer(nextPlayerID);
//}
#endregion MonoBehaviourPunCallbacks
// Called via onClick
private void TurnButton()
{
// this gets the next player after you sorted by the actor number (=> order they joined the room)
// wraps around at the end
var nextPlayer = Player.GetNext();
// Get the id
var nextPlayerID = nextPlayer.ActorNumber;
// and tell everyone via the room properties that this is the new active player
SetActivePlayer(nextPlayerID);
}
// This writes the new active player ID into the room properties
// You can see this as kind of SENDER since the room properties will be updated for everyone
private void SetActivePlayer(int id)
{
var hash = new ExitGames.Client.Photon.Hashtable();
hash[ACTIVE_PLAYER_KEY] = id;
room.SetCustomProperties(hash);
}
// this applies all local changes according to the active player
private void ApplyActivePlayer(int id)
{
// get the according player
var activePlayer = Player.Get(id);
// Am I this player?
var iAmActive = PhotonNetwork.LocalPlayer.ActorNumber == id;
// Set the button active/inactive accordingly
button.gameObject.SetActive(iAmActive);
// Set the text accordingly
Player_Name.text = string.Format(iAmActive ? ACTIVE_ME_FORMAT : ACTIVE_OTHER_FORMAT, activePlayer.NickName):
}
}

How can call method onEndEdit inputfield or Ok button clicked in unity?

I have an InputField for search terms in my application witch develop with unity.
On android mobile device , I need to find when Ok or Done clicked by user or edit the inputfield end to call a method to doing search.
Ok, After try many code and document ! solved it :
public void Start()
{
//Adds a listener that invokes the "LockInput" method when the player finishes editing the main input field.
//Passes the main input field into the method when "LockInput" is invoked
termInputField.onEndEdit.AddListener(delegate { LockInput(termInputField); });
}
void LockInput(TMP_InputField input)
{
if (input.text.Length > 2)
{
Debug.Log("Text has been entered");
DoSearch();
}
else if (input.text.Length == 0)
{
Debug.Log("Main Input Empty");
}
}
public void DoSearch()
{
//My Code For Doing Search!
}

How to delete dynamically loaded gameobjects from a List in Untiy?

I have a list that loads its content dynamically. The Elements of the List are buttons that are being transformed into gameobjects. For every object in the user list a new Element is created. Now I want to be able to delete the Element along with the button itself, when the button is pressed, where each Element has its own dynamically created delete button. I tried putting a box collider with an OnMouseDown Event, however onMouseDown is never called.
public void ShowLectures()
{
foreach (var course in selectedCourses)
{
AddMoreButton();
}
}
public void AddMoreButton()
{
GameObject button = (GameObject)Instantiate(prefabButton);
button.transform.SetParent(panel.transform, false);
button.layer = 5;
button.SetActive(true);
}
public void OnMouseDown()
{
Destroy(gameObject);
}
First of all OnMouseDown is not called on the created Button but in your case rather on the GameObject your script is attached to.
Then
Destroy(gameObject);
the same way would destroy the GameObject your script is attached to, not the instantiated button GameObjects.
Since you commented that you are using a UI.Button component rather add it to the onClick event as a callback when the Button is instantiated :
public void AddMoreButton()
{
GameObject button = (GameObject)Instantiate(prefabButton);
button.transform.SetParent(panel.transform, false);
button.layer = 5;
button.SetActive(true);
// get the Button on the button object or any child
var buttonInstance = button.GetComponentInChildren<Button>();
// add a callback to destroy the button gameObject
// () => {} is a lambda expression
buttonInstance.onClick.AddCallback(()=>{ Destroy(button); });
}
A little hint: In case the Button is already on the same GameObject anyway you should rather change the prefab type itself to Button like e.g.
public Button prefabButton;
and than simply use
public void AddMoreButton()
{
Button button = Instantiate(prefabButton, panel.transform);
button.gameObject.layer = 5;
button.gameObject.SetActive(true);
// add a callback to destroy the button gameObject
// () => {} is a lambda expression
button.onClick.AddListener(()=>{ Destroy(button.gameObject); });
}
Instead of creating a gameobject with an OnMouseDown, I'd probably create a Button instead and binding an event to it:
var closeButton = /* Dynamically create button */
closeButton.GetComponent<Button>().onClick.AddListener(HandleCloseClick);
void HandleCloseClick() {
Destroy(gameObject);
}
You can, however, do the architecture you've already implemented - you just need to implement IPointerClickHandler.
Here's an answer describing how to implement & use the interface.
Check the docs for instructions on how to use each event (Mouse Down, Up, Enter, Exit)

Unity C# Shop Menu

Hey guys I have been building a shop menu that is activated when the button is pressed. I have four buttons in the menu that correspond to several buy able items in a grid. The buttons and text and Image attached are inside a GameObject. I'm trying to switch between menus with SetActive. I've successfully used SetActive to open and close the menu but when I try with the other portions they stay inactive regardless. Even when the button supposedly activating is pressed. The picture I uploaded shows the hierarchy of the shop. The buttons are under ShopSelection and the actual menu is Under Shop
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBehaviour {
private static UIManager instance;
public static UIManager Instance;
public GameObject shopMenu, motherShips, resources, fleets, research;
bool menuIsOpen = false;
bool motherShipOpen = false;
bool resourcesOpen = false;
bool fleetOpen = false;
public Button shop, motherShipButton, resourceButton, fleetButton, exitButton;
void Start () {
shopMenu.SetActive(false);
//Open Shop Menu
Button btn = shop.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
//Open Motherships portion of shop
Button btn1 = shop.GetComponent<Button>();
btn1.onClick.AddListener(TaskOnClick3);
//Open resources portion of shop
Button btn2 = shop.GetComponent<Button>();
btn2.onClick.AddListener(TaskOnClick4);
//Open fleet portion of shop
Button btn3 = shop.GetComponent<Button>();
btn3.onClick.AddListener(TaskOnClick5);
//Open Research portion of shop
Button btn4 = shop.GetComponent<Button>();
btn4.onClick.AddListener(TaskOnClick6);
//Exit Menu
Button bttn = exitButton.GetComponent<Button>();
bttn.onClick.AddListener(TaskOnClick2);
}
// Update is called once per frame
void Update () {
}
void TaskOnClick()
{
shopMenu.SetActive(true);
menuIsOpen = true;
motherShips.SetActive(true);
}
void TaskOnClick2()
{
if (menuIsOpen == true)
{
shopMenu.SetActive(false);
menuIsOpen = false;
}
}
void TaskOnClick3()
{
if(menuIsOpen == true)
{
//Open Motherships Shop
motherShips.SetActive(true);
resources.SetActive(false);
fleets.SetActive(false);
}
}
void TaskOnClick4()
{
if (menuIsOpen == true)
{
//Open resources Shop
motherShips.SetActive(false);
resources.SetActive(true);
fleets.SetActive(false);
}
}
void TaskOnClick5()
{
if(menuIsOpen == true)
{
//Open Fleet Shop
motherShips.SetActive(false);
resources.SetActive(false);
fleets.SetActive(true);
}
}
void TaskOnClick6()
{
if (menuIsOpen == true)
{
//Open Research Page
motherShips.SetActive(false);
resources.SetActive(false);
fleets.SetActive(false);
}
}
}
You added all callbacks allways to the shop button e.g.
Button btn2 = shop.GetComponent<Button>();
btn2.onClick.AddListener(TaskOnClick4);
not to the supposed buttons motherShipButton, resourceButton, fleetButton
Note that you don't have to call GetComponent again if you declare the variable as Button it will automatically reference the Button component of the drag&dropped GameObject in the Inspector so instead it should simply be
shop.onClick.AddListener(TaskOnClick);
//Open Motherships portion of shop
motherShipButton.onClick.AddListener(TaskOnClick3);
//Open resources portion of shop
resourcesButton.onClick.AddListener(TaskOnClick4);
//Open fleet portion of shop
fleetButton.onClick.AddListener(TaskOnClick5);
//Open Research portion of shop
// Whatever button this belongs to
???.onClick.AddListener(TaskOnClick6);
//Exit Menu
exitButton.onClick.AddListener(TaskOnClick2);
Now also name the methods accordingly e.g. OpenMenu, CloseMenu etc. that would make it a lot easier for you and everyone else to understand the code.
I also doubt that you need the check for if(menuIsOpen). Since the other GameObjects are children of the menu anyway they will simply stay invisible even if SetActive was called. Instead I would make sure that only one panel is active by using a method with e.g. an enum instead like
enum MenuPanel
{
MotherShips,
Resources,
Fleets,
Research
}
private void ShowPanel(MenuPanel panel)
{
// First disable all
motherShips.SetActive(false);
fleets.SetActive(false);
resources.SetActive(false);
// Than only activate according panel
switch(panel)
{
case MenuPanel.MotherShips:
motherShips.SetActive(true);
break;
case MenuPanel.Reaources:
resources.SetActive(true);
break;
case MenuPanel.Fleets:
fleets.SetActive(true);
break;
}
}
And than I would still use dedicated methods for each panel like e.g.
void Start()
{
//...
motherShipButton.onClick.AddListener(ShowMotherShips);
//...
}
private void ShowMotherShips()
{
ShowPanel(MenuPanel.MotherShips);
}
you could do it also directly as lambda expression
void Start()
{
//...
motherShipButton.onClick.AddListener(() => {
ShowPanel(MenuPanel.MotherShips);
});
//...
}
I usually try to avoid it since 1. you can not reuse this expression but you might want to call it from else where as well and 2. you will not be able to use RemoveListener to eventually get rid of that call.

Categories