How to bind ngui events in StrangeIoC in unity3d - unity3d

I have some problem with binding ngui events in the StrangeIoC framework.
This is an unityGUI sample:
public class TestView : View
{
private readonly Rect buttonRect = new Rect(0, 0, 200, 50);
public Signal buttonClicked = new Signal();
public void OnGUI()
{
if (GUI.Button(buttonRect, "Test"))
{
buttonClicked.Dispatch();
}
}
}
This is the NGUI version:
public class NGUIView : View
{
public UIButton Button;
public Signal buttonClicked = new Signal();
private void Start()
{
if (Button != null)
{
EventDelegate.Add(Button.onClick, buttonClicked.Dispatch);
}
}
}
In the NGUI version, the the buttonClicked is never dispatched. I noticed in the scene the Notify property on that button has an empty value.
This one works, but the buttonClicked is triggered several times :(
public class NGUIView : View
{
public UIButton Button;
public Signal buttonClicked = new Signal();
void Update()
{
if (Button.state == UIButtonColor.State.Pressed)
{
buttonClicked.Dispatch();
}
}
}
Could you kindly tell me how do you handle this NGUI-StrangeIoC situation?
Thanks!

I finally figured out. Add the delegate in Awake instead of Start.
Now here's the perfect solution(not sure enough):
public class TestView : View
{
private readonly Rect buttonRect = new Rect(0, 0, 200, 50);
public UIButton Button;
public Signal buttonClicked = new Signal();
private void OnGUI()
{
if (GUI.Button(buttonRect, "Test"))
{
buttonClicked.Dispatch();
}
}
private void Awake()
{
EventDelegate.Add(Button.onClick, buttonClicked.Dispatch);
}
}

Related

Long Press Button issue on moving mouse

I use a long press button, which works very well, on MouseDown and if I don't move the mouse, at the end of my delay, I have my action.
If I move the mouse (still pressing down and still on the button) it resets my button's delay, and I don't understand why.
if anyone has an idea, it would help me a lot.
Thx
Here's my code :
private bool _PointerDown;
public float DelaiReponse;
private float _PointerDownTimer;
private bool _IsValidate = false;
private float _Delai;
public void OnPointerDown(PointerEventData eventData)
{
_PointerDown = true;
}
public void OnPointerUp(PointerEventData eventData)
{
_PointerDown = false;
_PointerDownTimer = 0;
}
void Start()
{
_Delai = DelaiReponse;
}
private void Update()
{
if (_PointerDown) // Timer Button Validation Hold
{
_PointerDownTimer += Time.deltaTime;
if (_PointerDownTimer >= _Delai)
{
_IsValidate = true;
}
}
}enter code here
Using Input.GetMouseDown(0) and Input.GetMouseButtonUp(0) could fix the problem:
private void Update()
{
if (Input.GetMouseDown(0))
{
_PointerDown = true;
}
if (Input.GetMouseUp(0))
{
_PointerDown = false;
_PointerDownTimer = 0;
}
if (_PointerDown) // Timer Button Validation Hold
{
:
:
}
:
:
}
I finally found
OnMouseDown even worked outside my button, and I preferred the OnPointerDown method.
I added IDragHandler to my class, and create a bool _PointerDrag
private bool _PointerDown;
private bool _PointerDrag;
public float DelaiReponse;
private float _PointerDownTimer;
private bool _IsValidate = false;
private float _Delai;
public class LongClickButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
public void OnPointerDown(PointerEventData eventData)
{
_PointerDown = true;
}
public void OnPointerUp(PointerEventData eventData)
{
_PointerDown = false;
_PointerDownTimer = 0;
}
public void OnDrag(PointerEventData eventData)
{
_PointerDrag = true;
}
void Start()
{
_Delai = DelaiReponse;
}
private void Update()
{
if (_PointerDown || _PointerDrag) // Timer Button Validation Hold
{
_PointerDownTimer += Time.deltaTime;
if (_PointerDownTimer >= _Delai)
{
_IsValidate = true;
}
}
}
}
and it works.
Thanks for your time, Frenchy

How to Get UI button to Stay in a Pressed State in Unity 3D

In Unity 3D, when you select a button, it will stay pressed until you click outside the button and basically goes back to its Normal Color. The problem is, I want the button to stay pressed (color-wise) when I click outside the button or scene. Does anyone know how to keep a button pressed or "selected" after clicking it?
You can use Unity UI Toggle (as said by Muhammad). Change the design to remove the checkmark and make it looking like a button.
With this component you have the state 'isOn' that you can use and change the color when selected for example.
public class Button_Stay_Pressed : MonoBehaviour
{
private Button btn;
[SerializeField]
private Sprite normal_sprite;
[SerializeField]
private Sprite pressed_sprite;
void Awake()
{
btn = gameObject.GetComponent<Button>();
btn.image.sprite = normal_sprite;
btn.onClick.AddListener(TaskOnClick);
}
void TaskOnClick()
{
btn.image.sprite = pressed_sprite;
}
}
Here is the C# script using delegate that'll (toggle between buttons) set clicked button to "on/pressed" (custom) colour and change the other button(s) with this script attached to them to deselect colour, Copy & paste solution(attach this script to buttons you want to toggle between):
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Functionality: Control UI Button clicks selected colour
/// Author: Akrima Huzaifa
/// Date Created: 1st-December-2022
/// </summary>
public class BtnClickHandler : MonoBehaviour
{
public delegate void OnBtnClick(BtnClickHandler obj);
public static event OnBtnClick onBtnClick;
public Button poleBtn;
public Image poleImage;
private void Awake()
{
if (GetComponent<Button>())
{
poleBtn = GetComponent<Button>();
poleImage = GetComponent<Image>();
poleBtn.onClick.AddListener(delegate { OnBtnClick(); });
}
}
private void OnEnable()
{
onBtnClick += SelectDeselectBtn;
}
private void OnDisable()
{
onBtnClick -= SelectDeselectBtn;
}
public void SelectDeselectBtn(BtnClickHandler obj)
{
if (obj == this)
{
OnClick_ObjButtonSelected();
}
else
{
DeselectBtn();
}
}
public void OnBtnClick()
{
BtnClickHandler.onBtnClick.Invoke(this);
}
//---For UI---
public void OnClick_ObjButtonSelected()
{
if (!poleImage.fillCenter)
{
print("if color");
poleImage.fillCenter = true;
poleImage.color = new Color32(230, 230, 230, 255);
poleImage.transform.GetComponentInChildren<TextMeshProUGUI>().color = new Color32(255, 115, 0, 255);
}
else
{
DeselectBtn();
}
}
public void DeselectBtn()
{
print("else color");
poleImage.fillCenter = false;
poleImage.color = new Color32(178, 178, 178, 255);
poleImage.transform.GetComponentInChildren<TextMeshProUGUI>().color = new Color32(255, 255, 255, 255);
}
}

Unity-How to stop a moving object when the Camera sees it

This is just a simple thing I want to do. I have my cube gameobject rotating and I want to make it so when the camera sees the cube, it stops rotating. If you could steer me in the right direction, I'd appreciate it. thank you
public class cubeMove : MonoBehaviour, MoveObject
{
public Renderer rend;
public void Update () {
rend = GetComponent<Renderer>();
stopWhenSeen();
}
public void move()
{
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
public void stopWhenSeen()
{
if (rend.enabled == false)
{
move();
}
}
}
Implement the OnBecameVisible and OnBecameInvisible MonoBehaviour's message :
private visible = false ;
// OnBecameVisible is called when the renderer became visible by any camera. INCLUDING YOUR EDITOR CAMERA
void OnBecameVisible()
{
visible = true ;
}
// OnBecameInvisible is called when the renderer is no longer visible by any camera. INCLUDING YOUR EDITOR CAMERA
void OnBecameInvisible()
{
visible = false;
}
void Update()
{
if( !visible )
move() ;
}
public void move()
{
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
You could try the .isVisible bool in your update method.
Here is a thread with other suggestions:
http://answers.unity3d.com/questions/8003/how-can-i-know-if-a-gameobject-is-seen-by-a-partic.html

Drag and Drop In ScrollRect (ScrollView) in Unity3D

I want to implement drag and drop on contents of scroll view.
The problem is when you try drag items in scroll view you can't scroll the view.
First, I've tried to implement drag and drop by IDragHandler, IBeginDragHandler, IEndDragHandle and IDropHandler interfaces. In a first sight, It worked pretty good but the problem was you can't scroll the ScrollRect.
I think the problem is because of overriding, When I use event triggers that the same as scroll rect like drag, the parent one don't work properly.
So after that, I've thought by myself and implement it by IPointerDown, IPointerUp interfaces and specific time for holding drag-gable UI in ScrollRect and if you don't hold it in specific time the scrolling work well.
But the problem is by enabling DragHandler script that I wrote before the OnDrag, OnBeginDrag and OnEndDrag functions doesn't work when time of holding ended.
First I want to know there is any way to call these functions ?
Second is there any way to implement drag and drop UI without using drag interfaces ?
DragHandler :
using System;
using UnityEngine;
using UnityEngine.EventSystems;
public class DragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
public static GameObject itemBeingDragged;
private Vector3 startPos;
private Transform startParent;
DragHandler dragHandler;
public void Awake()
{
dragHandler = GetComponent<DragHandler>();
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("Begin");
itemBeingDragged = gameObject;
startPos = transform.position;
startParent = transform.parent;
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log("Drag");
transform.position = Input.mousePosition;
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("End");
itemBeingDragged = null;
if (transform.parent == startParent)
{
dragHandler.enabled = false;
transform.SetParent(startParent);
transform.position = startPos;
}
}
}
ScrollRectController:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ScrollRectController : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public float holdTime;
public float maxVelocity;
private Transform scrollRectParent;
private DragHandler dragHandler;
private ScrollRect scrollRect;
private float timer;
private bool isHolding;
void Awake()
{
scrollRectParent = GameObject.FindGameObjectWithTag("rec_dlg").transform;
dragHandler = GetComponent<DragHandler>();
dragHandler.enabled = false;
}
// Use this for initialization
void Start()
{
timer = holdTime;
}
// Update is called once per frame
void Update()
{
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("Down");
scrollRect = scrollRectParent.GetComponent<ScrollRect>();
isHolding = true;
StartCoroutine(Holding());
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("Up");
isHolding = false;
}
IEnumerator Holding()
{
while (timer > 0)
{
//if (scrollRect.velocity.x >= maxVelocity)
//{
// isHolding = false;
//}
if (!isHolding)
{
timer = holdTime;
yield break;
}
timer -= Time.deltaTime;
Debug.Log(timer);
yield return null;
}
dragHandler.enabled = true;
//dragHandler.OnBeginDrag();
}
}
Slot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
DragHandler.itemBeingDragged.transform.SetParent(transform);
}
}
Answer:
I wrote some codes that handle drag and drop in scrollRect(scrollView) without using DragHandler interfaces.
DragHandler:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragHandler : MonoBehaviour, IPointerExitHandler
{
public static GameObject itemBeingDragged;
public static bool isCustomerDragged;
public Transform customerScrollRect;
public Transform dragParent;
public float holdTime;
public float maxScrollVelocityInDrag;
private Transform startParent;
private ScrollRect scrollRect;
private float timer;
private bool isHolding;
private bool canDrag;
private bool isPointerOverGameObject;
private CanvasGroup canvasGroup;
private Vector3 startPos;
public Transform StartParent
{
get { return startParent; }
}
public Vector3 StartPos
{
get { return startPos; }
}
void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
}
// Use this for initialization
void Start()
{
timer = holdTime;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
//Debug.Log("Mouse Button Down");
scrollRect = customerScrollRect.GetComponent<ScrollRect>();
isPointerOverGameObject = true;
isHolding = true;
StartCoroutine(Holding());
}
}
if (Input.GetMouseButtonUp(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
//Debug.Log("Mouse Button Up");
isHolding = false;
if (canDrag)
{
itemBeingDragged = null;
isCustomerDragged = false;
if (transform.parent == dragParent)
{
canvasGroup.blocksRaycasts = true;
transform.SetParent(startParent);
transform.localPosition = startPos;
}
canDrag = false;
timer = holdTime;
}
}
}
if (Input.GetMouseButton(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
if (canDrag)
{
//Debug.Log("Mouse Button");
transform.position = Input.mousePosition;
}
else
{
if (!isPointerOverGameObject)
{
isHolding = false;
}
}
}
}
}
public void OnPointerExit(PointerEventData eventData)
{
isPointerOverGameObject = false;
}
IEnumerator Holding()
{
while (timer > 0)
{
if (scrollRect.velocity.x >= maxScrollVelocityInDrag)
{
isHolding = false;
}
if (!isHolding)
{
timer = holdTime;
yield break;
}
timer -= Time.deltaTime;
//Debug.Log("Time : " + timer);
yield return null;
}
isCustomerDragged = true;
itemBeingDragged = gameObject;
startPos = transform.localPosition;
startParent = transform.parent;
canDrag = true;
canvasGroup.blocksRaycasts = false;
transform.SetParent(dragParent);
}
public void Reset()
{
isHolding = false;
canDrag = false;
isPointerOverGameObject = false;
}
}
Some explanation for this piece of code :
Your draggable UI element need intractable option, for me, I used button.
You need to attach this script to your draggable item.
Also you need add Canvas Group component.
customerScrollRect is a ScrollRect parent of your items.
dragParent can be a empty GameObject which is used because of mask of view port.
Slot:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
bool isEntered;
public void OnPointerEnter(PointerEventData eventData)
{
isEntered = true;
}
public void OnPointerExit(PointerEventData eventData)
{
isEntered = false;
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
if (isEntered)
{
if (DragHandler.itemBeingDragged)
{
GameObject draggedItem = DragHandler.itemBeingDragged;
DragHandler dragHandler = draggedItem.GetComponent<DragHandler>();
Vector3 childPos = draggedItem.transform.position;
//Debug.Log("On Pointer Enter");
draggedItem.transform.SetParent(dragHandler.StartParent);
draggedItem.transform.localPosition = dragHandler.StartPos;
draggedItem.transform.parent.SetParent(transform);
draggedItem.transform.parent.position = childPos;
isEntered = false;
}
}
}
}
}
Some explanation for this script:
1.Attach the script to the dropped item.
The easiest solution for this problem is actually to manually call the ScrollRect's events IF the user hasn't pressed long enough using ExecuteEvents.Execute. This solution has the least amount of additional code.
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragAndDropHandler : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IDragHandler, IBeginDragHandler, IEndDragHandler
{
// Don't forget to set this to TRUE or expose it to the Inspector else it will always be false and the script will not work
public bool Draggable { get; set; }
private bool draggingSlot;
[SerializeField] private ScrollRect scrollRect;
public void OnPointerDown(PointerEventData eventData)
{
if (!Draggable)
{
return;
}
StartCoroutine(StartTimer());
}
public void OnPointerExit(PointerEventData eventData)
{
StopAllCoroutines();
}
public void OnPointerUp(PointerEventData eventData)
{
StopAllCoroutines();
}
private IEnumerator StartTimer()
{
yield return new WaitForSeconds(0.5f);
draggingSlot = true;
}
public void OnBeginDrag(PointerEventData eventData)
{
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.beginDragHandler);
}
public void OnDrag(PointerEventData eventData)
{
if (draggingSlot)
{
//DO YOUR DRAGGING HERE
} else
{
//OR DO THE SCROLLRECT'S
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.dragHandler);
}
}
public void OnEndDrag(PointerEventData eventData)
{
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.endDragHandler);
if (draggingSlot)
{
//END YOUR DRAGGING HERE
draggingSlot = false;
}
}
}
I've managed to find an easier solution.
Maybe it must be customized by special needs, but if you put this script on your items and make the setup, it should work.
It's not easy from a prefab, but I let a controller make this.
I find all UIElementDragger inside a specified GameObject and add the needed GO instances programmatically.
But can use this code out of the box if you don't use prefabs.
using UnityEngine;
using UnityEngine.EventSystems;
public class UIElementDragger : MonoBehaviour, IPointerUpHandler, IPointerDownHandler
{
/// <summary>
/// Offset in pixels horizontally (positive to right, negative to left)
/// </summary>
[Range(40, 100)]
public float offsetX = 40;
/// <summary>
/// Offset in pixels vertically (positive to right, negative to left)
/// </summary>
[Range(40, 100)]
public float offsetY = 40;
/// <summary>
/// The Panel where the item will set as Child to during drag
/// </summary>
public Transform parentRect;
/// <summary>
/// The GameObject where the item is at start
/// </summary>
public Transform homeWrapper;
/// <summary>
/// The Object where the mouse must be when pointer is up, to put it in this panel
/// </summary>
public Transform targetRect;
/// <summary>
/// The GameObject where the item should live after dropping
/// </summary>
public Transform targetWrapper;
private int siblingIndex;
private bool dragging;
private void Start()
{
siblingIndex = transform.GetSiblingIndex();
}
private void Update()
{
if (dragging)
{
transform.position = new Vector2(Input.mousePosition.x + offsetX, Input.mousePosition.y + offsetY);
}
}
public void OnPointerDown(PointerEventData eventData)
{
transform.parent = parentRect;
dragging = true;
}
public void OnPointerUp(PointerEventData eventData)
{
if (eventData.pointerCurrentRaycast.gameObject.transform.IsChildOf(targetRect))
{
transform.parent = targetWrapper;
}
else
{
transform.parent = homeWrapper;
transform.SetSiblingIndex(siblingIndex);
}
dragging = false;
}
}
Here my solution, thank all.
I have to use a fake instance to keep the object over even if you move it down the list. I post a vertical and a horizontal solution. I hope it help
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragController : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
private RectTransform currentTransform;
private GameObject instancePrefab;
private GameObject mainContent;
private Vector3 initialePosition;
private int totalChild;
void Awake()
{
currentTransform = this.GetComponent<RectTransform>();
mainContent = currentTransform.parent.gameObject;
}
public void OnPointerDown(PointerEventData eventData)
{
initialePosition = currentTransform.position;
totalChild = mainContent.transform.childCount;
if (instancePrefab == null)
{
instancePrefab = Instantiate(this.gameObject, mainContent.transform.parent.transform);
instancePrefab.GetComponent<Image>().enabled = false;
}
}
public void OnDrag(PointerEventData eventData)
{
currentTransform.position = new Vector3(eventData.position.x, currentTransform.position.y, currentTransform.position.z);
if (instancePrefab != null)
{
instancePrefab.GetComponent<Image>().enabled = true;
currentTransform.GetComponent<Image>().enabled = false;
instancePrefab.transform.position = currentTransform.position;
}
for (int i = 0; i < totalChild; i++)
{
if (i != currentTransform.GetSiblingIndex())
{
Transform otherTransform = mainContent.transform.GetChild(i);
int distance = (int)Vector3.Distance(currentTransform.position, otherTransform.position);
if (distance <= 20)
{
Vector3 otherTransformOldPosition = otherTransform.position;
// Vertical
/*otherTransform.position = new Vector3(otherTransform.position.x, initialePosition.y,
otherTransform.position.z);
currentTransform.position = new Vector3(currentTransform.position.x, otherTransformOldPosition.y,
currentTransform.position.z);*/
// Horizontal
otherTransform.position = new Vector3(initialePosition.x, otherTransform.position.y,
otherTransform.position.z);
currentTransform.position = new Vector3(otherTransformOldPosition.x, currentTransform.position.y,
currentTransform.position.z);
currentTransform.SetSiblingIndex(otherTransform.GetSiblingIndex());
initialePosition = currentTransform.position;
}
}
}
}
public void OnPointerUp(PointerEventData eventData)
{
currentTransform.position = initialePosition;
instancePrefab.GetComponent<Image>().enabled = false;
currentTransform.GetComponent<Image>().enabled = true;
Destroy(instancePrefab);
instancePrefab = null;
}
}
You can just manually call ScrollRect events, because they are public. Smthing like this:
public void OnDrag(PointerEventData eventData)
{
_scrollRect.OnDrag(eventData);
}

MovieTexture Never Plays In Build

I have written a script to play OGG files as a MovieTexture, i've tried both embedded asset files and also from the web. The problem I'm having is that the videos play in debug move (When I hit the play button and test in the "Game" tab) but they never work when I build to an executable..
using UnityEngine;
namespace Assets.Scripts
{
[RequireComponent(typeof(AudioSource))]
public class VideoScreen : MonoBehaviour
{
public string videoUrl;
public bool autoPlay = true;
public bool loop = true;
public bool playAudio = true;
public float opacity = 1.0f;
private bool hasLoaded;
private MovieTexture movieTexture;
public void Start ()
{
if (string.IsNullOrEmpty(videoUrl))
{
return;
}
var data = new WWW(videoUrl);
movieTexture = data.movie as MovieTexture;
}
public void Update()
{
if (movieTexture.isReadyToPlay && !hasLoaded)
{
renderer.material = new Material(Shader.Find("Custom/Unlit Transparent Color")) { mainTexture = movieTexture };
audio.clip = movieTexture.audioClip;
SetLoop(loop);
if (autoPlay)
{
Play();
}
hasLoaded = true;
}
var textureColor = renderer.material.color;
textureColor.a = opacity;
renderer.material.color = textureColor;
}
private void Play()
{
movieTexture.Stop();
movieTexture.Play();
if (playAudio)
{
audio.Stop();
audio.Play();
}
}
private void Pause()
{
movieTexture.Pause();
if (playAudio)
{
audio.Pause();
}
}
private void Stop()
{
movieTexture.Stop();
if (playAudio)
{
audio.Stop();
}
}
private void SetLoop(bool loopStatus)
{
movieTexture.loop = loopStatus;
if (playAudio)
{
audio.loop = loopStatus;
}
}
}
}
Can anyone shed any light on this behaviour?
Thanks
Turns out the custom Transparent Diffuse shader I was using was causing the issue! Doh!!
renderer.material = new Material(Shader.Find("Custom/Unlit Transparent Color")) { mainTexture = movieTexture };
now becomes
renderer.material.mainTexture = movieTexture;