How replace OnMouseDown in Unity's new input system? - unity3d

Unity has a new inputsystem where the old OnMouseDown() {} no longer works.
In the migration guide they mention replacing this with Mouse.current.leftButton.isPressed.
And in other forum posts they mention using an InputAction.
The problem is that these options detect mouse clicks anywhere in the scene, instead of just on the object:
public InputAction clickAction;
void Awake() {
clickAction.performed += ctx => OnClickedTest();
}
void OnClickedTest(){
Debug.Log("You clicked anywhere on the screen!");
}
// this doesn't work anymore in the new system
void OnMouseDown(){
Debug.Log("You clicked on this specific object!");
}
How can I detect mouse clicks on a specific gameObject with the new input system in Unity?

With this code somewhere in your scene:
using UnityEngine.InputSystem;
using UnityEngine;
public class MouseClicks : MonoBehaviour
{
[SerializeField]
private Camera gameCamera;
private InputAction click;
void Awake()
{
click = new InputAction(binding: "<Mouse>/leftButton");
click.performed += ctx => {
RaycastHit hit;
Vector3 coor = Mouse.current.position.ReadValue();
if (Physics.Raycast(gameCamera.ScreenPointToRay(coor), out hit))
{
hit.collider.GetComponent<IClickable>()?.OnClick();
}
};
click.Enable();
}
}
You can add an IClickable Interface to all GameObjects that want to respond to clicks:
public interface IClickable
{
void OnClick();
}
and
using UnityEngine;
public class ClickableObject : MonoBehaviour, IClickable
{
public void OnClick()
{
Debug.Log("somebody clicked me");
}
}

Make sure you have a an EventSystem with an InputSystemUIInputModule in the scene and a PhysicsRaycaster or Physics2DRaycaster on your Camera, and then use the IPointerClickHandler interface on the object with a collider on itself or its children:
using UnityEngine;
using UnityEngine.EventSystems;
public class MyClass : MonoBehaviour, IPointerClickHandler {
public void OnPointerClick (PointerEventData eventData)
{
Debug.Log ("clicked");
}
}

Related

How to detect a mouse clicked on a UI element

I'm trying to make a toolbar system in my game but I can’t find a ways to detect a mouse click on a UI element only or to detect if it's over it, the regular detect system isn’t working.
I tried:
void OnMouseDown()
{
Debug.Log(“yay”);
}
But the message is never logged.
You can use EventSystems interfaces on your UI elements:
IPointerClickHandler
IPointerEnterHandler
IPointerExitHandler
For example in your case:
public class test : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Click");
}
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("Enter");
}
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("Exit");
}
}
Make sure your Scene has an EventSystem to make it works.
IsPointOverGameObject
The UI can be distinguished through the methods in the link above.
You can use it like below.
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (EventSystem.current.IsPointerOverGameObject())
{
Debug.Log("Clicked UI");
}
else
{
Debug.Log("Clicked Not UI");
}
}
}

Unity3D NavMeshAgent for abilities

I have been working to create mouse-based movement for my Unity3D game. I have gotten the movement, but I am having trouble setting of a variable for move speed that I can modify using a skill. This is my first attempt at using C# and I am very inexperienced. This is the beginnings of a long project, so any help or advice would be greatly appreciated.
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.AI;
namespace EO.ARPGInput
{
[RequireComponent(typeof(NavMeshAgent))]
public class PlayerController : MonoBehaviour
{
public Vector3 velocity;
[SerializeField] private InputAction movement = new InputAction();
[SerializeField] public LayerMask layerMask = new LayerMask();
private NavMeshAgent agent = null;
private Camera cam = null;
private void Start()
{
cam = Camera.main;
agent = GetComponent<NavMeshAgent>();
}
private void OnEnable()
{
movement.Enable();
}
private void OnDisable()
{
movement.Disable();
}
private void Update()
{
HandleInput();
}
public void HandleInput()
{
if (movement.ReadValue<float>() == 1)
{
Ray ray = cam.ScreenPointToRay(Mouse.current.position.ReadValue());
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100, layerMask))
{
PlayerMove(hit.point);
}
}
}
public void PlayerMove(Vector3 location)
{
agent.SetDestination(location);
}
}
}
Sometimes Unity docs have all the answers you need. NavMeshAgent-Speed
Try using agent.speed. create a global integer "public int sp=1;" above and then in Start or in Update do
agent.speed=sp;
Then once it is working you can just change that integer's value in whatever method you want. Good luck

Colliders and sound

When I enter a collider for a certain game object I would like to play a different sound according to whether its the first time entering the sphere collider or the 2nd or 3rd time. Can this all be written in the same script?
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
//attach in inspector or make private and get with code in the Start()
public AudioSource audioSource1;
public AudioSource audioSource2;
void Start() {
// get audioSources optional
}
int colCounter = 0;
void OnCollisionEnter(Collision collision) {
colCounter++;
if (colCounter == 1)
audioSource1.Play();
else
audioSource2.Play();
}
}

How to avoid object references for spawned objects in Unity 2D?

At the moment I am programming a Unity 2D game. When the game is running the cars start moving and respawn continuously. I added kind of a life system to enable the possibility to shoot the cars. My issue is that my health bar as well as my score board need references to the objects they refer to, but I am unable to create a reference to an object which is not existing before the game starts. Another issue is that I don't know how to add a canvas to a prefab in order to spawn it with the cars continuously and connect them to the car. Is there a way to avoid these conflicts or how is it possible to set the references into prefabs. I will add the code of the spawner, the car and the the scoreboard. Already thank you in advance
Spawner:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour
{
public GameObject carPrefab;
public GameObject enemyCarPrefab;
public GameObject kugel;
public float respawnTime = 10.0f;
public int counterPlayer1=0;
public int counterPlayer2=0;
public int counterEnergy=0;
// Use this for initialization
void Start () {
StartCoroutine(carWave());
}
private void spawnPlayerCars(){
GameObject a = Instantiate(carPrefab) as GameObject;
a.transform.position = new Vector2(-855f, -312.9426f);
counterPlayer1++;
}
private void SpawnEnemyCars(){
GameObject b = Instantiate(enemyCarPrefab) as GameObject;
b.transform.position = new Vector2(853,-233);
counterPlayer2++;
}
private void SpawnEnergy(){
GameObject c = Instantiate(kugel) as GameObject;
c.transform.position = new Vector2(-995,-192);
counterEnergy++;
}
IEnumerator carWave(){
while(true){
yield return new WaitForSeconds(respawnTime);
if(counterPlayer1<3){
spawnPlayerCars();
Debug.Log(counterPlayer1);
}
if(counterPlayer2<3){
SpawnEnemyCars();
Debug.Log(counterPlayer2);
}
if(counterEnergy<3){
SpawnEnergy();
}
}
}
}
Car:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyCar : MonoBehaviour
{
public float speed = 3f;
int zählerAuto1=0;
private Vector2 screenBounds;
public AnzeigePunktzahlPlayer2 points;
public Spawner sp;
public int maxHealth=100;
public int currentHealth;
public HealthBar healthbar;
void Start () {
screenBounds = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
points= GetComponent<AnzeigePunktzahlPlayer2>();
sp= GetComponent<Spawner>();
currentHealth=maxHealth;
healthbar.SetMaxHealth(maxHealth);
}
void Update()
{
Vector2 pos = transform.position;
if(pos.x>-855f){
pos = transform.position;
pos.x-= speed* Time.deltaTime;
transform.position=pos;
zählerAuto1++;
}else{
points.counter++;
Debug.Log(points.counter);
sp.counterPlayer2--;
Debug.Log(sp.counterPlayer2);
Destroy(this.gameObject);
}
}
private void OnCollisionEnter2D(Collision2D other) {
if (other.collider.tag=="Kugel"){
takeDamage(40);
//sp.counterPlayer2--;
if(currentHealth<=0)
{
Destroy(this.gameObject);
}
}
}
public void takeDamage(int damage){
currentHealth-= damage;
healthbar.SetHealth(currentHealth);
}
public void getHealed(int heal){
currentHealth+= heal;
healthbar.SetHealth(currentHealth);
}
}
Scoreboard(one part of it(the other one is almost the same)):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class AnzeigePunktzahlPlayer1 : MonoBehaviour
{
public int counter;
public TextMeshProUGUI textPlayer1;
void Start()
{
// counter=0;
textPlayer1= GetComponent<TextMeshProUGUI>();
}
// Update is called once per frame
void Update()
{
textPlayer1.SetText( counter.ToString());
}
}
You could make the health bars and the canvas children of the Car prefab and have them spawn together.

Is there a fast way to detect drag events on a game object in Unity?

Basically, I am designing a game where I need a canvas image element to respond quickly and move along when it is dragged. So for that, I am implementing IDragHandler interface. But the method OnDrag gets called after a delay of about half second.
public class InputHandler : MonoBehaviour, IDragHandler
{
public void OnDrag(PointerEventData eventData)
{
// this gets logged after about 500 milliseconds
Debug.Log("mouse dragged");
}
}
I've attached this script on the same image element that I want to move along with the drag. This element has raycast target on and the graphic raycast component is enabled for its parent canvas. The image element falls behind the touch point initially but catch up later on because of which it feels like there is some lag in the input. Is there a way to remove/minimize this delay?
The lag might be due to the DragThreshold that is active by default. You can disable it this way:
public class OnDragScript : MonoBehaviour, IDragHandler, IInitializePotentialDragHandler
{
public void OnDrag(PointerEventData ped)
{
transform.Translate(ped.delta);
}
public void OnInitializePotentialDrag(PointerEventData ped)
{
ped.useDragThreshold = false;
}
}
Although I am not finding any delay. Perhaps you should start with 3 functions (begin, drag and end) to find out what exactly is happening.
Also, the IDragHandler works only for canvas elements. So your pointer should be within the boundaries of UI element while you begin your drag.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class InputHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public void OnDrag(PointerEventData eventData)
{
Debug.Log("OnDrag");
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("Drag Begin");
}
public void OnEndDrag(PointerEventData eventData)
{
print("Drag End");
}
}