This question already has answers here:
How to detect click/touch events on UI and GameObjects
(4 answers)
Closed 4 years ago.
Is there way to call the onclick event from a raycast?
I have world scale canvas attached to an object that has images with buttons.
When I select the button with the mouse my event function is called.
But now I am trying to adjust the code so I can avoid using mouse all together.
[SerializeField]
private Image cursor;
[SerializeField]
private LayerMask uI;
if (Input.GetButtonDown("Fire1"))
{
Ray ray = Camera.main.ScreenPointToRay(cursor.transform.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100,uI))
{
Debug.Log(hit.collider);
}
}
This is the code I use to raycast into the world space canvas which works and returns the images but I am not sure how I can now call the onclick event since I am not using the mouse but a image instead
Is there way to call the onclick event attached to image that I raycast to or do I have to redo my entire script and not use on click events?
Hen you hit a GameObject, get its list of components that implement OnPointerClick event
IPointerClickHandler clickHandler=collider.gameObject.GetComponent<IPointerClickHandler>();
once you have that reference (its not null) you can call
PointerEventData pointerEventData=new PointerEventData(EventSystem.current);
clickHandler.OnPointerClick(pointerEventData)
That should do the job
I believe that the Button component does what you seek as well.
But to answer your question about raycasts.
Is there way to call the onclick event from a raycast?
//Example raycast code
//Variables
public RayCastHit _Hit;
public LayerMask _RaycastCollidableLayers; //Set this in inspector, makes you able to say which layers should be collided with and which not.
public float _CheckDistance = 100f;
//Method
void PerformRaycast(){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Physics.Raycast(ray, out _Hit, _CheckDistance + 0.1f, _RaycastCollidableLayers);
if (_Hit.collider == null)
{
Debug.Log("Raycast hit nothing");
return null;
}
GameObject go = _Hit.collider.gameObject;
}
Your raycast hits an object and stores a reference to that object. As you can see in my example you can fetch the game object through the RaycastHit.
When you have the game object you can access any scripts on it through GetComponent<>(), this means you can say.
GameObject go = _Hit.collider.gameObject;
OnClickScript ocs = go.GetComponent<OnClickScript>();
ocs.OnClick();
If I misunderstood your query, please let me know.
Related
I have a prefab that is instantiated when the user buys the item from my In-game store, how ever many is instantiated, the all of prefab has a start position of a certain position. The prefab can be dragged around the scene using this TouchScript package I found online! My issue: I want to play the prefab's animation every time the user is dragging the prefab around the screen, I attempted this by creating a RaycastHit2D function that would allow me to detect if the user has clicked on the prefab's collider, script below:
if (Input.GetMouseButtonDown (0)) {
Vector2 worldPoint = Camera.main.ScreenToWorldPoint (Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast (worldPoint, Vector2.zero);
if (hit.collider != null) {
if (this.gameObject.name == "Item5 (1)(Clone)" +item5Increase.i) {
monkeyAnim.SetBool ("draging", true);
Debug.Log (hit.collider.name);
}
} else {
monkeyAnim.SetBool ("draging", false);
}
}
However if I were to buy more than one prefab, all instantiated prefabs will play it's animation when I start to drag only one of the instantiated prefabs, hope I'm making sense. Can some one help me? Thank you!
I faced a similar issue with platforms in my 2D game. The solution I would suggest is to create a GameObject that acts as the current item you wish to animate, and a LayerMask that acts as a filter for which objects your raycast can hit. You can use this LayerMask in conjunction with the Physics2D.Raycast API, which has an overload method that takes a LayerMask as a parameter.
Start by creating a new layer, which can be done by going to the top right of an object in your scene and accessing the "Layer" box. Once you've created a new layer (I called mine "item"), make sure your prefab's layer is assigned correctly.
Then, create an empty object in your scene, and attach this script to it. On that object you will see a dropdown menu that asks which layers your raycast should hit. Assign it the "item" layer; this ensures that your raycast can only hit objects in that layer, so clicking on anything else in your game will produce no effect.
using UnityEngine;
public class ItemAnimation : MonoBehaviour
{
private GameObject itemToAnimate;
private Animator itemAnim;
[SerializeField]
private LayerMask itemMask;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
CheckItemAnimations();
}
else if (Input.GetMouseButtonUp(0) && itemToAnimate != null) //reset the GameObject once the user is no longer holding down the mouse
{
itemAnim.SetBool("draging", false);
itemToAnimate = null;
}
}
private void CheckItemAnimations()
{
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero, 1, itemMask);
if (hit) //if the raycast hit an object in the "item" layer
{
itemToAnimate = hit.collider.gameObject;
itemAnim = itemToAnimate.GetComponent<Animator>();
itemAnim.SetBool("draging", true);
Debug.Log(itemToAnimate.name);
}
else //the raycast didn't make contact with an item
{
return;
}
}
}
This question already has answers here:
How to detect click/touch events on UI and GameObjects
(4 answers)
Closed 4 years ago.
I'm a little new to unity and I'm unsure how to do this:
I've added a panel control to my app. I want to call a function on a script when the user touches the panel, and I want to receive the location of the touch in panel coordinates. None of the components seem to be able to do this. Maybe I have to write a bunch of raw code to watch all touches, do collision checks, etc?
The solution is to use Raycasting:
public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100))
print("Hit something!");
}
}
The example tells you how, you only need to know if the thing you touched was your panel.
For this, you need to use RaycastHit, checking the transform's names can be a good way.
This question already has answers here:
How to detect click/touch events on UI and GameObjects
(4 answers)
Closed 5 years ago.
In the code below, my issue is the parent object has two child objects, so whenever I click any child object, it is recognized twice. How can I get the mouse click to recognize only the child game object that is clicked and not both? Note that the parent object was made with an empty script. Please check the code below:
void Update() {
if (Input.GetMouseButtonDown(0)) {
Debug.Log("Pressed left click, casting ray.");
CastRay();
}
}
void CastRay() {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100)) {
Debug.DrawLine(ray.origin, hit.point);
}
}
If you have your script in each child, they will each be generating a ray and both recognizing that an object is hit (thus showing it twice). What you want to do instead is have one script in the parent. You can have this script check for the name of the gameobject that the ray hits in order to determine what action should occur.
Edit: Since you have a 2D scene you will need to do the following:
void CastRay()
{
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (hit.collider != null && hit.collider.gameObject.name == "object1")
{
// do something for gameobject with name of object1
}
}
I am new to unity and VR. I have been using google cardboard SDK to create VR apps in unity and am stuck at gazetimer. I want to trigger an action only if the user looks at any object for 3secs but have not been able to do so. Please help
Please see a similar question and answer here Use Gaze Input duration to select UI text in Google Cardboard
In summary, create a script to time the gaze, by cumulatively adding Time.deltaTime on each frame when the object is gazed at. When gaze time hits a pre-specified duration, trigger the button's OnClick event.
On the object, activate the script's gaze timing functions using event triggers Pointer Enter and Pointer Exit. See screenshot:
VR Camera usually contains a main camera and eye cameras (right and left). Since Main camera's center point will always be the center of the eyes of the user's point of view, you could use Raycast from its transform.position to its transform.forward and check whether it hits your object. Then simply add a timer which will call the action after it reaches the duration you have set.
For example:
using UnityEngine;
using System;
[RequireComponent(typeof(Collider))]
public class LookableObject : MonoBehaviour {
[SerializeField]
Transform cam; // This is the main camera.
// You can alternately use Camera.main if you've tagged it as MainCamera
[SerializeField]
float gazeDuration; // How long it should be gazed to trigger the action
public Action OnGazeAction; // Your object's action after being gazed
Collider gazeArea; // Your object's collider
float timer; // Gaze timer
public void Start () {
gazeArea = GetComponent<Collider> ();
}
public void Update () {
RaycastHit hit;
if (Physics.Raycast (cam.position, cam.forward, out hit, 1000f)) {
if (hit.collider == gazeArea) {
timer += Time.deltaTime;
if (timer >= gazeDuration) {
if (OnGazeAction != null)
OnGazeAction ();
}
} else {
timer = 0f;
}
} else {
timer = 0f;
}
}
}
Hope you get the idea.
I've tried some examples of code to handle click on object, but they are don't work.
I have object's mesh on scene:
On Main Camera there is one C# Script Component with code:
using UnityEngine;
using System.Collections;
public class cameraAnim3 : MonoBehaviour
{
void Update() {
if (Input.GetMouseButtonDown (0)) { // if left button pressed...
print ("cli!!!");
// create a ray passing through the mouse pointer:
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit)) { // if something hit...
print ("clicked on object!!!");
// if you must do something with the previously
// selected item, do it here,
// then select the new one:
Transform selected = hit.transform;
selected.gameObject.SetActive (true);
print (selected.gameObject.name);
// do whatever you want with the newly selected
// object
}
}
}
}
When I clicked with left button on the mesh of head, in console message "cli!!!" showed, but no message "clicked on object!!!" was showed.
How to catch click on this mesh?
Answer is here Unity: Object is not being detected by raycast for highlighting
The modern to detect collisions is to implement IPointerClickHandler interface, and ensure that you have an EventSystem and a relevant Raycaster (2d or 3d, depending on what collider are you using) present in the scene. It's much better than writing your own code to manage clicks and pointer positions. Also, the game object itself has to have a Collider component. It can either be a mesh collider, or a more generic (and better for performance) box collider.