[Scripting] Mein erstes Plugin (MV)

  • i_RMMV


    Hey! Heute gibt es das erste Tutorial von mir zum Thema Scripting/Plugins für den RPG Maker MV.


    Voraussetzungen: Ihr braucht ein Programm, mit dem man programmieren kann, da es im MV keinen eingebauten Editor mehr gibt, wie es beim VX Ace war. Ich benutze Notepad++ (Download).


    Erste Schritte

    Als erstes Starten wir mit dem Grundgerüst eines Plugins. Das könnt Ihr einfach kopieren und einfügen.


    Ganz oben steht der Name des Plugins. Viele haben ihr eigenes Nametag, meins ist zB. WAY, dass vor dem Pluginname hinzugefügt wird, so kann man schnell sehen, von wem welches Plugin ist und man kann sie leicht im Plugin-Manager sortieren.

    Außerdem kann man noch einiges an Info hinzufügen.


    Wenn Ihr den Namen eingetragen habt, könnt Ihr die Datei speichern. Plugins befinden sich im Projekt\js\plugins. Vergesst dabei nicht die Dateiendung .js.


    Ganz unten startet dann der Code. Der Code wird einfach immer in dieses Ding geschrieben. Ich werde hier nicht genau drauf eingehen, was genau das ist, da das den Rahmen dieses Tutorials sprengen würde. Wer gerne mehr darüber erfahren will, das Ding nennt man Immediately-Invoked Function Expression, oder kurz IIFE (mehr Infos hier). Das ist ein Konstrukt in JavaScript, mit dem man verhindern kann, dass Funktions- und Variablendeklarationen im globalen Namespace landen. Das klingt natürlich erstmal total heftig, aber im Grunde bedeutet das einfach nur wir haben einen eigen Raum in dem wir Dinge tun können und es geht weniger kaputt dabei.



    So nachdem wir mit dem ganzen Kram fertig sind, können wir mit dem eigentlichen Plugin beginnen.


    Heutiges Thema: Titelbildschirm

    • Position vom Command Window ändern
    • Spiel verlassen Command hinzufügen, um das Spiel vom Titelbildschirm aus zu beenden



    I. Position ändern

    Zuerst schauen wir uns mal an, wie der Titelbildschirm im MV funktioniert. Dafür gehen wir in den \js Ordner und finden dort eine Menge Dateien.

    Der Titelbildschirm ist eine Scene, deshalb schauen wir uns rpg_scenes.js an und suchen nach Scene_Title. Dort sehen wir dann, dass ein Window_TitleCommand erstellt wird.

    Das ist doch genau das, was wir verändern wollen. Also schauen wir in rpg_windows.js und suchen nach Window_TitleCommand.

    Wenn wir uns das genau anschauen, finden wir die Funktion updatePlacement. Das hört sich doch gut, also kopieren wir das ganze in unser eigenes Plugin.


    JavaScript
    1. (function() {
    2. //=============================================================================
    3. // Window_TitleCommand
    4. //=============================================================================
    5. Window_TitleCommand.prototype.updatePlacement = function() {
    6. this.x = (Graphics.boxWidth - this.width) / 2;
    7. this.y = Graphics.boxHeight - this.height - 96;
    8. };
    9. })();


    Dann sollte das ganze so aussehen. Zur Übersichtlichkeit habe ich den ganzen oberen Teil vom Plugin weggelassen, da das sonst viel zu lang wird. Außerdem kann man sein Plugin noch strukturieren, indem man über die einzelnen Funktionen den Namen schreibt. Ich würde das auf jeden Fall empfehlen, denn so findet man alles viel schneller.


    Schauen wir uns das Ganze mal genauer an. In der Funktion werden zwei Variablen Werte zugewiesen. Die beiden Variablen heißen x und y. Das this bezieht sich dabei auf das Window_TitleCommand und bedeutet, wir nehmen vom Command Window die x und y Position.

    (Mehr Infos zu this hier)

    Hier können wir jetzt unsere gewünschten Positionen eintragen. Das kann man entweder mit festen Zahlen machen oder mit einer Berechnung.

    Man kann sich den Bildschirm als ein x,y-Koordinatensystem vorstellen. Dabei ist die linke obere Ecke vom Bildschirm 0,0. Graphics.boxHeight und Graphics.boxWidth sind schon vorhandene Variablen, die wir benutzen können. Die beiden Variablen stehen für die Auflösung des Spiels, per default sind die Werte 816 bzw. 624. this.height und this.width ist die Höhe bzw. Breite des Command Windows.


    JavaScript
    1. Window_TitleCommand.prototype.updatePlacement = function() {
    2. this.x = 42;
    3. this.y = Graphics.boxHeight - this.height - 42;
    4. };


    Nun würde das Command Window unten links in der Ecke sein.


    Den ersten Teil haben wir also schon geschafft.


    II. Command hinzufügen

    Um ein neues Command hinzufügen schauen wir uns wieder das Window_TitleCommand an.

    Dort finden wir die Funktion makeCommandList, diese erstellt alle Commands. Also kopieren wir uns die Funktion wieder ins unser Plugin.



    Hier können wir nun unser eigenes Command hinzufügen. Dazu benutzen wir die Funktion this.addCommand(name, handler, enabled). Der erste Parameter ist der Name des Commands, welcher später im Spiel zu sehen ist. Als Zweites kommt der Name des Handlers, der später nochmal wichtiger wird. Der dritte Parameter gibt an, ob man das Command benutzen kann oder nicht. Das wird beim Spiel laden Command benutzt, denn wenn man das Spiel startet und kein gespeichertes Spiel vorhanden ist, kann man das Command nicht benutzen und es ist ausgegraut.



    Wenn wir jetzt das Spiel starten, sehen wir das neue Command im Command Window. Jedoch passiert noch gar nichts. Das liegt daran, dass wir das noch nicht implementiert haben. Die Funktionsweise dahinter wird getrennt implementiert.

    Diesmal schauen wir wieder in rpg_scenes.js und finden createCommandWindow. Dort wird das Fenster erstellt und alle Handler für die einzelnen Commands.


    JavaScript
    1. Scene_Title.prototype.createCommandWindow = function() {
    2. this._commandWindow = new Window_TitleCommand();
    3. this._commandWindow.setHandler('newGame', this.commandNewGame.bind(this));
    4. this._commandWindow.setHandler('continue', this.commandContinue.bind(this));
    5. this._commandWindow.setHandler('options', this.commandOptions.bind(this));
    6. this.addWindow(this._commandWindow);
    7. };


    Hier erstellen wir also auch den Handler für unser neues Command. Dafür benutzen wir die Funktion setHandler(handler, method). Der erste Parameter gibt an, zu welchen Command der Handler gehört und der zweite Parameter ist die Funktion, die dann ausgeführt wird, wenn man auf das Command klickt.

    Für das Spiel starten Command, wird dann die Funktion this.commandNewGame ausgeführt. Wenn wir unseren 'exitGame' Handler hinzufügen wollen, müssen wir also erstmal eine neue Funktion erstellen.


    JavaScript
    1. //=============================================================================
    2. // Scene_Title
    3. //=============================================================================
    4. Scene_Title.prototype.commandExitGame = function() {
    5. this.fadeOutAll();
    6. SceneManager.exit();
    7. };


    Wir erstellen eine Funktion mit dem Namen commandExitGame. Die Funktion blendet den Bildschirm aus und beendet dann das Spiel.

    Jetzt können unseren Handler erstellen. Der Name vom Handler muss gleich dem Namen sein, den wir benutzt haben, als wir das Command erstellt haben.


    JavaScript
    1. Scene_Title.prototype.createCommandWindow = function() {
    2. this._commandWindow = new Window_TitleCommand();
    3. this._commandWindow.setHandler('newGame', this.commandNewGame.bind(this));
    4. this._commandWindow.setHandler('continue', this.commandContinue.bind(this));
    5. this._commandWindow.setHandler('options', this.commandOptions.bind(this));
    6. this.addWindow(this._commandWindow);
    7. this._commandWindow.setHandler('exitGame', this.commandExitGame.bind(this));
    8. };


    Wenn wir jetzt unser Spiel starten und im Titelbildschirm auf Spiel beenden, klicken sich das Spiel. ^^


    Eigentlich sind wir fertig, wir haben alles gemacht, was wir scripten wollten. Jedoch haben wir einfach alle vorhandenen Funktionen überschrieben und somit ersetzt. Hätten wir auch noch ein anderes Plugin installiert, dass auch ein neues Command zum Command Window hinzufügt, würden wir das überschreiben. Deshalb gibt es das Aliasing.

    In JavaScript können wir Funktionen in Variablen speichern.


    JavaScript
    1. var _Window_TitleCommand_makeCommandList = Window_TitleCommand.prototype.makeCommandList;


    Wir speichern also die alte Funktion makeCommandList vom Window_TitleCommand in einer Variable. Die Variable nennen wir _Window_TitleCommand_makeCommandList. Wenn wir jetzt also die Funktion überschreiben, haben wir immernoch eine Kopie der alten Funktion. Diese können wir auch immernoch aufrufen.


    JavaScript
    1. var _Window_TitleCommand_makeCommandList = Window_TitleCommand.prototype.makeCommandList;
    2. Window_TitleCommand.prototype.makeCommandList = function() {
    3. _Window_TitleCommand_makeCommandList.call(this);
    4. this.addCommand("Spiel verlassen", 'exitGame');
    5. };


    Jetzt können wir einfach die alte Funktion aufrufen, dass macht man mit call. Und danach können wir unsere neuen Sachen hinzufügen.

    Das Gleiche machen wir mit der Funktion createCommandWindow.


    JavaScript
    1. var _Scene_Title_createCommandWindow = Scene_Title.prototype.createCommandWindow;
    2. Scene_Title.prototype.createCommandWindow = function() {
    3. _Scene_Title_createCommandWindow.call(this);
    4. this._commandWindow.setHandler('exitGame', this.commandExitGame.bind(this));
    5. };


    Damit sind wir am Ende dieses Tutorials angekommen.

    Das komplette Plugin sieht nun so aus:



    Vielen Dank für's lesen! Ich hoffe es hat Spaß gemacht und es konnte einen kleinen Einblick geben, wie man ein Plugin erstellt.

    Wer direkt mit dem zweiten Teil weiter machen will, kann hier klicken! :)


    lg

    waynee95

  • Die "Spiel beenden"-Funktion sollte in keinem Spiel fehlen! Zu dumm, dass sie von Haus aus nicht mehr integriert ist...

    Schönes Tutorial, welches neben dem Erstellen einer neuen Funktion auch beim Lesen fremder Skripte einen guten Einblick gewähren dürfte, um die ersten Schritte zu machen. :)

  • Dankeschön! Ja, dass hat mich auch gestört. Aber man kann es ja recht schnell selber basteln :)


    Das nächste Tutorial ist auch schon in Arbeit und wird auf diesem aufbauen. Unter anderem wird es um Plugin Parameter und Icons gehen und ein bisschen JavaScript wie Arrays und Schleifen.


    Falls jemand irgendwelche Wünsche oder Ideen für ein Plugin/Tutorial hat, schreibt mir gerne eine PM :D!

  • Ich finde es richtig klasse, dass du für uns ein solch geniales Tutorial erstellst.


    Es gewährt einen sehr schönen ersten Einblick und deine Erklärungen dazu sind ebenso super!

    Weiter so :)

    :s_info: Ehemalig in dieser Community als Toothless bekannt, habe ich nun meinen Künstlernamen angenommen: Cryptogene

    So manch einer kennt ja ohnehin schon meine 3D Szenen.


    ninja_pointright Ihr wollt euch für das Forum bedanken und dieses zu 100% unterstützen? Ihr könnt uns finanziell durch eine Schenkung unterstützen. Danke für euren Support!

  • Perfekt.

    Die komplizierten Themen wie IIFE und this gekonnt umgangen, sodass das Tutorial klar definiert ist und nicht den Rahmen sprengt.

    Hut ab! Weiter so. :)


    Wenn du Hilfe brauchst oder nen Vorschlag für andere Tutorials aber dir die Zeit fehlt, gib Bescheid.

  • Wenn ich mal selber so weit bin, kann ich mir den Thread hier ja merken^^ Ich wusste garnicht, dass der MV keinen Editor mehr hat..

  • Whalfar Gut so. So spart man sich unnötige Herumkopiererei und kann mit seinem Tool der Wahl arbeiten. Einfach im Editor speichern und Schuss im Maker drücken um zu Testen.

  • <3=O:thumbup: Vielen, vielen Dank! Das hilft so Nullpen wie mir ungemein! Es ist wirklich sehr verständlich geschrieben.

    Sobald ich mit einem eigenen MV-Projekt beginne, werde ich deine Tutorials alle noch mal intensiv wälzen.

  • Ich hab heute mal das Aliasing ausprobiert, aber irgendwie will das nicht funktionieren... Ich möchte ein neues Objekt erstellen wenn alle anderen spielrelevanten Objekte erstellt werden.

    Code
    1. (function() {
    2. mrfucgo = DataManager.prototype.createGameObjects;
    3. DataManager.prototype.createGameObjects = function() {
    4. mrfucgo.call(this);
    5. console.log("Alias cgo");
    6. };
    7. })();

    In meiner Konsole erscheint aber nie 'Alias cgo'. Was mache ich falsch? Habe das auch mit 'var' vor 'mrfucgo' probiert und auch außerhalb der Funktion...

  • Mr. Fu  

    Das Problem ist, dass du die Funktion falsch aliast. Die Funktionen im DataManager gehen nicht über den Prototype.


    Code
    1. var _DataManager_createGameObjects = DataManager.createGameObjects;
    2. DataManager.createGameObjects = function() {
    3. _DataManager_createGameObjects.call(this);
    4. console.log("hi");
    5. };
  • Mr. Fu

    Bei anderen Classes brauchst du den Prototype aber zb. Wenn du eine Funktion vom Game_Actor aliast.


    Warum du es bei dem einen brauchst und beim anderen nicht könnte ich jetzt noch genau erklären aber habe gerade nicht dir Zeit dafür. Schreibe das hier auch gerade von Handy.


    Falls du dir mal nicht sicher bist, was du benutzen musst, schau einfach in den MV Files nach.

  • Wir mir scheint mangelt es bei mir an Intelligenz... Ich habe vorher noch nie in meinem Leben mit sowas gearbeitet und habe mich trotzdem dazu entschieden ein Spiel zu machen. Naja jetzt wollte ich mich mit dieser Materie auseinandersetzen, da ich das meiste drum herum auch hinbekommen habe. Mein Ziel war es ein "Kochbuch" zu erstellen, wo mein Protagonist eintragen kann, mit welchen Zutaten er welche Items erstellen kann (Kraftpillen und so ein Kram). Jedoch verstehe ich ehrlich gesagt gar nix in diesem Blog.

    Ich weiß jetzt zwar wie ich hinzufüge "Spiel verlassen" aber nur weil es dort ja eins zu eins auf Bildern zu sehen ist. Allerdings habe ich absolut keine Ahnung, was das alles überhaupt bedeutet. Ich bin seit Wochen danach auf der Suche, irgendetwas zu finden, dass mir erklärt was überhaupt was in einem Plugin ist. Momentan bin ich am Verzweifeln und komme überhaupt nicht darauf klar, dass ich es nicht verstehe. Ich komme mir massiv zu dumm vor und als könnte ich eigentlich gar nichts. Kannst du mir nicht erklären, wie ich überhaupt alles zu verstehen habe? Mich macht das Thema langsam wahnsinnig. Ich verstehe nicht einmal, wieso manches farbig ist und warum nicht. An Englischkenntnissen mangelt es meinerseits auch nicht und keine Ahnung, bitte hilf mir einer....