It's one of the reasons I didn't initially mention IFFE in my tutorial, to be honest. There are arguments for adding functions straight into window, and not every coder will agree on a convention.
The anatomy of a plugin
● ARCHIVED · READ-ONLY
-
-
I should probably let the IFFE discussion die, and let this thread thrive for its own topic, but I've switched sides on my debate.
It's kinda funny after all the fuss I've put up for window variables, but I've learned IFFE are superior for aliasing harmony among lots of plugins. This is only half on-topic, but I've discovered how these things are really useful in plugins which is the on-topic part.
The original function is aliased as an argument, so there are no possible SameName conflicts. See how I use alias twice?
PHP:(function(alias){ Window_Base.prototype.drawText = function() { // do stuff to arguments[0] alias.apply(this, arguments); }; })(Window_Base.prototype.drawText);PHP:(function(alias){ Game_Message.prototype.add = function() { // do stuff to arguments[0] alias.apply(this, arguments); }; })(Game_Message.prototype.add);
Window aliases would only be better than this if you needed to access the original function in other functions, which is really impossible anyway, if you consider the original function has probably been aliased a few times by other plugins, anyway.
And any var variable you use inside the IFFE, even it's an identical variable name to a global, only the local var will be used inside the IFFE.
Awesome! -
hi there
i replace the text with "$gameParty.gold()", but the gold amount won't refresh
i want to refresh the gold amount as soon as the amount of gold is updated, what should i do? thx! -
hi there
i replace the text with "$gameParty.gold()", but the gold amount won't refresh
i want to refresh the gold amount as soon as the amount of gold is updated, what should i do? thx!
The refresh function by default is only called when the window is created. If you want it to constantly renew its current value without having to specifically call refresh, put the drawText call in the "update" function, which will cause it to run every frame. -
Just an update for js newcomers who'll just copy/paste this as a first try:
Instead of playing around with prototype you can just create a new class extending the base one and use super to call inherited methods -
okay so question if i want to disable a main menu command would I find the way to do that in the RPG_Window.js?
-
I actually do that in my plugins now, and may add that to the original post.Just an update for js newcomers who'll just copy/paste this as a first try:
Instead of playing around with prototype you can just create a new class extending the base one and use super to call inherited methods
Yes! If you look at the windows js file, specifically at Window_Command, you'll see that the addCommand function has "enabled" as a parameter.okay so question if i want to disable a main menu command would I find the way to do that in the RPG_Window.js? -
Hi @Trihan ! RPG Maker MZ newbie here. Where do I look into the software to see its API Source code so that I can learn and make my own JavaScript plugins?? It doesn't show like how Ace did...
-
The js folder has the entire source code for your game.Where do I look into the software to see its API Source code so that I can learn and make my own JavaScript plugins??
-
LOL Now I feel so silly xDThe js folder has the entire source code for your game.
Thanks for pointing me the right direction.
Oh goshhh..I wish I could delete my question zzz -
Hey, don't feel bad, it's only easy if you know the answer. :pLOL Now I feel so silly xD
Thanks for pointing me the right direction.
Oh goshhh..I wish I could delete my question zzz
Don't hesitate to ask if you have further questions. <3 -
Ahaa, right, thanks Trihan. Now I feel better.
And yes, I'm going to ask a lot more questions.
:) -
The refresh function by default is only called when the window is created. If you want it to constantly renew its current value without having to specifically call refresh, put the drawText call in the "update" function, which will cause it to run every frame.
I'm being very slow here.
I tried removing the this.refresh(); from the "Window_MyWindow.prototype.initialize" function, and instead storing the "Scene_Map.prototype.update" function from rmmz_scenes.js into a variable (similar to how you did it for "Scene_Map.prototype.createAllWindows") and then calling the drawText from there in various ways, but I'm getting an error each time.
E.g., I've tried placing the refresh function, which houses the drawText, in the update function:
JavaScript:// Copy the update function from mmz_scenes.js, call it, and also the refresh function for text var _Scene_Map_Update = Scene_Map.prototype.update; Scene_Map.prototype.update = function(){ _Scene_Map_Update.call(this); Window_MyWindow.prototype.refresh(); }; // Define a new method called refresh on Window_MyWindow.prototype Window_MyWindow.prototype.refresh = function() { // Draw some text in the window at coordinates (0, 0) with a width equal to the window contents width and a height equal to one line of text this.drawText("This is a test message", 0, 0, this.contentsWidth(), this.lineHeight()); };
It spits out the following error:
I then thought maybe I call Window_MyWindow.prototype.drawText directly? No dice:
JavaScript:var _Scene_Map_Update = Scene_Map.prototype.update; Scene_Map.prototype.update = function(){ _Scene_Map_Update.call(this); Window_MyWindow.prototype.drawText("This is a test message", 0, 0, this.contentsWidth(), this.lineHeight()); };
Replacing "this.contentsWidth()" with "Window_MyWindow.prototype.contentsWidth()" (same for lineHeight) circles back to the bitmap error.
UnrelatedUnrelated, but I wasn't able to get your original "Window_MyWindow.prototype.initialize" working as MZ was expecting a rectangle for some reason? Ended up changing it to this, which worked:
JavaScript:// Define a new method called initialize on Window_MyWindow.prototype Window_MyWindow.prototype.initialize = function(x, y, width, height) { // Create a new Rectangle object with the given x, y, width and height parameters var rect = new Rectangle(x, y, width, height); // Call the initialize method of Window_Base with this object and the rect object as arguments Window_Base.prototype.initialize.call(this, rect); // Call the refresh method of this object //this.refresh(); //commented to try the update method instead so anything within is updated in realtime };
PS. Great introductory tutorial by the way. -
First tip - any time you're looking at errors in the game, you need to use the console. Just seeing the error message by itself is almost always next to useless. Press F12, go to the Console tab, and you'll see the full error trace that gives you the exact line of code from the exact file that produced the error, as well as the sequence of functions that led up to it.
This is incorrect.JavaScript:// Copy the update function from mmz_scenes.js, call it, and also the refresh function for text var _Scene_Map_Update = Scene_Map.prototype.update; Scene_Map.prototype.update = function(){ _Scene_Map_Update.call(this); Window_MyWindow.prototype.refresh(); };Window_MyWindow.prototype.refreshis a function definition, not the syntax for calling it. That's saying a name of a kind of object and expecting something to happen from it - like "Automobile, open door!" In order for anything to actually happen, you need a point of reference to a specific object: "Open the door of my Ford."
You need to have created an actual instance of that object type in your game and have a point of reference to it. You may want to read more through the default scenes and see how they handle windows. For an example of a scene that has attached windows:
Code:Scene_Item.prototype.create = function() { Scene_ItemBase.prototype.create.call(this); this.createHelpWindow(); this.createCategoryWindow(); this.createItemWindow(); this.createActorWindow(); };
After those functions are run, the scene you're using has a member variable, e.g.this._actorWindowthat has been created and set to a Window_Item type. You can then run methods from it such asthis._actorWindow.refresh();
Again, you can't just call a method of an object type without having an instance of that object you're referencing.I then thought maybe I call Window_MyWindow.prototype.drawText directly? No dice:
JavaScript:var _Scene_Map_Update = Scene_Map.prototype.update; Scene_Map.prototype.update = function(){ _Scene_Map_Update.call(this); Window_MyWindow.prototype.drawText("This is a test message", 0, 0, this.contentsWidth(), this.lineHeight()); };
For a simple example, look at one of JavaScript's included functions - the push method of arrays. If you just callpush(5)you'll get a reference error, because push is a method of an object type and doesn't do anything unless it's called from an instance of that type.
However, if you dovar test=new Array;(and there's simpler notation for this, but for the sake of consistency with the above), now you have a point of reference to an instance of an array object. And now you can saytest.push(5);and it has an actual object to work with.
As far as:
Well, that's patently true. In addition to confusion between calling a function declaration and having a variable you're calling a method of, you also seem to have some confusion between what you're actually inserting your code into. You wrote the above code inside of the update() method of Scene_Map. Scenes don't have a contentsWidth() method, windows do.
Correct, MZ slightly changed the way windows are drawn.Unrelated, but I wasn't able to get your original "Window_MyWindow.prototype.initialize" working as MZ was expecting a rectangle for some reason?
This may be helpful reading for you. But you're also trying to jump into something fairly complex in how RPG Maker handles the interactions between windows and scenes. This article should at least help in terms of the concepts and syntax.
W3Schools.com -
Appreciate the detailed response, that's lead me in the right direction!Again, you can't just call a method of an object type without having an instance of that object you're referencing.
Interestingly, I appear to be endlessly drawing text on top of the old, as opposed to updating the current one.
I've tried clear() to no avail :aswt: I imagine it's the same issue you mentioned above, where I'm calling a function on the wrong object.
JavaScript:var textDrawn = false; // Define a new method called refresh on Window_MyWindow.prototype Window_MyWindow.prototype.refresh = function() { // Draw the amount of gold that the party has at coordinates (0, 0) with a width equal to the window contents width and a height equal to one line of text if(textDrawn == true){ console.log("Text is already drawn") //this.clear(); // Doesn't work... this.drawText($gameParty.gold(), 0, 0, this.contentsWidth(), this.lineHeight()); // Gold as an example of something I can easily update and see reflected in the box }else{ console.log("First time drawing text") this.drawText($gameParty.gold(), 0, 0, this.contentsWidth(), this.lineHeight()); // Gold as an example of something I can easily update and see reflected in the box textDrawn = true; } };
Full Plugin CodeJavaScript:/*: * @target MZ * @plugindesc Testing plugins. * @author holymotherofchristsendhelp */ // Define a new function called Window_MyWindow function Window_MyWindow() { // Call the initialize method of this function with the given arguments this.initialize.apply(this, arguments); } // Set the prototype of Window_MyWindow to be an object that inherits from Window_Base Window_MyWindow.prototype = Object.create(Window_Base.prototype); // Set the constructor property of Window_MyWindow.prototype to be Window_MyWindow Window_MyWindow.prototype.constructor = Window_MyWindow; // Define a new method called initialize on Window_MyWindow.prototype Window_MyWindow.prototype.initialize = function(x, y, width, height) { // Create a new Rectangle object with the given x, y, width and height parameters var rect = new Rectangle(x, y, width, height); // Call the initialize method of Window_Base with this object and the rect object as arguments Window_Base.prototype.initialize.call(this, rect); // Call the refresh method of this object this.refresh(); }; var textDrawn = false; // Define a new method called refresh on Window_MyWindow.prototype Window_MyWindow.prototype.refresh = function() { // Draw the amount of gold that the party has at coordinates (0, 0) with a width equal to the window contents width and a height equal to one line of text if(textDrawn == true){ console.log("Text is already drawn") //this.clear(); // Doesn't work... this.drawText($gameParty.gold(), 0, 0, this.contentsWidth(), this.lineHeight()); // Gold as an example of something I can easily update and see reflected in the box }else{ console.log("First time drawing text") this.drawText($gameParty.gold(), 0, 0, this.contentsWidth(), this.lineHeight()); // Gold as an example of something I can easily update and see reflected in the box textDrawn = true; } }; // Store the original createAllWindows method of Scene_Map.prototype in a variable var _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows; // Overwrite the createAllWindows method of Scene_Map.prototype with a new function Scene_Map.prototype.createAllWindows = function() { // Call the original createAllWindows method with this object as argument _Scene_Map_createAllWindows.call(this); // Call the createMinimapWindow method of this object only once if (!this._minimapCreated) { this.createMinimapWindow(); this._minimapCreated = true; // Set a flag so I don't call it again console.log("I was called"); } }; // Define a new method called createMinimapWindow on Scene_Map.prototype Scene_Map.prototype.createMinimapWindow = function() { // Create a new instance of Window_MyWindow with some parameters for x, y, width and height this.myWindow = new Window_MyWindow(0, 0, 200, 200); // Add the myWindow object to the children array of this object this.addChild(this.myWindow); }; // Store the original update method of Scene_Map.prototype in a variable var _Scene_Map_update = Scene_Map.prototype.update; // Overwrite the update method of Scene_Map.prototype with a new function Scene_Map.prototype.update = function() { // Call the original update method with this object as argument _Scene_Map_update.call(this); // Call the refresh method on the instance of Window_MyWindow this.myWindow.refresh(); };
I'm obviously very slow, apologies. First time touching JavaScript; I'm a PowerShell guy by day, which ironically uses objects... Just, not in the way mainstream OOP does, so this is all very abstract to me.
I'll get there eventually. -
TryI've tried clear() to no avail
this.contents.clear()
The best way to learn is to look at the default code.
For example, this is how Window_Help refreshes its content.
Code:Window_Help.prototype.refresh = function() { const rect = this.baseTextRect(); this.contents.clear(); this.drawTextEx(this._text, rect.x, rect.y, rect.width); }; -
That did it! And noted, will keep that in mind.
-
thanks endlessly for this!! an absolute dream of a post <33
-
I’m very very new to game development and I know that there are plugins that already do what I’m about to ask but I’m trying to learn scripting by doing it myself. I’m trying to create a system to give my on map enemies line of sight and then determine whether the battle is an ambush or preemptive attack based on the direction the player and enemy are facing at battle start. I’m not sure if I would need to look into the actual game files like previously stated or if I’m actually introducing some new code into the game. As it stands I’m using code already to give my enemies line of sight but I’d like to put it all together into a plugin that I could then create skills to interact with the line of sight.