Unity Gelişmiş Input Sistemi (Mobil Destekli)

Yayınlandı: 19 Temmuz 2017 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde
Etiketler:, , , , , , , , , , , , , , , ,

SON GÜNCELLEME: 10 Eylül 2017 (kodun önemli bir kısmı yeniden yazıldı ve joystick, direksiyon, d-pad gibi hazır input’lar eklendi)

Hepinize yeniden merhabalar,

Son zamanlarda Input.GetAxis, Input.GetButton veya Input.GetKey kullanan kodların Android cihazlarda nasıl çalıştırılabileceği ile ilgili çeşitli sorular alıyordum. Ben de bu konuda basit bir çözüm üretmeye çalıştım ve ortaya SimpleInput adını verdiğim sistem çıktı.

SimpleInput sistemi ile UI butonlarına dokunarak, dokunmatik ekranda parmağınızı sürükleyerek, joystick kullanarak, direksiyon çevirerek, belirlediğiniz klavye tuşlarına dokunarak vb. Input fonksiyonlarını simüle edebiliyorsunuz.

Unitypackage linki (örnek sahne içerir): https://github.com/yasirkula/UnitySimpleInput/raw/master/SimpleInput.unitypackage

Detaylar için yazının devamını okuyabilirsiniz…

Sistemin işleyişi çok basit: öncelikle üstteki unitypackage‘ı projenize import ediyorsunuz. Ardından kodlarınızdaki multi-platform olmasını istediğiniz Input fonksiyonlarını aşağıdaki gibi SimpleInput versiyonu ile değiştiriyorsunuz:

  • Input.GetAxis -> SimpleInput.GetAxis
  • Input.GetAxisRaw -> SimpleInput.GetAxisRaw
  • Input.GetButtonDown -> SimpleInput.GetButtonDown
  • Input.GetButton -> SimpleInput.GetButton
  • Input.GetButtonUp -> SimpleInput.GetButtonUp
  • Input.GetMouseButtonDown -> SimpleInput.GetMouseButtonDown
  • Input.GetMouseButton -> SimpleInput.GetMouseButton
  • Input.GetMouseButtonUp -> SimpleInput.GetMouseButtonUp
  • Input.GetKeyDown -> SimpleInput.GetKeyDown
  • Input.GetKey -> SimpleInput.GetKey
  • Input.GetKeyUp -> SimpleInput.GetKeyUp

SimpleInput’ta karşılığı olmayan tek Input fonksiyonu Input.GetKey(string) fonksiyonu. Kodlarınızda bu fonksiyonu kullanıyorsanız o zaman fonksiyonun aldığı string parametreyi, KeyCode türündeki karşılığı ile değiştirmeniz lazım.

Artık geriye, bu input’lara değerlerini verecek olan component’leri/objeleri oyuna eklemek kalıyor. Mesela SimpleInput.GetAxis(“Horizontal”) ve SimpleInput.GetAxis(“Vertical”) fonksiyonlarına değerlerini vermesi için oyuna bir joystick veya d-pad ekleyebilirsiniz.

Paketle birlikte gelen Prefabs klasörünün içerisinde bazı hazır input objeleri bulunmakta: joystick, direksiyon (SteeringWheel), d-pad, yatay yön tuşları (ArrowsHorizontal), dikey yön tuşları (ArrowsVertical) ve 4 yöne yön tuşları (ArrowsAllDirections). Bu objeleri rahatça kişiselleştirebilmeniz için de Sprites klasöründe bir takım hazır görseller bulunmakta. Tabi eğer dilerseniz kendi görsellerinizi de kullanabilirsiniz. Paketle gelen hazır görsellerin hepsinin lisansı CC0 Creative Commons, yani istediğiniz sprite’ları herhangi bir credit vermeden istediğiniz gibi kullanabilirsiniz.

Diyelim ki oyuna joystick eklemek istiyorsunuz. Bu durumda yapmanız gereken şey, Prefabs klasöründeki Joystick prefab’ını sahnenizdeki canvas‘ın içerisine sürükleyip (canvas yoksa oluşturun) ardından joystick’i istediğiniz gibi konumlandırmak. Bundan sonra tek yapmanız gereken, joystick hareket ettikçe hangi axis’lerin değerlerinin değişeceğini belirlemek:

X Axis“e atanmış axis, joystick’i yatayda hareket ettirdikçe değer alırken “Y Axis“e atanmış axis ise joystick’i dikeyde hareket ettirdikçe değerini alır. “Movement Axes” değişkeni joystick’in hangi eksenlerde hareket edebileceğini belirtirken “Movement Area Radius” değişkeni ise joystick’in hareket alanı yarıçapını belirler. “Is Dynamic Joystick” seçeneği seçilirse joystick normalde ekranda gözükmez ancak sadece ekrana bir parmak dokununca, parmağın olduğu noktada belirir; yani konumu dinamik olur. “Dynamic Joystick Movement Area” ise, joystick eğer ki dinamik ise bu joystick’in nerelerde oluşabileceğini belirler. Bu alanın dışına dokunulursa orada joystick oluşmaz. Eğer değeri verilmezse joystick ekranın herhangi bir yerine dokununca oluşabilir.

2 boyutlu bir oyun yapıyorsunuz ve karakterinizin ekrandaki sol ve sağ ok tuşlarına dokundukça hareket etmesini istiyorsunuz diyelim. Bu durumda Prefabs klasöründeki ArrowsHorizontal prefab’ını canvas’ınıza sürükleyebilirsiniz. Bu objenin içerisinde Left (sol) ve Right (sağ) adında iki obje, bu objelerde de “Axis Input UI” isminde bir component bulunmakta. Bu component’i bir UI elemanına atarsanız, o UI elemanına basılı tutulduğu sürece “Axis” değişkeninde belirlenen axis input’unun değeri “Value” olur:

Eğer anlattıklarım birazcık kafanızı karıştırdıysa Example klasöründeki örnek sahneyi açıp oradaki sistemi inceleyebilirsiniz:

Bu örnekte hareket edebilen ve zıplayabilen 2 player var ve ilk player hareket etmek için Horizontal ve Vertical axis’lerini kullanırken ikinci player ise Horizontal2 ve Vertical2 axis’lerini kullanıyor. Zıplamak için ise Jump ve Jump2 button’larını kullanıyorlar. Yani SimpleInput ile, normalde Unity’de var olmayan axis’leri ve button’ları da kullanabiliyorsunuz.

Üstte bahsettiğim component’ler de dahil olmak üzere, plugin ile beraber gelen tüm component’lerden kısaca bahsedecek olursam:

SimpleInput.GetAxis İçin Component’ler

  • AxisInputKeyboard: klavyedeki bir tuşa basılı tuttuğunuz sürece axis’in değerini değiştirir
  • AxisInputUI: bir UI elemanına (mesela Button, Image, Text vs.) basılı tuttuğunuz sürece axis’in değerini değiştirir
  • Dpad: genellikle joystick’lerin solunda gördüğümüz d-pad’leri simüle eder. D-pad’lerde input ya tamamen vardır (-1 veya 1 değerini alır) ya da hiç yoktur (0 değerini alır). Yani 0.5 gibi bir ara değer döndürülmez
  • Joystick: alışageldiğimiz joystick input’u
  • SteeringWheel: ekrandaki bir direksiyonu simüle eder. Direksiyonu sola veya sağa çevirdikçe axis’in değeri değişir
  • Touchpad: atandığı RectTransform‘un üzerinde parmak sürüklenirse bu sürükleme miktarı kadar axis’in değerini değiştirir; yani ekranda parmağı sürükledikçe axis’e değer verir. Eğer tüm ekranda parmağı sürükleyebilmek istiyorsanız Canvas objesinin kendisine bu component’i verebilirsiniz. Component’teki “Allow Mouse Input” değişkenini işaretlerseniz mouse ile de touchpad’i kullanabilirsiniz. “Ignore UI Elements” seçeneğini işaretlerseniz, bir parmak bir UI elemanının üzerine dokunsa bile touchpad’e input sağlanırken bu seçeneği işaretlemezseniz sadece hiç bir UI elemanına dokunmayan parmaklar touchpad’e input sağlayabilir.

SimpleInput.GetButton İçin Component’ler

  • ButtonInputKeyboard: klavyedeki bir tuşa basılı tuttuğunuz sürece button’un değerini değiştirir
  • ButtonInputUI: bir UI elemanına basılı tuttuğunuz sürece button’un değerini değiştirir

SimpleInput.GetMouseButton İçin Component’ler

  • MouseButtonInputKeyboard: klavyedeki bir tuşa basılı tuttuğunuz sürece mouse button’un değerini değiştirir
  • MouseButtonInputUI: bir UI elemanına basılı tuttuğunuz sürece mouse button’un değerini değiştirir

SimpleInput.GetKey İçin Component’ler

  • KeyInputKeyboard: klavyedeki bir tuşa basılı tuttuğunuz sürece key’in değerini değiştirir
  • KeyInputUI: bir UI elemanına basılı tuttuğunuz sürece key’in değerini değiştirir

Bu component’ler arasından ButtonInputKeyboard gibilerini oyununuzdaki herhangi bir objeye component olarak verebilirken KeyInputUI gibilerini ise sadece UI objelerine component olarak verebilirsiniz. Joystick, SteeringWheel veya Dpad için ise Prefabs’taki hazır prefab’ları kullanmanızı öneririm.

Eğer ki SimpleInput ile bir klavye tuşuna tıklayınca değil de bir mouse tuşuna tıklayınca bir axis’i simüle etmek gibi bir niyetiniz olursa da o zaman sahnedeki bir objeye AxisInputKeyboard component’i verebilir ve “Key” olarak sol mouse tuşu için Mouse0, sağ mouse tuşu için Mouse1 ve orta mouse tuşu için de Mouse2 değerini verebilirsiniz.

 

Umarım faydalı olur. Daha sonra görüşmek dileğiyle!

yorum
  1. ekrem doğa dedi ki:

    ilginç emeğinize sağlık sizi takip ediyorum hocam benim bi sitem var http://siteneradyoekle.net adında buna uygulama yazarmısınız?

  2. enceweb dedi ki:

    merhabalar hocam, emek ve gayretleriniz için çok teşekkür ederim bu alanda bildiğimiz herşeyi sizden öğrendik desem abartmış sayılmam sanırım 🙂 . hocam daha önce yayınlamış olduğunuz temple run tarzı oyun yapımı ile alakalı scriptte bir yerde takıldım yardımlarınızı rica ediyorum. yolu sağa veya sola döndürmeden subway surf tarzı düz ilerlemek istiyorum ama pooling sistemini uygulayamıyorum. düz ilerleyen infinete bir yol ve puan objelerini koyabilmek için scriptte nasıl değişiklik yapmam gerekiyor yardımcı olabilirseniz çok sevinirim… saygılarımla….

    • yasirkula dedi ki:

      Temple Run örneğini yazdığım zamanlarda henüz şimdikinden daha acemiydim ve dürüst olmak gerekirse o örneğin kodu çok da iyi olmadı. Temel çok iyi olmayınca da onun üzerine kat çıkmak zor oluyor. Dediğiniz şeyi bir miktar eforla yapabiliriz elbette ama benim önerim Unity’nin fırından yeni çıkardığı kendi infinite runner örneğine bakmanız yönünde; gördüğüm kadarıyla burada yol düz bir şekilde oluşturuluyor: https://www.assetstore.unity3d.com/en/#!/content/87901

      • enceweb dedi ki:

        hocam bu tavsyenizi görmüş ve incelemiştim ama henüz bu oyundaki scriptleri anlayabilecek kadar birikimim yok :/ 🙂

      • yasirkula dedi ki:

        SonsuzYolScript’in içeriğini şu şekilde değiştirerek düz infinite yol oluşturmayı başardım: https://www.dropbox.com/s/7c7g2d68jo8iqnh/TempleRunKlonInfiniteDuzYol.cs?dl=0

        Basit anlamda yaptığım değişiklikler şöyle:
        – Start fonksiyonunda ileri yönde 1 değil 2 tane YolContainer oluşturdum
        – Update fonksiyonunda Player’ın yolun ilk yarısını geçip geçmediğini kontrol ettim
        – Eğer player yolun ilk yarısını geçmişse yolun ilk yarısını havuza yollayıp sonra yolun ikinci yarısının ucunda tekrar oluşturdum

        Yani aslında tahminimin aksine çok az bir kodla (yaklaşık 15-20 satır) dediğiniz şeyi yapmak mümkünmüş 😀 Oyunu test ederken bir de şunu gördüm ki; Window-Lighting-Settings’teki Fog’u açıp rengini de Main Camera’nın Background rengi ile aynı renk yapınca, özellikle zıplarken yolun ucu daha bir güzel duruyor.

  3. enceweb dedi ki:

    emekleriniz için çok teşekkür ederim hocam, karşılık beklemeden yaptığınız çalışmalarla bizleri mahçup ediyorsunuz başarılarınızın devamını dilerim, saygılarımla….

  4. Muhammed dedi ki:

    S.a yasir abi nasılsın ben sana 3 tane bir şey soracağım yardım edersen sevinirim ilk olarak ben oyunda atiyorum bir ayarlar bolumu ekledim ve ben butona basinca grafik kodunun acilip kapanmasini istiyorum kisacasi butona tiklayinca yada OnMouseDown ile bir objeye tiklayinca scriptin kapanip acilmasini istiyorum birde ben zombi yapay zekasi olusturdum mesela ben mesafe 2 den az olursa zombinin saldirma animasyonu devreye giriyor uzaklasirsam pesimden kosuyor evet onu normal olarak yaptim fakat zombi duvarin arkasina gecince dolasmiyor navigasyonu haritaya ekledim objelere bunu karaktere nasil vericem ki etrafini dolasip beni bulsun ama yine mesafe azalinca animasyonlar devreye girsin kısacası benim yaptığım yapay zekada zombi modelinin beni navigationdan bulmasını istiyorum son olarak benim oyunum çok kasmaya başladı farkettim 3d model ekleyince kasmaya başlıyor bahçenin etrafını demirlerle kapattım yaklaşık 30 tane nesne kopyaladım kasmaya başladi oyunun grafiklerini düşürtmeden kasmasını nasıl önleyebilirimyardim edersen sevinirim abicim (:

    • Muhammed dedi ki:

      Son bir şey daha sormak istiyorum abi ben şimdi unity deki hazir joysickleri kullaniyorum fakat pc uzerinden joystickler işlemiyor bende hep build edip telefondan bakmak zorunda kaliyorum ve zaman kaybi oluyor hem pc uzerinden hemde telefondan işleyen joystickleri nasil yapabilirim

      • yasirkula dedi ki:

        Açıkçası şu dersimdeki joystick’in her platformda düzgün çalışıyor olması lazım: https://yasirkula.com/2016/06/17/unity-ui-dokunmatik-ekran-joystick-kullanimi-multi-touch-destekli/

        Ekrandaki butonu UI-Button ile yaparsanız On Click event’i vasıtasıyla, butona basınca çalışacak fonksiyonlar belirleyebilirsiniz. Bu fonksiyonların birinin içerisinde ise grafik scripti component’ine GameObject.Find ve GetComponent fonksiyonları yardımıyla erişip component’in enabled’ını değiştirebilirsiniz.

        Zombilere NavMeshAgent vermeniz lazım. Zombiler player’ı kovalarken pathfinding yapması için NavMeshAgent’ta SetDestination( player.transform.position ); gibi bir kod çalıştırmalısınız. NavMeshAgent zombiyi kendi başına hareket ettireceği için başka Translate veya AddForce gibi kodlarınız varsa onları silin veya comment’leyin. Zombi ile player arasındaki gerçek mesafeyi bulmak için de NavMeshAgent’ın remainingDistance değişkeninden faydalanabilirsiniz.

  5. enceweb dedi ki:

    hocam tekrar merhaba, sonsuz yolda değişiklikleri uyguladım normal oyunda sorun yok ama ileri yol objelerine oyundakinden farklı kendi yaptığım zemin prefablarını kullanınca 2 sorunla karşılaşıyorum 1.si yol sonsuz oluşmuyor, 2.si puan objeleri gözükmüyor nerede hata yapıyor olabilirim hocam yardımlarınızı rica ediyorum, saygılarımla…

  6. enceweb dedi ki:

    tamamdır hocam bu kısmı hallettim bi noktayı atlamışım 🙂 teşekkürler…

  7. Hocam ben unity ile android’de kullanıcıdan isim gibi bir şey almak istiyorum butona tılayınca klavye gelicek ve oraya ismini yazıcak ve onu kaydedicem klavye için tek kaynak bunu bulabildim:
    https://docs.unity3d.com/Manual/MobileKeyboard.html
    bunu da yapamadım

    Bildiğiniz başka bir kaynak var mıdır

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class klavyeaçma : MonoBehaviour {

    public string stringToEdit = “Hello World”;
    private TouchScreenKeyboard keyboard;

    // Opens native keyboard
    void OnGUI ()
    {
    stringToEdit = GUI.TextField (new Rect (10, 10, 200, 30), stringToEdit, 30);

    if (GUI.Button (new Rect (10, 50, 200, 100), “Default”)) {
    keyboard = TouchScreenKeyboard.Open (“”, TouchScreenKeyboardType.NumberPad);
    }

    }
    }

    kodum bu ekranda yazı yazılabilen bi ekran çıkıyor (pc için klavye ile yazılabiliyor) altında bir de klavye olması gerek fakat onun yerine default yazan bir buton var

    kodu açıklayabilir misiniz ?

    hata nerde ?

    • yasirkula dedi ki:

      Bu kod, artık performansından dolayı tavsiye edilmeyen OnGUI fonksiyonunu kullanıyor ve de benim hiç kullanmadığım TouchScreenKeyboard sınıfından faydalanıyor. Onun yerine UI sistemini kullanarak bir Input Field objesi oluşturmak isteyebilirsiniz. Input Field’a kullanıcı mobil cihazda tıklayınca ekranda otomatik olarak bir sanal klavye belirmekte.

      UI dersim için bkz: https://yasirkula.com/2015/01/21/unity-ui-arayuz-sistemi/

  8. Muhammed dedi ki:

    S.a yasir abi konuyla alakalı değil fakat 2 şey kafama takıldı bulamadım 1.si ben androide bir uygulama yapıp açtığımda telefonun bildirim çubuğu kapanıyor ben bunu nasıl önlerim yani uygulama açıldığında telefonun bildirim çubuğuda gözüksün. 2.si de mesela bir canvas icine panel olusturdum ben bir butona tıkladığım zaman panelin yandan sürülerek açılmasını istiyorum aynı google play de soldan açılan pencere gibi butonu ben hallederim sadece birden değil yavaş yavaş açılmasını istiyorum bunları nasıl yapabilirim cevaplarsan sevinirim iyi geceler abicim.

    • yasirkula dedi ki:

      1- Android’deki Immersive Mode’u kodunuzun Start fonksiyonuna “Screen.fullScreen = false;” yazarak çözebildiğiniz söyleniyor.
      EDIT: fullScreen kodu bildirim çubuğunu açmıyor olabilir. Bunun için o koda ilaveten projenizin Plugins/Android klasörüne şu 2 dosyayı kopyalamanız gerekebilir: https://github.com/Over17/UnityShowAndroidStatusBar/tree/master/Assets/Plugins/Android
      2- Panelinizin Anchor X değerlerini ve Pos X değerini 0 yapın. Pivot X değerini ise 1 yapın. Ardından şu fonksiyonlar vasıtasıyla paneli açıp kapatabilirsiniz (kodun panelde olması lazım ve fonksiyonları StartCoroutine ile çalıştırmalısınız):

      IEnumerator PaneliAc( float sure )
      {
      	RectTransform tr = (RectTransform) transform;
      	Vector2 pivot = tr.pivot;
      
      	if( sure <= 0f )
      		sure = 0.0001f;
      
      	float delta = pivot.x / sure;
      	while( pivot.x > 0f )
      	{
      		pivot.x -= delta * Time.deltaTime;
      
      		if( pivot.x <= 0f )
      		{
      			pivot.x = 0f;
      			tr.pivot = pivot;
      		}
      		else
      		{
      			tr.pivot = pivot;
      			yield return null;
      		}
      	}
      }
      
      IEnumerator PaneliKapat( float sure )
      {
      	RectTransform tr = (RectTransform) transform;
      	Vector2 pivot = tr.pivot;
      
      	if( sure <= 0f )
      		sure = 0.0001f;
      
      	float delta = ( 1f - pivot.x ) / sure;
      	while( pivot.x < 1f )
      	{
      		pivot.x += delta * Time.deltaTime;
      
      		if( pivot.x >= 1f )
      		{
      			pivot.x = 1f;
      			tr.pivot = pivot;
      		}
      		else
      		{
      			tr.pivot = pivot;
      			yield return null;
      		}
      	}
      }
      
  9. enceweb dedi ki:

    Merhabalar hocam,

    Player Pref kullanımı ile alakalı bir sorum olacaktı. Oyun içi toplanılan skorla menüde kilidi açılmamış bir objenin(oyuncu,araba vs) kilidini açıp oyuna o obje ile devam etmek için nasıl bir script yazmalıyız? Bu konu ile alakalı forumlarda bir sürü soru var ama hiç cevap yok yabancı kaynak da bulamadım yardımcı olabilirseniz çok sevinirim hocam.
    Saygılarımla…

    • yasirkula dedi ki:

      Oyun bitiminde elimizdeki skoru “score” isminde bir değişken tutuyor diyelim. Bu durumda şöyle bir kod ile toplam skoru artırabilirsiniz:

      PlayerPrefs.SetInt( “ToplamSkor”, PlayerPrefs.GetInt( “ToplamSkor”, 0 ) + score );
      PlayerPrefs.Save();

      Oyun esnasında herhangi bir anda da bu skora PlayerPrefs.GetInt( “ToplamSkor” ); şeklinde erişebilir ve bu değeri kontrol ederek kilitleri açabilirsiniz.

  10. Y4kup dedi ki:

    TouchPad scriptini entegre edemedim hocam.Basitçe anlatırmısınız.

    • yasirkula dedi ki:

      Bir UI objesine (mesela Image) Touchpad scriptini verip “X Axis” ve “Y Axis”e değerlerini vermeniz lazım. Diyelim ki değerlerini “Horizontal” ve “Vertical” yaparsanız kodlarınızda SimpleInput.GetAxis(“Horizontal”) ve SimpleInput.GetAxis(“Vertical”) fonksiyonlarını kullanarak touchpad’in döndürdüğü x ve y değerlerinden faydalanabilirsiniz. Eğer touchpad’i mouse ile de kullanabilmek istiyorsanız “Allow Mouse Input” seçeneğini işaretlemeyi unutmayın.

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Connecting to %s