So erstellen Sie einen Infinite Runner unter iOS: Cocos2D, Automatisierung und mehr

Veröffentlicht: 2022-03-11

Die Entwicklung von iOS-Spielen kann eine bereichernde Erfahrung in Bezug auf persönliches und finanzielles Wachstum sein. Anfang dieses Jahres habe ich ein Cocos2D-basiertes Spiel, Bee Race, im App Store bereitgestellt. Sein Gameplay ist einfach: ein endloser Läufer, in dem Spieler (in diesem Fall Bienen) Punkte sammeln und Hindernissen ausweichen. Sehen Sie hier für eine Demo.

In diesem Tutorial erkläre ich den Prozess hinter der Entwicklung von Spielen für iOS, von Cocos2D bis zur Veröffentlichung. Zur Orientierung hier ein kurzes Inhaltsverzeichnis:

  • Sprites und physische Objekte
  • Eine kurze Einführung in Cocos2D
  • Verwendung von Cocos2D mit Storyboards
  • Gameplay und (kurze) Projektbeschreibung
  • Jobs automatisieren. Verwenden Sie Werkzeuge. Sei cool.
  • In-App-Abrechnung
  • Multiplayer-Gameplay mit dem Game Center
  • Raum für Verbesserung
  • Fazit

Sprites und physische Objekte

Bevor wir uns mit den groben Details befassen, ist es hilfreich, den Unterschied zwischen Sprites und physischen Objekten zu verstehen.

Für jede gegebene Entität, die auf dem Bildschirm eines Endlos-Runner-Spiels erscheint, wird die grafische Darstellung dieser Entität als Sprite bezeichnet, während die polygonale Darstellung dieser Entität in der Physik-Engine als physisches Objekt bezeichnet wird.

Das Sprite wird also auf dem Bildschirm gezeichnet, unterstützt von seinem entsprechenden physischen Objekt, das dann von Ihrer Physik-Engine verarbeitet wird. Dieses Setup kann hier visualisiert werden, wo Sprites auf dem Bildschirm angezeigt werden, wobei ihre physischen polygonalen Gegenstücke grün umrandet sind:

In iOS-Infinite-Runner-Spielen koexistieren Sprites und physische Objekte.

Physische Objekte sind standardmäßig nicht mit ihren jeweiligen Sprites verbunden, was bedeutet, dass Sie als iOS-Entwickler auswählen können, welche Physik-Engine verwendet werden soll und wie Sprites und Körper verbunden werden. Die gebräuchlichste Methode besteht darin, das Standard-Sprite zu unterteilen und ihm einen konkreten physischen Körper hinzuzufügen.

In diesem Sinne …

Ein kurzes Tutorial zur Entwicklung von Cocos2D iOS-Spielen

Cocos2D-iphone ist ein Open-Source-Framework für iOS, das OpenGL für die Hardware-Grafikbeschleunigung verwendet und die Physik-Engines Chipmunk und Box2D unterstützt.

Erstens, warum brauchen wir einen solchen Rahmen? Nun, für den Anfang implementieren Frameworks die oft verwendeten Komponenten der Spieleentwicklung. Zum Beispiel kann Cocos2D Sprites laden (insbesondere Sprite-Sheets (warum?)), eine Physik-Engine starten oder stoppen und Timing und Animation richtig handhaben. Und das alles mit Code, der ausgiebig überprüft und getestet wurde – warum sollten Sie Ihre eigene Zeit damit verbringen, wahrscheinlich minderwertigen Code neu zu schreiben?

Am wichtigsten ist jedoch vielleicht, dass die Cocos2D-Spieleentwicklung Grafikhardwarebeschleunigung verwendet . Ohne eine solche Beschleunigung läuft jedes iOS-Infinite-Runner-Spiel mit sogar einer moderaten Anzahl von Sprites mit bemerkenswert schlechter Leistung. Wenn wir versuchen, eine kompliziertere Anwendung zu erstellen, werden wir wahrscheinlich einen „Bullet-Time“-Effekt auf dem Bildschirm sehen, dh mehrere Kopien jedes Sprites, wenn es versucht, es zu animieren.

Schließlich optimiert Cocos2D die Speichernutzung, da es Sprites zwischenspeichert. Daher benötigen alle duplizierten Sprites nur minimalen zusätzlichen Speicher, was für Spiele offensichtlich nützlich ist.

Verwendung von Cocos2D mit Storyboards

Nach all dem Lob, das ich Cocos2D überreicht habe, mag es unlogisch erscheinen, die Verwendung von Storyboards vorzuschlagen. Warum manipulieren Sie Ihre Objekte nicht einfach mit Cocos2D usw.? Nun, um ehrlich zu sein, für statische Fenster ist es oft bequemer, Xcodes Interface Builder und seinen Storyboard-Mechanismus zu verwenden.

Erstens erlaubt es mir, alle meine grafischen Elemente für mein Endlos-Runner-Spiel mit meiner Maus zu ziehen und zu positionieren. Zweitens ist die Storyboard-API sehr, sehr nützlich. (Und ja, ich kenne Cocos Builder).

Hier ist ein kurzer Blick auf mein Storyboard:

Beginnen Sie mit einem guten Storyboard, um zu lernen, wie man ein endlos laufendes Spiel erstellt.

Der Hauptansicht-Controller des Spiels enthält nur eine Cocos2D-Szene mit einigen HUD-Elementen darüber:

Der Start unseres Cocos2D-Tutorials ist beim View-Controller.

Achten Sie auf den weißen Hintergrund: Es handelt sich um eine Cocos2D-Szene, die alle notwendigen Grafikelemente zur Laufzeit lädt. Andere Ansichten (Live-Indikatoren, Löwenzahn, Schaltflächen usw.) sind alle Cocoa-Standardansichten, die dem Bildschirm mit Interface Builder hinzugefügt werden.

Ich werde nicht auf die Details eingehen – falls Sie interessiert sind, finden Sie Beispiele auf GitHub.

Gameplay und (kurze) Projektbeschreibung

(Zur weiteren Motivation möchte ich mein Endlosläufer-Spiel etwas detaillierter beschreiben. Sie können diesen Abschnitt gerne überspringen, wenn Sie mit der technischen Diskussion fortfahren möchten.)

Während des Live-Spiels ist die Biene bewegungslos, und das Feld selbst rauscht tatsächlich vorbei und bringt verschiedene Gefahren (Spinnen und giftige Blumen) und Vergünstigungen (Löwenzahn und seine Samen) mit sich.

Cocos2D hat ein Kameraobjekt, das entwickelt wurde, um dem Charakter zu folgen; In der Praxis war es weniger kompliziert, den CCLayer zu manipulieren, der die Spielwelt enthält.

Die Steuerung ist einfach: Durch Antippen des Bildschirms bewegt sich die Biene nach oben und ein weiteres Antippen bewegt sie nach unten.

Die Weltschicht selbst hat eigentlich zwei Unterschichten. Wenn das Spiel beginnt, wird die erste Unterschicht von 0 bis BUF_LEN gefüllt und anfangs angezeigt. Die zweite Teilschicht wird im Voraus von BUF_LEN bis 2*BUF_LEN gefüllt. Wenn die Biene BUF_LEN erreicht, wird die erste Unterschicht gereinigt und sofort von 2*BUF_LEN auf 3*BUF_LEN neu bevölkert, und die zweite Unterschicht wird präsentiert. Auf diese Weise wechseln wir zwischen Ebenen und behalten niemals veraltete Objekte bei, was ein wichtiger Teil der Vermeidung von Speicherlecks ist.

Mein Infinity-Runner-Spiel besteht aus einer vielschichtigen Welt.

In Bezug auf Physik-Engines habe ich Chipmunk aus zwei Gründen verwendet:

  1. Es ist in reinem Objective-C geschrieben.
  2. Ich habe vorher mit Box2D gearbeitet, also wollte ich die beiden vergleichen.

Die Physik-Engine wurde wirklich nur zur Kollisionserkennung verwendet. Manchmal werde ich gefragt: „Warum haben Sie keine eigene Kollisionserkennung geschrieben?“. In Wirklichkeit hat das nicht viel Sinn. Physik-Engines wurden genau für diesen Zweck entwickelt: Sie können Kollisionen zwischen Körpern mit komplizierten Formen erkennen und diesen Prozess optimieren. Beispielsweise teilen Physik-Engines die Welt oft in Zellen auf und führen Kollisionsprüfungen nur für Körper in derselben oder benachbarten Zellen durch.

Jobs automatisieren. Verwenden Sie Werkzeuge. Sei cool.

Eine Schlüsselkomponente bei der Entwicklung von Indie-Infinite-Runner-Spielen besteht darin, zu vermeiden, über kleine Probleme zu stolpern. Zeit ist eine entscheidende Ressource bei der Entwicklung einer App, und die Automatisierung kann unglaublich zeitsparend sein.

Aber manchmal kann Automatisierung auch ein Kompromiss zwischen Perfektionismus und Termintreue sein. In diesem Sinne kann Perfektionismus ein Killer für Angry Birds sein.

In einem anderen iOS-Spiel, das ich gerade entwickle, habe ich beispielsweise ein Framework erstellt, um Layouts mit einem speziellen Tool (verfügbar auf GitHub) zu erstellen. Dieses Framework hat seine Grenzen (z. B. hat es keine schönen Übergänge zwischen Szenen), aber wenn ich es verwende, kann ich meine Szenen in einem Zehntel der Zeit erstellen.

Obwohl Sie mit speziellen Supertools kein eigenes Superframework erstellen können, können und sollten Sie dennoch so viele dieser kleinen Aufgaben wie möglich automatisieren.

Perfektionismus kann ein Killer für Angry Birds sein. Zeit ist eine entscheidende Ressource bei der Entwicklung von iOS-Spielen.
Twittern

Beim Bau dieses unendlichen Läufers war die Automatisierung wieder einmal der Schlüssel. Zum Beispiel schickte mir mein Künstler hochauflösende Grafiken über einen speziellen Dropbox-Ordner. Um Zeit zu sparen, habe ich einige Skripte geschrieben, um automatisch Dateisätze für die verschiedenen vom App Store geforderten Zielauflösungen zu erstellen, wobei ich auch -hd oder @2x hinzufügte (diese Skripte basieren auf ImageMagick).

In Bezug auf zusätzliche Tools fand ich TexturePacker sehr nützlich – es kann Sprites in Sprite-Sheets packen, sodass Ihre App weniger Speicher verbraucht und schneller geladen wird, da alle Ihre Sprites aus einer einzigen Datei gelesen werden. Es kann auch Texturen in fast allen möglichen Framework-Formaten exportieren. (Beachten Sie, dass TexturePacker kein kostenloses Tool ist, aber ich denke, es ist den Preis wert. Sie können sich auch kostenlose Alternativen wie ShoeBox ansehen.)

Die Hauptschwierigkeit im Zusammenhang mit der Spielphysik besteht darin, geeignete Polygone für jedes Sprite zu erstellen. Mit anderen Worten, das Erstellen einer polygonalen Darstellung einer obskur geformten Biene oder Blume. Versuchen Sie nicht einmal, dies von Hand zu tun – verwenden Sie immer spezielle Anwendungen, von denen es viele gibt. Einige sind sogar ziemlich … exotisch – wie das Erstellen von Vektormasken mit Inkspace und das anschließende Importieren in das Spiel.

Für meine eigene Entwicklung von Endlos-Runner-Spielen habe ich ein Tool erstellt, um diesen Prozess zu automatisieren, das ich Andengine Vertex Helper nenne. Wie der Name schon sagt, wurde es ursprünglich für das Andengine-Framework entwickelt, obwohl es heutzutage mit einer Reihe von Formaten angemessen funktioniert.

In unserem Fall müssen wir das plist-Muster verwenden:

 <real>%.5f</real><real>%.5f</real>

Als nächstes erstellen wir eine Plist-Datei mit Objektbeschreibungen:

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>jet_ant</key> <dict> <key>vertices</key> <array> <real>-0.18262</real><real>0.08277</real> <real>-0.14786</real><real>-0.22326</real> <real>0.20242</real><real>-0.55282</real> <real>0.47047</real><real>0.41234</real> <real>0.03823</real><real>0.41234</real> </array> </dict> </dict> </plist>

Und ein Objektlader:

 - (void)createBodyAtLocation:(CGPoint)location{ float mass = 1.0; body = cpBodyNew(mass, cpMomentForBox(mass, self.sprite.contentSize.width*self.sprite.scale, self.sprite.contentSize.height*self.sprite.scale)); body->p = location; cpSpaceAddBody(space, body); NSString *path =[[NSBundle mainBundle] pathForResource:@"obj _descriptions" ofType:@"plist"]; // <- load plist NSDictionary *objConfigs = [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease]; NSArray *vertices = [[objConfigs objectForKey:namePrefix] objectForKey:@"vertices"]; shape = [ChipmunkUtil polyShapeWithVertArray:vertices withBody:body width:self.sprite.contentSize.width height:self.sprite.contentSize.height]; shape->e = 0.7; shape->u = 1.0; shape->collision_type = OBJ_COLLISION_TYPE; cpSpaceAddShape(space, shape); }

Um zu testen, wie Sprites ihren physischen Körpern entsprechen, siehe hier.

Viel besser, oder?

Zusammenfassend: Immer automatisieren, wenn möglich. Selbst einfache Skripte können Ihnen viel Zeit sparen. Und was noch wichtiger ist, diese Zeit kann zum Programmieren verwendet werden, anstatt mit der Maus zu klicken. (Zur zusätzlichen Motivation ist hier ein Token XKCD.)

In-App-Abrechnung

Gesammelte Blowballs im Spiel fungieren als In-App-Währung, mit der Benutzer neue Skins für ihre Biene kaufen können. Diese Währung kann jedoch auch mit echtem Geld gekauft werden. Ein wichtiger Punkt, der in Bezug auf die In-App-Abrechnung zu beachten ist, ist, ob Sie serverseitige Überprüfungen der Gültigkeit des Kaufs durchführen müssen oder nicht. Da alle käuflichen Waren in Bezug auf das Gameplay im Wesentlichen gleich sind (nur das Aussehen der Biene ändern), ist es nicht erforderlich, eine Serverprüfung auf Kaufgültigkeit durchzuführen. In vielen Fällen müssen Sie dies jedoch unbedingt tun.

Für mehr hat Ray Wenderlich das perfekte In-App-Abrechnungs-Tutorial.

Multiplayer-Gameplay mit dem Game Center

Beim Mobile Gaming ist Socializing mehr als nur das Hinzufügen eines „Gefällt mir“-Buttons auf Facebook oder das Einrichten von Ranglisten. Um das Spiel spannender zu machen, habe ich eine Multiplayer-Version implementiert.

Wie funktioniert es? Zunächst werden zwei Spieler über das Echtzeit-Match-Making des iOS Game Center verbunden. Da die Spieler wirklich dasselbe Endlosläufer-Spiel spielen, muss es nur einen einzigen Satz von Spielobjekten geben. Das bedeutet, dass die Instanz eines Spielers die Objekte generieren muss und die des anderen Spielers sie auslesen wird. Mit anderen Worten, wenn die Geräte beider Spieler Spielobjekte generieren würden, wäre es schwierig, das Erlebnis zu synchronisieren.

In diesem Sinne senden sich beide Spieler nach dem Verbindungsaufbau gegenseitig eine Zufallszahl. Der Spieler mit der höheren Zahl fungiert als „Server“ und erstellt Spielobjekte.

Erinnern Sie sich an die Diskussion über die Generation der aufgeteilten Welt? Wo wir zwei Unterschichten hatten, eine von 0 bis BUF_LEN und die andere von BUF_LEN bis 2*BUF_LEN? Diese Architektur wurde nicht zufällig verwendet – sie war notwendig, um reibungslose Grafiken über verzögerte Netzwerke bereitzustellen. Wenn ein Teil der Objekte generiert wird, wird er in eine Plist gepackt und an den anderen Spieler gesendet. Der Puffer ist groß genug, um den zweiten Spieler auch bei einer Netzwerkverzögerung spielen zu lassen. Beide Spieler senden sich gegenseitig im Abstand von einer halben Sekunde ihre aktuelle Position, ebenso ihre Auf-Ab-Bewegungen sofort. Um das Erlebnis abzurunden, werden Position und Geschwindigkeit alle 0,5 Sekunden mit einer flüssigen Animation korrigiert, sodass es in der Praxis so aussieht, als würde sich der andere Spieler allmählich bewegen oder beschleunigen.

Es gibt sicherlich noch mehr Überlegungen in Bezug auf das endlose Mehrspieler-Gameplay, aber hoffentlich gibt Ihnen dies ein Gefühl für die Art der damit verbundenen Herausforderungen.

Raum für Verbesserung

Spiele sind nie fertig. Zugegeben, es gibt einige Bereiche, in denen ich mich verbessern möchte, nämlich:

  1. Kontrollprobleme: Antippen ist oft eine unintuitive Geste für Spieler, die lieber rutschen.
  2. Die Weltebene wird mithilfe der CCMoveBy-Aktion verschoben. Dies war in Ordnung, wenn die Geschwindigkeit der Weltebene konstant war, da die CCMoveBy-Aktion mit CCRepeatForever durchlaufen wurde:

     -(void) infiniteMove{ id actionBy = [CCMoveBy actionWithDuration: BUFFER_DURATION position: ccp(-BUFFER_LENGTH, 0)]; id actionCallFunc = [CCCallFunc actionWithTarget:self selector:@selector(requestFillingNextBuffer)]; id actionSequence = [CCSequence actions: actionBy, actionCallFunc, nil]; id repeateForever = [CCRepeatForever actionWithAction:actionSequence]; [self.bufferContainer runAction:repeateForever]; }

    Aber später fügte ich eine Erhöhung der Weltgeschwindigkeit hinzu, um das Spiel im Laufe der Zeit schwieriger zu machen:

     -(void) infiniteMoveWithAccel { float duration = BUFFER_DURATION-BUFFER_ACCEL*self.lastBufferNumber; duration = max(duration, MIN_BUFFER_DURATION); id actionBy = [CCMoveBy actionWithDuration: duration position: ccp(-BUFFER_LENGTH, 0)]; id restartMove = [CCCallFunc actionWithTarget:self selector:@selector(infiniteMoveWithAccel)]; id fillBuffer = [CCCallFunc actionWithTarget:self selector:@selector(requestFillingNextBuffer)]; id actionSequence = [CCSequence actions: actionBy, restartMove, fillBuffer, nil]; [self.bufferContainer runAction:actionSequence]; }

    Diese Änderung führte dazu, dass die Animation bei jedem Neustart der Aktion zerfetzte. Ich habe versucht, das Problem zu beheben, ohne Erfolg. Meine Beta-Tester haben das Verhalten jedoch nicht bemerkt, also habe ich die Fehlerbehebung verschoben.

  3. Einerseits musste ich keine eigene Autorisierung für Multiplayer schreiben, wenn ich das Game Center verwende oder einen eigenen Gameserver betreibe. Andererseits ist es unmöglich geworden, Bots zu erstellen, was ich vielleicht gerne ändern würde.

Fazit

Das Erstellen Ihres eigenen Indie-Infinite-Runner-Spiels kann eine großartige Erfahrung sein. Und sobald Sie den Veröffentlichungsschritt des Prozesses erreicht haben, kann es ein wunderbares Gefühl sein, wenn Sie Ihre eigene Kreation in die Wildnis entlassen.

Der Überprüfungsprozess kann mehrere Tage bis mehrere Wochen dauern. Für mehr gibt es hier eine hilfreiche Seite, die Crowd-Sourcing-Daten verwendet, um aktuelle Überprüfungszeiten zu schätzen.

Darüber hinaus empfehle ich die Verwendung von AppAnnie, um verschiedene Informationen zu allen Anwendungen im App Store zu untersuchen, und die Registrierung bei einigen Analysediensten wie Flurry Analytics kann ebenfalls hilfreich sein.

Und wenn dieses Spiel Sie fasziniert hat, schauen Sie sich unbedingt Bee Race im Store an.