Unity3d OneLine – problemy, które da się rozwiązać w jednej linii kodu. Dosłownie!

Linia: Jak wykryć podwójne kliknięcie myszy lub przycisku?

Taka mała pierdoła, a w sumie często przydatna. Kiedy brakuje nam już klawiszy na klawiaturze, albo chcemy wykonać podobną akcję, możemy się posłużyć tak zwanym Double clickiem, czyli dość szybkim podwójnym kliknięciem klawisza myszki, albo przycisku na klawiaturze. Ogólnie sprawa, wydaje się trywialna. Ale zrobienie tego porządnie, może nie być takie oczywiste.

Rozwiązanie

Zaczniemy od wykrycia podwójnego kliknięcia myszki, bo sprawa jest banalnie prosta.

void OnGUI() 
{
	Event e = Event.current;
	if(e.isMouse && e.type == EventType.MouseDown && e.clickCount == 2)	{
		Debug.Log("Double click");
	}
}

Serio, tylko tyle. Najpierw tworzymy sobie obiekt typu Event, który wykrywa zdarzenia. Następnie sprawdzamy, czy event dotyczy myszki, czy jest to kliknięcie przycisku myszki i czy doliczyliśmy się dwóch kliknięć. Jeśli tak, wypisujemy sobie komunikat na konsole.

Niestety w przypadku klawiatury, zmienna eventowa, nie dostarcza nam aż tyle informacji. Brakuje nam liczby kliknięć klawisza, co musimy sobie obsłużyć sami. Deklarujemy sobie 3 zmienne pomocnicze:

private int buttonClicks = 0;
private float timer = 0;
private float delay = 0.5f;

Pierwsza zlicza kliknięcia, a pozostałe dwie, to timer mierzący czas między kliknięciami. (Nie chcemy policzyć jako podwójnego kliknięciach dwóch kliknięć z odstępu kilku minut – dlatego opóźnienie ustawiłem na 0.5 czyli jakieś pół sekundy).

Teraz sam kod czyniący magię:

void OnGUI() 
{
	Event e = Event.current;

	if (e.isKey && e.type == EventType.KeyDown && e.keyCode == KeyCode.A) {
		buttonClicks++;
		if(buttonClicks == 2) {
			Debug.Log("A pressed 2 times!"); 
			buttonClicks = 0;
		}
		timer = 0;
	}

	if (buttonClicks > 0) {
		timer += Time.deltaTime;
		if(timer >= delay) {
			buttonClicks = 0;
			timer = 0;
		}
	}
}

Pierwszy if, to powtórka tego od myszki. Tylko sprawdzamy, czy event wykonuje klawiatura, czy mamy do czynienia z naciśnięciem klawisza (KeyDown zamiast MouseDown), oraz jaki jest kod tego klawisza. Tutaj oczekuje naciśnięcia literki A.

Jeżeli taki event nastąpi, naliczam kliknięcie. Jeśli kliknięcia są dwa, wypisuje na konsoli informację i zeruję licznik – można by tutaj liczyć np. do potrójnego kliknięcia. Na końcu zeruje timer.

Drugi if, wykonuje się, jeśli mamy więcej niż jedno kliknięcie. Jeśli tak, to zwiększamy wartość timera, aż przekroczy opóźnienie. Jeśli tak się stanie, to liczymy od nowa, czyli zerujemy licznik i timer.

Oba zdarzenia, można łapać w jednym pliku, używając jednej zmiennej typu Event. Wtedy całość wygląda tak:

using UnityEngine;
using System.Collections;

public class DoubleClick : MonoBehaviour {

	private int buttonClicks = 0;
	private float timer = 0;
	private float delay = 0.5f;

	void OnGUI() 
	{
		Event e = Event.current;
		if(e.isMouse && e.type == EventType.MouseDown && e.clickCount == 2)	{
			Debug.Log("Double click");
		}

		if (e.isKey && e.type == EventType.KeyDown && e.keyCode == KeyCode.A) {
			buttonClicks++;
			if(buttonClicks == 2) {
				Debug.Log("A pressed 2 times!"); 
				buttonClicks = 0;
			}
			timer = 0;
		}

		if (buttonClicks > 0) {
			timer += Time.deltaTime;
			if(timer >= delay) {
				buttonClicks = 0;
				timer = 0;
			}
		}
	}
}

Kod znajduje się w funkcji OnGUI, ponieważ tylko tam rozpoznawana jest zmienna typu Event. Jeżeli przemieścimy ten kod np. do funkcji Update, otrzymamy NullReferenceException.

Koniec!