RMMZ Anyone's Magical JavaScript Spellbook for Novices (New: Basic Template Window)

Anyone

Veteran
Veteran
Joined
Aug 24, 2019
Messages
256
Reaction score
351
First Language
German
Primarily Uses
RMMV
Changelog:
-Improved the text drawing to always be compatible with the window position.

Overview:
As part of getting to know MZ & how it works, I've created a template & commented template plugin for creating basic Windows.

You can use the template plugin as orientation to see how you can create a basic window & make it show via plugin commands.
It features a window written with prototype and one with ES6, giving you an exact comparison so you can pick what you fancy.

Additionally, there's an in-depth commented version of the same plugin. LOTS of commentary. But if a lot of the prototype stuff confused you, and you often feel like you're blindly repeating stuff someone told you to do without understanding, this might help a little.

If the fancy takes me, I may create more on other stuff.
JavaScript:
  //===============================================================================================================//
//                                        ANYONE'S TEMPLATE WINDOW (v1.0)                                        //
//===============================================================================================================//
     //  ANY_Template_Window.js  //  14/11/2020  ||
    //==========================//===============||

/*:
* @target MZ
* @author Anyone
* @plugindesc Templates for Windows
* @help
* ||========================================================================//
* ||                      Anyone's Template Window (v1.0)                  //
* ||======================================================================//
*
* These are Window Templates to learn or use them for your plugins.
* There are two variants: ES6 Classes and the old Prototype.
* Both are written differently, but function identical. The ES6 class is
* merely a JS command that makes JS create the prototype version. ES6 is
* easier to write, though.
*
* Both are written right next to each other, to allow you easy comparison
* & comprehension.
*
* You can use this as template reference for normal windows.
*
* A commented version of this file exists, with in-depth commentary
* for beginners. (ANY_Template_Window_Commented.js)
*
* ||======================================================================\\
* ||                              END                                      \\
* ||========================================================================\\
*
* @command ProtoTemplateWindow
* @text Proto Template Window
* @desc Call the Proto Template Window
*
* @command ClassTemplateWindow
* @text Class Template Window
* @desc Call the Class Template Window
*/

//=================================================================================================================//
//                                                  REGISTER PLUGIN COMMAND                                       //
//===============================================================================================================//

// -->Plugin Command PROTO
PluginManager.registerCommand("ANY_Template_Window", "ProtoTemplateWindow", function (args) {
    SceneManager.push(Scene_ProtoScene);
});

// -->Plugin Command CLASS
PluginManager.registerCommand("ANY_Template_Window", "ClassTemplateWindow", args => {
    SceneManager.push(Scene_ClassScene);
});

//=================================================================================================================//
//                                                  CREATE THE SCENE                                              //
//===============================================================================================================//

// -->Scene PROTO
function Scene_ProtoScene() {
    this.initialize(...arguments);
};

Scene_ProtoScene.prototype = Object.create(Scene_Base.prototype);       
Scene_ProtoScene.prototype.constructor = Scene_ProtoScene;

Scene_ProtoScene.prototype.initialize = function() {
    Scene_Base.prototype.initialize.call(this);
    this.createWindow();
};

Scene_ProtoScene.prototype.update = function () {
    Scene_Base.prototype.update.call(this);
    this.Window_ProtoTemplate.refresh();
    if(Input.isTriggered("escape") || TouchInput.isCancelled()) {
        SoundManager.playCancel();
        SceneManager.pop(this);
    };
};

Scene_ProtoScene.prototype.createWindow = function () {
    this.Window_ProtoTemplate = new Window_ProtoTemplate(new Rectangle(0, 0, Graphics.width, getWLH(2)))
    this.addChild(this.Window_ProtoTemplate);
};



// -->Scene CLASS
class Scene_ClassScene extends Scene_Base {
    constructor(){
        super();
        this.createWindow();
    }
    update() {
        super.update();
        this.Window_ClassTemplate.refresh();
        if(Input.isTriggered("escape") || TouchInput.isCancelled()) {
            SoundManager.playCancel();
            SceneManager.pop(this);
        };
    }
    createWindow() {
        this.Window_ClassTemplate = new Window_ClassTemplate(new Rectangle(0, 0, Graphics.width, getWLH(2)))
        this.addChild(this.Window_ClassTemplate);
    }
};

//=================================================================================================================//
//                                                 CREATE THE WINDOW                                              //
//===============================================================================================================//

// -->Window PROTO
function Window_ProtoTemplate() {
    this.initialize(...arguments);
}

Window_ProtoTemplate.prototype = Object.create(Window_Base.prototype);
Window_ProtoTemplate.prototype.constructor = Window_ProtoTemplate;

Window_ProtoTemplate.prototype.initialize = function (rect) {
    Window_Base.prototype.initialize.call(this, rect);
    this._text = "Proto";
    this.refresh();
}

Window_ProtoTemplate.prototype.refresh = function () {
        const rect = this.baseTextRect();
        this.contents.clear();
        this.drawTextEx(this._text, rect.x, rect.y, rect.width);
}



// -->Window CLASS
class Window_ClassTemplate extends Window_Base {
    constructor(rect) {
        super(rect);
        this._text = "Class";
        this.refresh();
    }

    refresh() {
        const rect = this.baseTextRect();
        this.contents.clear();
        this.drawTextEx(this._text, rect.x, rect.y, rect.width);
    }
};

//=================================================================================================================//
//                                                  FUNCTIONS                                                     //
//===============================================================================================================//

// -->Function
function getWLH (mult) {
    return Window_Base.prototype.lineHeight() * mult;
};
JavaScript:
  //===============================================================================================================//
//                                        ANYONE'S TEMPLATE WINDOW COMMENTED (v1.0)                              //
//===============================================================================================================//
     //  ANY_Template_Window_Commented.js  //  14/11/2020  ||
    //==========================//=========================||

/*:
* @target MZ
* @author Anyone
* @plugindesc Templates for Windows & How to use them
* @help
* ||========================================================================//
* ||                Anyone's Template Window Commented (v1.0)              //
* ||======================================================================//
*
* These are Window Templates to learn or use them for your plugins.
* There are two variants: ES6 Classes and the old Prototype.
* Both are written differently, but function identical. The ES6 class is
* merely a JS command that makes JS create the prototype version. ES6 is
* easier to write, though.
*
* Both are written right next to each other, to allow you easy comparison
* & comprehension.
*
* Note: This is the highly commented version!
*
* Below this, inside the *.js file, you will find the commands.
* The moment you use an "at" symbol the help text will stop, and the next
* word will be something the Plugin Manager will look to as attempt
* of you to communicate something to it.
* So when "at"command appears below this in the js file, the plugin command
* references you can use in the editor will be created with...
* - an id so you can reference it called "command"
* - a "text" which is what the command will display as its name
* - a description "desc" which will add a description in the Plugin Command
*   of the editor
*
* An uncommented version of this file exists that is easier to glance over.
* (ANY_Template_Window.js)
*
* ||======================================================================\\
* ||                              END                                      \\
* ||========================================================================\\
*
* @command ProtoTemplateWindow
* @text Proto Template Window
* @desc Call the Proto Template Window
*
* @command ClassTemplateWindow
* @text Class Template Window
* @desc Call the Class Template Window
*/

/*===STRUCTURE README===
This plugin follows a specific logical structure.
1. At the top, in the commented code, the Plugin Commands are created inside the editor. (The command, text, desc right above this)
2. To ensure that they actually do something, the plugin have a function registered to them that calls the Scene. (Register Plugin Command)
3. The Scene is like a "map", it serves as a canvas where we can put things on. One of the things we make it do is call for a window
   to be displayed. (Create the Scene)
4. For there to be a window the scene can call, it as to be created here. (Create the Window)
5. For convenience's sake, there are shortcut functions that can be useful. (Functions)
*/

//=================================================================================================================//
//                                                  REGISTER PLUGIN COMMAND                                       //
//===============================================================================================================//
/* This registers what the command does. It links it to the Editor Plugin Command that was created underneath the
help text at the beginning of the Plugin:
         - @command, @text and @desc create the ability to select a Plugin Command inside the editor's Plugin command
            @command => is the name of the command. This is the reference the registerCommand needs!
        @text => this is the name of the command that's shown in the MZ Editor!
        @desc => this is the description text shown in the MZ editor!

PluginManager.registerCommand uses the PluginManager's registerCommand function to link functions to the Editor's
Plugin Command. If you don't register the command, you can still see & use it in the editor, but it will never do
anything.
    1. Link the Plugin Command to the name of the plugin file & the @command defined earlier:
        PluginManager.registerCommand("The FILENAME of this plugin", "The @command you wish to link it to",
       
    2. Use a function or arrow function to receive the arguments of the plugin and hand them over to be used in
       this function, even if your @command has no arguments!

        function (args)
        OR in the new ES6 style arrow function
        args =>
    3. Handle the arguments & call the functions to let your Plugin Command actually do something.
       Here, we're going to use the push() function of the SceneManager to call a Scene we've created.
       (Scene_ProtoScene) for the Scene designed via prototype
       (Scene_ClassScene) for the Scene designed via class
        {
            SceneManager.push("The name of your Scene created in the 'Create the Scene' section");
        });
===================================================================================================================*/

// -->Plugin Command PROTO
PluginManager.registerCommand("ANY_Template_Window_Commented", "ProtoTemplateWindow", function (args) {
    SceneManager.push(Scene_ProtoSceneExample);
});

// -->Plugin Command CLASS
PluginManager.registerCommand("ANY_Template_Window_Commented", "ClassTemplateWindow", args => {
    SceneManager.push(Scene_ClassSceneExample);
});

//=================================================================================================================//
//                                                  CREATE THE SCENE                                              //
//===============================================================================================================//
// -->Scene PROTO EXAMPLE -- COMMENTED, this only serves as easy way to comment it, the actual Scene used is the one below this|=====================|
function Scene_ProtoSceneExample() {                             // First we declare the function of the scene so it exists
    this.initialize(...arguments);                                 // (...arguments) => ... is a rest operator, it gathers all arguments up
}                                                                //  and puts it into "arguments"

Scene_ProtoSceneExample.prototype = Object.create(Scene_Base.prototype);    // We attach a .prototype to the function we just created.
                                                                // The prototype is set to be an object created based on the "Scene_Base.prototype" so we can
                                                                // inherit its prototype functions!

Scene_ProtoSceneExample.prototype.constructor = Scene_ProtoSceneExample;      // We overwrite the prototype's constructor function so that it now uses the function
                                                                            // we declared earlier. This ensures that "this.initalize(...arguments)" will now be
                                                                            // executed when the Scene is created.

Scene_ProtoSceneExample.prototype.initialize = function() {        // We just ensured that the function Scene_Protoscene will be executed through the constructor
                                                                // Now we make sure that the initalize function it is calling actually exists and is attached
                                                                // to the SceneProtoSceneExample.prototype.
    Scene_Base.prototype.initialize.call(this);            // Since we overwrote the constructor function that was inherited from Scene_Base when we used
                                                        // Object.create(Scene_Base) and we still want to have Scene_Base's functions initialized, too
                                                        // we now have to call this function directly via Scene_Base.prototype.initalize.call
                                                        // and to make it use its functions on this function, "Scene_ProtoSceneExample" instead of itself,
                                                        // we hand over the Scene_ProtoSceneExample object via "(this)"!
    this.createWindow();            // this calls the createWindow function of this scene which we define further down in and attach it to this
                                    // prototype (Scene_ProtoSceneExample)

    // we can insert any kind of function we wish to call at creation,
    // arrays or variables or objects which we want to set at creation
    // right here. Example:
    //this.opacity = 125;
    //alert("Your Computer will self-destruct in one minute!");
};

Scene_ProtoSceneExample.prototype.update = function () {        // This is the update function. It is called every frame and updates the scene
                                                                // For performance reasons, it's usually a good idea to check what requires an update
                                                                // via if(condition) {then}, otherwise everything will be updated all the time.
    Scene_Base.prototype.update.call(this);   
    this.Window_ProtoTemplateExample.refresh();                    // When the scene gets refreshed, we also refresh the window to keep it up to date.
                                                                // Every time the window gets refreshed, it will redraw itself.
                                                                // If you only want to draw the window once, you can use an if condition here to only
                                                                // have it refresh once. Note that in cases where you have high graphic loads, you
                                                                // may want to only prevent the refreshing after everything has actually been loaded.
    if(Input.isTriggered("escape") || TouchInput.isCancelled()) {            // Since this Scene is based on Scene_Base and not Scene_Selectable, it has no handler.
                                                                            // This instead checks if the cancel key is triggered via touch or device input and if so,
        SoundManager.playCancel();                                            // It will play the cancel sound defined in the game's System Database
        SceneManager.pop(this);                                                // And pop this scene from the SceneManager's stack. (Bringing us back to the previous scene, e.g. the map)
    };
}

Scene_ProtoSceneExample.prototype.createWindow = function () {            // This function was called earlier on initialization and is defined here. This is where a window is created.
    this.Window_ProtoTemplateExample = new Window_ProtoTemplateExample(new Rectangle(0, 0, Graphics.width, getWLH(2)))        // We're using the new Keyword to create a new Object
                                                                                                                            // based on the window we'll define further down.
                                                                                                                            // The Window is created as a new Rectangle at
                                                                                                                            // x = 0, y = 0, width = Graphics.width and height = getWLH(2)
                                                                                                                            // which is a function defined at the bottom the plugin. It returns
                                                                                                                            // a number twice (2) the height of a line.
    this.addChild(this.Window_ProtoTemplateExample);                                                // We're adding the window we just created as a child to this Scene.
}
//=============================================================================================================================||=====================|





// -->Scene CLASS EXAMPLE -- COMMENTED, this only serves as easy way to comment it, the actual Scene used is the one below this|=====================|
class Scene_ClassSceneExample extends Scene_Base {        // instead of .prototype we're using the class keyword to extend the Scene_Base, thus inheriting everything from Scene_Base
    constructor(){                                        // The constructor is assigned to the Scene_ClassSceneExample object here
        super();                                // super() is a new ES6 way to call the initialize function of this object's parent
                                                // when we extended a class. In this case, we extended Scene_Base, so to use it's
                                                // initalize function, instead of Scene_Base.prototype.initialize.call(this);
                                                // we can just use super();
                                                // which is...supercool
        this.createWindow();            // this calls the createWindow function of this scene which we define further down in this class
                                        // and assign to this new object (Scene_ClassSceneExample)

        // we can insert any kind of function we wish to call at creation,
        // arrays or variables or objects which we want to set at creation
            // right here. Example:
        //this.opacity = 125;
        //alert("Your Computer will self-destruct in one minute!");
    }
    update() {                                            // This is the update function. It is called every frame and updates the scene
                                                        // For performance reasons, it's usually a good idea to check what requires an update
                                                        // via if(condition) {then}, otherwise everything will be updated all the time.
        super.update();                                            // Since we're overwriting this Scene's update function right now, we don't want to lose
                                                                // the update functions of the original Scene_Base we used as basis.
                                                                // To also update everything we received from Scene_Base we have to call its update function.
                                                                // Just like earlier, we can use the ES6 super() function for this.
        this.Window_ClassTemplateExample.refresh();                            // When the scene gets refreshed, we also refresh the window to keep it up to date.
                                                                        // Every time the window gets refreshed, it will redraw itself.
                                                                        // If you only want to draw the window once, you can use an if condition here to only
                                                                        // have it refresh once. Note that in cases where you have high graphic loads, you
                                                                        // may want to only prevent the refreshing after everything has actually been loaded.
        if(Input.isTriggered("escape") || TouchInput.isCancelled()) {        // Since this Scene is based on Scene_Base and not Scene_Selectable, it has no handler.
                                                                            // This instead checks if the cancel key is triggered via touch or device input and if so,
            SoundManager.playCancel();                                        // It will play the cancel sound defined in the game's System Database
            SceneManager.pop(this);                                            // And pop this scene from the SceneManager's stack. (Bringing us back to the previous scene, e.g. the map)
        };
    }
    createWindow() {                                                            // This function was called earlier on initialization and is defined here. This is where a window is created.
        this.Window_ClassTemplateExample = new Window_ClassTemplateExample(new Rectangle(0, 0, Graphics.width, getWLH(2)))    // We're using the new Keyword to create a new Object
                                                                                                                            // based on the window we'll define further down.
                                                                                                                            // The Window is created as a new Rectangle at
                                                                                                                            // x = 0, y = 0, width = Graphics.width and height = getWLH(2)
                                                                                                                            // which is a function defined at the bottom the plugin. It returns
                                                                                                                            // a number twice (2) the height of a line.
        this.addChild(this.Window_ClassTemplateExample);                                                        // We're adding the window we just created as a child to this Scene.
        //this.Window_ClassTemplateExample.setHandler("cancel", this.popScene.bind(this));        // We're using the setHandler command to link the "cancel" command to the this Scene's
                                                                                                // "popScene" function which is a function inherited from Scene_Base.
                                                                                                // If we now press the cancel command (right mouse button, escape, etc.), it will close
                                                                                                // this scene.

    }
}
//=============================================================================================================================||=====================|



//=================================================================================================================//
//                                                 CREATE THE WINDOW                                              //
//===============================================================================================================//
// Much of the prototype/ES6 Class handling is identical to the above, check it for reference on it.

// -->Window PROTO
function Window_ProtoTemplateExample() {                                                        // We define the function object so it exists and directs to its initialize function
    this.initialize(...arguments);
}

Window_ProtoTemplateExample.prototype = Object.create(Window_Base.prototype);                    // We create the prototype object from the Window_Base prototype, inheriting its functions & properties
Window_ProtoTemplateExample.prototype.constructor = Window_ProtoTemplateExample;                // We assign the function we created just above this to be the constructor function

Window_ProtoTemplateExample.prototype.initialize = function (rect) {                        // We initialize the function with the arguments "rect" which is the new Rectangle created in the createWindow
                                                                                            // function of the Scene.
    Window_Base.prototype.initialize.call(this, rect);                                // We also call the Window_Base prototype and initalize it with the same rectangle. Unlike in ES6, we need to specify "this",
                                                                                    // Otherwise it will not run the Window_Base's initalized functions on this Window.
    this._text = "Proto";                                                            // We set a text for the Window. The text can be anything.
    this.refresh();                                                                    // We refresh the window, which, in the refresh function, will cause the window's contents to be drawn
}

Window_ProtoTemplateExample.prototype.refresh = function () {
        const rect = this.baseTextRect();                        // We're using an inbuilt function of Window_Base to get the innter dimensions if the rectangle Winow
        this.contents.clear();                                            // This clears the window's contents to make sure we don't draw over existing stuff
        this.drawTextEx(this._text, rect.x, rect.y, rect.width);            // This uses the drawTextEx rather than drawText for the text (thus allowing text colors, etc.)
                                                                            // we reference the text set in the initialization of the scene, and let it be drawn based on the x and y of the
                                                                            // rectangle inside the window. (So that it's based drawn on the window position, rather than the overall screen position)
    }


// -->Window CLASS
class Window_ClassTemplateExample extends Window_Base {
    constructor(rect) {                                                                // We use the Rectangle that's sent to this class by the new Window_ClassTemplateExample command to construct the object
        super(rect);                                                            // We also pass the Rectangle's values over the the parent object (Window_Base) so it can initalize with it
        this._text = "Class";                                                        // We set a text for the Window. The text can be anything.
        this.refresh();                                                                // We refresh the window, which, in the refresh function, will cause the window's contents to be drawn
    }

    refresh() {
        const rect = this.baseTextRect();                        // We're using an inbuilt function of Window_Base to get the innter dimensions if the rectangle Winow
        this.contents.clear();                                            // This clears the window's contents to make sure we don't draw over existing stuff
        this.drawTextEx(this._text, rect.x, rect.y, rect.width);            // This uses the drawTextEx rather than drawText for the text (thus allowing text colors, etc.)
                                                                            // we reference the text set in the initialization of the scene, and let it be drawn based on the x and y of the
                                                                            // rectangle inside the window. (So that it's based drawn on the window position, rather than the overall screen position)
    }
};

//=================================================================================================================//
//                                                  FUNCTIONS                                                     //
//===============================================================================================================//
//This function makes our life a little easier by allowing us to use getWLH(2) instead of Window_Base.prototype.lineHeight() * 2
//This helps prevent long statement, since we'll often have to get the lineHeight for the positioning of Windows

// -->Function
function getWLH (mult) {
    return Window_Base.prototype.lineHeight() * mult;                // this gives just gives us a shorter way of writing this by writing getWLH().
};

~~~ If you see any mistakes, do tell me. I'm in this to learn as well. ~~~
 

Attachments

  • ANY_Template_Window.js
    5.8 KB · Views: 1
  • ANY_Template_Window_Commented.js
    19.6 KB · Views: 1
Last edited:

Latest Profile Posts

Worked on a cutscene skip domino effect using Maker Systems' script as the basis. Basically if I have a batch of cutscenes in a row on different maps, now when you skip one cutscene it will skip the entire set. No more spamming X to skip a scene every new map.

Oh and it will work regardless of where you do it from in the set. Convenient!
seems absolutely WILD to me now all the hundreds of hours of work I used to do in 2k(3) over a decade ago with a resolution of 320x240. that seems so insanely TINY now, seemed so normal at the time!
Playing Aroma Indosiar theme song.
Aroma is an Indonesian TV show about cooking. :)
Working on a characteeer! (Why is it so hard to color hair?) ;-;
Silly-Sketches.png
Just finished eventing a couple simple puzzles in RMMV, for my very first game "Sample Quest." Just messing around, throwing things together, and calling it a story XD On a non-RM note, got my hair cut today!

Forum statistics

Threads
115,378
Messages
1,089,390
Members
150,075
Latest member
Bridge36000
Top