Wir zeichnen, codieren für libGDX und andere kleine Freuden aus dem Leben eines Indie-Entwicklers


    Hallo habr In diesem Thema möchte ich meine Eindrücke von der libGDX-Game-Engine teilen, über den Alltag eines gewöhnlichen Indie-Entwicklers sprechen und den Schleier der Geheimhaltung über das Spiel öffnen, das ich in meiner Freizeit in den letzten Monaten aus der Büro-Sklaverei gemacht habe. Ich hoffe, dass meine Notizen für diejenigen nützlich sein werden, die gerade anfangen, etwas mit libGDX zu tun, oder für diejenigen, die die Engine für das "Spiel ihrer Träume" auswählen.

    Und entschuldigung für die Katzen. Sie haben absolut nichts mit Iglu zu tun. Ich lerne (versuche zu lernen) gleichzeitig zu zeichnen und jetzt sind meine Trainingskatzen einfach überall! Sie fordern, dass sie, Faulenzer, jemandem gezeigt werden.

    Zeichnen


    Apropos Zeichnung. Natürlich werden erfahrene CG-Künstler mir Pantoffeln werfen (und sie werden absolut Recht haben), aber wie trete ich aus dem Prozess heraus! Ich fand das Zeichnen nicht so cool! Vor langer Zeit hatte ich unter all dem Müll ein Geschenk für ein Grafiktablett. Bambus ist etwas da, ich denke, jeder kauft das gleiche "um sich zu verwöhnen". Und dann fiel mir einmal ein Buch von Mark Kistler auf: "Sie können in 30 Tagen zeichnen." Nein, das Zeichnenlernen in 30 Tagen ist natürlich dasselbe wie das Erlernen von C ++ in derselben Zeit. Jeder versteht das. Aber es stellt sich heraus, dass das Zeichnen dort kein immaterielles Talent ist, keine Elfen, die Einhörner auf den Wiesen von unbekannten Inseln weiden lassen. Es ist nur ein Satz von Regeln, so einfach wie die Syntax einer Programmiersprache. Plus Erfahrung natürlich! Hände füllen. Aber ein guter Programmierer entwickelt sich auf ähnliche Weise.


    In diesem Buch (genauer gesagt, das Buch ist überhaupt nicht ernst gemeint) gibt es also alle Grundregeln, um etwas mehr als eine Stange-Stange-Gurke zu zeichnen. Und wenn die handgezeichneten Schnörkel aufhören, zumindest in dir Horror zu verursachen, ist es cool! Der Prozess selbst beginnt Vergnügen zu bereiten. Für mich persönlich war dies eine Offenbarung.


    Bei dieser Gelegenheit möchte ich auch einen hervorragenden Redakteur beraten - SketchBook Pro. Darin werden auch Profis gezeichnet, aber genau das braucht ein Nicht-Profi. Benutzerfreundlich, nicht mit Funktionalität überladen. Eine Lizenz ist im Gegensatz zu Photoshop relativ günstig. Obwohl dieses abscheuliche Abonnement-Software-Schema hier gilt, stehen die Grundfunktionen kostenlos zur Verfügung.

    Ich benutze nur 3 Werkzeuge: Bleistift, Kugelschreiber, Pinsel. Ich weiß nicht, wie ich es richtig nennen soll. Die Funktion, deine Krümmungen unterwegs zu begradigen, ist eine überaus nützliche Sache! Wir nehmen einen Stift in die eine Hand, den zweiten auf ein Feld (Drehung und Skalierung der Leinwand) und gehen! Kreativität schaffen.

    Warum nicht die Einheit?


    Aber ich war abgelenkt. Wenn es um die Auswahl einer Spiel-Engine geht, stellt sich als erstes und einziges die Frage: "Warum nicht die Einheit, Mann?" Und deshalb! Da ich an Android Studio gewöhnt bin (ich habe kürzlich eine Unternehmensanwendung geschrieben), kenne ich Java mehr oder weniger, Android SDK. Und die Verwendung eines solchen multifunktionalen Monsters wie "Unity" für einfache 2D-Spiele ist ein bisschen wie eine "Spatzenwaffe", nicht wahr? Eine ungewohnte IDE, wieder ein anderer Ansatz. Und die Größe des leeren Projekts beträgt 20 MB? Ja, ich habe auf libGDX das ganze Spiel zusammen mit der Grafik (die hier nicht so klein ist) weniger wiegt! Ich verstehe, dass wir in einem Zeitalter des schnellen Internets leben, aber es gibt dennoch einen Zusammenhang zwischen der Größe der Anwendung und der Anzahl der Installationen.

    Wenn Sie genauer hinschauen, wird unter dem Strich die Warnung angezeigt, dass die Anwendungsgröße zu groß ist. Möchten Sie sie wirklich nicht über WLAN herunterladen? (Ich erinnere mich buchstäblich nicht, aber das Wesentliche ist, dass) - einige impulsive Installationen werden abgeschnitten.

    Wenn Sie sich zuvor mit dem Android SDK befasst haben, ist libGDX im Allgemeinen eine ausgezeichnete Wahl für einen reibungslosen Übergang zur plattformübergreifenden Entwicklung. Ich werde versuchen, alle Vor- und Nachteile zu formulieren, die ich aus meiner ersten Bekanntschaft mit libGDX für mich gelernt habe.

    Vorteile


    • Frei.

    • Plattformübergreifend. Die Desktop-Erstellung funktioniert unter Windows und Mac gleichermaßen nahtlos (unter Linux gab es keine Möglichkeit, dies zu überprüfen, aber ich bin mir sicher, dass dies auch so ist). Bei HTML bin ich auf eine kleine Nuance gestoßen: Alle Pakete, die Sie hinzufügen, müssen im Core-Projekt in gwt.xml registriert sein, sonst wird es nicht erstellt. Es gibt überhaupt keine Probleme mit Android, iOS ist bisher nur in meinen Plänen.

    • Niedrige Einstiegsschwelle für Android-Entwickler. Das gleiche Studio, der gleiche Gradle. Wir haben ein Core-Projekt, in dem wir die gesamte Spielelogik beschreiben, und ein Android-Projekt - das ist grob gesagt die MainActivity, auf der die Ansicht basiert, und in der das Core-Projekt ausgeführt wird. Vom Kernprojekt aus können wir den plattformabhängigen Teil, den wir im Android-Projekt schreiben, problemlos aufrufen. Und was sehr schön ist, wir implementieren den Plattformcode (Werbung, Analytics, Spieledienste) direkt aus den Tutorials von Google. Wie bei einer regulären Anwendung. Das heißt, keine Bibliotheken, Erweiterungen von Drittanbietern und so weiter!

    Nachteile


    • Ich habe kein relevantes, sinnvolles Tutorial gefunden. Selbst hier gibt es viele Informationen über Habré, aber normalerweise kommt es darauf an, wie ein Sprite auf dem Bildschirm angezeigt wird. In der Praxis ist dies nicht notwendig, warum? Es ist klüger, Abstraktionen einer höheren Ebene zu verwenden: Schauspieler, Szene (mehr dazu weiter unten). Wenn ich mich mit der neuen Engine vertraut mache, möchte ich in der Kurzanleitung Folgendes sehen: Das Spiel für verschiedene Bildschirme richtig skalieren, Ressourcen im Hintergrund laden (das ist alles gut ), Bildschirme / Szenen und Objekte auf ihnen verwalten.


    Wenn ich das Gespräch über die Nachteile fortsetze, habe ich ein leichtes Understatement in libGDX. Hier gibt es hervorragende Abstraktionen: Bildschirm - ein Spielbildschirm, Bühne - eine Szene oder Ebene, Schauspieler - ein beliebiges Objekt in dieser Szene. In meinem Spiel habe ich beschlossen, auf allen Spielbildschirmen einen und mehrere Bildschirme zu erstellen: Ebenen, Menüs usw. Wir erben Spielobjekte von Actor, machen dann einfach stage.addActor (ball) und fertig . Next Stage ist mit dem Rendern, Verschieben usw. beschäftigt. dieses Objekt. Der Schauspieler tut also nichts für sich. Es werden keine Sprites angezeigt (und 99% der Spielobjekte sind Sprites). Sie können im Allgemeinen keine Kollision zwischen zwei Akteuren feststellen.

    Sie müssen Ihren eigenen SimpleActor erstellen und bereits Spielobjekte erben:

    Code
    public class SimpleActor extends Actor {
        private final TextureRegion region;
        public SimpleActor(TextureRegion region) {
            this.region = region;
            setSize(region.getRegionWidth(), region.getRegionHeight());
            setBounds(0, 0, getWidth(), getHeight());
        }
        @Override
        public void draw(Batch batch, float parentAlpha) {
            batch.draw(region, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
        }
    }
    

    Wenn Sie animierte Spielobjekte benötigen (na ja, wo ohne?), Schreiben wir SimpleAnimatedActor:

    Code
    public class SimpleAnimatedActor extends Actor {
        private Animation animation;
        private TextureRegion currentFrame;
        private float stateTime;
        private boolean started;
        public SimpleAnimatedActor(float frameDuration, Array frames) {
            animation = new Animation(frameDuration, frames);
            currentFrame = animation.getKeyFrame(stateTime);
            setBorders(frames.get(0));
        }
        private void setBorders(TextureRegion sample) {
            setSize(sample.getRegionWidth(), sample.getRegionHeight());
            setBounds(0, 0, getWidth(), getHeight());
        }
        public void start() {
            stateTime = 0;
            started = true;
        }
        public boolean isFinished() {
            return animation.isAnimationFinished(stateTime);
        }
        @Override
        public void act(float delta) {
            super.act(delta);
            if (!started) {
                return;
            }
            stateTime += delta;
            currentFrame = animation.getKeyFrame(stateTime);
        }
        @Override
        public void draw(Batch batch, float parentAlpha) {
            batch.draw(currentFrame, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
        }
    }
    

    Um eine einfache Kollisionsprüfung durchzuführen, können Sie unserem SimpleActor Polygon hinzufügen:

    Code
    Polygon polygon = new Polygon(new float[]{0, 0, getWidth(), 0, getWidth(), getHeight(), 0, getHeight()});
    polygon.setPosition(getX(), getY());
    polygon.setOrigin(getOriginX(), getOriginY());
    polygon.setScale(getScaleX(), getScaleY());
    polygon.setRotation(getRotation());
    

    Usw. Dies bereitet natürlich keine besonderen Schwierigkeiten. Trotzdem kann ich nicht verstehen, warum ich nicht etwas Ähnliches im Motor mache. Und so müssen Sie Ihren angehängten Code von Projekt zu Projekt ziehen.

    Fragmentierung


    Wie kann das Spiel auf dem gesamten Zoo von Android-Geräten gleichermaßen cool aussehen? Für mich ist dies eines der Schlüsselthemen. Daher werde ich detaillierter beschreiben, wie ich das Problem des Skalierens eines Bildes in libGDX gelöst habe.

    Ich mag den bereits klassischen Ansatz, wenn wir auf Tablets (4: 3) mehr Umgebung und auf Smartphones (16: 9) weniger zeigen. In diesem Fall wird nirgendwo etwas gedehnt, und man könnte sagen, dass Spielobjekte ihre Größe nicht ändern. Wir speichern alle Grafiken in einer Auflösung, ich habe es 960x1280 (4: 3). In der Mitte des Bildschirms haben wir einen „Spielbereich“ von 720 x 1280 (16: 9), in den alle Objekte, mit denen der Spieler interagiert, hineingelangen müssen. Der Rest ist die Szenerie und kann je nach Gerät zugeschnitten werden. Der einfachste Weg, dieses Prinzip zu veranschaulichen, ist mit einem Bild:


    LibGDX bietet hierfür alle Funktionen. Die einzige Einschränkung: Möglicherweise müssen einige Objekte am Rand des Bildschirms angebracht werden. Wie die Home-Taste im Bild oben. Dazu müssen wir den tatsächlichen linken und rechten Rand des Bildschirms in Spielkoordinaten kennen (wobei oben und unten einfacher sind - es ist immer 1280 bzw. 0). Schreiben wir einen Code:

    Code
    public class MyGame extends Game {
        public static final float SCREEN_WIDTH = 960f;
        public static final float SCREEN_HEIGHT = 1280f;
        public static float VIEWPORT_LEFT;
        public static float VIEWPORT_RIGHT;
        private GameScreen mGameScreen;
        @Override
        public void create() {
            mGameScreen = new GameScreen();
            setScreen(mGameScreen);
        }
        @Override
        public void resize(int width, int height) {
            super.resize(width, height);
            float aspectRatio = (float) width / height;
            float viewportWidth = SCREEN_HEIGHT * aspectRatio;
            VIEWPORT_LEFT = (SCREEN_WIDTH - viewportWidth) / 2;
            VIEWPORT_RIGHT = VIEWPORT_LEFT + viewportWidth;
        }
        @Override
        public void dispose() {
            super.dispose();
            mGameScreen.dispose();
        }
    }
    

    Was ist hier los? Dies ist die Hauptklasse des Spiels, die von Game geerbt wurde. Hier erstellen und setzen wir Screen (in meinem Fall den einzigen Bildschirm) und überschreiben resize () . Dieses Ereignis für Android wird ausgelöst, wenn die Anwendung gestartet wird. Hier können Sie den linken und rechten Bildrand berechnen (VIEWPORT_LEFT und VIEWPORT_RIGHT).


    In GameScreen brauchen wir setzen FillViewport , ist es verantwortlich für die Tatsache , dass das Bild , wenn das Seitenverhältnis beschnitten wird das Ziel nicht entsprechen. Viewport ist unser Fenster zur Spielwelt. Es gibt verschiedene Typen, die Dokumentation dazu wird es noch besser als ich sagen, und ich gebe nur den Code:

    Code
    public class GameScreen implements Screen {
        private final OrthographicCamera mCamera;
        private final Viewport mViewport;
        private final AssetManager mAssetManager;
        private Stage mActiveStage;
        public GameScreen() {
            mCamera = new OrthographicCamera();
            mViewport = new FillViewport(MyGame.SCREEN_WIDTH, MyGame.SCREEN_HEIGHT, mCamera);
            mAssetManager = new AssetManager();
            mActiveStage = new MyStage(mViewport, mAssetManager);
        }
        @Override
        public void render(float delta) {
            mCamera.update();
            Gdx.gl.glClearColor(65 / 255f, 65 / 255f, 65 / 255f, 1f); // просто цвет фона
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
            mActiveStage.act(delta);
            mActiveStage.draw();
        }
        @Override
        public void resize(int width, int height) {
            mViewport.update(width, height, true);
        }
        @Override
        public void dispose() {
            mActiveStage.dispose();
            mAssetManager.dispose();
        }
    }
    

    Hier sollte im Allgemeinen alles intuitiv klar sein, vergessen Sie nicht, nur mViewport.update (width, height, true) mit resize () auszuführen .

    Manuelle Box


    Nachdem ich kurz über die Engine gesprochen habe, möchte ich noch ein paar Worte über das Spiel selbst sagen. Ich habe seit einem Jahr keine Spiele mehr gespielt, der Firmensumpf hat mich fast reingelegt. Aber das hinderte mich nicht daran zu träumen. Träume von einer Aufgabe, einem möglichst komplexen Rätsel. Ohne Anhaltspunkte für Geld und andere freispielige dumme Sachen.

    Die Idee einer mechanischen Box - ein Gerät, das nur einem Zweck dient: den Inhalt zuverlässig zu schützen. Wobei jede Schutzschicht ein separates, unabhängiges Puzzle mit neuer Spielmechanik ist.

    Wir können es uns leisten, das zu tun, was wir wollen. Ich interessiere mich nicht für Retention Rate und andere Marketing-Sachen. Ja, das Spiel eines kommerziellen Studios wird sich von selbst drehen, wenn der Prozentsatz der Spieler im ersten Level hängen bleibt! Und ich kann einfach ein Spiel machen, das ich selbst spielen möchte.


    Generell habe ich im August dieses Jahres mit dem Bau der Box begonnen. Nachdem ich ein wenig gezeichnet hatte, wurde mir klar, dass ich solche Bände nicht zeichnen konnte und meine Kunst in der Qualität nicht zu mir passte. Er ist, gelinde gesagt, eigenartig. Infolgedessen wurde auf gamedev.ru ein Künstler gefunden, der bereit war, sich auf dieses Abenteuer einzulassen. Überraschenderweise stellte sich heraus, dass Vladimir und ich nicht nur in derselben Stadt, sondern auch auf den benachbarten Straßen leben. Er war es, der der Mechanical Box ein angemessenes Aussehen verlieh. Ich habe sogar "wie es war" und "wie es wurde" als Andenken behalten. Der Unterschied liegt auf der Hand.



    Während ich weiter an der Mechanical Box arbeite, habe ich einige Gedanken zur Entwicklung dieser Idee. Wenn Sie Ihre Stärke testen möchten, ist das Spiel bereits auf Google Play veröffentlicht. Ich gebe keinen Link an, um die Aufmerksamkeit des UFO nicht noch einmal auf sich zu ziehen . Und obwohl die Box in einer populären Ressource schnell in Teile zerlegt wurde, ist dieses Puzzle für eine einzelne Person eine ziemlich ernste Herausforderung. Was mir persönlich gefällt. Ich kann sogar vorhersagen, wo Sie stecken bleiben werden. Dies ist entweder ein Level mit einem Kran (wie kann man diese verdammte Klaue nach rechts bewegen?) Oder drei bunte Quadrate (dieses Rätsel scheint mir einfach, aber Statistiken sind hartnäckig). Oder willkommen im "Club der verlorenen Null" - das ist die Elite.


    Danke fürs Lesen, Fragen stellen, Kommentare schreiben!
    Tu Gutes und wirf es ins Wasser.

    Jetzt auch beliebt: