Detect Object Click in Unity - c#

and Working on a Project.
I just wanted to know, Is There any way to detect if a GameObject is clicked ?
More precisely, To Destroy an Object when it is Clicked.
i.e.
if (Object_is_clicked) {
Destroy(this.gameObject);
}

You can use the event system.
Create a MonoBehavior
using UnityEngine.EventSystems;
public class ClickDetector : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Clicked: " + eventData.pointerCurrentRaycast.gameObject.name);
}
}
Attach to the game object you want to monitor
Check here on how to do it
You can you the generic GameObject.AddComponent<Type>() to do it in runtime.

Related

What do I need to use in order to make an interact method that acts differently for each object? Unity3D

sorry if this seems like an idiot's question but I am very bad at programming.
Basically, I want to make a script that has an Interact method that does something different based on what the object is.
If you played something like Max Payne 2, you might have noticed how you can open doors, interact with sinks & toilets and they do something different.
What I did was attach the script that shows the button prompt to the object that I would be colliding with, but I have no idea how to move forward. Which script should check for the "E" button down once the player collides with the object, and how do I define the Interaction() method based on the object I collided with without making a script for each object? (Unless that's how you make this kind of interaction system?)
Sorry if I am not making much sense, english isn't my main langauge. Thanks in advance.
public class Interactable : MonoBehaviour {
public GameObject canvas;
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Player")
{
Debug.Log("enabled");
canvas.SetActive(true);
}
}
void OnCollisionExit(Collision collision)
{
if (collision.gameObject.tag == "Player")
{
Debug.Log("exit");
canvas.SetActive(false);
}
}
One of the best ways to handle the problem is to use an interface. Of course, keep in mind that avoiding creating different scripts for interactive objects will take the player code out of control as the project expands. So you can create an interface like the one below outside the player class:
public interface IInteractable
{
void OnAction(Player player);
}
You can also assign this interface away as follows. Here the door will be an interactable Monobehavior. Other game objects such as lights, books and can be defined as follows.
public class Door : MonoBehaviour, IInteractable // for e.g
{
public void OnAction(Player player)
{
// Play Open door animation
}
}
public class Book : MonoBehaviour, IInteractable // for e.g
{
public void OnAction(Player player)
{
// Read the book
}
}
public class Agent : MonoBehaviour, IInteractable // even you can use this for agents that can interact with them
{
public void OnAction(Player player)
{
Debug.Log(player.name + " is talking with " + name);
}
}
Finally, the only code you need to write in the player is a raycast. Because the collider only works when your player is inside the body, but the interact mode, like skyrim or max payne, works via raycast or spherecast. The code below can cover any object that benefits from Interactable. Not only can you access the player, but as the project expands, you no longer need to define multiple ifs for different objects. Also keep in mind that this is a standard way to solve this problem.
public LayerMask interactLayer; // interact layer for avoiding ray detection mistakes
public void Update()
{
if (Physics.Raycast(transform.position, transform.forward, out var hit, 2f, interactLayer.value))
{
if (Input.GetKeyDown(KeyCode.E))
{
var _interactable = hit.transform.GetComponent<IInteractable>();
_interactable?.OnAction(this);
}
else
{
Debug.Log("Press E Key to interact with "+ hit.transform.name);
}
}
}
Welcome to Stack-overflow and Programming
What you are looking for is Inheritance.It allows you to create a 'base' class to use and reference to.
In this case, you can classify those objects as Interactable, and create another script to describe their usage further, like so:
public abstract class Interactable : MonoBehaviour {
// ...
public abstract void Interact();
void OnCollisionEnter(Collision collision) {
if (collision.gameObject.tag == "Player") {
// EXAMPLE: Now it will interact dynamically whenever player enters it's range
Interact();
}
}
}
// ......
public class Door : Interactable {
public override void Interact() {
Debug.Log("Open Door");
}
}
// ......
public class Toliet : Interactable {
public override void Interact() {
Debug.Log("Flush Toliet");
}
}
// Or maybe on the player's POV
public class Player : MonoBehaviour {
void OnCollisionEnter(Collision collision) {
if (collision.gameObject.tag == "Interactable") {
// We only have to concern if its an interactable,
// no need to concern what type of interactable it is
gameObject.GetComponent<Interactable>().Interact();
}
}
}
You can check some online tutorials if it is still confusing to you.
You may also want to look at Interfaces. Nearly identical to Inheritance.

How to use "OnClick.AddListener" on multiple GameObjects in one Frame

I'm pretty new to Unity and C# scripting.
In my scene I have four buttons. I declared them in my script as public and put the items (on type Button) via drag and drop in my inspector in unity. Depending on which button is clicked, i want my program to do something. You can see in the script below what I've done. That scripts works perfectly just like I want it to.
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Example : MonoBehaviour
{
public Button Left;
public Button Right;
public Button Starten;
public Button Zurueck;
private void Start()
{
loadRezept(0);
Right.onClick.AddListener(iterationUp);
Left.onClick.AddListener(iterationDown);
Starten.onClick.AddListener(starten);
Zurueck.onClick.AddListener(zurueck);
}
... (here are the methods "iterationUp" and so on...)
This script work perfectly. But now there is my question: how can I do the same on using gameobjects?
If I just change the type "Button" to "GameObject" I don't have the possibility to use "onClick.AddListener". I don't want a script for every single gameobject. I just want something like I posted above.
GameObject itself has no such events.
Sounds like what you are asking for is a custom UnityEvent
You can create your own component like e.g.
public class HighlightController : MonoBehaviour
{
public UnityEvent OnHighlight;
// Somewhere Invoke the event e.g.
public void SetHighlighted()
{
OnHighlight.Invoke();
}
}
where you can add listeners now either via code or via the Inspector (just like the onClicked).
So put this on your GameObjects and then e.g. have fields like
[SerializeField] private HighlightController highlight;
//etc...
private void Awake()
{
highlight.OnHighlight.AddListener(HandleHighlight);
//etc...
}
private void HandleHighlight ()
{
...
}
// Make sure to cleanup listeners when not needed anymore
private void OnDestroy()
{
highlight.OnHighlight.RemoveListener(HandleHighlight);
//etc...
}
Or yes as mentioned as simple event could do the same without the serialization:
public class HighlightController : MonoBehaviour
{
public event Action OnHighlight;
public void SetHighlighted ()
{
OnHighlight?.Invoke();
}
}
and do
private void Awake()
{
highlight.OnHighlight += HandleHighlight;
}
private void OnDestroy ()
{
highlight.OnHighlight -= HandleHighlight;
}

Unity3d - Define event in another script

Let's say I would like to add functionality to the OnSelect() Event of a dropdown element.
Normally I would just add a new script to the specific dropdown gameObject:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class LanguageDropdown : MonoBehaviour, ISelectHandler// required interface when using the OnSelect method.
{
//Do this when the selectable UI object is selected.
public void OnSelect(BaseEventData eventData)
{
Debug.Log(this.gameObject.name + " was selected");
}
}
Hint: The script simply outputs a message if the Dropdown is getting selected.
Question: Is it possible to define the functionality inside another script?
E.g. I have a script attached to the master parent "Menue" where I am referencing this specific dropdown gameobject.
How can I define the OnSelect inside another script?
PS: Is this the correct place to ask this question, or should I ask it on gamedevelopement instead?
Use event and delegate. You can find a simplified tutorial for that here if this is new to you.
It should be something like this:
public delegate void SelectAction(GameObject target);
public static event SelectAction OnSelectedEvent;
Add that to your LanguageDropdown script and you should get this:
public class LanguageDropdown : MonoBehaviour, ISelectHandler// required interface when using the OnSelect method.
{
public delegate void SelectAction(GameObject target);
public static event SelectAction OnSelectedEvent;
//Do this when the selectable UI object is selected.
public void OnSelect(BaseEventData eventData)
{
Debug.Log(this.gameObject.name + " was selected");
//Invoke Event
if (OnSelectedEvent != null)
{
OnSelectedEvent(this.gameObject);
}
}
}
Now, you can subscribe and un-subscribe to the event in the OnEnable and OnDisable functions respectively script from another script:
void OnEnable()
{
//subscribe to event
LanguageDropdown.OnSelectedEvent += SelectAction;
}
void OnDisable()
{
//Un-subscribe to event
LanguageDropdown.OnSelectedEvent -= SelectAction;
}
//This will be called when invoked
void SelectAction(GameObject target)
{
Debug.Log(target.name + " was selected");
}
Basically I wanted to know if I am forced to attach the script
LanguageDropdown to the gameobject, or If this is not required and I
can setup everything from another script which is not attached to that
specific dropdown.
No, you can use the EventTrigger class to register the events like below and you won't have to attach it to each object:
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.Select;
entry.callback.AddListener((eventData) => { SelectAction(); });
Please, do not use that. It is slow and I have verified this from multiple people too.
A Unity-centric solution would be to use a UnityEvent which lets you make these changes in the inspector.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class LanguageDropdown : MonoBehaviour, ISelectHandler// required interface when using the OnSelect method.
{
public UnityEvent Selected;
//Do this when the selectable UI object is selected.
public void OnSelect(BaseEventData eventData)
{
Debug.Log(this.gameObject.name + " was selected");
Selected.Invoke();
}
}
Then the LanguageDropdown component will have a Selected member visible in the inspector to which you can then assign an Object and method target (much like a Button).
Note: You can change UnityEvent to UnityEvent<LanguageDropdown> if you want to include the source object:
public class LanguageDropdown : MonoBehaviour, ISelectHandler// required interface when using the OnSelect method.
{
public UnityEvent<LanguageDropdown> Selected;
//Do this when the selectable UI object is selected.
public void OnSelect(BaseEventData eventData)
{
Debug.Log(this.gameObject.name + " was selected");
Selected.Invoke(this);
}
}
The target method must then have the correct parameter list
(i.e. public void method(LanguageDropdown dropdown) )
You can define public method in another script, and call it int OnSelect() implementation.
For example:
public interface IDropdownContext
{
void OnDropdownSelected(BaseEventData eventData);
}
public class Test : MonoBehaviour, IDropdownContext
{
public void OnDropdownSelected(BaseEventData eventData)
{
Debug.Log("OnDropdownSelected");
}
}
public class LanguageDropdown : MonoBehaviour, ISelectHandler// required interface when using the OnSelect method.
{
[SerializeField]
public Test context;
//Do this when the selectable UI object is selected.
public void OnSelect(BaseEventData eventData)
{
Debug.Log(this.gameObject.name + " was selected");
context.OnDropdownSelected(eventData);
}
}

Unity open external link

By placing the unity file on the page I can not redirect the action to another page. What happens is that the new page is opened inside the frame intended for the unity file.
using UnityEngine;
using System.Collections;
public class Urlazerecovelo : MonoBehaviour {
void OnMouseDown ()
{
Application.OpenURL("https://www.google.pt");
}
}
public class OpenWebPage : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Application.ExternalEval("window.open('www.google.pl', '_blank');");
}
}
I assume from what you're saying you use WebGL as target platform. More about here

Unity 3d script adding functions as trigger on Inspector window

I have defined three functions (OnReticleEnter(),Exit() and hover()) in the script and attached with a game object:
using UnityEngine;
using System.Collections;
using TMPro;
public class MyObject : MonoBehaviour
{
// Custom reticle events
public GameObject gOBJ;
void OnReticleEnter()
{
gOBJ.SetActive(true);
}
void OnReticleExit()
{
gOBJ.SetActive(false);
}
void OnReticleHover()
{
gOBJ.SetActive(true);
}
}
My problem is I want these functions in the inspector window so that I can define multiple actions like event trigger's pointer enter.
Is there any way I can make these functions available as event trigger on inspector window?

Categories

Resources