discussion on how to 'properly' code in RM MV

Iavra

Veteran
Veteran
Joined
Apr 9, 2015
Messages
1,797
Reaction score
863
First Language
German
Primarily Uses
Though in an actual game, there will be more plugins than just yours, making it worthwhile to optimize (because others might not, so the least thing you can do is to ensure, thattheir performance impact doesn't snowball). And while it doesn't matter that much in battle, real games are usually much more complex, than our 17x13 (maybe 18x13, if you want to test scrolling behaviour) empty test maps.
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,789
Reaction score
941
First Language
Chinese
Primarily Uses
N/A
Though in an actual game, there will be more plugins than just yours, making it worthwhile to optimize (because others might not, so the least thing you can do is to ensure, thattheir performance impact doesn't snowball). And while it doesn't matter that much in battle, real games are usually much more complex, than our 17x13 (maybe 18x13, if you want to test scrolling behaviour) empty test maps.
So I'll still optimize even if it just reduces the final load by 1ms per frame, as it's still detectable.


Back in optimizing DoubleX RMVXA Enhanced YSA Battle System: Classical ATB, the average fps started from about 87. Then I began to optimize bit by bit.


While most major optimization only led to roughly 1 -2 average FPS boost, I still persisted and continued to optimize. Eventually the average fps is now boosted to about 117.


Although 1-2 average FPS boost seem tiny, the combined effect from many such tiny boost, which is 30 FPS boost, is indeed massive.


Nevertheless, I still think that performance isn't always so important that I can freely sacrifice any other important code quality without solid reasons.


I usually compare maximally optimized codes and 100% unoptimized ones. If there are absolutely not even minimally detectable performance difference between them at all, then I'll generally leave performance optimization to the future. I feel that it's a working compromise between writing unperformant codes and being a performance freak.


To prevent many such undetectable differences to be the last straw that makes performance drop detectable, I can even multiply that difference using a reasonably large number.


For example, to show the performance difference between a for loop and an Array.prototype.forEach which are run per battler per frame:


// Original code
for (var i = start; i < end; i++) { doesSomething(array); }

Code:
// Original code
array.forEach(function(element) { doesSomething(element); });

I can change those original codes into this:


// Modified code
for (var i = 0; i < 100; i++) {
for (var i = start; i < end; i++) { doesSomething(array); }
}

Code:
// Modified code
for (var i = 0, i < 100; i++) {
    array.forEach(function(element) { doesSomething(element); });
}

Of course some tweaks might be needed for doesSomething, which might be supposed to be run at most once per battler per frame.


If 1 plugin's using the above codes, the above test can somehow mimic the performance effect of using 100 such plugins.


Here 100 should be a reasonably large enough number, as few projects will ever have 100+ plugins all having performance critical sections.
 
Last edited by a moderator:

nio kasgami

VampCat
Veteran
Joined
May 21, 2013
Messages
8,949
Reaction score
3,042
First Language
French
Primarily Uses
RMMV
If it is totally not readable to you, that means you don't know the basics of JavaScript yet then. While reading DoubleX's post, I got the idea right away and tried to subsequently code like it myself.
@Milenathis not because I don't understand his jigjag not mean I don't understand JS I just learned differently


The fact I understand the difference it's jagged in ALL compact material and he writted a 'essay' take in count that my english is not my native language so when people do Walls of text it's will be obvious I will get lost.


I do know how works container and the logic Double X done here it's the 10000 lines explanation he provide with who just lost me. (no offense DoubleX lol)


and Honestly his coding could use a little more of cleaning but after this just my tendancy to use clean code who speak here.


Anyway's let's return to the topic of what I succeed to read about performance (of what I understand) 


I understand the logics of the for loops and with that a each loop in the same times


it's not in a way's kinda counter productive? Maybe it's offers a little more of performance but it's seem a hassle to play with.


what's the 'improvement' we get? do it's really 'value' the improvement :/?
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,848
First Language
English
Excessive commenting can make it difficult to read the actual code, especially if there is no syntax highlighting.


I would say that while comments are good, it is not necessary to point out where a 3-line method has started and ended.


It should be clear from the syntax.


// start of myFunc
function myFunc() {
return 1;
}
// end of myFunc


Those comments are largely redundant and not useful.
 
Last edited by a moderator:

nio kasgami

VampCat
Veteran
Joined
May 21, 2013
Messages
8,949
Reaction score
3,042
First Language
French
Primarily Uses
RMMV
@Tsukihime lol!  I found those comment useless generally I comment like that and in really order it's permit to make the code 'breathing' 


//----------------------------------------------------------------------------
// ○ new function: setNumber
//----------------------------------------------------------------------------
// * It's create the plugin command into number but also permit to add maths
// * conversion.
// * They have multiple options who permit to quick convert your number in
// * math process. Process who are :
// * 'default' or "" : transform the param string in a regular number.
// * 'floor' : round your number to the lowest round. E.g : 3.9 -> 3
// * 'ceil' : round your number to the highest round. E.g : 3.9 -> 4
// * 'round' : round your number to the nearest values. E.g : 5.35 -> 5
// * 'topercent' : convert your number in a Percentage value.
// * 'todecimal' : convert your percent in a decimal value.
// * 'topi' : convert your number in a PI value.
// * 'abs' : return the absolute value of your number
// *
// * You can use this method by doing this.setNumber or $emoji.setNumber.
// * the function works like this :
// * this.setNumber(Plugin_var,ParamName,type,max_number);
// * The definition of these arguments are :
// * Plugin_var : The variable you stored your plugin name.
// * ParamName : The Name of your Param command.
// * Type : Set the Number process you want to do (set to 'default' for reg number).
// * max_number : set the limit of your number (use only for topercent and todecimal).
// * (PS : you can setup a varaible for max_number. E.g : this.maxHP)
//
Emoji.setNumber = function(plugin,param,type,maxNumber){
var number = Number(plugin[param]);
switch(type.toLowerCase()){
// Get the regular number.
default :
return number;
break;
// Get the low round.
case 'floor' :
return Math.floor(number);
break;
// Get the uppest round.
case 'ceil' :
return Math.ceil(number);
break;
// Round to the nearest value.
case 'round' :
return Math.round(number);
break;
// Convert number to percent.
case 'topercent' :
return (number / maxNumber) * 100;
break
// Convert the percent in float number.
case 'todecimal' :
return (number / 100) * maxNumber;
break;
// Convert the number in PI value.
case 'topi' :
return Math.PI(number);
break;
// Return the absolute value of the number.
case 'abs' :
return Math.abs(number);
break;
case 'tocos' :
return Math.cos(number);
break;
case 'tosin' :
return Math.sin(number);
break;
case 'totan' :
return Math.tan(number);
break;
}
};


the comment is the older one but it's nice to have clear comment instead of : 
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,848
First Language
English
I use in-line comments to explain the purpose of a piece of code if it is not obvious.
When I look at larger pieces of code, it is usually not immediately obvious "why" something is being done the way it's done.


For example, you can see that a variable is being assigned to, and some numbers are being added, but why are you doing that?


Why do I need to have an if/else here?


Why do I need this condition?


It is perfectly possible that the logic is wrong, but unless you understood the purpose of the code, simply looking at what it's doing won't tell you whether it's correct or not.



Perhaps it is lack of experience, but determining why something is done based on what is being done is pretty slow for me.


There is that extra step of having to first understand what the code is doing, and then think about what the code *should* be doing, and then determine whether it's correct.


It's pretty much reverse engineering at this point, and even then, your conclusions may or may not be correct.
 
Last edited by a moderator:

xDGameStudios

Veteran
Veteran
Joined
Sep 15, 2012
Messages
102
Reaction score
60
First Language
Portuguese
Cound't we enchance the performance of the base RMMV engine by changing the for each to for loops?! and those things? how can they didn't do it already.. it isn't that much hard to read..

I'm thinking of a way load note tags... right now I use the this method:


PLUGIN 1:
loadNoteTags() {
for (var i = 1; i < $dataEnemies.lenght; i++)
{
//do stuff
}
}

PLUGIN 2:
loadNoteTags() {
for (var i = 1; i < $dataEnemies.lenght; i++)
{
//do stuff
}
}

PLUGIN 2:
loadNoteTags() {
for (var i = 1; i < $dataEnemies.lenght; i++)
{
//do stuff
}
}


But the loop is called a lot of times this way, isn't it?
 


PLUGIN CORE:
loadNoteTags = function() {
for (var i = 1; i < $dataEnemies.lenght; i++)
{
loadEnemyTags($dataEnemies);
}
}

loadEnemyTags = function (enemy) {
//do stuff
}

PLUGIN 1:

_loadEnemyTags = loadEnemyTags;
loadEnemyTags = function(enemy) {
_loadEnemyTags.call(this, enemy);
//load plugin 1 notetags
}

PLUGIN 2:

_loadEnemyTags = loadEnemyTags;
loadEnemyTags = function(enemy) {
_loadEnemyTags.call(this, enemy);
//load plugin 1 notetags
}


Would it be better or would the excessive CALL use be bad?! it is just to load data so it is not that important :)  but it's just an ideia. NOTE: the alias are enclused inside the module and are well accessed and the names do not conflict ;)

I'll also ask something: in the damage calculation for the action, there is a function called when the item/skill doesn't have element type.... the function is elementsMaxRate.... I wanted to know the elementId corresponding to that max rate. The only thing I can think of is do another run using a reduce:


Game_Action.prototype.elementsMaxRateId = function (target, elements) {
return elements.reduce(function (prev, current) {
return target.elementRate(prev) > target.elementRate(current) ? prev : current;
}, 0);
};


What do you think? I think it is a little ugly (no?) xD
 

xDGameStudios

Veteran
Veteran
Joined
Sep 15, 2012
Messages
102
Reaction score
60
First Language
Portuguese
My plugins are structured in a similar way than Hime's. Since i started my particle engine, my standard looks like this:



(function($, undefined) {
"use strict";
// check for dependencies.

// read plugin parameters, if any.

// declare private functions, that are not available for public.

$.MODULE = { // declare public classes/functions.
Class: function() { this.initialize(); }
};

$.MODULE.Class.prototype = { // define classes

initialize: function() {

}

};

// extend existing classes, if any.

// do static initialization, that depends on classes.

})(this.IAVRA || (this.IAVRA = {})); // create namespace, if it doesn't already exist.


The "undefined" parameter isn't really needed, though in older browsers it was possible to overwrite the global undefined, which is preserved that way.


Speaking of Yanfly, personally i think there's a lot of bad practice in that plugins:


- No encapsulation, forcing them to store everything inside the namespace, like this:



for (Yanfly.i = 1; Yanfly.i < 21; Yanfly.i += 1)


- No strict mode, making eval dangerous (among others).


- No technical documentation (at all).


- Adding lots of functions to existing classes, that aren't prefixed or uniquely marked in any way, which in turn forces all other plugin writers to do so.


There are some minor issues, too, like suboptimal looping or leaving our optional blocks, like this:



if (command === 'LetterSoundReset') $gameSystem.initMessageSounds();




Don't misunderstand me, i have huge respect for all the work Yanfly is putting into making all of these plugins, i simply don't agree with their standards.
I like this style ;)  how do you do dependencies checking? do you throw error? another question I wanted to ask is regarding plugin parameters how do you do it? I mean the variables are they local, with function access for the public ones? 


and how about registering your plugin? I see a lot of plugins using


Imported.Blah = true;


for latter know I you included this script... do you have to do this? 'Static initialisation'... what you mean by that? if I want to create a new kind of window... for instance:

WINDOW_DETAILS

and I want it to become accessible to other plugins so then can inherit from it.. do I need to add something to the template?! Thank so much ;)  
 
Last edited by a moderator:

Iavra

Veteran
Veteran
Joined
Apr 9, 2015
Messages
1,797
Reaction score
863
First Language
German
Primarily Uses
So far, i've only needed to check for my own plugins, so i do it like this:


(function($, undefined) {
"use strict";

if(!$.PARTICLE) { throw new Error("This plugin depends on 'Iavra Particle - Core'."); }

//...

})(this.IAVRA || (this.IAVRA = {}));


I'm throwing an error, because the plugin can't work without the core engine, but i could also set a variable depending on if a plugin is present or not. Personally, i don't need "Imported", but it might be useful for other plugins.


Static initialization is everything, that depends on previous declared classes being defined. For example singletons, that i want to instantiate directly.


By default, all of my classes are available for public usage via my namespace, which is provided as the first argument to the anonymous function. "this" in that case referes to the window object, but you could use "window" as well, which is more obvious. Beware, that if you want to store instanzes of a given class into the savefile, you might need to directly register them on the window (see my Self Variables plugin). For me this also counts as "static initialization".
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

This is relevant so much I can't even!
Frostorm wrote on Featherbrain's profile.
Hey, so what species are your raptors? Any of these?
... so here's my main characters running around inside "Headspace", a place people use as a safe place away from anxious/panic related thinking.
Stream will be live shortly! I will be doing some music tonight! Feel free to drop by!
Made transition effects for going inside or outside using zoom, pixi filter, and a shutter effect

Forum statistics

Threads
105,999
Messages
1,018,219
Members
137,777
Latest member
Bripah
Top