Show the GUI button when mouse hover to the object - c#

i already have this player on my screen. And i want, whenever the mouse hover at the object, the GUI button show itself (like tooltip). I tried below code, but the button is not showed up when i hover at the object. Here is my code:
void OnMouseEnter()
{
Rect buttonRect = new Rect(250, Screen.height - buttonHeight, textInfoPlayerButtonWidth, textInfoPlayerButtonHeight);
if (GameManager.instance.currentPlayerIndex == 0) (the object)
{
if (GUI.Button(buttonRect, "This is player 1"))
{
}
}
}
I want to be it like this:
But i want it to be show that GUI hovering button on that character, not when the character selected.
Thank you

You may want to try using the MouseHover event instead. MouseEnter would be called as soon as the mouse is over the given object. MouseHover on the other hand is only triggered when the mouse remains over the given object for X amount of time (although I'm not sure exactly how long this takes).
(Also, I'm not sure if you had correctly set-up the your event handler as a subscriber of the MouseEnter event in your example, but here's a link explaining it : http://msdn.microsoft.com/en-us/library/vstudio/awbftdfh.aspx)
You can then show your Rect object :
Component myComponent.MouseHover += new EventHandler(OnMouseHover);
...
void OnMouseHover(object sender, EventArgs e)
{
Rect buttonRect = new Rect(250, Screen.height - buttonHeight, textInfoPlayerButtonWidth, textInfoPlayerButtonHeight);
if (GameManager.instance.currentPlayerIndex == 0) (the object)
{
if (GUI.Button(buttonRect, "This is player 1"))
{
//accomplish whatever you had wanted here
}
}
}

if the object is a 3d object, then the only way I know of to find out if the mouse is hovering above that object is with raycasting. Here's a quick example:
void Update()
{
Ray ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray,out hit) && hit.collider.gameObject == playerObject)
{
//Do something here
}
}
OR
void Update()
{
Ray ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray,out hit) && hit.collider.gameObject.name == "myPlayerObjectName")
{
//Do something here
}
}
This however is probably going to be very cpu intensive as is, so you may want to run it on a timer or something, eg once every 5 seconds, depending on your needs.

Related

How to change the position of GameObjects with Unity Input.GetMouseButtonDown method?

I already know how to click on 3D Objects in the scene by using the Input.GetMouseButtonDown. I'm trying to change the 3D Object position by clicking on the object. I added a Box Collider in the object and I'm calling the following method.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
foreach (GameObject child in floorTiles) {
BoxCollider box = child.GetComponentInChildren<BoxCollider>();
if (hit.transform.name.Equals(box.name))
{
handleOnMouseDown(hit.collider);
}
}
}
}
}
floorTiles is an array of GameObjects.
If I hit one of these objects the below function is called:
void handleOnMouseDown(Collider box)
{
GameObject parent = box.transform.parent.gameObject;
Vector3 position = parent.transform.position;
positionX.GetComponent<TextMeshProUGUI>().text = position.x.ToString();
posXButtonPlus.GetComponent<Button>().onClick.AddListener(() => handleOnChangePosition("posx", parent));
}
This works, however, when I click many objects, all the last objects clicked also keep changing their positions. How can I change one position per time?
Each click on an object, adds listener to your button, but you don't ever remove listeners. You end up with multiple listeners, that's why more objects are moved than intended.
You could remove listener after each button click, but that seems like a total overkill.
Instead of adding multiple listeners, consider adding just one which will remember the last clicked object, and clicking your button will move only that object.
Also, if you want to move objects just by clicking on them, not on button click, you can simplify all these, and move the object directly in handleOnMouseDown.
Remove listeners variant:
void handleOnMouseDown(Collider box)
{
posXButtonPlus.GetComponent<Button>().onClick.AddListener(() => handleOnChangePosition("posx", box.gameObject));
}
void handleOnChangePosition(string pos, GameObject go)
{
// I don't have code for moving, but I imagine looks something like this. right * 0.5f can be anything, did it just for tests.
go.transform.position += Vector3.right * 0.5f;
posXButtonPlus.GetComponent<Button>().onClick.RemoveAllListeners();
}
Last clicked variant:
GameObject lastClicked;
void Awake()
{
posXButtonPlus.GetComponent<Button>().onClick.AddListener(() => handleOnChangePosition());
}
void handleOnMouseDown(Collider box)
{
lastClicked = box.gameObject;
}
void handleOnChangePosition()
{
lastClicked.transform.position += Vector3.right * 0.5f;
}
Without buttons and other stuff:
void handleOnMouseDown(Collider box)
{
box.transform.position += Vector3.right * 0.5f;
}

How to check if clicked on UI object?

I am new to Unity and trying to make a basic minesweeper game. I have a square prefab and I want to learn if it is clicked. But I can not do it listening because I need both left click and right click. How can I do that?
The absolute quickest way should be to implement something like this on the prefab you wish to listen for clicks on:
void OnMouseOver()
{
if (Input.GetMouseDown(0)) {
// Left click
}
else if (Input.GetMouseDown(1)) {
// Right click
}
}
If you instead want to detect mouseclicks from a more central position (as in, not distributed to each GameObject) you will need to create a component that fires Raycasts depending on left & right-clicks and look for specific objects, and then do you logic
Short example:
if (Input.GetMouseDown(0)) {
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100)) {
// something was hit
}
}
https://docs.unity3d.com/ScriptReference/Physics.Raycast.html
You can try usign the Input.GetKeyDown function in the Update:
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
//print("Right click");
}
else if (Input.GetKeyDown(KeyCode.Mouse1))
{
//print("Left click");
}
}
For detecting if the mouse is over the spesific game object you can use:
void OnMouseOver()
{
///
}
Or
Ray ray;
RaycastHit hit;
void Update()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit))
{
print (hit.collider.name);
}
}

Unity GameOject .SetActive(false) when clicked or touched

I wish to detect if a GameObject is touched or clicked and deactivate it. I have followed a Youtube tutorial but cant get it to work.
I get the error Cannot convert from UnityEngine.Ray to UnityEngine.Vector2
I have the script attached to the object.
public class Hand : MonoBehaviour {
void Update() {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit2D;
if (Input.GetMouseButtonDown(0)) {
if (Physics2D.Raycast(ray, out hit2D)) {
transform.gameObject.SetActive(false);
}
}
}
}
You are doing it wrong.
When a click is detected you are disabling the object. Unity has a very handy way of dealing with this problem. Here is the code for it:
private void OnMouseDown()
{
if (Input.GetMouseButtonDown(0))
{
this.SetActive(false);
}
}
Physics2D.Raycast has no version with Ray parameters; and is not really intended to work with the Z axis, which a camera-to-world cast needs, either.
Use OnMouseDown() instead. If on the clicked object itself, as transform.gameObject.SetActive(false); indicates to be the case, no further action is needed.
If for an external object, you can get the mouse world position with var worldMousePoint
= (Vector2)Camera.main.ScreenPointWorldPoint(Input.mousePosition);, and then check for overlap on a target Collider2D with worldMousePoint == targetCollider2D.ClosestPoint(worldMousePoint).

How to avoid placing object behind buttons?

Google Tango and Unity related question.
Using
this tutorial we can place an object on the surface by tapping the screen.
Here is the code:
using UnityEngine;
using System.Collections;
public class KittyUIController : MonoBehaviour
{
public GameObject m_kitten;
private TangoPointCloud m_pointCloud;
void Start()
{
m_pointCloud = FindObjectOfType<TangoPointCloud>();
}
void Update ()
{
if (Input.touchCount == 1)
{
// Trigger place kitten function when single touch ended.
Touch t = Input.GetTouch(0);
if (t.phase == TouchPhase.Ended)
{
PlaceKitten(t.position);
}
}
}
void PlaceKitten(Vector2 touchPosition)
{
// Find the plane.
Camera cam = Camera.main;
Vector3 planeCenter;
Plane plane;
if (!m_pointCloud.FindPlane(cam, touchPosition, out planeCenter, out plane))
{
Debug.Log("cannot find plane.");
return;
}
// Place kitten on the surface, and make it always face the camera.
if (Vector3.Angle(plane.normal, Vector3.up) < 30.0f)
{
Vector3 up = plane.normal;
Vector3 right = Vector3.Cross(plane.normal, cam.transform.forward).normalized;
Vector3 forward = Vector3.Cross(right, plane.normal).normalized;
Instantiate(m_kitten, planeCenter, Quaternion.LookRotation(forward, up));
}
else
{
Debug.Log("surface is too steep for kitten to stand on.");
}
}
}
I have buttons on the screen, and when I press them I also place an object on the surface behind it.
How can I avoid it? So if I'm pressing a button I don't want to place an object at the same time.
If I have a function which executes when I tap on the screen, how can I prevent it from executing if I click on a button on the screen?
One way to accomplish this would be to add a tag to your buttons, cast a ray on touch, and see if the ray is colliding with an object with the button's tag.
if (Input.touchCount == 1)
{
// Trigger place kitten function when single touch ended.
Touch t = Input.GetTouch(0);
Ray ray = Camera.main.ScreenPointToRay(t.position);
RaycastHit hit;
if(t.phase == TouchPhase.Ended && Physics.Raycast(ray,out hit,100))
{
if(hit.collider.tag == "button")
{
//do button stuff
}
else
{
PlaceKitten(t.position);
}
}
}
I've answered this before but couldn't find the duplicate to close this question. When I do find it, I will close it.
You need to check if the mouse position is over the UI before considering that as a valid click.
This is done with the IsPointerOverGameObject function.
void Update()
{
if (Input.touchCount == 1)
{
// Trigger place kitten function when single touch ended.
Touch t = Input.GetTouch(0);
if (t.phase == TouchPhase.Ended)
{
//Make sure we are not over the UI
if (!UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
{
Debug.Log("Clicked outside the UI");
PlaceKitten(t.position);
}
}
}
}
For a touch screen devices, you have to pass the fingerId to the function:
void Update()
{
if (Input.touchCount == 1)
{
// Trigger place kitten function when single touch ended.
Touch t = Input.GetTouch(0);
if (t.phase == TouchPhase.Ended)
{
//Make sure we are not over the UI
if (!EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
Debug.Log("Touched outside the UI");
PlaceKitten(t.position);
}
}
}
}

Issues using a 2D Raycast to detect mouse hover on object colliders

Im currently working on a 2D character selection screen in Unity that should operate similarly to the Mortal Kombat character selection screen. Currently, I have a class called CharacterSelector attached to the main camera. The class holds methods for selection/deselection of characters, hover events, and selection confirmation. I was able to use a RayCast2D to build my character selection method; however, I am running into issues using it for hover events.
In my scene, I have a group of character images that the player can choose from (if they are unlocked). When the player hovers over the character with his/her mouse, the character image should be surrounded by a yellow border. When the user clicks on the desired character, a larger version of the image will popup to the left of the character image group.
Right now, I have the following code for the hover method:
public void onHover(Ray ray, RaycastHit2D hit)
{
if(hit.collider == null)
{
Debug.Log("nothing hit");
}
if (Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity))
{
print(hit.collider.name);
}
}
This method belongs to a class that the CharacterSelection class inherits from. The following is on the CharacterSelection class:
class CharacterSelector : Selector
{
Ray ray;
RaycastHit2D hit;
public void Start()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
}
void Update()
{
onHover(ray, hit);
if (Input.GetMouseButtonDown(0))
{
selectCharacter();
}
}
}
Also, all the character images that I am trying to hover over currently have 2D Box Colliders. As of right now, I am unable to get hover operation to work. It does not print the name of the character image to the console. I am using this as a first step to see if Unity recognizes the character image or not. Let me know if I can provide additional information!
Mouse changes position on screen almost every frame. This means your ray should be updated every frame according to mouse position. So I moved the corresponding statement from Start() to Update();
class CharacterSelector : Selector
{
Ray ray;
RaycastHit2D hit;
public void Start()
{
}
void Update()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
onHover(ray, hit);
if (Input.GetMouseButtonDown(0))
{
selectCharacter();
}
}
}
Secondly, if you look in the definition of Physics2D.Raycast you'll find that it gives you back the RaycastHit2D object. This is the object you should check the collider of, not your hit object which should have thrown an NullReferenceException, I don't know why it didn't. So this:
public void onHover(Ray ray, RaycastHit2D hit)
{
hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity);
if(hit.collider == null)
{
Debug.Log("nothing hit");
}
else
{
print(hit.collider.name);
}
}
Apart from this you don't really need the hit argument in onHover() function, it can be a local variable in the function. But if you are planning on using your hit variable in CharacterSelector script than you should change the declaration of onHover to: onHover(Ray ray, out RaycastHit2D hit) the out keyword passes the variable by reference instead of a copy of its value.
Also, I think checking if mouse is hovering over an object shouldn't be done in onHover, it's kinda misleading and doesn't seem logical to me. I'd move the body of onHover to another function like RaycastChecker(). I'd call onHover() only if mouse is actually hovering over the sprite. (like in OnCollisionEnter you take it granted that the collision did happen, so should the onHover, I think)

Categories