Merhabalar,
Bu konuya değinmeden önce neden bunu seçtiğimden bahsedeyim biraz. Bu konuda yüzlerce hatta belki de binlerce kaynak bulunuyor fakat çok azı Türkçe olduğundan bu konu ile alakalı Türkçe kaynakların sayısını ve çeşitliliğini arttırmak için bu ve bunun gibi benzer konuları ele alacağım.
Input Nedir ?
Kullanıcının oyunumuzla etkileşime girebildiği her şey birer inputtur. Türkçe meali ile “Girdi“, fakat anlaşılır olması ve her yerde Input adı ile kullanıldığı için Input kelimesi ile devam edeceğim. Ekrandaki butonlar veya klavyedeki tuşları kullanarak etkileşime geçebiliriz. Tam da burada platform farklılıkları işin içine giriyor. Bir bilgisayar veya konsol oyununda oyun süresince ekranda buton pek olmaz. Tüm inputlar klavyeden, fareden veya gamepad gibi araçlardan alınmaktadır. Fakat mobilde işler değişiyor. Dokunmatik bir ekrandan input alabilmek için kullanabileceğimiz farklı şeyler işin içine giriyor. Mobilde 4 şekilde input alabiliriz; Butonlar, Sensörler, Swipe diye tabir ettiğimiz sürüklemeler ve pinch-pan gesture dediğimiz çift parmak ile büyütme ve küçültme olarak bildiğimiz yapılan hareket. Tabii ki bunların dışında bir veya birden fazla dokunma ile oluşturabileceğimiz birden fazla kombinasyonu da kendi algoritmalarımız ile algılayıp kullanabiliriz. Fakat basit düzeyde kullanabileceklerimiz şimdilik bunlar. Klavye Inputları kolay olduğundan önce klavye Inputlarına değineceğiz ve ardından Mobil inputlara değineceğim.
Sahne Hazırlama
Tabii ki bu inputları test etmek ve yazmak için bir proje kullanacağız. InputsSample adında 3D eksende bir proje oluşturdum.
Üstteki karakter olarak kullancağımız küçük kübe fizik olaylarını tetikleyebilmemiz için RigidBody adındaki Componenti vermeyi unutmayalım. Varsayılan olarak sağda bulunan Inspector panelinin altında Add Component butonuna tıklayarak Physics > Rigidbody yolunu izleyip Rigidbody’i objemize ekleyelim.
Bu işlemi yaptıysak input almaya geçebiliriz. CTRL + S veya File > Save Scenes yolunu izleyerek sahnemizi “Game” adında kaydedelim.
Ortak Inputlar
Ortak Input olarak adlandırmamın sebebi ise bu inputlar her platformda o platformda karşılığı olan şekilde çalışır. Örnek vermek gerekirse Escape inputu. Bilgisayarlarda ESC tuşuna bastığımızda çalışırken Android‘de Geri tuşuna bastığımızda tetiklenen bir inputtur. Aynı şekilde Axis’ler de öyledir. Bilgisayarda yön tuşları olarak bildiğimiz inputlar aynı şekilde xbox ve playstation’daki yön tuşlarında da aynen çalışmaktadır. Farklı bir işlem yapmak gerekmemektedir. Fakat Mobilde herhangi bir axis olmadığı için manuel olarak bir joystik yapıp onun konumunu da kendimiz hesaplayıp ona göre kullanabileceğimiz bir input değerine çevirmemiz gerekmekte. Cross-Platform çalışmaları için çok daha detaylı ayrı bir yazı yazmayı düşünüyorum. Şimdilik bilgi olarak bilinmesi yeterli
Klavye Inputları
Öncelikle en temel olan yön tuşlarını yapmak isterdim fakat orada birbiri ile çalışan 2 düzlem bulunmakta. X ve Y düzlemi. Bu yüzden öncesinde bağımsız tuşlara değinelim. Biraz önce oluşturduğumuz Unity 3D sahnemize geri dönelim. Hareket ettireceğimiz objemize kendi yazacağımız bir Script’i ekleyelim. Bunun için tekrar Add Component yolunu izleyip yukarıdaki arama kutusuna KlavyeInput ismini yazıp New Script seçeneğini seçip devam ediyoruz. Bu aşamada Language‘ın C# seçili olduğuna emin olun. Enter’a basıp ekledikten sonra sağda gözüken scriptimize sağ tıklayarak Edit Script diyoruz.
TUŞ KONTROLLERİ
Update() metodunun içinde basit bir if kontrolü ile Inputları algılayabiliriz. Bildiğiniz gibi Update metodu her bir frame’de çalıştığından oyun esnasında saniyede defalarca kez çalıştığından sürekli bu tuşa basılıp basılmadığının kontrolünü yapacağız. Diğer bir yol ise Mouse veya Click olaylarında tetiklenen OnMouseDown, OnMouseDrag, OnMouseUp, OnMouseEnter, OnMouseExit, OnMouseOver, OnMouseUpAsButton gibi metotlar da bulunmakta. Fakat klavye için şu anda update içerisinde kontrol yazmaktayız. Hemen Escape ile başlayalım.
using System.Collections.Generic;
using UnityEngine;
public class KlavyeInput : MonoBehaviour {
void Start () {
}
void Update () {
//if ile o anda bu olayın olup olmadığını kontrol ediyoruz.
//Input class'ından çağırdığımız GetKeyDown() methodu belirlediğimiz input'a ilk basıldığında veya ilk dokunulduğunda çalışmakta,
// KeyCode'dan Escape'i içine yazdığımızda ESC'ye basıldığında True olduğunda if şartı gerçekleşmiş olacak.
if (Input.GetKeyDown(KeyCode.Escape))
{
// Bu tuşa basıldığında Output console'unda görebilmemiz için Debug'a yazdıralım.
Debug.Log(" ESCAPE TUŞUNA BASILDI");
}
}
}
Oyunu Çalıştırdıktan sonra klavyeden ESC tuşuna bastığımızda bizim belirlediğimiz mesajın Output Console’unda gözüktüğünü görebilirsiniz.
Tabii ki buraya yapmak istediğiniz herhangi bir şeyi yazabilirsiniz. Bu yazıda sadece inputları almaya değiniyorum. Aynı şekilde diğer tuşlarda da aynen çalışacaktır. Şunu deneyebilirsiniz. Visual Studio kullananlar için daha kolay olacaktır. Keycode enumundan sonra nokta (.) koyarak kullanabileceğimiz Inputların bir önerisi geliyor. Bunları kullanarak dilediğiniz tuşa basıldığında neler yapılacağını ayarlayabilirsiniz. |
Birbirinden bağımsız iki if kullanarak bu iki inputun da kontrolünü sağlayabiliriz. Bir de F tuşununa basılma olayını algılayalım. Deminki kodumuzun altında şunu ekleyelim:
{
Debug.Log(" F TUŞUNA BASILDI");
}
Şimdi de oyunlarda olmazsa olmazlardan tuşa ilk basıldığında ve elimizi tuştan kaldırdığımızda çalışan 2 farklı kontrol yazalım. Bu sefer boşluk tuşunu ele alalım. İlk dokunduğumuzda çalışması için Input.GetKeyDown() metodunu, Basılı tuttuğumuz sürece çalışması için Input.GetKey() metodu ve elimizi tuştan kaldırdığımızda çalışması için Input.GetKeyUp() metodunu kullanıyoruz. Hemen bu üçünü de boşluk tuşuna uygulayalım ve console’dan izleyelim.
Script dosyamızın son hali şu şekilde oldu:
using System.Collections.Generic;
using UnityEngine;
public class KlavyeInput : MonoBehaviour {
void Start () {
}
void Update () {
//Tuşa ilk basıldığında çalışması için GeyKeyDown metodunu kullandık.
//Boşluk tuşunu algılamak için ise KeyCode enumundan Space'i metodun içine verdik.
if (Input.GetKeyDown(KeyCode.Space))
{
//Çalıştığını kontrol edebilmemiz için output console'a yazdırmak için Debug.Log() metodunu kullanıyoruz.
Debug.Log(" Space tuşuna basıldı.");
}
//Tuşa basılı tuttuğumuz sürece çalışması için GetKey metodunu kullanıyoruz.
if (Input.GetKey(KeyCode.Space))
{
Debug.Log(" Space tuşuna basılıyor.");
}
if (Input.GetKeyUp(KeyCode.Space))
{
Debug.Log(" Space tuşuna basma eylemi sona erdi.");
}
}
}
Bir deneme ile test edelim. Tuşa bastım ve 5 saniye bekleyip elimi kaldırdım. Console’da şu sonucu gördüm:
Eğer Collapse seçili değil ise seçin. Aksi takdirde görüldüğü gibi 214 tane “Space tuşuna basılıyor.” mesajı alt alta listelenecektir. Görüldüğü gibi tuşa ilk dokuntuğumda GetKeyDown çalıştı. Dokunduğum süre zarfında defalarda GeyKey çalışmış durumda. Buna yürüme veya yarış oyunlarındaki gaza basma eylemi örnektir. İlk dokunuşta araca hız verip daha sonrasında basmanıza rağmen aracın ilerlememesi söz konusu olmayacağı için bu tarz hareketlerde GetKey kullanılabilir.
AXIS KONTROLLERİ
Böyle bahsedince değişik bir şey gibi görünmesine karşın bu aslında bizim bildiğimiz yön tuşları. Fakat birbiri ile kesişen bir eksende -1 ile 1 arasında değer döndürüyor olmaları onları diğer şekilde kullanmamızı sağlıksız kılıyor. Şu an için bilgisayarda basmıyorken 0 ve basıyorken de 1 veya -1 döndürmekte fakat aynı şey konsollar ve mobil için geçerli olmadığından doğru olan GetAxis() metodu ile kullanılmasıdır.
Öncelikle Kamerayı oyunu daha iyi görebilecek bir konuma alalım. Kameranın konumunu oyunu daha iyi görebilecek bir yere alalım. Position değerlerini X 1 Y 14 Z 14 yapıp Rotation değerlerini ise X 45 Y -180 Z 0 olarak değiştirdim. Artık sahneyi daha iyi bir şekilde görebilir konuma geldi. Axis kontrolleri için yeni bir Script ekleyelim. Hareket ettirmek istediğimiz kübün Inspector panelinden yeniden Add Component ile “AxisControl” adında yeni bir C# Scripti ekleyelim ve yine üzerine sağ tıklayarak Edit Script diyelim.
Şu şekilde uzun uzun yorumlamalar ile yazabilirsiniz
using System.Collections.Generic;
using UnityEngine;
public class AxisControl : MonoBehaviour {
// Öncelikle Unity Panelinden kod kullanmadan ayarlama yapabilmek için Public olarak hareket hızı ve donme hızı tanımlıyoruz.
public float hareketHizi = 3.5f, donmeHizi = 120f;
// Kameranın pozisyonunu dikkate alabilmek için kameranın önünü ve sağını tutacağım 2 değişken tanımlayalım.
private Vector3 CameraForward, CameraRight;
// yatay düzlemdeki input ve dikey düzlemdeki input değerlerini tutmak için 2 değişken daha tanımladık.
private float horizontalInput, verticalInput;
//Hareket etmek için RigidBody'i kullanacağımızı söylemiştik. Bu scripti üstüne eklediğimiz objenin rigidbody'sine ulaşıp kullanacağız.
//Her bir frame'de RigidBody'e tekrar tekrar ulaşıp işlemcimizi zorlamaktansa onu bir değişkende tutalım
Rigidbody rb;
void Start ()
{
//Kameram sabit olacağı için kameranın konumunu alma işlemini Start Metodunda yapıyorum. Eğer dinamik bir kameranız varsa bu işlemi Update içerisinde yapmalısınız
CameraForward = Camera.main.transform.forward.normalized;
CameraRight = Camera.main.transform.right.normalized;
// Kamera eğimli bir şekilde yüzeye baktığı için aşağı ok tuşuna bastığımızda kameraya doğru çapraz bir şekidle yukarı gelmemesi için y değerlerini sıfırlıyoruz
CameraForward.y = 0;
CameraRight.y = 0;
//Rigidbody'i oyun açılışında bir kere bulup onu artık rb değişkeni ile kullanabilelim
rb = this.GetComponent();
}
void Update () {
// Tuşa basılıp basılmadığı her karede güncellenmesi için Update metodunun içinde -1 ile 1 arasında değişken 2 düzlemdeki veriyi değişkene aktarıyorum.
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
}
// Fizik olaylarını daha hassas bir metot olan FixedUpdate içinde yapmak daha sağlıklı olacağından hareket işlemini buraya yazacağız.
private void FixedUpdate()
{
// Eğer bir tuşa basılmıyorsa boşu boşuna işlemleri yapmaması için bir kontrol yazıyoruz.
//iki axis'den biri 0 değilse kontrolü
if (horizontalInput != 0 || verticalInput != 0)
{
// Hareket yönünü hesaplayacağım 3 boyutlu (x,y,z) bir vektör tanımlıyorum
Vector3 hareketYonu;
//Hareket yönünü hesaplarken kameranın baktığı yönün vektörü ile dikey eksende aldığım inputu çarpıyorum.
// Ve tabii ki kameranın sağ tarafına bakan vektörü de yatay eksenden aldığım input ile çarpıp topluyorum.
// Bu ikisini toplayıp birim vektöre çeviriyorum. (normalized) Bu işlem yön vektördeki 3 değeri de 0 ile 1 arasında tutmak istediğimizde kullanılır
// Hareket işlemi zamanla gerçekleşen bir şey olduğundan hareket hızımı Time.DeltaTime ile çarpıyorum. (Objenin istediğimiz yöne ışınlanarak gitmesini istemeyiz değil mi?)
// bu değeri de çarparak asıl sonucu elde ediyorum. Hangi yöne ne kadar hızla hareket edeceğimi vektör olarak elimde tutuyorum artık.
hareketYonu = (CameraForward * verticalInput + CameraRight * horizontalInput).normalized * hareketHizi * Time.deltaTime;
// Hareket ederken aynı anda hareket ettiği yöne de dönmesi gerektiğinden hareket rotasyonunu da hesaplamamız gerekmekte
// Quaternation türünden bir değişken tanımlıyorum. Bu da rotasyon türünde elimde dereceleri tutmamı sağlayan bir tür
Quaternion hareketRotasyonu;
// Bu aşamada elimde hareket yönüm olduğu için LookRotation metodu işimi görecektir.
// Hareket yönüne doğru dönmek için hareket yönünü metodun içine verdikten sonra dikey düzlemi dikkate almaması için dönme işlemi tamamlandıktan sonra üstünün neresi olacağını atamamız gerekiyor.
// Üst olarak Vector3.up veriyorum. Vector3.up bize 3 boyutlu eksende Y ekseninin üstünü vermektedir.
// Bu işlem ile hareket esnasında Y eksenini önemsememiş olduk.
hareketRotasyonu = Quaternion.LookRotation(hareketYonu, Vector3.up);
// Rigidbody sayesinde hareketi uygulayalım
// MovePosition() metoduna Doğrudan hareket yönü verirsem hareket yönü olarak tuttuğum vektörün koordinatına gidecektir.
// Bu yüzden objenin şu anki pozisyonuna hareket yönünü ekleyerek o hareket yönü eklendiğinde hangi koordinata gideceğini vermiş oldum
rb.MovePosition(this.transform.position + hareketYonu);
// Dönme işlemi için de RotateTowards() metodunu kullanacağız.
// Hangi rotasyondan, hangi rotasyona döneceği bilgisini ve derece isteyen bir metot olduğundan bu bilgileri giriyoruz.
// this.transform.rotation ile şu anki rotasyonu alabiliyoruz. hareket rotasyonunu da hesaplamıştık onu da veriyoruz.
// ve yine zamanla olmasını istediğimiz bir işlem olduğu için dönme hızını Time.deltatime ile çarpıyoruz.
this.transform.rotation = Quaternion.RotateTowards(this.transform.rotation, hareketRotasyonu, donmeHizi * Time.deltaTime);
}
}
}
Scripti kaydedip Unity 3D’den Play tuşuna basıp oyunu çalıştırdığımızda W,A,S ve D tuşları ile karakterimizi hareket ettirdiğimizi göreceksiniz. Public olarak tanımladığımız hareket hızını ve dönme hızını arayüzden değiştirebildiğimizi de göreceksiniz.
Basitçe Input almaya değindik. Bir sonraki yazıda ise Mobil kontrollerden bahsediyor olacağım. Sensör kullanımı, Joystick yapımı ve kullanımını ele alacağız. Herhangi bir sıkıntıda veya sorunda mail atmaktan çekinmeyin iletisim@enisnecipoglu.com adresinden ulaşabilirsiniz.
simdeye kadan boyle ayrintili anlatan gormemidim
gerçekten cok iyi anlatmışşınız yorum satırları cok faydalı olmuş