OnMouseDown not work in Vuforia - Unity C# - c#

I'm testing AR in Unity with Vuforia and I can't have the event OnMouseDown() working correctly.
It happens that the first time I hit play it works but just one time.
I've already checked that the collider is activated and well positioned.
Also I see that the check of the script in the GameObject (Cube in this case) is not enabled, it doesn't even appear like the rest of the scripts when components are made.
This is the code:
using System.Collections.Generic;
using UnityEngine;
public class Click : MonoBehaviour
{
void OnMouseDown()
{
Debug.Log("CLICK!!!");
}
}
I don't have any error messages or warnings in the console.
This is the repository, branch develop:
https://github.com/emicalvacho/MapaMentalAR.git

I just found out: You are always hovering the Hola text on the object .. not the cube. It blocks the raycast!
How I found out: I wrote a simple script for finding out what is currently hovered:
public class RayDebugger : MonoBehaviour
{
private void OnGUI()
{
GUI.color = Color.green;
var hovering = EventSystem.current.IsPointerOverGameObject();
var isHovering = hovering ? "Yes" : "No";
GUI.Label(new Rect(100, 100, 200, 200), $"Is hovering something? - {isHovering}");
if (!hovering) return;
var pointer = new PointerEventData(EventSystem.current) { position = Input.mousePosition };
var raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointer, raycastResults);
if (raycastResults.Count > 0)
{
GUI.Label(new Rect(100, 200, 200, 200), $"Currently Hovered: {raycastResults[0]}");
}
}
}
As you can see it is always your "Hola" Text component:
(and yes I just used a "dynamic image" target :D )
You can fix this in a few steps:
Disable RaycastTarget on the Text component:
this way it doesn't interfere with the pointer raycast
For getting a 3D collider your Camera should have a PhysicsRaycaster component attached:
I don't know why exactly but it only works if you use a Perspective Camera. Vuforia somehow seems to have a trouble with an Orthographic one .. understandable because for such a camera no distances exist. So rather switch you camera to Perspective
Now I can add and click on the cubes:
Btw
I don't think it worked with Overlay, but I can try.
as the info box says without a Camera referenced (which is the case in your scene) a ScreenSpace - Camera just behaves equal to a ScreenSpace - Overlay.

Related

Detecting if 2D Collider is touching Mouse Pointer from Other script in Unity 2D

I am working on a project using Unity2D, the goal is to be able to reference other main scripts to gain information from. In this specific case, I need to detect if the mouse pointer is touching a collider, however, from a separate script.
Usually, I would be able to create a boolean, and on mouse over set it to true, on mouse exit set it to false, like this:
bool isHovered;
void OnMouseEnter() {
isHovered = true;
}
void OnMouseExit() {
isHovered = false;
}
However, in the script, instead of doing this for each individual script, I would like to reference another script, like this:
public GameManager g;
void Update() {
if (g.IsTouchingMouse(gameObject)) { //Code }
}
But there's multiple problems with this. In my game manager class, I would need something like this
public bool IsTouchingMouse(gameObject g) { return value }
Which there is multiple issues with this, because I don't have a way to register the OnMouseEnter and OnMouseExit events for those objects on another script, and I don't have a way to store the values for every single gameObject to ensure this will work for every object without having to manually modify this script.
I'm looking for two things, #1, how can I detect mouseovers on objects from scripts who's parents are not that gameObject, two, are there any ideas on how I would go about creating a function to return this variable instantly?
Somewhat annoying, but I figured out a solution a few minutes after posting. So I will share it here.
public bool IsTouchingMouse(GameObject g)
{
Vector2 point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
return g.GetComponent<Collider2D>().OverlapPoint(point);
}
What this code is basically doing, is making a function that takes a gameObject as an input, creates a vector2 based on the position of the mouse cursor in world space, and then returns weather or not the 2D collider that the object contains is actually touching this imaginary point, the variable "point" should be interchangable with any 2D world space location. I was pretty much overcomplicating the entire issue.
Find two resources you like and import them into Unity's Assets and set their Texture Type to Cursor
Create a new script and mount it to an empty object.
Open the script, create three public variables of type Texture2D, return to Unity and drag your favorite pointer map to the variable window.
To set the object label, we judge which pointer to change by customizing the label; so first set the label for the object. For example, the ground, I added the Ground tag to it, the wall added the Wall tag; the column added the Cylinder tag.
Write a method to change the mouse pointer, where the main API for changing the pointer is Cursor.SetCursor()
void setCursorTexture()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//Define the ray pointed by the mouse in the game window
RaycastHit hitInfo; //Information of ray collision
if (Physics.Raycast(ray, out hitInfo))//Determine whether to hit the object
{
// switch pointer
switch (hitInfo.collider.gameObject.tag)
{
case "Ground":
Cursor.SetCursor(groundCr, new Vector2(16, 16), CursorMode.Auto);
break;
case "Wall":
Cursor.SetCursor(wallCr, new Vector2(16, 16), CursorMode.Auto);
break;
case "Cylinder":
Cursor.SetCursor(CylinderCr, new Vector2(16, 16), CursorMode.Auto);
break;
default:
Cursor.SetCursor(null,Vector2.zero,CursorMode.Auto);
break;
}
}
}
Implement this method in the Update() method called every frame.
END (you can go to run the program) Thank you and hope to help you
This method works without exception. To solve the problem try the following method:
public Collider2D collider; // target Collider
void Update()
{
var mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
if (collider.bounds.IntersectRay(mouseRay)) Debug.Log("Mouse on collider..");
}
For New Input System?
But Input.mousePosition gives a new system error in Unity. To solve this problem, call the mouse position as shown below:
var mousePos = Mouse.current.position.ReadValue();
You can also check if (new input system enabled) is active as below:
#if ENABLE_INPUT_SYSTEM
var mousePos = Mouse.current.position.ReadValue();
#else
var mousePos = Input.mousePosition;
#endif
then follow the direction of the camera ray:
var mouseRay = Camera.main.ScreenPointToRay(mousePos);

How can I make the animation of a button happen when pressed on the mobile screen?

I'm sorry if my English is bad at first.
The button
This is the button I want to run the animation when pressed.
Animations
Sprites I want to change between these two states when pressing the button
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
public class Button : MonoBehaviour
{
private Animator animator;
public void SetTrigger(string Pressed) { }
Collider2D col;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
animator.SetFloat("Position", 0);
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
Vector2 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
if (touch.phase == TouchPhase.Began)
{
Collider2D touchedCollider = Physics2D.OverlapPoint(touchPosition);
if (col == touchedCollider)
{
animator.SetFloat("Position", 1);
}
}
}
}
}
This is how the code has been after the last attempt I have made, it has things that may not make sense because I have been mixing things while testing. I have tried it with floats, bools and triggers. With the bool it has worked halfway for me, if I touched the button it did not sink but if from unity I pressed the button manually changing the boolean to true, and after touching from the mobile screen it recognized the touch and returned the button to the original position. In all situations what did not work well was the touch control but I have revised the touch control code and I would say that it is fine.
Sorry if it is not understood well, I am new to unity and programming, also English is not my main language
Are you sure Button does not already have implementation for what you are trying to achieve? Check what options are available under "Transition" in Button inspector. You can pick between Color Tint, Sprite Swap or Animation there, I suppose it handles most of the cases and I've never seen anyone implemeting animations to button in custom way.

Mouse events for Unity3D isometric tile map

I have been reading up on the new tile map system in Unity3D. I have managed to get to the point of setting up a grid -> tile-map and setting up a tile palette. However now i'm struggling with finding up-to-date tutorials for handling mouse events for this new tile map system.
I'm attempting to set a highlight when the mouse is over the tile and if the tile is clicked I want to be able to trigger scripts and other events. However the available tutorials online don't go into mouse events for the tile map system and very few talk about isometric tile maps.
Are there any good up to date tutorials for handling mouse events on an isometric tile map? Even a simple tutorial showing a hover effect on the tile and a "hello world from tile x.y" when tile is clicked, would be all i would really need to get going.
This is what I have so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseManager : MonoBehaviour
{
void Update()
{
Vector3 clickPosition = Vector3.one;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
clickPosition = hit.point;
}
Debug.Log(clickPosition);
}
}
This should get you started:
using UnityEngine;
using UnityEngine.Tilemaps;
public class Test : MonoBehaviour {
//You need references to to the Grid and the Tilemap
Tilemap tm;
Grid gd;
void Start() {
//This is probably not the best way to get references to
//these objects but it works for this example
gd = FindObjectOfType<Grid>();
tm = FindObjectOfType<Tilemap>();
}
void Update() {
if (Input.GetMouseButtonDown(0)) {
Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3Int posInt = gd.LocalToCell(pos);
//Shows the cell reference for the grid
Debug.Log(posInt);
// Shows the name of the tile at the specified coordinates
Debug.Log(tm.GetTile(posInt).name);
}
}
}
In short, get a reference to the grid and tilemap. Find the local coordinates using ScreenToWorldPoint(Input.mousePosition). Call the LocalToCell method of the grid object to get your local coordinates (Vector3) converted to cell coordinates (Vector3Int). Pass the cell coordinates to the GetTile method of the Tilemap object to get the Tile (then use the methods associated with the Tile class to make whatever changes you want to make).
In this example, I just attached the above script to an empty GameObject in the world. It would probably make sense to attach it to the Grid, instead. The general logic remains the same nonetheless.
This is a slightly different version from the way HumanWrites does it. It doesn't require a reference to the grid, and the mousePos is declared as a Vector2, rather than a Vector3 - this will avoid problems when working in 2D.
using UnityEngine;
using UnityEngine.Tilemaps;
public class MouseManager : MonoBehaviour
{
private Tilemap tilemap;
void Start()
{
tilemap = FindObjectOfType<Tilemap>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3Int gridPos = tilemap.WorldToCell(mousePos);
if (tilemap.HasTile(gridPos))
Debug.Log("Hello World from " + gridPos);
}
}
}
The 'tilemap' that we're referencing is a gameObject in your scene. You may have renamed it to something else, but it would be a child of the 'Grid' object.

Open GUI on Certain HTC VIVE Controller Angle/Turn

I am Trying to make a GUI for HTC VIVE but having trouble in opening it on certain controller angle.
I have done some work and achieved a bit sketchy one because my object is a child which make it hard for me to track its rotation or position, as i wanted it to open only when controller is at certain angle (as a guy looking at his watch)
Here is some visual Example:
This is my controller rotation without GUI:
As i rotate the controller the GUI should show something like this:
Here is some code I have managed
void RayCastFromHead() // is just a name for Method i am raycasting from a dummy which contains left Grip button
{
if (Physics.Raycast(dummy.position, dummy.up, out hitInfo, 30))
{
transform.rotation.ToAngleAxis(out tempAngle, out tempAxis);
if (hitInfo.collider.name.Contains("Camera (eye)"))
{
if (dummy.gameObject.GetComponent<MeshRenderer>().enabled)
{
if ((transform.localEulerAngles.z > 270.0f && transform.localEulerAngles.z < 315.0f)&&
(transform.position.y > 0.9f && transform.position.y < 2f))
{
staticRotaion = transform.localRotation;
canvasOnHead.GetComponent<TweenScale>().PlayForward();
}
}
}
}
}
I do not know that it is a right method to do this kind of task? In Simple manner i want to show GUI on certain controller rotation.
This is My hierarchy what i am talking about
This is the same i wanna do with my GUI it should open when my hand angle is something like this image
There is a simple solution to handle UI rotation.
I suppose you have a canvas for your GUI. This canvas can be child of any object. If you add the canvas (root of this menu) as a child of the left hand it should move and rotate with the left hand.
Note that the render mode of the canvas must be World Space.
This is the parent (left hand):
set the values of canvas's rect transform correctly (most important part is pos.z, I changed the scale of the canvas instead of changing the z. I could change width and height of canvas but it would have adverse effects)
it will behave as you described when rotating the parent object (left hand):
Edit
Add this script to your camera
public class LookAtWatchController : MonoBehaviour
{
public GameObject menuGUI;
public GameObject hand;
void Update(){
if(transform.eulerAngles.x > 10)
{
menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, 0, 0);
menuGUI.SetActive(true);
menuGUI.transform.position = hand.transform.position;
}
else{
menuGUI.SetActive(false);
}
}
}
assign the gui menu to menuGUI
assign the left hand to hand
you can also include the rotation elements of the hand in the menuGUI rotation:
menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, hand.transform.eulerAngles.y, hand.transform.eulerAngles.z);
I haven't tested this yet but menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, 0, 0); should also work fine.
As you see below the rotation.eulerAngles.x of camera and canvas are the same when canvas is seen right in front of camera

UI and unity position

I have this problem, that I want to be able to click on a "tile" on the screen and then a pop-up menu should be shown just next to the tile. I can click on the tile and then a pop-up menu shows up but not where I want it.
On the picture here I've clicked on the top left one.
My code for placing the picture is as following:
using UnityEngine;
using System.Collections;
public class TowerMenu : MonoBehaviour
{
bool showMenu = false;
float x;
float y;
GUIStyle myStyle;
public Texture2D[] towers;
void OnGUI()
{
if(showMenu)
{
//Bear tower
GUI.Button(new Rect(x + 10, y - 25, 50, 50), towers[0]);
//Seal tower
GUI.Button(new Rect(x + 10, y + 25, 50, 50), towers[1]);
}
}
public void ShowMenu(Vector2 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}
}
Hope anyone can help me :)
Sry, i cant comment because i dont have enough rep, this is a comment to Steven Mills answer and comments to that post.
The first error comes because you are calling WorldToViewportPoint as if it was a static member function which it isnt(Think of if you had 2 Cameras you would have to specify which Camera you want, reading up on what a static member is would be helpful here). What you need to do to fix this is get a reference of your MainCamera and call the function from that instance(best method would probably be with a public variable and dragging the camera on the script in the editor)
The second error occurs because you are trying to give a Vector3 to ShowMenu() which requires a Vector2. The third is probably a product of the compiler trying to fix error 2
This is a logical error because the tiles are GameObjects and thus the transform.position are positions in 3d space. What you actually want is the 2d-pixel-position on the screen of your MainCamera. To get this you need to call WorldToScreenPoint instead of WorldToViewportPoint. Sadly, as you will notice you will also get a Vector3 here which is not what you want, but you can just take the x and y coordinates as your pixel screen coordinates. the z-coordinate denotes the distance from the camera.
Hope that clears it up a little instead of confusing you ;D
Feel free to ask again, but also try to read the Unity Script Reference and try to understand what is written there and what it means :)
By the look of it, your ShowMenu method is receiving a pos of (0,0), which is why the two buttons are placed at what seems to be a position of (10,-25) and (10,25) respectively.
Without seeing the code calling ShowMenu I can't be sure what location you're giving, but my guess would be that the tiles belong to a parent object, and you're passing the local position instead of the world position.
If you post the code in which you call ShowMenu I may be able to point out any problems.
EDIT:
Based on the information provided in the comments, the problem is that the position needs converting between the world coordinates and screen coordinates:
void OnMouseDown()
{
if(state == State.water)
{
errorHandler.sendError("You can't click on that");
}
if(state == State.ice)
{
towerMenu.ShowMenu(camera.WorldToViewportPoint(this.transform.position));
}
}
and change the ShowMenu to this:
public void ShowMenu(Vector3 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}

Categories