PARTIE # 2 du début à la fin
Nous continuons à faire un jeu sur arduino et plus tard, mettons ce jeu dans le programme que je fais pour la voiture et en nous basant sur nos connaissances, nous créerons un deuxième jeu pour le plaisir et ferons la bonne musique pour cela.
Pour comprendre ce que nous devons écrire maintenant, nous devons faire un plan pour ce que nous aurons et sous quelle forme. Nous avons le personnage principal, il a deux images d'animation, et nous l'avons déjà compris dans la dernière leçon. Je n'ai pas commencé à changer le sprite de saut pour lui, pas parce que j'étais trop paresseux, je ne vois tout simplement pas l'intérêt de cela. Ensuite, nous devrions avoir une désignation de vie, juste faire des coeurs d'affilée n'est pas intéressant, et les chiffres sont également banals, faisons trois points de vie et marquons-les avec, par exemple, le niveau de la batterie. Et pour le plaisir des yeux, un cœur battra près de cette batterie. Le nombre de points par tour, fixé sur la gauche de l'écran, purement numérique et l'ennemi nous aurons un cactus diabolique, pour commencer ça le fera.
Nous avons décidé des objets et dessinons-les, immédiatement tous les sprites et notons-les.









Nous avons des sprites de travail et nous pouvons déjà imaginer à quoi cela ressemblera à l'écran, après la première leçon, nous les écrirons dans le système binaire, nous souviendrons où le zéro est vide et où se trouve l'unité, notre pixel brûle. Continuez:
"--------------------------------------------------------------------------" // : 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,}; "--------------------------------------------------------------------------"
Nous avons maintenant des sprites, et il est temps de tout revivre. Tout d'abord, réfléchissons aux fonctionnalités supplémentaires dont nous avons besoin. Sachant que l'arduino ne fonctionne pas parfaitement et dans des endroits même très capricieux, nous commençons à essayer de simplifier au maximum la vie de ce microcontrôleur. Ne surchargez pas et exigez en même temps un retour complet. Ainsi, nous introduisons de telles fonctions supplémentaires qui vivront leur propre vie et feront tout ce dont nous avons besoin:
- animation cardiaque
- animation de héros
- vérification des dégâts des héros
- mouvement du mal cactus
- accumulation de points (pour l'instant, chaque seconde +1, puis changez)
- mise à jour de l'écran (mais ce n'est pas précis, très probablement nous allons supprimer cette fonction et en ajouter une autre, je n'ai pas aimé le clignotement de l'écran, je veux de la stabilité). Par la suite, nous remplaçons cette fonction par la suppression de l'emplacement passé du héros, cela supprimera le scintillement réel de l'écran, et la mise à zéro du méchant sera à l'intérieur du script diabolique, je pense qu'il y aura un maximum d'une ou deux lignes.
- télécommande
- paramètres de boucle et de configuration
Nous voulons que nous ayons une animation du rythme cardiaque. En le ramenant dans une fonction distincte et en nous forçant à vivre nos propres vies, il nous sera plus facile de suivre le travail et à l'avenir, il sera plus facile de le modifier, car nous avons tout, enfin, ou presque tout en un seul endroit. Ce code pourrait être affiché dans loop () et commenté, mais j'ai l'habitude de le diviser en fonctions distinctes, vous ne recherchez pas le code dans toute la liste et vous savez qu'une fonction séparée contrôle les éléments individuels de notre jeu.
Maintenant, je vais écrire des morceaux de code, nous allons les connecter à la fin et obtenir un script à part entière, je vais maintenant vous expliquer l'essence et l'idée, puis nous assemblerons le puzzle et apprécierons le résultat.
Avant de commencer le code lui-même, je vais expliquer quelques points.
lcd.createChar // c'est une commande pour accéder à l'écran et utiliser l'une des cellules de mémoire pour enregistrer de nouveaux caractères. Le numéro de la cellule et, séparés par une virgule, le nom de la variable avec des informations, sont écrits entre parenthèses.
Nous contrôlerons le rendu via une variable numérique, en utilisant quatre chiffres, pour que l'animation soit correcte, si nous voulions faire battre le cœur ici et là, alors la variable bool ordinaire nous conviendrait. Mais mon idée est différente, un gros coup et deux courts, donc ça aura l'air plus intéressant.
"--------------------------------------------------------------------------" 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;} // , } } } "--------------------------------------------------------------------------"
Encore une fois, je veux attirer votre attention sur ce code:
lcd.createChar (x, y); affectation à la cellule mémoire «x» des données (0 ... 7) pour affichage sur l'écran «y»
Allez-y =)
Maintenant, nous avons un code qui crée l'effet d'un battement de coeur intéressant, il ne fait rien d'utile, seulement des démonstrations =)
De plus, sur la base de cela, nous créerons une animation de notre héros, il y a d'énormes avantages, plus nous approfondissons cet article, plus vous apprenez mon style de pensée, et pour moi, moins vous avez besoin d'expliquer et de vous concentrer davantage sur le code et de construire l'idée. Je vais essayer d'expliquer plus dans les commentaires du script pour écrire moins en dehors du script.
Commençons donc le personnage principal et créons une autre fonction pour cela:
"--------------------------------------------------------------------------" // (). =) , . 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(" "); // } "--------------------------------------------------------------------------"
Maintenant, le minuteur, euh, ou plutôt nos points qui seront attribués, écrivons simplement un minuteur et supposons que ce sont des points.
"--------------------------------------------------------------------------" void timer () // { if (currentMillis - DHTTimeRCheck >= DHTTimeR) // { DHTTimeRCheck = currentMillis; // Timer_z ++; // lcd.setCursor(0, 0); // lcd.print(Timer_z); // } } --------------------------------------------------------------------------"
C’est tout. Plus c'est loin, plus c'est facile.
Reste maintenant à travailler notre cactus.
Sa tâche est simple, d'apparaître, d'aller de droite à gauche et d'essayer de toucher le héros afin de lui causer des dégâts. Avec des dégâts, tout est plus facile, une touche - un coup. Jusqu'à présent, la complexité croissante, nous ne le ferons pas. Laissez le cactus se déplacer à une vitesse de 0,5f (complexité, ce sera déjà votre devoir =)) bien, ou en russe, une demi-seconde est une étape.
Voyons à quoi ressemblera ce morceau de code:
"--------------------------------------------------------------------------" 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; // - } } } } "--------------------------------------------------------------------------"
Cela reste un peu et après le test de chaque pièce, je peux déjà disposer le script complet assemblé, configuré et prêt pour le test sur vos appareils.
Alors maintenant, nous avons l'un des scripts les plus importants en ligne, c'est un script de vérification des dommages et l'inclusion d'un joueur en l'absence de vie. Il n'y a rien de surnaturel dans le script. Par conséquent, nous pouvons commencer à le démonter (au fait, si vous faites attention, vous remarquerez que lorsque nous avons créé le cœur, nous ne l'avons pas affiché à l'écran, et donc, maintenant vous verrez où je mets cette partie du code):
"--------------------------------------------------------------------------" 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); // } } "--------------------------------------------------------------------------"
Ce code est très simple, sa fonction principale est de vérifier et d'attendre que toutes les conditions soient remplies pour arrêter le jeu et nous dire que nous avons perdu.
Maintenant, la dernière fonction est la gestion. En fait, si nous analysons le code ci-dessus, cela nous semblera plus facile que simple. Dès la première leçon, nous avons sorti les codes de télécommande, je les ai tous écrits, ils ressemblent à ceci:
* 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
Touche _ code (attention!) (Les codes de télécommande peuvent varier)
Qui n'a pas lu, je vous conseille de lire la 1ère partie.
Quelque chose de similaire, vous l'aurez et vous pourrez facilement configurer tout ce dont vous avez besoin.
Nous allons maintenant créer l'algorithme le plus simple, basé sur ce que nous savons déjà et notre jeu prendra vie.
"--------------------------------------------------------------------------" 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(); // } "--------------------------------------------------------------------------"
Conclusion du code écrit ci-dessus:
le bouton 2 est un saut
le bouton 4 est un pas vers la gauche
le bouton 6 est un pas vers la droite
le bouton 0 réinitialise le jeu et le redémarre
Maintenant, il nous reste à configurer la configuration et la boucle, tout se termine déjà. Nous avons créé toutes les fonctions supplémentaires et il ne nous restait plus qu'à coller et ajouter toutes les bibliothèques. Je pense que nous allons examiner les variables et les principaux paramètres setup \ loop déjà dans le code général, alors commençons, puis vous devez ctrl + c & ctrl + v et c'est tout =) et un développement indépendant supplémentaire dans cette direction, si vous êtes tous bien sûr J'ai bien aimé.
"--------------------------------------------------------------------------" #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
. , , . 80% , , , , .

A5 1602 — SCL
A4 1602 — SDA
A0
arduino, 1602 ( , , ), , - ( 4 , ), , 2000 Rock n Roll Racing. =) arduino ( ), ~60 % 15% — 20%, … … , , , 10 , . , . - - , , . ? .
, , , .
, -!
PS: , . - .
->