İçindekiler:

Joystick ve IR Alıcılı Arduino Kontrollü Platform Oyunu: 3 Adım (Resimli)
Joystick ve IR Alıcılı Arduino Kontrollü Platform Oyunu: 3 Adım (Resimli)

Video: Joystick ve IR Alıcılı Arduino Kontrollü Platform Oyunu: 3 Adım (Resimli)

Video: Joystick ve IR Alıcılı Arduino Kontrollü Platform Oyunu: 3 Adım (Resimli)
Video: Mario Bile Oynatan Arduino Tabanlı Game Boy 2024, Kasım
Anonim
Joystick ve IR Alıcılı Arduino Kontrollü Platform Oyunu
Joystick ve IR Alıcılı Arduino Kontrollü Platform Oyunu

Bugün, basit bir C# tabanlı platform oyununu kontrol etmek için bir Arduino mikro denetleyicisi kullanacağız. Arduino'yu bir joystick modülünden giriş almak ve bu girişi Seri bağlantı üzerinden girişi dinleyen ve kodunu çözen C# uygulamasına göndermek için kullanıyorum. Projeyi tamamlamak için video oyunları oluşturma konusunda daha önce herhangi bir deneyime ihtiyacınız olmasa da, daha sonra tartışacağımız "oyun döngüsünde" olup bitenlerden bazılarını özümsemek biraz zaman alabilir.

Bu projeyi tamamlamak için ihtiyacınız olacak:

  • Visual Studio Topluluğu
  • Arduino Uno (veya benzeri)
  • Bir joystick denetleyici modülü
  • Sabır

Başlamaya hazırsanız, devam edin!

Adım 1: Joystick'i ve IR LED'i Bağlayın

Joystick'i ve IR LED'i Bağlayın
Joystick'i ve IR LED'i Bağlayın
Joystick'i ve IR LED'i Bağlayın
Joystick'i ve IR LED'i Bağlayın

Burada, bağlantı oldukça basittir. Sadece bağlı olan joystick'i gösteren diyagramların yanı sıra, joystick'i ve birçok Arduino kitiyle birlikte gelen uzaktan kumanda ile oyunu kontrol etmek için bir kızılötesi LED'i içeren kurulumu da ekledim. Bu isteğe bağlıdır, ancak kablosuz oyun yapabilmek harika bir fikir gibi görünüyordu.

Kurulumda kullanılan pinler:

  • A0 (analog) <- Yatay veya X ekseni
  • A1 (analog) <- Dikey veya Y ekseni
  • Pin 2 <- Joystick Anahtar girişi
  • Pin 2 <- Kızılötesi LED girişi
  • VCC <- 5V
  • Zemin
  • Zemin #2

2. Adım: Yeni Bir Eskiz Oluşturun

Yeni Bir Eskiz Oluştur
Yeni Bir Eskiz Oluştur

Arduino eskiz dosyamızı oluşturmaya başlayacağız. Bu, joystick'i değişiklikler için yoklar ve bu değişiklikleri her birkaç milisaniyede bir C# programına gönderir. Gerçek bir video oyununda, bir oyun döngüsündeki seri bağlantı noktasını girdi için kontrol ederdik, ancak oyuna bir deney olarak başladım, bu nedenle kare hızı aslında seri bağlantı noktasındaki olay sayısına bağlıdır. Aslında projeye Arduino kardeş projesi Processing'de başlamıştım, ancak çok, çok daha yavaş olduğu ve ekrandaki kutu sayısını kaldıramadığı ortaya çıktı.

Bu nedenle, önce Arduino kod düzenleyici programında yeni bir Sketch oluşturun. Kodumu göstereceğim ve sonra ne yaptığını açıklayacağım:

#include "IRremote.h"

// IR değişkenleri int alıcı = 3; // IR alıcısının sinyal pini IRrecv irrecv(alıcı); // 'irrecv' decode_results sonuçlarının örneğini oluştur; // 'decode_results' örneğini oluştur // Joystick/oyun değişkenleri int xPos = 507; int yPos = 507; bayt joyXPin = A0; bayt joyYPin = A1; bayt joySwitch = 2; geçici bayt clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int akımHız = 550; // Varsayılan = ortalama hız int speedIncrement = 25; // Y girişi işaretsiz uzun akım ile hızı artırma/azaltma miktarı = 0; // Geçerli zaman damgasını tutar int wait = 40; // mesajlar arasında beklenecek msn [Not: daha düşük bekleme = daha hızlı kare hızı] volatile bool buttonPressed = false; // Butona basılıp basılmadığını ölçer void setup() { Serial.begin(9600); pinMode(joySwitch, INPUT_PULLUP); ataşeKesme(0, atlama, DÜŞÜYOR); akım = millis(); // Geçerli saati ayarla // Kızılötesi alıcıyı ayarla: irrecv.enableIRIn(); // Alıcıyı başlat } // void loop() { int xMovement = analogRead(joyXPin); int yPos = analogRead(joyYPin); // Joystick X hareketini zamanlamadan bağımsız olarak ele alın: if (xMovement > minMoveHigh || xMovement current + wait) { currentSpeed = yPos > minMoveLow && yPos < minMoveHigh // Birazcık hareket etseydi… ? currentSpeed // …sadece mevcut hızı döndürün: getSpeed(yPos); // yPos'u sadece joystick önemli ölçüde hareket ettiyse değiştirin //int uzaklık =; Serial.print((Dize) xPos + ", " + (Dize) yPos + ', ' + (Dize) currentSpeed + '\n'); akım = millis(); } } // loop int getSpeed(int yPos) { // Negatif değerler Joystick'in yukarı hareket ettiğini gösterir if(yPos 1023 ? 1023: currentSpeed + speedIncrement; } else if(yPos > minMoveHigh) // "Aşağı" olarak yorumlandı { // Koruyun 0'ın altında dönüş akımıHız - speedIncrement < 0 ? 0: currentSpeed - speedIncrement; } } // getSpeed void jump() { buttonPressed = true; // Düğmeye basıldığını belirtin. } // atlama // Ekranda bir düğmeye basıldığında uzak, uygun yanıtı işleyin void translateIR(decode_results sonuçları) // alınan IR koduna göre işlem yapar { switch(results.value) { case 0xFF18E7: //Serial.println("2"); currentSpeed += speedIncrement * 2; break; case 0xFF10EF: //Serial.println("4"); xPos = -900; break; case 0xFF38C7: //Serial.println("5"); jump(); break; case 0xFF5AA5: //Seri. println("6"); xPos = 900; break; case 0xFF4AB5: //Serial.println("8"); currentSpeed -= speedIncrement * 2; break; default: //Serial.println(" diğer düğme "); break; }// Son anahtar } //END translateIR

Kodu çoğunlukla açıklayıcı olacak şekilde oluşturmaya çalıştım, ancak bahsetmeye değer birkaç şey var. Hesaplamaya çalıştığım bir şey aşağıdaki satırlardaydı:

int minYMoveUp = 520;

int minYMoveDown = 500;

Program çalışırken, joystick'ten gelen analog giriş, genellikle 507 civarında kalarak etrafta zıplama eğilimindedir. Bunu düzeltmek için, giriş, minYMoveUp'tan büyük veya minYMoveDown'dan küçük olmadıkça değişmez.

pinMode(joySwitch, INPUT_PULLUP);

ataşeKesme(0, atlama, DÜŞME);

AttachInterrupt() yöntemi, herhangi bir zamanda normal döngüyü kesmemize izin verir, böylece joystick düğmesine tıklandığında düğmeye basılması gibi girdi alabiliriz. Burada, pinMode() yöntemini kullanarak kesmeyi önündeki satıra ekledik. Burada önemli bir not, Arduino Uno'ya bir kesme eklemek için pin 2 veya 3'ü kullanmanız gerektiğidir. Diğer modeller farklı kesme pinleri kullanır, bu nedenle modelinizin Arduino web sitesinde hangi pinleri kullandığını kontrol etmeniz gerekebilir. İkinci parametre, burada bir ISR veya "Kesme Hizmeti Rutini" olarak adlandırılan geri arama yöntemi içindir. Herhangi bir parametre almamalı veya hiçbir şey döndürmemelidir.

Seri.baskı(…)

Bu, verilerimizi C# oyununa gönderecek olan satırdır. Burada X ekseni okumasını, Y ekseni okumasını ve bir hız değişkenini oyuna gönderiyoruz. Bu okumalar, oyunu daha ilginç hale getirmek için diğer girdileri ve okumaları içerecek şekilde genişletilebilir, ancak burada sadece birkaçını kullanacağız.

Kodunuzu test etmeye hazırsanız, Arduino'ya yükleyin ve seri monitörü açmak ve herhangi bir çıktı alıp almadığınızı görmek için [Shift] + [Ctrl] + [M] tuşlarına basın. Arduino'dan veri alıyorsanız, kodun C# kısmına geçmeye hazırız…

3. Adım: C# Projesini Oluşturun

Grafiklerimizi görüntülemek için başlangıçta İşleme'de bir projeye başladım, ancak daha sonra görüntülememiz gereken tüm nesneleri göstermenin çok yavaş olacağına karar verdim. Bu yüzden, girdilerimizi işlerken çok daha yumuşak ve daha duyarlı olduğu ortaya çıkan C# kullanmayı seçtim.

Projenin C# kısmı için,.zip dosyasını indirip kendi klasörüne çıkartmak ve sonra değiştirmek en iyisidir. Zip dosyasında iki klasör vardır. Projeyi Visual Studio'da açmak için Windows Gezgini'nde RunnerGame_CSharp klasörüne girin. Burada.sln (çözüm) dosyasına çift tıklayın, VS projeyi yükleyecektir.

Oyun için oluşturduğum birkaç farklı sınıf var. Her sınıfla ilgili tüm ayrıntılara girmeyeceğim, ancak ana sınıfların ne için olduğuna dair bir genel bakış sunacağım.

Kutu Sınıfı

Bir pencere biçiminde ekranda çizilebilen basit dikdörtgen nesneler oluşturmanıza izin vermek için kutu sınıfını oluşturdum. Buradaki fikir, bir tür grafik çizmek isteyebilecek diğer sınıfları kullanarak genişletilebilecek bir sınıf yaratmaktır. "Sanal" anahtar sözcüğü, diğer sınıfların bunları geçersiz kılabilmesi için kullanılır ("geçersiz kılma" anahtar sözcüğü kullanılarak). Bu şekilde, gerektiğinde Player sınıfı ve Platform sınıfı için aynı davranışı alabilir ve ayrıca nesneleri gerektiği gibi değiştirebiliriz.

Tüm özellikler hakkında çok fazla endişelenmeyin ve çağrılar çizin. Bu sınıfı, gelecekte yapmak isteyebileceğim herhangi bir oyun veya grafik programı için genişletebilmek için yazdım. Anında bir dikdörtgen çizmeniz gerekiyorsa, bunun gibi büyük bir sınıf yazmanız gerekmez. C# belgelerinde bunun nasıl yapılacağına dair iyi örnekler vardır.

Ancak, "Box" sınıfımın bazı mantığını ortaya koyacağım:

public virtual bool IsCollidedX(Box otherObject) { … }

Burada X yönündeki nesnelerle çarpışmaları kontrol ediyoruz, çünkü oyuncunun ekranda onunla aynı hizada olması durumunda yalnızca Y yönündeki (yukarı ve aşağı) çarpışmaları kontrol etmesi gerekir.

public virtual bool IsCollidedY(Box otherObject) { … }

Başka bir oyun nesnesinin üstünde veya altında olduğumuzda, Y çarpışmalarını kontrol ederiz.

public virtual bool IsCollided(Box otherObject) { … }

Bu, X ve Y çarpışmalarını birleştirerek herhangi bir nesnenin bununla çarpışıp çarpışmadığını döndürür.

genel sanal boşluk OnPaint(Grafik grafikler) { … }

Yukarıdaki yöntemi kullanarak herhangi bir grafik nesnesini içeri aktarır ve program çalışırken onu kullanırız. Çizilmesi gerekebilecek herhangi bir dikdörtgen oluşturuyoruz. Ancak bu, çeşitli animasyonlar için kullanılabilir. Bizim amacımıza göre, dikdörtgenler hem platformlar hem de oyuncu için yeterli olacaktır.

Karakter Sınıfı

Karakter sınıfı, Box sınıfımı genişletiyor, bu nedenle kutunun dışında belirli bir fiziğimiz var. Oluşturduğumuz tüm platformları bir çarpışma için hızlı bir şekilde kontrol etmek için "CheckForCollisions" yöntemini oluşturdum. "Jump" yöntemi, oyuncunun yukarı doğru hızını JumpSpeed değişkenine ayarlar, bu daha sonra MainWindow sınıfında kare kare değiştirilir.

Çarpışmalar burada Box sınıfından biraz farklı şekilde işlenir. Bu oyunda, eğer yukarı zıplarsak bir platformdan atlayabileceğimize karar verdim, ancak aşağı inerken ona çarparsa oyuncumuzu yakalayacaktır.

Platform Sınıfı

Bu oyunda, MainWindow sınıfındaki tüm platformların X konumlarını hesaplayarak, girdi olarak bir X koordinatı alan bu sınıfın yalnızca yapıcısını kullanıyorum. Her platform, ekranın 1/2'sinden ekran yüksekliğinin 3/4'üne kadar rastgele bir Y koordinatında kurulur. Yükseklik, genişlik ve renk de rastgele oluşturulur.

MainWindow Sınıfı

Oyun çalışırken kullanılacak tüm mantığı buraya koyuyoruz. İlk olarak, yapıcıda program için mevcut olan tüm COM bağlantı noktalarını yazdırıyoruz.

foreach(SerialPort. GetPortNames() içindeki dize bağlantı noktası)

Console. WriteLine("MEVCUT PORTLAR: " + port);

Arduino'nuzun halihazırda kullandığı bağlantı noktasına göre hangisinde iletişimi kabul edeceğimizi seçiyoruz:

SerialPort = new SerialPort(SerialPort. GetPortNames()[2], 9600, Parity. None, 8, StopBits. One);

Şu komuta çok dikkat edin: SerialPort. GetPortNames()[2]. [2] hangi seri bağlantı noktasının kullanılacağını belirtir. Örneğin, program "COM1, COM2, COM3" yazdırsaydı, dizide numaralandırma 0'dan başladığı için COM3'ü dinliyor olurduk.

Ayrıca yapıcıda, tüm platformları yarı rasgele aralıklarla ve ekranda Y yönünde yerleştirme ile oluşturuyoruz. Tüm platformlar, C#'ta dizi benzeri bir veri yapısını yönetmenin çok kullanıcı dostu ve verimli bir yolu olan bir List nesnesine eklenir. Daha sonra Karakter nesnemiz olan Player'ı oluşturuyoruz, puanı 0'a ayarlıyoruz ve GameOver'ı false olarak ayarlıyoruz.

özel statik geçersiz DataReceived(nesne gönderen, SerialDataReceivedEventArgs e)

Seri porttan veri alındığında çağrılan metottur. Burası, tüm fiziğimizi uyguladığımız, oyunun tekrar gösterilip gösterilmeyeceğine, platformların taşınıp taşınmayacağına vb. karar verdiğimiz yerdir. Daha önce bir oyun yaptıysanız, genellikle "oyun döngüsü" olarak adlandırılan ve çerçevenin her seferinde adlandırılan bir şeye sahip olursunuz. tazeler. Bu oyunda, DataReceived yöntemi oyun döngüsü olarak işlev görür, yalnızca denetleyiciden veri alındığında fiziği manipüle eder. Ana pencerede bir Zamanlayıcı kurmak ve alınan verilere göre nesneleri yenilemek daha iyi sonuç verebilirdi ama bu bir Arduino projesi olduğu için aslında ondan gelen verilere göre çalışan bir oyun yapmak istedim..

Sonuç olarak, bu kurulum, oyunu kullanılabilir bir şeye genişletmek için iyi bir temel sağlar. Fizik tam olarak mükemmel olmasa da, Arduino'yu herkesin sevdiği bir şey için kullanmak olan amaçlarımız için yeterince iyi çalışıyor: oyun oynamak!

Önerilen: