Pressing UI buttons alongside processing Input.GetMouseDown() in Update - c#

The game I'm making is meant for mobile devices.
I have a PlayerInput class in which I check for mouse events in Update():
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//hide UI elements
}
}
I have a button which I hide when I detect mouse input in PlayerInput class but I don't want to hide it if the player presses the button.
I've managed to solve this issue by adding this component to my UI elements:
public class UiPointerHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerEnter(PointerEventData eventData)
{
//disable mouse checks
}
public void OnPointerExit(PointerEventData eventData)
{
//enable mouse checks
}
}
It allows me to disable processing mouse events in PlayerInput's Update() to interact with certain UI elements.
This does its job fairly well on PC when I'm testing/prototyping the game but when I build the game for mobile it doesn't work at all and I can't press the buttons.
I'm looking for a solution that would work on mobile as well.

You can solve this fairly easily by adding the following check
void Update()
{
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
//hide UI elements
}
}
What this does is it checks if your pointer (mouse or finger) is over an UI element. By checking if it's not, you get your desired behaviour.

See "Input.GetTouch" on 'Input' class on Unity, GetMouseButtonDown doesn't work on mobile. Unity designed 'Touch' event on mobile instead of mouse event so try it. it has to work with your code.

Thanks to user Immorality I've managed to solve my problem.
I've added the EventSystem.current.IsPointerOverGameObject() check to the Update() inside of my PlayerInput class.
void Update()
{
if(EventSystem.current.IsPointerOverGameObject()) return;
if (Input.GetMouseButtonDown(0))
{
//hide UI elements
}
}
I've tested this solution on its own and it did not help in my case, I still wasn't able to press the buttons.
I've introduced a bool in PlayerInput which controls whether the mouse input is being processed and 2 static methods allowing to change this variable.
public class PlayerInput : MonoBehaviour
{
private static bool _transmitInput;
void Update()
{
if(!_transmitInput || EventSystem.current.IsPointerOverGameObject()) return;
if (Input.GetMouseButtonDown(0))
{
//hide UI elements
}
}
public static void DisableInput()
{
if (!_transmitInput) return;
_transmitInput = false;
}
public static void EnableInput()
{
if (_transmitInput) return;
_transmitInput = true;
}
}
These are called from the UiPointerHandler:
public class UiPointerHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerEnter(PointerEventData eventData)
{
PlayerInput.DisableInput();
}
public void OnPointerExit(PointerEventData eventData)
{
PlayerInput.EnableInput();
}
}
At this point I was still having problems on mobile. When pressing the button, the OnPointerEnter() would be called but OnPointerExit() would not.
I assume it is because of how my scene is set up. The 2 buttons I'm working with are in the same position and are the same size. I just disable one and enable the other.
I solved this issue by calling PlayerInput.EnableInput() in the onClick of the buttons.

Related

Character jumps only when player touch and release finger Unity 2D

So I have a 2D platformer mobile game I'm about to release soon but there is this issue bothers me and appearently my testers.
In the game, you must touch screen to jump. But character only jumps when you touch and release your finger. This causes delay and affect gameplay badly. I need it to jump immediately when player touch. Not after releasing her/his finger.
Here is the code block jumps the character:
public void Jump(){
if (currentJumpRights > 0){
gameObject.GetComponent<Rigidbody2D>().AddForce(Vector2.up*jumpForce,ForceMode2D.Impulse);
soundManager.PlaySound("jumpSound");
currentJumpRights--;
}
}
I have an invisible jump button that covers most of the screen to prevent jumping when player clicks pause button. And this function is assigned to that invisible button.
How can I achieve this? Thanks for help!
Instead of using Button (since you don't want any visual effects anyway) you can use IPointerDownHandler interface and do e.g.
public class MyButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public UnityEvent onClick;
public void OnPointerDown(PointerEventData pointerEventData)
{
onClick.Invoke();
}
public void OnPointerUp(PointerEventData pointerEventData)
{
// not doing anything but from the Documentation I'm never sure if needed
// "Note: In order to receive OnPointerUp callbacks, you must also implement the IPointerDownHandler interface"
// Not sure if this also goes for the other direction ;)
}
}
This way you receive the callback immediately when pressing down instead of "clicking".
If you rather want the button to continuously trigger as long as it stays pressed you can extend this and do e.g.
public class MyButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
{
public UnityEvent onPointerDown;
public UnityEvent onPointerUp;
public UnityEvent whilePressed;
public void OnPointerDown(PointerEventData pointerEventData)
{
onPointerDown.Invoke();
StartCoroutine(PressedRoutine);
}
public void OnPointerUp(PointerEventData pointerEventData)
{
StopAllCoroutines();
onPointerUp.Invoke();
}
public void OnPointerEnter(PointerEventData pointerEventData)
{
// nothing but needed for exit event
}
public void OnPointerUp(PointerEventData pointerEventData)
{
StopAllCoroutines();
onPointerUp.Invoke();
}
private IEnumerator PressedRoutine()
{
while(true)
{
yield return null;
whilePressed.Invoke();
}
}
}

Having trouble calling a ServerRpc function from button - Unity Netcode

I'm trying to spawn a monster when the player click a button but when doing so it return a NullReference. What's weird about it it's that the NullReference point to the first line of the ServerRpc function so even a Debug.Log is considered Null. (The testButton function was created to check if anything was wrong with my button, but it does work fine).
To give more context, the buttons are instantiated when the player spawn. The player is linked to the button from the prefab directly.
The player is able to spawn monsters by pressing A and that's working wonderfully so the all the logic of spawning works fine.
public class PlayerNetwork : NetworkBehaviour
{
private SpawnMonsters spawn;
public MonsterCardGame[] monsterDeck;
public Transform[] cardEmps;
public override void OnNetworkSpawn()
{
spawn = FindObjectOfType<SpawnMonsters>();
}
private void Update()
{
if (!IsOwner) return;
if (Input.GetKey(KeyCode.A))
{
SpawnMonsterServerRpc();
}
}
[ServerRpc(RequireOwnership = false)]
public void SpawnMonsterServerRpc()
{
Debug.Log("ServerRpc");
spawn.SpawnMonster(0);
}
public void testButton()
{
Debug.Log("Clickbutton");
SpawnMonsterServerRpc();
}
}
Adding an EventListener to the button fixed the problem!

On-Screen Joystick is causing held on-screen button to cancel mistakenly in Unity

I'm making some on-screen controls for a mobile game. Movement is handled by an on-screen joystick. Attacking can be done via an on-screen button. I want it so that while I'm holding down the attack button that the player attacks for as long as the button is held.
This works however if I'm holding down the joystick simultaneously then the hold is canceled prematurely (before the attack button is released). I see that the context did in fact get canceled - likely the Joystick is triggering OnPointerUp.
My expectation is that no other input should be able to interrupt/break the HoldInteraction
This issue doesn't happen on PC so it may be because both the on-screen joystick/button use the same OnPointerDown/OnPointerUp Events.
The closest to this issue I've found is: https://forum.unity.com/threads/on-screen-button-holds-inadvertently-calling-cancel.998021/
But creating my own on-screen button and adding an OnDrag handler doesn't solve the issue.
So how is one supposed to handle multiple on-screen buttons being pressed more or less at the same time? Shouldn't each button react independently to being pressed down/unpressed?
MyControllerScript
public void OnAttack(InputAction.CallbackContext value)
{
// BasicAttackSideEffects(0);
if(value.interaction is HoldInteraction)
{
Debug.Log(value.interaction);
basicAttackHeld = true;
}
else {
Debug.Log("Press only " + value.interaction);
StartCoroutine(mPlayerAnimOrchestrator.AttackAnim());
}
if(value.canceled) {
Debug.Log("Hold canceled");
basicAttackHeld = false;
// BasicAttackSideEffects();
}
}
void Update()
{
CalculateMovementInputSmoothing();
UpdatePlayerMovement();
UpdatePlayerAnimationMovement();
if(basicAttackHeld)
{
StartCoroutine(mPlayerAnimOrchestrator.AttackAnim());
}
}
MyButtonScript
namespace UnityEngine.InputSystem.OnScreen
{
public class Action : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
public void OnPointerUp(PointerEventData eventData)
{
SendValueToControl(0.0f);
}
public void OnPointerDown(PointerEventData eventData)
{
SendValueToControl(1.0f);
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log("Dragging " + gameObject.name);
}
[InputControl(layout = "Button")]
[SerializeField]
private string m_ControlPath;
protected override string controlPathInternal
{
get => m_ControlPath;
set => m_ControlPath = value;
}
}
}

multi-touch in the unity game not working

I am following this video here
The tutorial and everything works fine except the multi-touch parts. I have two buttons that are actually two different images on the canvas but when I use one I can't use the other touch button. Each one of my buttons has this script.
Here is the code:
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class SimpleTouchShoot : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
private bool touched;
private int pointerID;
private bool canFire;
void Awake()
{
touched = false;
canFire = false;
}
public void OnPointerDown (PointerEventData data)
{
if(!touched)
{
touched = true;
pointerID = data.pointerId;
canFire = true;
}
}
public void OnPointerUp (PointerEventData data)
{
if(data.pointerId == pointerID)
{
touched = false;
canFire = false;
}
}
public bool CanFire ()
{
return canFire;
}
}
The version of Unity is 4.6.
You're using the Interface for the Event Handlers. It doesn't implement its own multi touch function so you would have to make your own touch logic. In most cases, it is a hacky way of doing it. Making an array or a list of touch inputs and having cases for it.
Unity3D Forum - Event System
Click on the link and check the Answer number 5. The answer is an hacky way of doing it. Because the Event Interface is adding EventHandler to whatever GameObject you have for the script. But it you would always need to tell the game engine that you accept more than one input <- to make it simple. Catch the 2nd touch input that is being ignored.

how to make image appear when player is dead in unity

I need to make an image pop up when the player has died or crashed but i do not know how to do it, i'm trying to make a game in unity using c#
but i have made a code that will tell show the user an image before they start (tap to start image) and all i want to do is display another one that tell to user to start again
does the code have to be similar to this or do i have to start from scratch?
public class StartScreenScript : MonoBehaviour {
static bool sawOnce = false;
// Use this for initialization
void Start () {
if(!sawOnce) {
GetComponent<SpriteRenderer>().enabled = true;
Time.timeScale = 0;
}
sawOnce = true;
}
// Update is called once per frame
void Update () {
if(Time.timeScale==0 && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) ) {
Time.timeScale = 1;
GetComponent<SpriteRenderer>().enabled = false;
}
}
}
this code show the an image telling the user to tap the screen and the image then goes away until the user closes the game then comes back on however i want to display a "you are dead image" every time the player dies can someone please help me
p.s this is for a 2d game
Well one way to do it would be using Unity3D's GUI.DrawTexture that given a texture draws it at a given position. Here is a sample call to the method.
GUI.DrawTexture(new Rect(leftAnchor, topAnchor, textureWidth, textureHeight), textureSource);
This is my approach and it works in most cases:
Create a GameObject that will work as a dead screen. Apply a sprite
or whatever telling the user to click to restart.
Add the previous GameObject to the PlayerController so he can
instantiate it.
When the player is dead call PlayerController.ShowDeadScreen()
When the user clicks inside DeadScreen GameObject it will call your
PlayerController.PlayAgain function and destroy itself. So you must handle everything
the game need to be restarted.
PlayerController example code
public class PlayerController : MonoBehaviour {
public GameObject deadScreen;
void Start() { }
void Update() { }
public void ShowDeadScreen()
{
// show DeadScreen GameObject on the center of the screen
GameObject go = Instantiate(deadScreen, new Vector(0, 0, 0), Quaternation.Identity) as GameObject;
go.playerController = this;
}
public void PlayAgain()
{
// handle game restart
}
}
DeadScreen example code
public class DeadScreen : MonoBehaviour {
public PlayerController playerController;
void Start() { }
void Update() { }
void OnMouseDown()
{
// when user clicks inside this GameObject start the game again
playerController.PlayAgain();
Destroy(this.gameObject);
}
}

Categories