Erfahrung in der Entwicklung von Arcades für Android in C ++ und Qt


    Der Raum wird sich nicht selbst aufzwingen

    Hintergrund


    Wie viele Programmierer habe ich diesen Beruf gewählt, weil ich in meiner Kindheit Computerspiele gespielt und davon geträumt habe, sie zu entwickeln. Sobald ich gelernt hatte, mehr oder weniger Code zu schreiben, der ohne Syntaxfehler kompiliert werden konnte, begann ich natürlich, alle möglichen dummen Spiele zu machen, die ich all meinen Freunden und Bekannten zeigte. Aber die Zeit verging und es zwang uns, völlig andere Dinge zu tun, um an Projekten zu arbeiten, die, gelinde gesagt, ernster sind als Spiele. Und so ging es in den letzten Jahren weiter. Aber die ursprünglichen Wünsche verschwanden nicht, nur die Freizeit verschwand.

    Ich wollte schon lange eine Art Projekt für Android erstellen, und wie Sie wissen, wird der Großteil der Projekte auf dem Android SDK und Java entwickelt, und es wird empfohlen, NDK nur an „geschwindigkeitskritischen“ Orten zu verwenden und nicht alles vollständig zu erledigen.

    Aber wer braucht all diese Empfehlungen und Regeln, wenn es Qt gibt? Ich kenne Java nicht in dem Maße, wie es meiner Meinung nach für eine qualitativ hochwertige Entwicklung des Spiels ausreicht, und ich wollte es nicht lernen, aber ich habe C ++ - Kenntnisse. Nach mehreren Testprojekten auf Qt für Android wurde mir klar, dass es durchaus möglich ist, eine vollständige Anwendung darauf zu entwickeln und sie sogar auf andere Plattformen zu übertragen. Nachdem ich mir das Video Shia LaBeouf - Just Do it angesehen hatte, wurde mir klar, dass ich dazu verdammt war.

    Ich möchte über die Erfahrungen bei der Entwicklung eines Spiels für Android auf Qt 5.5.1 und C ++ sprechen.


    Idee


    Seltsamerweise kam die Idee des Spiels ziemlich schnell und auf sehr ungewöhnliche Weise. Wir haben mit den Sensoren des Telefons experimentiert, um ein Spielzeug als „Schnatz“ (temporärer Name) zu definieren, dessen Bedeutung lautete: Je öfter Sie auf das Telefon schlagen, desto mehr Punkte erhalten Sie. Dazu musste der Schlag vom Schlag unterschieden werden, und es gelang uns glücklicherweise nicht, aber als wir die Grafiken auf dem Bildschirm zeigten, wurden interessante Bilder gezeichnet, die uns zu der Idee des Spiels veranlassten, auf die noch eingegangen werden soll.

    Plötzlich wollte ich ein Spiel über etwas machen, das in eine Höhle fällt und dessen Konturen sich mit der Zeit ändern. Es sollte ursprünglich ein zweidimensionales Spiel mit Grafiken in einem gezeichneten Stil machen. In Zukunft floss alles in ein dreidimensionales Spiel mit einer Draufsicht. Es wurde ein Höhlengenerator geschrieben, mit dem Sie Ebenen mit Konturen erstellen können. Wie berechnet man Kollisionen mit den Wänden der Höhle und wie wandelt man sie in ein dreidimensionales Modell um? Es war lange Zeit möglich, unglaublich coole Dinge zu denken und zu erfinden, aber ich machte einen Umweg und machte die Voxel-Geometrie der Welt. Die Berechnung von Kollisionen und die Anzeige auf dem Bildschirm sind viel einfacher geworden, jedoch auf Kosten der Tatsache, dass das Spiel Minecraft ähnlich geworden ist. Ich war nicht überrascht und brachte sie dazu, ihm noch ähnlicher zu werden, indem ich ein Charaktermodel von ihm hinzufügte. So wurde das Aussehen und Konzept des Spiels gebildet.


    Die erste Version des Höhlengenerators (Archivfoto)

    Mit der Entwicklung des Spiels habe ich mir nicht das Ziel gesetzt, wie viele andere auch Geld damit zu verdienen, sondern wollte einfach mein Projekt starten und es zum Ende bringen. Daher sollte das Spiel kostenlos sein (wer kauft es bei mir?), Aber immer noch mit einer minimalen Menge an Werbung.

    Grafik


    Mittel

    In Qt können Sie OpenGL ES 2.0 für 3D-Grafiken verwenden. Die folgenden Klassen können uns dabei helfen:
    • QGLWidget ist eine veraltete Klasse, ein Nachkomme von QWidget. Wird vor Qt 5.0 verwendet
    • QOpenGLWidget - eine neue Klasse, die die gleichen Funktionen wie QGLWidget ausführt, jedoch bei der Implementierung einen Zwischenframebuffer verwendet
    • QOpenGLWindow - Entwickelt für die Anzeige von OpenGL-Grafiken. Es ist kein Widget und ruft kein Abhängigkeits-Widget-Modul ab


    Beim Experimentieren mit diesen Widgets habe ich mehrere Schlussfolgerungen gezogen:
    • QGLWidget ist auf schwachen Smartphones viel schneller als QOpenGLWidget
    • QOpenGLWidget ändert die Größe des internen Framebuffers nicht, wenn die Größe des Fensters geändert wird. Es handelt sich wahrscheinlich um einen Fehler oder eine Funktion, oder ich bin nur ein Idiot. Bei Verwendung dieses Widgets stimmte die Fensterauflösung jedoch nicht mit der Größe des Ansichtsfensters überein, was entweder zu einem gestreckten Bild oder einem gereisten Bild führte Projektionsmatrix. Trotzdem war die Leistung mit diesem Widget extrem gering
    • QOpenGLWindow ist der am besten geeignete Kandidat. Es kann nicht als Ansichtsfenster für eine Grafikszene verwendet werden und Sie können keine untergeordneten Widgets hinzufügen, sodass es unmöglich ist, eine Benutzeroberfläche mit Qt zu erstellen. Aber er ist der produktivste von allen dreien


    Um das Spiel zu implementieren, entschied ich mich für QOpenGLWindow und musste die Benutzeroberfläche selbst wechseln.

    Eine Rahmenaktualisierung wurde unter Verwendung des Signals frameSwapped () implementiert, das nach swapBuffers generiert wird. Mit diesem Signal können Sie einen ruhigeren Bildwechsel als mit Timern erzielen.

    Um die Animation zu berechnen, musste ich die Bildzeit berechnen. Zu diesem Zweck habe ich zuerst QTime verwendet , was eine schlechte Idee war, da diese Klasse eine ungleichmäßige Zeit berücksichtigt. Auf dem mobilen Gerät treten häufig Zeitanpassungen auf, die dazu führen, dass je nach Abweichung der Uhr vom Gerät in die Vergangenheit oder in die Zukunft gewechselt wird. Außerdem ist die Berechtigung zum Ändern dieser Klasse auf Millisekunden beschränkt, was für eine reibungslose Animation mit instabilen FPS nicht ausreicht.

    Nachdem ich überlegt und auf die Dokumentation verwiesen hatte , entschied ich mich für die QElapsedTimer- Klasse , die versucht, monotone Zeit zu verwenden und eine Auflösung von bis zu Nanosekunden hat.

    Texturen und Interface

    Für die ersten Versionen und das Debuggen wurden die Texturen vorübergehend von Minecraft ausgeliehen, ebenso wie einige Charaktere. Die erste Version der Benutzeroberfläche war ein grauer rechteckiger Knopf und wurde am Abend erstellt, und die Verarbeitung dauerte einen ganzen Monat.

    Der erste Screenshot des Spiels


    Mein Freund wurde als Designer ausgewählt. Die Vorteile dieser Wahl sind, dass Sie diesem Designer vertrauen können, und die Nachteile sind, dass er kein Designer ist - er ist ein Automechaniker.

    In Zukunft haben wir die ursprünglichen Texturen für mehrere Ebenen gezeichnet und die Texturen der Zeichen erstellt.
    Das Zeichnen einer „schönen“ Oberfläche und von Zeichen erwies sich als ziemlich langwierig. Während der Designer versuchte, einen neuen Buchstaben oder Knopf aus mir herauszupressen, hatte ich keine andere Wahl, als den Code weiter zu optimieren.

    Screenshot aus der vorletzten Version


    Die Level-Textur ist ein großer Atlas aller Blöcke und bietet Platz für 32 Würfel mit einer Seite von 16 Pixeln. Bei diesem Ansatz müssen Sie beim Zeichnen von Ebenen nicht ständig die aktuelle Textur neu installieren, sondern können die gesamte Ebene mithilfe von Scheitelpunktpuffern in mehreren Aufrufen zeichnen.

    Das Problem trat in den extremen Pixeln von Blöcken auf, die an andere Blöcke angrenzen. Beim Runden der Texturkoordinaten traten Artefakte in Form von Streifen an den Kanten der Blöcke auf. Ich habe dieses Problem gelöst, indem ich zu jedem Block einen Rand von einem Pixel Breite hinzugefügt habe, der das Pixel der Kante des Blocks dupliziert. So ein eigenartiges CLAMP_TO_EDGE.

    Leider konnte ich mit diesem Ansatz kein mipmap für das Level verwenden, weil Die Texturkoordinaten im Scheitelpunktpuffer müssen diesen Versatz um ein Pixel berücksichtigen. Wenn Sie eine Textur mit reduziertem Detail erstellen, wird dieser Versatz kleiner und ich müsste je nach Detailgrad eine andere Ebenengeometrie verwenden. Ich habe beschlossen, mich nicht damit zu beschäftigen, weil Die Textur selbst ist nur 256x256 Pixel groß, und die bilineare Filterung würde nicht viel Leistungsgewinn bringen, sondern nur zusätzliche Schwierigkeiten bei der Implementierung mit sich bringen.

    Ich wollte auch beachten, dass ich in den Level-Eigenschaften, obwohl es nur 32 Blöcke gibt, die Möglichkeit festgelegt habe, Blöcke um 90, 180 und 270 Grad gedreht anzuordnen, sowie die Animation des Wechsels zwischen den Blocktexturen, wodurch die visuelle Komponente des Spiels variiert werden konnte. Ich habe die Animation jedoch nur auf einer der Ebenen angewendet, um den Effekt der Drehung der Lüfter zu erzielen.

    Shader

    Qt bietet praktische Klassen für die Arbeit mit Shadern. Ich habe QOpenGLShaderProgram verwendet . Mit dieser Klasse können Sie Vertex- und Fragment-Shader hinzufügen, kompilieren, verknüpfen, uniformieren und attrubutieren. Die Klasse selbst ist nur ein Wrapper für viele OpenGL-Aufrufe und dementsprechend kein vollwertiges Objekt, da die Klasse mithilfe von GL-Aufrufen direkt zwischen Aufrufen dieser Klasse getrennt werden kann.

    Zweckmäßigerweise fügt die Klasse define automatisch so hinzu, dass der ES-Shader sowohl auf dem Desktop als auch auf dem mobilen Gerät normal kompiliert wird. Dies gilt vor allem für Präzisionsspezifizierer, die auf dem Desktop zu nichts werden.

    Ich musste separate Shader für die Spielwelt schreiben, einschließlich der Beleuchtung und Animation einiger Blöcke, eines Charaktershaders und von Interface-Shadern.

    Interface Shader enthalten
    • einfacher Textur-Shader
    • Shader Bar HP \ Schild
    • Kreisshader

    In der ersten Version habe ich einen Fortschrittsbalken mit einer Reihe von Rechtecken implementiert, die den Indikatorkolben und den Indikator selbst bilden und in der Birne versteckt sind. Als ich jedoch das Layout der neuen Leiste sah, musste ich diese Methode ablehnen.


    Bar xn \ shield

    Ich habe mich dazu entschlossen, diese Bar mit einem Shader zu implementieren. Anfangs schien es mir eine sehr seltsame Idee zu sein, aber am Ende akzeptierte ich sie als unvermeidlich und implementierte sie auf diese Weise:
    Shader-Code
    #ifdef GL_ES
    precision highp int;
    #endif
    varying highp vec4 v_position;
    varying highp vec2 v_dim;
    uniform lowp vec4 u_color;
    uniform highp float u_tg;
    uniform highp float u_value_a;
    uniform highp float u_value_b;
    uniform highp int u_step;
    uniform lowp vec3 u_pallete[3];
    void main()
    {
        int hstep = u_step/2;
        int w = int(v_dim.x);
        int h = int(v_dim.y);
        int wd = u_step*3;
        int pos_bl = int(v_position.x - u_tg*v_position.y + v_dim.y);
        int pos_br = int(v_position.x + u_tg*v_position.y);
        int pos_l = (pos_bl - wd*(pos_bl/wd))/u_step;
        lowp float b0 =   float(pos_l == 0) * float(pos_bl <= int(u_value_a*v_dim.x));
        lowp float b1 =   float(pos_l == 1) * float(pos_bl >= int((1.0-u_value_b)*v_dim.x));
        lowp float b2  =  clamp(float(pos_l == 2) + 1.0-(b0+b1), 0.0, 1.0);
        highp float p = abs(2.0*(v_position.w - 0.5));
        highp float out_p = (1.0 - 0.25*p);
        lowp float i = float(int(v_position.y) > hstep) * float(int(v_position.y) < h - hstep);
        lowp float o = (1.0-i)*float(pos_br >= h) * float(pos_bl <=w);
        lowp float a = i*float(pos_br >= h+u_step)  * float(pos_bl <=w - u_step);
        lowp float b = i*float(pos_br < h+u_step)   * float(pos_br >= h);
        lowp float c = i*float(pos_bl > w - u_step) * float(pos_bl <= w);
        highp float pr = (1.0 - p)*a;
        gl_FragColor = vec4(  u_pallete[0]*pr*b0
                            + u_pallete[1]*pr*b1
                            + u_pallete[2]*pr*b2
                            + u_pallete[0]*out_p * b
                            + u_pallete[1]*out_p * c
                            + mix(u_pallete[0], u_pallete[1], v_position.z)*out_p*o,
                            clamp(a+b+c+o, 0.0, 1.0)*u_color.a);
    }
    


    Ich möchte auch über die Vielfalt der Android-Geräte und deren Grafikbeschleuniger sprechen. Ich bin auf Probleme gestoßen:
    • Der Shader-Code wird auf einem Gerät problemlos kompiliert, und auf einem anderen Gerät treten Fehler auf
    • Der Shader wird normal kompiliert, funktioniert jedoch auf einigen Geräten nicht richtig. Wenn beispielsweise in PowerVR die lokale Variable als Uniform oder Attribut bezeichnet wird, führt dies nicht zu Fehlern, aber der Shader selbst funktioniert nicht mehr ordnungsgemäß
    • Bei einigen Geräten treten Fehler auf, wenn die Variable oder Funktion genauso wie die integrierte Funktion aufgerufen wird. Zum Beispiel die variable Mischung oder Klammer
    • Bei einigen Geräten gab es Probleme mit der Genauigkeit des Schwimmers


    Das Ergebnis all dessen: Wenn Sie vorhaben, Shader in einem Handyspiel zu verwenden, testen Sie sie mit den gängigsten Modellen von Grafikbeschleunigern. Wenn der Shader auf Ihrem Computer kompiliert und ausgeführt wird, bedeutet dies nicht, dass er auf dem Telefon Ihres Nachbarn ausgeführt wird. Die neue Vulkan-API sollte das Problem mit verschiedenen Shader-Compilern lösen und Ordnung in diese verrückte Welt bringen, aber das ist das Geschäft der Zukunft, und heute haben wir das, was wir haben.

    Klingt


    Suche

    Sounds sind in der Regel ein anderes Lied. Sie können sie selbst aufnehmen, was ziemlich mühsam ist und ein normales Mikrofon und Hören erfordert (nicht unser Fall). Und die gewünschten Sounds finden Sie im Internet.
    Es ist wünschenswert, mit einer Creative Commons 0-Lizenz nach Sounds zu suchen, um nicht die Urheberschaft für jeden Sound anzugeben, von denen es mehrere Dutzend geben kann. Es mag so aussehen, als ob es ziemlich schwierig ist, einen normalen freien Sound zu finden, und das ist es auch. Das Problem ist nicht, dass es nur wenige gibt, im Gegenteil, es gibt viele von ihnen, von denen die meisten schrecklich sind. Die Klangsuche ist ein Vorgang, bei dem Sie viele Klänge anhören und die am besten geeigneten auswählen müssen.

    Mittel

    In Qt gibt es die Klassen QSound , QSoundEffect , QAudioOutput und QMediaPlayer für die Ausgabe von Sounds . In den ersten Versionen verwendete ich QSoundEffect zur Ausgabe von Effekten und QMediaPlayer zur Ausgabe von Sounds. Aber wie sich herausstellte, passen sie alle nicht zusammen.

    Nur QMediaPlayer kann mit komprimierten Audiodateien arbeiten, aber diese Klasse, genauer gesagt, ihre Implementierung unter Android, hat einige unangenehme Momente.
    • Friese zu Beginn des Tons. Wenn die Musik wiederholt in einer Schleife abgespielt wird, tritt in der gesamten Anwendung eine spürbare Verzögerung auf.
    • Beim Lesen einer Mediendatei aus Ressourcen wird eine temporäre Datei im Anwendungsdatenordner erstellt und nicht immer nacheinander gelöscht, was zu einer Vergrößerung der Anwendung führt. Es wurde zufällig entdeckt und nun, zu dieser Zeit.

    QSound und QSoundEffect können nur mit nicht komprimierten WAV-Dateien arbeiten. QSoundEffect ist für die verzögerungsfreie Ausgabe von Sounds ausgelegt und kann Sounds selbst schleifen. Bei Verwendung unter Android wird jedoch häufig die Meldung AUDIO_OUTPUT_FLAG_FAST vom Client verweigert in den Protokollen angezeigt. Dies bedeutet, dass das Audiodateiformat nicht ohne Verzögerungen vom Medienserver ausgegeben werden kann. Dies liegt an einer falschen Abtastrate, die auf verschiedenen Geräten unterschiedlich ist. Einige Geräte verschlucken 44 kHz, andere benötigen 48 kHz, und das Objekt selbst überträgt den Ton so, wie er in der WAV-Datei aufgezeichnet ist. Die Größe der Soundressourcen machte einen erheblichen Prozentsatz der Größe der Anwendung aus.

    All diese Mängel führten dazu, dass nach dem Hinzufügen von Sounds zum Spiel beim Abspielen von Sounds und Musik ein spürbares FPS-Absinken auftrat.

    Die Lösung bestand darin, diese Klassen aufzugeben und die SFML- Bibliothek für Sounds zu verwenden . Sehr einfache und leichte Bibliothek ähnlich zu SDL. Praktische Kurse für die Arbeit mit Grafiken, Sound und Eingabegeräten. Diese Bibliothek kann nicht mit MP3 arbeiten (Lizenz, alles), aber sie kann noch viel mehr. Ich habe das ogg-Format für Effekte und Musik verwendet.

    Tonausgabe

    Für die Verwendung in einer Anwendung, in der Sounds optional sind, sind native Qt-Klassen geeignet. Für die Spieleentwicklung - überhaupt nicht. Besser und einfacher zu SFML.

    In-App-Werbung


    Für die Werbung habe ich eine fertige AdMob-Implementierung für Qt - QtAdMob verwendet .

    Zuerst wurde nur ein kleines Banner zum Menü hinzugefügt, später wurde eine Zwischenbildschirmanzeige erstellt.
    Es ist interessant, dass die Inter-Screen-Anzeige, selbst wenn sie geladen ist, mit einiger Verzögerung angezeigt wird. Das heißt, die Benutzeroberfläche musste zum Zeitpunkt des Erscheinens der Anzeige blockiert und nach dem Schließen wiederhergestellt werden. Gleichzeitig erlaubte die Bibliothek nicht, die Momente zu erfassen, in denen die Anzeige gezeigt und geschlossen wurde. Ich habe diese Bibliotheksfunktionalität zu der Version für Android hinzugefügt. Die Version für ios wurde noch nicht angerührt, da die Funktion nicht überprüft werden kann.

    Analytik und Statistik


    Durch das Veröffentlichen der ersten Version auf dem Play Market erhoffte ich mir Statistiken in der Entwicklerkonsole. Wie sich herausstellte, ist die Statistik der aktiven Nutzer jedoch an Google Analytics gebunden und funktioniert erst, wenn Sie den Analyzer Tracker in der Anwendung aktivieren. Die verfügbaren Statistiken werden mit einer Verzögerung von mehr als einem Tag erstellt und nach pazifischer Zeit berechnet. Aufgrund dieses Sachverhalts können wir nicht nachvollziehen, wie sich Ihre Handlungen auf Downloads auswirken. Daher habe ich die Aktivitätsklasse von QtAdMob hinzugefügt, die von QtActivity durch Funktionen zur analytischen Initialisierung und zum Senden von Spielereignissen geerbt wird. Ich gebe keine Beispiele für den Code an, weil Alles ist schön in der Dokumentation beschrieben.

    In den Ereignissen machte ich das Drücken aller Tasten auf der Oberfläche, das Auftreten einiger Spielsituationen, das Öffnen und Entsperren von Charakteren mit Ebenen.

    Dank der Sammlung all dieser Statistiken kann ich am Laptop sitzen und in Echtzeit beobachten, wie in Brasilien jemand das Spiel startete, die erste Mission nicht beenden konnte, das Spiel verließ und wahrscheinlich das Spiel löschte.

    Laut Statistik sind wir jetzt auch Meister unseres Spiels.

    Über Google Play


    Die Entwicklerkonsole selbst ist ein recht praktisches Tool, die Funktionalität von Statistiken und Werbung ist jedoch an andere Konten gebunden.

    Um die Anwendung vollständig selbst entwickeln zu können, benötigen Sie mindestens ein AdWords-, AdSense-, AdMob- und Google Analytics-Konto. In diesem Fall wird eine Verbindung zwischen ihnen hergestellt. Alle diese Konten sind separate Google-Produkte und verfügen über verschiedene technische Unterstützung und Einstellungen. Beachten Sie auch, dass für ein AdMob-Konto ein AdWords- und ein AdSense-Konto erforderlich sind. Alle diese Konten können jedoch in einer einzigen Kopie mit dem Haupt-Google Mail-Konto verknüpft werden. Wie die Praxis gezeigt hat, kann dies jedoch von Anfang an zu Verwirrung führen, da Sie einen Dienst eröffnen und einen neuen Account in einem anderen erstellen können, einen im dritten und so weiter.

    Auf magische Weise konnte der technische Support-Mitarbeiter nicht erklären, was passiert ist. Er erstellte zwei AdWords-Konten und verknüpfte sie mit einer E-Mail, während er ein Konto mit der Entwicklerkonsole und das andere mit AdMob verknüpfte (ich wusste nichts davon).

    Ich habe 500r auf einen Account geworfen, um die Werbekampagne zu überprüfen. In dem Versuch, damit umzugehen und den technischen Support-Tipps zu folgen, habe ich eines der Konten auf die "linke" Mail übertragen und meinen Zugriff darauf gesperrt. All dies führte zunächst dazu, dass beide Konten in meiner E-Mail nicht mehr funktionsfähig waren, und nach mehrmaligem Trennen und Verbinden von mir selbst kehrte die Leistung zurück. Es stellte sich jedoch heraus, dass AdMob nicht mehr funktionierte. Da mir AdMob wichtiger war als diese 500r, musste ich diesen gesamten Vorgang erneut durchführen und nebenbei beten, dass ich nicht den Zugriff auf alles verlieren würde, um AdMob wieder zum Laufen zu bringen. Und natürlich blieben diese 500r auf einem nicht verbundenen Konto hängen.

    Also sei vorsichtig damit.

    Übersetzung


    Im Spiel

    Wir haben das Spielemenü in 2 Sprachen übersetzt - Russisch und Englisch. Die Wahl der Spielsprache erfolgt durch das Systemgebietsschema. Wenn das System russisch ist, dann sind die Spiele in Russisch, in allen anderen Fällen - in Englisch.

    Zum Übersetzen von Textinformationen in Qt gibt es einen integrierten Mechanismus, der von der Klasse ausgeführt wird
     QTranslator myTranslator;
     myTranslator.load(":/translations/neverfall_" + QLocale::system().name());
     a.installTranslator(&myTranslator);
    

    Alle zu übersetzenden Zeilen werden an die Funktion QObject :: tr () übergeben. Für Klassen, die keine QObject-Nachkommen sind, können Sie die Funktion QApplication :: translate verwenden und für Zeichenfolgen, die in Arrays deklariert sind, die Makros QT_TRANSLATE_NOOP, QT_TR_NOOP.

    Das ist aber nur die halbe Miete. Es ist notwendig, die Übersetzungen selbst zu erstellen, was von den Programmen lupdate und lrelease durchgeführt wird. Der erste sammelt Informationen aus dem Quellcode, der diese Funktionen und Makros enthält, und erstellt eine XML-Datei mit Informationen zur Übersetzung.
    Der zweite sammelt die qm-Binärdatei aus der XML-Datei, die direkt in QTranslator geladen wird .

    Wir haben so etwas wie Tags als übersetzbare Zeichenfolgen verwendet, die dann ins Englische und Russische übersetzt wurden. Beispielsweise bedeutet "#GameOverText" "Spiel vorbei". Es wurde so gemacht, dass es nicht notwendig war, den Quellcode zu ändern, etwas anderes zu schreiben und dann auch alle Übersetzungen zu ändern, weil für lupdate ist dies eine andere zeile.

    Auf dem Markt

    In Google Play haben wir den einfachsten Weg eingeschlagen: den Text auf Russisch geschrieben - in einen Google-Übersetzer geworfen - ins Englische übersetzt, korrigiert. Und dann wurde der englische Text von demselben Google-Übersetzer in die gängigsten Sprachen übersetzt. Es ist komisch, dass eine der Optionen für die Beschreibung den Satz „Tauchen Sie mit Ihrem Kopf in den Kerker“ enthielt, der nach all diesen Übersetzungen auf Chinesisch „Springen in eine Höhle auf Ihrem Kopf“ bedeutete. Also sind wir gegangen, denn da sie uns bei AliExperse Perlen geben, werden wir nicht zurückgelassen.

    Fazit und Pläne


    Ergebnis Video


    Abschließend möchte ich sagen, dass der Entwicklungsprozess dieses Spiels eine der interessantesten Aktivitäten war und ist, es hat uns große Freude und Erfahrung gebracht, die ich bescheiden in diesem Artikel teile. Die Entwicklung wurde seit August dieses Jahres in der Freizeit, nach der Arbeit und in der Nacht durchgeführt. Das Geld wurde nur für das Konto des Entwicklers und ein paar Tausend für Werbung ausgegeben. Ich bin also nicht verärgert, wenn dieses Spiel uns ein bisschen weniger bringt als nichts.

    Zukünftige Pläne hängen davon ab, wie die Menschen auf unsere Schöpfung reagieren. Nach den Bewertungen zu urteilen, ist das ziemlich gut, aber nach den Downloads und Löschungen möchte ich hinter das Seil zum nächsten Haushaltswarengeschäft gehen. Das Spiel war wahrscheinlich ziemlich kompliziert und wir haben einen klaren Mangel an Werbung

    Wir planen, das Spiel auf ios zu übertragen, aber dies wird durch den Mangel an Apfeltechnologie und 100 USD pro Jahr sowie die Aussicht auf Kommunikation über das Elfenziel C behindert.

    Ich hoffe auch, dass dies nicht unser letztes Spiel ist. Es gibt viele neue Ideen, die ich versuchen werde, umzusetzen im Leben, angesichts der gesammelten Erfahrungen. Dieses Spiel - der erste Pfannkuchen, ob klumpig oder nicht - kann ich nicht beurteilen.

    Ich erwarte Kommentare dazu, dass dies mit vorgefertigten Engines einfacher und schneller gemacht werden kann, was Designer und Verleger anzieht. Ich werde darauf antworten, dass wir den Weg der Jedi-Entwickler von Anfang bis Ende auf eigene Faust gehen wollten, um uns kopfüber darauf einzulassen.

    Jetzt auch beliebt: