So entwickeln Sie mit Unity einen weiteren Plattformer. Ein weiteres Tutorial, Teil 2

In der Fortsetzung des ersten Artikels ( hier ) entwickle ich weiterhin einen Plattformer, der auf dem Artikel „Level Design Patterns for 2D Games“ basiert.

Nach der Veröffentlichung des ersten Artikels wurde eindeutig entschieden, dass die darin beschriebene Tastensteuerung völlig unpraktisch war. Daher wurden die Steuerelemente im Spiel auf dem Joystick überarbeitet. Außerdem hat das Spiel auf dem Spielmarkt leider keine Moderation bestanden. Letzten Freitag erhielt ich eine Benachrichtigung, dass das Projekt aufgrund der Sammlung von Metadaten abgelehnt wurde. Übrigens wurde mein erster Plattformer "Knight Kadavar" auch zum ersten Mal abgelehnt, weil er angeblich um Erlaubnis gebeten hatte, Anrufe zu verwalten und SMS anzuzeigen (was für seinen Bot eine völlige Dummheit war. Für das Spiel waren keine Berechtigungen erforderlich). Google forderte dann von mir eine schriftliche Mitteilung darüber, warum ich es brauche. Aber alles endete mit der Tatsache, dass ich einige Fehler behoben habe, die mir aufgefallen sind, und das Spiel zur erneuten Moderation geschickt habe. Sie wurde erfolgreich zum Spielmarkt hinzugefügt. Jetzt habe ich vor, genau das Gleiche mit diesem Spiel zu tun.

Sobald die zweite Szene erstellt wurde, wurde das Muster automatisch geschlossen

Szene


Ein Fragment eines Levels / einer Welt, das auf einem Konzept basiert, ist normalerweise eine Überwindung der Schwierigkeit.

Bonus


Sammlerstück, das sich positiv auf die Spieler auswirkt

Wir realisieren zwei Arten von Boni für Lucas:

  • Erste-Hilfe-Kasten, der fallen wird, wenn Sie Monster zerstören
  • Truhen mit Schwertern, die Lucas auf Feinde werfen kann

Um einen Bonus mit einem Erste-Hilfe-Kasten zu implementieren, müssen Sie die Fertighäuser mit Monstern modifizieren. Geben Sie genauer an, an welcher Stelle Boni angezeigt werden.



Ändern Sie dann das Skript Enemy.cs:

Spoiler Überschrift
/* ,        */ [SerializeField] private GameObject bonusPref; //   [SerializeField] private Transform instBonus; //     [SerializeField] private int isBonus; //    ,     /*   */ public void ifDie() { if (Damage(0) <= 0) { isBonus = Random.Range(0,3); if (isBonus == 0) { Instantiate(bonusPref, instBonus.position, instBonus.rotation); } Destroy(this.gameObject); } } 


Wir rufen die Funktion mit dem zurückgegebenen Typ Damage (0) auf und prüfen, ob Health 0 zurückgibt. Wenn ja, rufen wir den Zufallszahlengenerator auf. Wenn der Generator durch Auswahl der Zahl 0 stoppt, werfen wir dem Spieler einen Bonus und zerstören das Monster.

Als nächstes beschreiben wir, was Sie mit diesem Bonus machen können. Erstellen Sie dazu das Fertighaus mit den Komponenten SpriteRenderer, BoxCollider2D und Rigidbody2D. Erstellen Sie außerdem ein Skript, das dafür verantwortlich ist, was zu tun ist, wenn der Apfel mit dem Player kollidiert:

Spoiler Überschrift
 public void OnTriggerEnter2D(Collider2D collision) { switch (collision.gameObject.tag) { case "Player": { HeroScript.Health = 100; Destroy(this.gameObject); } break; } } 


Vorschau-Video anzeigen .

Als nächstes erkennen wir den Bonus des Verlustes von Schwertern. Es kann nach dem gleichen Prinzip wie im ersten Teil implementiert werden, Protokollverlust wurde implementiert. Der interessante Teil wird sein, dass wenn Lucas die Schwerter aufhebt, sie nur in das Sichtfeld des Feindes geworfen werden müssen und nicht, wenn Lucas die Protokolle sammelt. In der Form, in der die Schaltfläche Attack \ item collection jetzt implementiert ist, würde dies genau das tun. Schwerter wurden in jeder Situation weggeworfen. Dazu ändern wir den Code des Angriffs- / Sammlungsskripts:

Spoiler Überschrift
  /*      */ [SerializeField] private GameObject swordPref; //    [SerializeField] private Transform instSword; //     [SerializeField] private float swordSpeed; //    private float attackInBoxX, attackInBoxY; //    /*       */ // ED  EnemyDamage Collider2D[] ED = Physics2D.OverlapBoxAll(Hero.position, new Vector2(attackInBoxX, attackInBoxY), 12, lEnemy); { if (ED.Length > 0) { if (InventoryOnHero.swordCount == 0) { Debug.Log(" "); } if (InventoryOnHero.swordCount > 0) { instantiateSword(); InventoryOnHero.swordCount = InventoryOnHero.swordCount - 1; } else { for (int i = 0; i < ED.Length; i++) { ED[i].GetComponent<Enemy>().Damage(1); } } } } 


Was bedeuten diese Codezeilen? Zuerst definieren wir eine Reihe von Collidern und überprüfen alles, was in unseren Würfel gefallen ist:

 Collider2D[] ED = Physics2D.OverlapBoxAll(Hero.position, new Vector2(attackInBoxX, attackInBoxY), lEnemy); 

Achten Sie auf die übergebenen Parameter, sie unterscheiden sich stark von denen, die für OvelapCircleAll verwendet werden. Schlüsselparameter -

 Vector2(attackInBoxX, attackInBoxY) 

Dann ist die Bedingung erfüllt, wenn das Collider-Array größer als 0 ist, überprüfen wir das Inventar auf Schwerter. Wenn die Anzahl der Schwerter 0 ist, tun wir nichts und führen die Methode aus
 ED[i].GetComponent<Enemy>().Damage(1); 
als wäre es ein regelmäßiger Treffer. Wenn größer als 0, lassen Sie das Schwert los und reduzieren Sie die Anzahl der Schwerter um 1.

Als nächstes die Implementierung der Methode instantiateSword ();

Spoiler Überschrift
  private void instantiateSword() { GameObject newArrow = Instantiate(swordPref) as GameObject; newArrow.transform.position = instSword.transform.position; Rigidbody2D rb = newArrow.GetComponent<Rigidbody2D>(); if (GameObject.Find("Hero").GetComponent<HeroScript>().localScale.x > 0) { rb.velocity = new Vector3(swordSpeed, 0, 0); } else { rb.velocity = new Vector3(-swordSpeed, 0, 0); newArrow.transform.Rotate(0,0,-180); } } 


Wenn Sie den vorherigen Artikel gut gelesen haben, haben Sie möglicherweise bemerkt, dass dieser Code einem Codeabschnitt ähnelt, der für das Schießen einer Sonnenblume verantwortlich ist. Diesem Codeabschnitt wurden Zeilen hinzugefügt, die für die Bestimmung des Maßstabs von Lucas verantwortlich sind. Das heißt, er schaut nach links oder rechts:

 (GameObject.Find("Hero").GetComponent<HeroScript>().localScale.x > 0) 

Wenn Lucas nach links schaut, dann

 rb.velocity = new Vector3(-swordSpeed, 0, 0); newArrow.transform.Rotate(0,0,-180); 

Das Schwert fliegt nach links und dreht es ebenfalls um 180 Grad.

Vorschau-Video anzeigen .

Durch Ausführen dieser Aktion haben wir automatisch ein weiteres 1-Muster geschlossen:

Objekt


Jede Entität, die in der Spielszene erscheint und ihren Status ändern kann. Objekte sind Gefahren, Feinde, Boni usw.

Obwohl dieses Muster höchstwahrscheinlich früher implementiert wurde, als das erste Monster programmiert wurde.

Infolgedessen sind derzeit 3 ​​Muster nicht implementiert:

  • Nicht erreichbarer Bereich
  • Die Mechanik
  • Der Chef

Die Mechanik im Moment ist für mich von großem Interesse. Weil ich mir nicht sagen kann, dass ich genau verstehe, was verschiedene Leute in diese Definition einfließen lassen.

Weiter ein unerreichbarer Bereich . In dieser Ausgabe werde ich mich einige Zeit mit Level-Design-Problemen befassen. Erstens, weil ich die dritte Ebene dunkel machen möchte. Höchstwahrscheinlich eine Höhle oder ein Verlies. Mit der Fähigkeit, Lichteffekte zu realisieren.

Boss ! Es wird auch eine Kirsche auf dem Kuchen bleiben. Ich möchte es so unabhängig wie möglich machen und mein Aussehen ändern können.

Der erste Teil des Artikels
Alle Spielobjekte wurden von https://opengameart.org/ übernommen , nämlich:



Fühlen Sie sich frei und schreiben Sie Kommentare zu Habré oder zu mir unter worldofonehero@gmail.com.

Danke fürs Lesen, viel Glück.

Source: https://habr.com/ru/post/de460561/


All Articles