Refresh ScrollView In Unity3D - c#

does someone know how to detect if the UI Component "ScrollView" has been pulled up?.
This is planned to be like, when you refresh the feed in youtube or facebook, with the swipe up gesture.
It should detect the gesture and then, called a method that I have : refresh();
Thanks.

ScrollRect:
You can subscribe to ScrollRect's onValueChanged event and it will be called when there are changes on the ScrollRect.
public ScrollRect scrollRect;
void OnEnable()
{
scrollRect.onValueChanged.AddListener(ScrollChanged);
}
void OnDisable()
{
scrollRect.onValueChanged.RemoveAllListeners();
}
void ScrollChanged(Vector2 pos)
{
Debug.Log("Scroll changed pos to: " + pos);
}
or you can implement the IScrollHandler interface and use the OnScroll function. The script will have to be attached to the GameObject that has the ScrollRect component for it to work.
public class ScrollDetector : MonoBehaviour, IScrollHandler
{
public void OnScroll(PointerEventData eventData)
{
}
}
Scrollbar:
If using Scrollbar, then the callback function you register with the onValueChanged event should use float instead vector2 as param.
void ScrollChanged(float val)
{
}
or implement the IMoveHandler interface and use the OnMove function
public class ScrollDetector : MonoBehaviour, IMoveHandler
{
public void OnMove(AxisEventData eventData)
{
}
}

Related

Unity - One Button for all Clone Objects

Hallo,
I followed this tutorial: https://www.youtube.com/watch?v=dMROaOQs7z8&t=7s
Selecting cars in the game using the Instantiate () function changes the prefabricated cars and I want to control them (throttle, brake, etc.) with using the UI buttons
I have a problem that the button does not find the event trigger (pointerDown, pointerUp) on newly created cloned objects, because the prefab is still changing
I have buttons and not keys (as in the video), the buttons do not find inputs to newly created objects.
I tried to do this using a script pinned to a button, with OnPointerEnter () and OnPointerExit () but it doesn't work, how should I do it? I will be grateful for any answer, thanks.
unity version 2019.4.14f1
public class GasButton : MonoBehaviour
{
public CarController controller;
private void Update()
{
controller = GameObject.FindGameObjectWithTag("Player").GetComponent<CarController>();
}
public void OnPointerEnter(PointerEventData eventData)
{
controller.GasPressed();
Debug.Log("Gas Pressed");
}
public void OnPointerExit(PointerEventData eventData)
{
controller.GasReleased();
Debug.Log("Gas Released");
}
OnPointerEnter and OnPointerExit should implement the IPointerEnterHandler and IPointerExitHandler.
To do this append interface in the monobehavior like this.
public class GasButton : MonoBehaviour,IPointerEnterHandler, IPointerExitHandler
{
public CarController controller;
private void Update()
{
controller = GameObject.FindGameObjectWithTag("Player").GetComponent<CarController>();
}
public void OnPointerEnter(PointerEventData eventData)
{
controller.GasPressed();
Debug.Log("Gas Pressed");
}
public void OnPointerExit(PointerEventData eventData)
{
controller.GasReleased();
Debug.Log("Gas Released");
}

Is there a way to drag and drop UI buttons in unity 3d?

Is there a way to drag and drop UI buttons in unity 3d?
Can I add two functions to a button?
The first when it is normally clicked it does something.
The second when it is clicked and held, it can be dragged and dropped somewhere else on the screen?
This is the code I have so far but it's not working on the button.
void Update()
{
if (isDragged)
{
transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
}
public void OnMouseOver()
{
if (Input.GetMouseButtonDown(0))
{
isDragged = true;
}
}
public void OnMouseUp()
{
isDragged = false;
}
You can use unity built-in interfaces,
Use IPointerClickHandler to do something when it is clicked and implement another three interface for handling dragging which is IBeginDragHandler, IDragHandler, IEndDragHandler
public class Example : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
//Detect if a click occurs
public void OnPointerClick(PointerEventData pointerEventData)
{
Debug.Log(name + " Game Object Clicked!");
}
public void OnBeginDrag(PointerEventData eventData)
{
}
public void OnDrag(PointerEventData data)
{
}
public void OnEndDrag(PointerEventData eventData)
{
}
}
References : https://docs.unity3d.com/2018.1/Documentation/ScriptReference/EventSystems.IDragHandler.html

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

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.

Use EventSystem for key-pressing events

Context: say you're checking whether "W" is pressed on the keyboard, the most common way to check this is through the following code:
void Update(){
if (Input.GetKeyDown("W"))
DoSomething();
}
Is there a way to do the following, using Unity's EventSystem? In other words, is there an implementation of an interface like IPointerClickHandler, for example, to check whether a button is pressed, without doing so in an Update() function?
Is there a way to do the following, using Unity's EventSystem? In other words, is there an implementation of an interface like IPointerClickHandler,
No. The EventSystem is mostly used for raycasting and dispatching events. This is not used to detect keyboard events. The only component from the EventSystem that can detect keyboard events is the InputField component. That's it and it can't be used for anything else.
Check whether a button is pressed, without doing so in an Update()
function?
Yes, there is a way with Event.KeyboardEvent and this requires the OnGUI function.
void OnGUI()
{
if (Event.current.Equals(Event.KeyboardEvent("W")))
{
print("W pressed!");
}
}
This is worse than using the Input.GetKeyDown function with the Update function. I encourage you to stick with Input.GetKeyDown. There is nothing wrong with it.
If you are looking for event type InputSystem without Input.GetKeyDown then use Unity's new Input API and subscribe to the InputSystem.onEvent event.
If you are looking for feature similar to the IPointerClickHandler interface you can implement it on top of Input.GetKeyDown.
1.First, get all the KeyCode enum with System.Enum.GetValues(typeof(KeyCode)); and store it in an array.
2.Create an interface "IKeyboardEvent" and add functions such as OnKeyDown just like OnPointerClick in the IPointerClickHandler interface.
3.Loop through the KeyCode from #1 and check if each key in the array is pressed, released or held down.
4.Get all the components in the scene and check if they implemented the IKeyboardEvent interface. If they do, invoke the proper function in the interface based on the key status from #3.
Here is a functional example that can still be extended or improved:
Attach to an empty GameObject.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class KeyboardEventSystem : MonoBehaviour
{
Array allKeyCodes;
private static List<Transform> allTransforms = new List<Transform>();
private static List<GameObject> rootGameObjects = new List<GameObject>();
void Awake()
{
allKeyCodes = System.Enum.GetValues(typeof(KeyCode));
}
void Update()
{
//Loop over all the keycodes
foreach (KeyCode tempKey in allKeyCodes)
{
//Send event to key down
if (Input.GetKeyDown(tempKey))
senEvent(tempKey, KeybrdEventType.keyDown);
//Send event to key up
if (Input.GetKeyUp(tempKey))
senEvent(tempKey, KeybrdEventType.KeyUp);
//Send event to while key is held down
if (Input.GetKey(tempKey))
senEvent(tempKey, KeybrdEventType.down);
}
}
void senEvent(KeyCode keycode, KeybrdEventType evType)
{
GetAllRootObject();
GetAllComponents();
//Loop over all the interfaces and callthe appropriate function
for (int i = 0; i < allTransforms.Count; i++)
{
GameObject obj = allTransforms[i].gameObject;
//Invoke the appropriate interface function if not null
IKeyboardEvent itfc = obj.GetComponent<IKeyboardEvent>();
if (itfc != null)
{
if (evType == KeybrdEventType.keyDown)
itfc.OnKeyDown(keycode);
if (evType == KeybrdEventType.KeyUp)
itfc.OnKeyUP(keycode);
if (evType == KeybrdEventType.down)
itfc.OnKey(keycode);
}
}
}
private static void GetAllRootObject()
{
rootGameObjects.Clear();
Scene activeScene = SceneManager.GetActiveScene();
activeScene.GetRootGameObjects(rootGameObjects);
}
private static void GetAllComponents()
{
allTransforms.Clear();
for (int i = 0; i < rootGameObjects.Count; ++i)
{
GameObject obj = rootGameObjects[i];
//Get all child Transforms attached to this GameObject
obj.GetComponentsInChildren<Transform>(true, allTransforms);
}
}
}
public enum KeybrdEventType
{
keyDown,
KeyUp,
down
}
public interface IKeyboardEvent
{
void OnKeyDown(KeyCode keycode);
void OnKeyUP(KeyCode keycode);
void OnKey(KeyCode keycode);
}
Usage:
Implement the IKeyboardEvent interface and the functions from it in your script just like you would with IPointerClickHandler.
public class test : MonoBehaviour, IKeyboardEvent
{
public void OnKey(KeyCode keycode)
{
Debug.Log("Key held down: " + keycode);
}
public void OnKeyDown(KeyCode keycode)
{
Debug.Log("Key pressed: " + keycode);
}
public void OnKeyUP(KeyCode keycode)
{
Debug.Log("Key released: " + keycode);
}
}
I created an simples script to trigger simple event.
I used OnguiGUI instead of Update.
See it bellow!
using UnityEngine;
using UnityEngine.Events;
public class TriggerKey : MonoBehaviour
{
[Header("----Add key to trigger on pressed----")]
public string key;
// Unity event inspector
public UnityEvent OnTriggerKey;
public void OnGUI()
{ // triiger event on trigger key
if (Event.current.Equals(Event.KeyboardEvent(key)))
{
OnTriggerKey.Invoke();
print("test trigger btn");
}
}
}

Buttons in Unity, without using UI?

Is there a way in Unity to create a simple 2D button without using the UI layer. I have a game with a lot of buttons and I don't want to make the whole app in the UI. Some more controls are welcome too: switches, sliders etc.
PS. I saw NGUI and I don't like it so far. Anything else?
Is there a way in Unity to create a simple 2D button without using the
UI layer
You can use Sprite/Sprite Render as a Button.First Create a GameObject and attach EventSystem and StandaloneInputModule to it. Attach Physics2DRaycaster to the Camera, implement IPointerClickHandler and override OnPointerClick function. Create a 2D Sprite by going to GameObject->2D Object->Sprite then attach your script to the Sprite. Here is a complete code to do that:
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
public class SPRITEBUTTON: MonoBehaviour, IPointerClickHandler,
IPointerDownHandler, IPointerEnterHandler,
IPointerUpHandler, IPointerExitHandler
{
void Start()
{
//Attach Physics2DRaycaster to the Camera
Camera.main.gameObject.AddComponent<Physics2DRaycaster>();
addEventSystem();
}
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Mouse Clicked!");
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("Mouse Down!");
}
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("Mouse Enter!");
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("Mouse Up!");
}
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("Mouse Exit!");
}
//Add Event System to the Camera
void addEventSystem()
{
GameObject eventSystem = null;
GameObject tempObj = GameObject.Find("EventSystem");
if (tempObj == null)
{
eventSystem = new GameObject("EventSystem");
eventSystem.AddComponent<EventSystem>();
eventSystem.AddComponent<StandaloneInputModule>();
}
else
{
if ((tempObj.GetComponent<EventSystem>()) == null)
{
tempObj.AddComponent<EventSystem>();
}
if ((tempObj.GetComponent<StandaloneInputModule>()) == null)
{
tempObj.AddComponent<StandaloneInputModule>();
}
}
}
}
EDIT:
If this is a 3D GameObject/Mesh, then you need to add a simple collider to it. If it is just Sprite then you must add a 2D collider to the sprite.
Another approach that is even simpler, is to just add a BoxCollider2D component, then add the following methods to the a new componenent, say UIButton, where you will to perform the button actions :
void OnMouseOver()
void OnMouseDown()
void OnMouseUp()
This avoids the use of an EventSystem, StandaloneInputModule and Physics2DRaycaster.
Example :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class UIButton : MonoBehaviour {
public Sprite regular;
public Sprite mouseOver;
public Sprite mouseClicked;
public TextMeshPro buttonText;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
private void OnMouseDown()
{
}
private void OnMouseEnter()
{
}
private void OnMouseExit()
{
}
private void OnMouseUpAsButton()
{
}
}
Tested in unity 2018.1. One difference I initially noticed to this and the above approach is that the right mouse button click is not detected in this model, but is detected in the EventSystemModel.

Categories