BAGIAN # 2 dari awal hingga selesai
Kami terus membuat game di Arduino dan kemudian memasukkan game ini ke dalam program yang saya lakukan untuk mobil dan berdasarkan pengetahuan kami, kami akan membuat game kedua untuk bersenang-senang dan membuat musik yang tepat untuk itu.
Untuk memahami apa yang perlu kita tulis sekarang, kita perlu membuat rencana untuk apa yang akan kita miliki dan dalam bentuk apa. Kami memiliki karakter utama, dia memiliki dua frame animasi, dan kami sudah berhasil keluar di pelajaran terakhir. Saya belum mulai mengubah lompatan lompatan untuknya, bukan karena saya terlalu malas, saya hanya belum mengerti intinya dalam hal ini. Selanjutnya, kita harus memiliki penunjukan seumur hidup, hanya membuat hati berturut-turut tidak menarik, dan jumlahnya juga basi, mari kita buat tiga poin kehidupan dan tandai dengan, misalnya, tingkat baterai. Dan untuk kesenangan mata, jantung akan berdetak di dekat baterai ini. Jumlah poin per putaran, ditetapkan di sebelah kiri layar, murni digital dan musuh kita akan memiliki kaktus jahat, untuk memulai akan.
Kami memutuskan pada objek dan mari kita menggambar mereka, segera semua sprite dan menuliskannya.









Kami memiliki sprite yang berfungsi dan kami sudah bisa membayangkan bagaimana tampilannya di layar, mengikuti pelajaran pertama kita akan menuliskannya di sistem biner, ingat di mana nol kosong dan di mana unit itu, piksel kita terbakar. Lanjutkan:
"--------------------------------------------------------------------------" // : byte Player_1[SYMBOL_HEIGHT] = {B01110,B01110,B00100,B01110,B10101,B00100,B01110,B01010,}; // : byte Player_2[SYMBOL_HEIGHT] = {B00000,B01110,B01110,B00100,B11111,B00100,B01110,B01010,}; // : byte Enemy_1[SYMBOL_HEIGHT] = {B00010,B00110,B10111,B10110,B11111,B00110,B00110,B11111,}; // : byte Heart_L[SYMBOL_HEIGHT] = {B00000,B01010,B11111,B11111,B11111,B01110,B00100,B00000,}; // : byte Heart_R[SYMBOL_HEIGHT] = {B00000,B00000,B01010,B11111,B01110,B00100,B00000,B00000,}; // : byte Battery1[SYMBOL_HEIGHT] = {B01110,B11111,B11111,B11111,B11111,B11111,B11111,B11111,}; // : byte Battery2[SYMBOL_HEIGHT] = {B01110,B10001,B10011,B10111,B11111,B11111,B11111,B11111,}; // : byte Battery3[SYMBOL_HEIGHT] = {B01110,B10001,B10001,B10001,B10011,B10111,B11111,B11111,}; // : byte Battery4[SYMBOL_HEIGHT] = {B01110,B10001,B10001,B10001,B10001,B10001,B10001,B11111,}; "--------------------------------------------------------------------------"
Sekarang kita memiliki sprite, dan sekarang saatnya untuk menghidupkan kembali semuanya. Pertama, mari kita pikirkan tentang fitur tambahan apa yang kita butuhkan. Mengetahui bahwa arduino tidak bekerja dengan sempurna dan di beberapa tempat bahkan sangat berubah-ubah, kami mulai mencoba menyederhanakan kehidupan mikrokontroler ini sebanyak mungkin. Jangan berlebihan dan pada saat yang sama menuntut pengembalian penuh. Jadi, kami memperkenalkan fungsi tambahan seperti itu yang akan menjalani kehidupan mereka sendiri dan melakukan semua yang kami butuhkan:
- Animasi hati
- Animasi pahlawan
- cek kerusakan pahlawan
- Pergerakan kaktus jahat
- akrual poin (untuk saat ini, setiap detik +1, lalu ubah)
- Memperbarui layar (tapi ini tidak akurat, kemungkinan besar kami akan menghapus fungsi ini dan menambahkan yang lain, saya tidak suka layar berkedip, saya ingin stabilitas). Selanjutnya, kami mengganti fungsi ini dengan menghapus lokasi pahlawan sebelumnya, ini akan menghapus layar yang sebenarnya berkedip, dan memusatkan penjahat akan berada di dalam skrip jahat, saya pikir akan ada maksimum satu atau dua baris.
- Remote control
- pengaturan loop dan pengaturan
Kami ingin kami memiliki animasi detak jantung. Membawa itu ke dalam fungsi yang terpisah dan memaksa kita untuk menjalani kehidupan terpisah kita sendiri, akan lebih mudah bagi kita untuk melacak pekerjaan dan di masa depan akan lebih mudah untuk diedit, karena kita memiliki segalanya, baik, atau hampir semuanya di satu tempat. Kode ini dapat ditampilkan dalam loop () dan dikomentari, tetapi saya pribadi menggunakannya untuk memisahkan fungsi, Anda tidak mencari kode di seluruh daftar dan Anda tahu bahwa fungsi terpisah mengontrol elemen individual dari permainan kami.
Sekarang, saya akan menulis potongan-potongan kode, kita akan menghubungkan mereka di akhir dan mendapatkan skrip lengkap, sekarang saya akan menjelaskan esensi dan ide kepada Anda, dan kemudian kita akan mengumpulkan teka-teki dan menikmati hasilnya.
Sebelum memulai kode itu sendiri, saya akan menjelaskan beberapa poin.
lcd.createChar // ini adalah perintah untuk mengakses layar dan menggunakan salah satu sel memori untuk merekam karakter baru. Jumlah sel dan, dipisahkan oleh koma, nama variabel dengan informasi, ditulis dalam tanda kurung.
Kami akan mengontrol rendering melalui variabel digital, menggunakan empat digit, agar animasi menjadi benar, jika kami ingin membuat jantung berdetak di sana-sini, maka variabel bool biasa akan cocok untuk kami. Tapi ide saya berbeda, satu pukulan besar dan dua yang pendek, sehingga akan terlihat lebih menarik.
"--------------------------------------------------------------------------" void HeartHit () // { if (HeartControl == 0 || HeartControl == 2){lcd.createChar(1, Heart_L);} // , if (HeartControl == 1 || HeartControl == 3){lcd.createChar(1, Heart_R);} // , if (currentMillis - HeartHitBigCheck >= HeartHitBig) { // if (currentMillis - HeartHitLightCheck >= HeartHitLight) { // HeartHitLightCheck = currentMillis; // if (HeartControl<3){HeartControl++;} // , else {HeartControl = 0; HeartHitBigCheck = currentMillis;} // , } } } "--------------------------------------------------------------------------"
Sekali lagi, saya ingin memusatkan perhatian Anda pada kode ini:
lcd.createChar (x, y); penugasan ke sel memori "x" dari (0 ... 7) data untuk ditampilkan di layar "y"
Silakan =)
Sekarang, kami memiliki kode yang menciptakan efek detak jantung yang menarik, tidak ada gunanya, hanya pamer =)
Selanjutnya, berdasarkan ini, kita akan membuat animasi pahlawan kita, ada nilai tambah yang besar, semakin jauh kita masuk ke artikel ini, semakin banyak Anda akan belajar gaya berpikir saya, dan semakin sedikit Anda perlu menjelaskan kepada saya dan lebih fokus pada kode dan membangun ide. Saya akan mencoba menjelaskan lebih dalam komentar skrip untuk menulis lebih sedikit di luar skrip.
Jadi mari kita mulai karakter utama dan buat fungsi lain untuk ini:
"--------------------------------------------------------------------------" // (). =) , . void PlAn () // { If (JumpB == true && GGpozY == 0){ // ( ) = . if (currentMillis - JumpUPCheck >= JumpUP) { // 0.8f JumpB = false; GGclear (); GGpozY = 1; // , . = ; (); = ; } } if (AnimPlayer == 1){lcd.createChar(0, Player_1);} // , if (AnimPlayer == 2){lcd.createChar(0, Player_2);} // , if (AnimPlayer < 2) // , , { lcd.setCursor(GGpozX, GGpozY); // lcd.write(0); // } if (currentMillis - AnimatedTimeCheck >= AnimatedTime) { // AnimatedTimeCheck = currentMillis; // if (AnimPlayer == 2){AnimPlayer = 1;} // else{AnimPlayer = 2;} // , . } } void GGclear () // { lcd.setCursor(GGpozX, GGpozY); // lcd.print(" "); // } "--------------------------------------------------------------------------"
Sekarang timer, um, atau lebih tepatnya poin kami yang akan diberikan, mari kita menulis timer dan menganggap bahwa ini adalah poin.
"--------------------------------------------------------------------------" void timer () // { if (currentMillis - DHTTimeRCheck >= DHTTimeR) // { DHTTimeRCheck = currentMillis; // Timer_z ++; // lcd.setCursor(0, 0); // lcd.print(Timer_z); // } } --------------------------------------------------------------------------"
Itu saja. Semakin jauh semakin mudah.
Sekarang, masih bekerja di luar kaktus kami.
Tugasnya sederhana, untuk tampil, bergerak jauh dari kanan ke kiri dan mencoba menyentuh pahlawan untuk menyebabkan kerusakan. Dengan kerusakan semuanya lebih mudah, satu sentuhan - satu pukulan. Sejauh ini, meningkatkan kompleksitas, kami tidak akan melakukannya. Biarkan kaktus bergerak dengan kecepatan 0,5f (kompleksitas, ini sudah menjadi pekerjaan rumah Anda =)), atau dalam bahasa Rusia, setengah detik adalah satu langkah.
Mari kita lihat bagaimana tampilan kode ini:
"--------------------------------------------------------------------------" void enemy_go () // { if (Emeny_check_1 == 0) // , , , { Emeny_control = random (100); // , , , , , . if (Emeny_control == 1) { // = 1 100 . Emeny_check_1 = 1; // , , bool , , hitON = false; // } } if (Emeny_check_1 == 1) // , { if (currentMillis - TimeBlinkCheck >= TimeBlink) // 0.5f { TimeBlinkCheck = currentMillis; // lcd.createChar(2, Enemy_1); // 2 lcd.setCursor(E1pozX, E1pozY); // 1 lcd.print(" "); // E1pozX--; // lcd.setCursor(E1pozX, E1pozY); // 2 lcd.write(2); // if (E1pozX <= 0) // { lcd.setCursor(0,1); // lcd.print(" "); // Emeny_control = 0; // Emeny_check_1 = 0; // E1pozX = 16; // - \/ \/ \/ E1pozY = 1; // - } } } } "--------------------------------------------------------------------------"
Masih sedikit dan setelah uji coba masing-masing bagian, saya sudah bisa meletakkan skrip lengkap yang disusun, dikonfigurasi dan siap untuk pengujian pada perangkat Anda.
Jadi sekarang kita memiliki salah satu skrip yang paling penting sejalan, ini adalah skrip periksa kerusakan dan dimasukkannya seorang gamer tanpa adanya kehidupan. Tidak ada yang supernatural dalam naskah. Oleh karena itu, kita dapat mulai membongkarnya (omong-omong, jika Anda berhati-hati, Anda akan melihat bahwa ketika kami membuat hati, kami tidak menampilkannya di layar, dan sekarang, Anda akan melihat di mana saya meletakkan bagian kode ini):
"--------------------------------------------------------------------------" void check_hit_gg_1 () // { if (E1pozX == GGpozX && E1pozY == GGpozY && hitON == false){ // Y , , LifeCheck -= 1; // hitON = true; // if (LifeCheck <= 0){ // AnimPlayer = 50; // loop () Emeny_check_1 = 50; // lcd.clear(); // lcd.setCursor(3, 0); // lcd.print("GAME OVER"); // } } else { // ! … lcd.setCursor(13, 0); // … lcd.write(1); // lcd.setCursor(14, 0); lcd.print("="); // lcd.setCursor(15, 0); lcd.write(3); // } } "--------------------------------------------------------------------------"
Kode ini sangat sederhana, fungsi utamanya adalah untuk memeriksa dan menunggu sampai semua kondisi terpenuhi untuk menghentikan permainan dan memberi tahu kami bahwa kami kalah.
Sekarang fungsi terakhir adalah manajemen. Bahkan, jika kita mem-parsing kode di atas, maka bagi kita itu akan tampak lebih mudah daripada sederhana. Dari pelajaran pertama, kami mengeluarkan kode kendali jarak jauh, saya menulis semuanya, mereka terlihat seperti ini:
* CH- 0xFFA25D
* CH 0xFF629D
* CH+ 0xFFE21D
* << 0xFF22DD
* >> 0xFF02FD
* >|| 0xFFC23D
* - 0xFFE01F
* + 0xFFA857
* EQ 0xFF906F
* 0 0xFF6897
* 100+ 0xFF9867
* 200+ 0xFFB04F
* 1 0xFF30CF
* 2 0xFF18E7
* 3 0xFF7A85
* 4 0xFF10EF
* 5 0xFF38C7
* 6 0xFF5AA5
* 7 0xFF42BD
* 8 0xFF4AB5
* 9 0xFF52AD
Tombol _ kode (perhatian!) (Kode kendali jarak jauh mungkin beragam)
Siapa yang belum membaca, saya menyarankan Anda untuk membaca bagian 1.
Sesuatu yang serupa, maka Anda akan memilikinya, dan Anda dapat dengan mudah mengkonfigurasi semua yang Anda butuhkan.
Sekarang kita akan membuat algoritma yang paling sederhana, berdasarkan apa yang sudah kita ketahui dan permainan kita akan hidup kembali.
"--------------------------------------------------------------------------" void IRCheck () // { if ( irrecv.decode( &results )) // , { if (results.value == 0xFF18E7 && GGpozY == 1){ // « 2 » «» GGclear (); // GGpozY = 0; // 2 ( ) JumpB = true; // JumpUPCheck = currentMillis; // } // 2 if (results.value == 0xFF10EF && GGpozX >= 0){ // GGclear (); // GGpozX -= 1; // } // 4 if (results.value == 0xFF5AA5 && GGpozX <= 15){ // GGclear (); // GGpozX += 1; // } // 6 if (results.value == 0xFF6897){ // 0 // , … lcd.clear(); // AnimPlayer = 1; // LifeCheck = 3; // Timer_z = 0; // GGpozX = 8; // \/ \/ \/ GGpozY = 1; // Emeny_check_1 = 0; // E1pozX = 16; // \/ \/ \/ E1pozY = 1; // . } irrecv.resume(); // } "--------------------------------------------------------------------------"
Kesimpulan dari kode tertulis di atas:
tombol 2 adalah lompatan
tombol 4 adalah langkah ke kiri
tombol 6 adalah langkah ke kanan
tombol 0 mengatur ulang game dan me-restart-nya
Sekarang, tetap bagi kita untuk mengkonfigurasi setup & loop, semuanya sudah berakhir. Kami menciptakan semua fungsi tambahan dan yang tersisa bagi kami adalah merekatkan dan menambahkan semua perpustakaan. Saya pikir kita akan melihat variabel dan pengaturan \ loop pengaturan utama sudah dalam kode umum, jadi mari kita mulai, dan kemudian Anda diminta untuk ctrl + c & ctrl + v dan itu saja =) dan pengembangan independen lebih lanjut ke arah ini, jika Anda semua tentu saja Saya menyukainya.
"--------------------------------------------------------------------------" #include <IRremote.h> // #include <Wire.h> // i2P #include <LiquidCrystal_I2C.h> // 1602 LiquidCrystal_I2C lcd(0x3F,16,2); // int AnimPlayer = 1; // int GGpozX = 8; // int GGpozY = 1; // int Emeny_check_1 = 0; // int Emeny_control = 0; // int E1pozX = 16; // int E1pozY = 1; // int HeartControl = 0; // int LifeCheck = 3; // long Timer_z = 0; // long AnimatedTime = 300; // long AnimatedTimeCheck = 0; // long HeartHitBig = 800; // long HeartHitLight = 250; // long HeartHitBigCheck = 0; // long HeartHitLightCheck = 0; // long BatteyBlink = 200; // 1 long BatteyBlinkCheck = 0; // long JumpUP = 800; // long JumpUPCheck = 0; // long DHTTimeR = 1000; // long DHTTimeRCheck = 0; // long TimeBlink = 500; // long TimeBlinkCheck = 0; // long currentMillis = 0; // bool JumpB = false; // bool BatteryB = false; // bool hitON = false; // decode_results results; // IRrecv irrecv(A0); // enum { SYMBOL_HEIGHT = 8 }; byte Player_1[SYMBOL_HEIGHT] = {B01110,B01110,B00100,B01110,B10101,B00100,B01110,B01010,}; byte Player_2[SYMBOL_HEIGHT] = {B00000,B01110,B01110,B00100,B11111,B00100,B01110,B01010,}; byte Enemy_1[SYMBOL_HEIGHT] = {B00010,B00110,B10111,B10110,B11111,B00110,B00110,B11111,}; byte Heart_L[SYMBOL_HEIGHT] = {B00000,B01010,B11111,B11111,B11111,B01110,B00100,B00000,}; byte Heart_R[SYMBOL_HEIGHT] = {B00000,B00000,B01010,B11111,B01110,B00100,B00000,B00000,}; byte Battery1[SYMBOL_HEIGHT] = {B01110,B11111,B11111,B11111,B11111,B11111,B11111,B11111,}; byte Battery2[SYMBOL_HEIGHT] = {B01110,B10001,B10011,B10111,B11111,B11111,B11111,B11111,}; byte Battery3[SYMBOL_HEIGHT] = {B01110,B10001,B10001,B10001,B10011,B10111,B11111,B11111,}; byte Battery4[SYMBOL_HEIGHT] = {B01110,B10001,B10001,B10001,B10001,B10001,B10001,B11111,}; void setup() { Serial.begin(9600); // irrecv.enableIRIn(); // lcd.init(); // Wire.begin(); // lcd.backlight();// } void loop() { currentMillis = millis(); // IRCheck (); // if (AnimPlayer < 3){ // , , if (LifeCheck == 3) {lcd.createChar(3, Battery1);} // if (LifeCheck == 2) {lcd.createChar(3, Battery2);} // if (LifeCheck == 1) {// , 1 if (BatteryB == false){lcd.createChar(3, Battery3);} // if (BatteryB == true){lcd.createChar(3, Battery4);} // if (currentMillis - BatteyBlinkCheck >= BatteyBlink) {BatteyBlinkCheck = currentMillis; // if (BatteryB == false) {BatteryB = true;} else {BatteryB = false;}} // } timer(); // check_hit_gg_1 (); // PlAn(); // HeartHit (); // enemy_go(); // } } void IRCheck () // { if ( irrecv.decode( &results )) // , { if (results.value == 0xFF18E7 && GGpozY == 1){ // « 2 » «» GGclear (); // GGpozY = 0; // 2 ( ) JumpB = true; // JumpUPCheck = currentMillis; // } // 2 if (results.value == 0xFF10EF && GGpozX >= 0){ // GGclear (); // GGpozX -= 1; // } // 4 if (results.value == 0xFF5AA5 && GGpozX <= 15){ // GGclear (); // GGpozX += 1; // } // 6 if (results.value == 0xFF6897){ // 0 // , … lcd.clear(); // AnimPlayer = 1; // LifeCheck = 3; // Timer_z = 0; // GGpozX = 8; // \/ \/ \/ GGpozY = 1; // Emeny_check_1 = 0; // E1pozX = 16; // \/ \/ \/ E1pozY = 1; // . } irrecv.resume(); // } } void timer () // { if (currentMillis - DHTTimeRCheck >= DHTTimeR) // { DHTTimeRCheck = currentMillis; // Timer_z ++; // lcd.setCursor(0, 0); // lcd.print(Timer_z); // } } // (). =) , . void PlAn () // { if (JumpB == true && GGpozY == 0){ // ( ) = . if (currentMillis - JumpUPCheck >= JumpUP) { // 0.8f JumpB = false; GGclear (); GGpozY = 1; // , . = ; (); = ; } } if (AnimPlayer == 1){lcd.createChar(0, Player_1);} // , if (AnimPlayer == 2){lcd.createChar(0, Player_2);} // , if (AnimPlayer < 2) // , , { lcd.setCursor(GGpozX, GGpozY); // lcd.write(0); // } if (currentMillis - AnimatedTimeCheck >= AnimatedTime) { // AnimatedTimeCheck = currentMillis; // if (AnimPlayer == 2){AnimPlayer = 1;} // else{AnimPlayer = 2;} // , . } } void GGclear () // { lcd.setCursor(GGpozX, GGpozY); // lcd.print(" "); // } void enemy_go () // { if (Emeny_check_1 == 0) // , , , { Emeny_control = random (100); // , , , , , . if (Emeny_control == 1) { // = 1 100 . Emeny_check_1 = 1; // , , bool , , hitON = false; // } } if (Emeny_check_1 == 1) // , { if (currentMillis - TimeBlinkCheck >= TimeBlink) // 0.5f { TimeBlinkCheck = currentMillis; // lcd.createChar(2, Enemy_1); // 2 lcd.setCursor(E1pozX, E1pozY); // 1 lcd.print(" "); // E1pozX
Dengan menghubungkan. Kami membuat kodenya, tapi inilah cara mengumpulkan kabel dan apa dan di mana menempel, saya tidak menjelaskan ini kepada Anda. Meskipun saya sangat yakin bahwa lebih dari 80% dari mereka yang memutuskan untuk membaca artikel ini sudah mengetahui hal ini, tetapi bagi saya, artikel tersebut tidak akan lengkap jika saya tidak memberikan informasi yang maksimal.
Tampilan A5 1602 - SCLA4 Display 1602 - SDAA0 IR sensorarduino, 1602 ( , , ), , - ( 4 , ), , 2000 Rock n Roll Racing. =) arduino ( ), ~60 % 15% — 20%, … … , , , 10 , . , . - - , , . ? .
Semua, berlangganan, suka, ikuti artikel baru.Terima kasih atas perhatian Anda, ciao cocoa!PS: Saya masih tidak bisa merekam kinerja permainan di video, kamera di ponsel mati dan sangat sedih. Tapi saya akan membuat sesuatu dan menambahkan video nanti ke artikel.Bagian pertama artikel ->