ES6 class not inherited after load save data?

Rholin

Warper
Member
Joined
Jun 26, 2015
Messages
3
Reaction score
1
First Language
Chinese
Primarily Uses
Update: I just found the solution:
When the game load the save data, it uses JsonEx._decode() to rebuild the objects. To find the corresponding class constructor, the statement var constructor = window[value['@']]; is used:
Code:
JsonEx._decode = function(value, circular, registry) {
    var type = Object.prototype.toString.call(value);
    if (type === '[object Object]' || type === '[object Array]') {
        registry[value['@c']] = value;
        if (value['@']) {
            var constructor = window[value['@']];
            if (constructor) {
                value = this._resetPrototype(value, constructor.prototype);
            }
        }
        for (var key in value) {
            if (value.hasOwnProperty(key)) {
                if(value[key] && value[key]['@a']){
                    //object is array wrapper
                    var body = value[key]['@a'];
                    body['@c'] = value[key]['@c'];
                    value[key] = body;
                }
                if(value[key] && value[key]['@r']){
                    //object is reference
                    circular.push([key, value, value[key]['@r']])
                }
                value[key] = this._decode(value[key], circular, registry);
            }
        }
    }
    return value;
};
However, a ES6 declared class is not a property of window, so this method fails. Instead, we could use eval() to get the correct constructor of a ES6 declared class:
Code:
let constructor = window[value['@']] || eval(value['@']);




I made an ES6 class to manage the actor parameters:
Code:
System.Param.Types = {
    mhp: 0, // max hp 500 + 100 * lv (600-8500)
    mmp: 1, // max mp 100 + 10 * lv (100-900)
    pat: 2, // physical attack 50 + 10 * lv (50-850)
    mat: 3, // magical attack 50 + 10 * lv (50-850)
    pdf: 4, // physical defense 20 + 8 * lv (20-660)
    mdf: 5, // magical defense 20 + 8 * lv (20-660)
    cri: 6, // critical chance 5 + 1 * lv (5-85)
    eva: 7, // evade chance 1 + 1 * lv (1-80)
    spd: 8  // speed 50 + 1 * lv (50-130)
};

class BasicParam {
    /**
     *
     * @param params {Array/Undefined}
     * @param owner {Game_BattlerBase}
     */
    constructor(params, owner) {
        if (params) {
            if (params.length === this.paramNum) {
                this.values = params;
            } else {
                throw 'invalid params length: ' + params.length;
            }
        } else {
            this.values = new Array(this.paramNum);
            this.clear();
        }
        if (owner) this._owner = owner;
    }

    get paramTypes() {
        return System.Param.Types;
    }
    get paramNum() {return Object.keys(this.paramTypes).length; }
    get owner() {return this._owner;}

    /**
     *
     * @param type {String/Number} type can be index integer or param's name
     * @returns {Number}
     */
    getValue(type) {
        let index = ((typeof type) === 'string')? this.paramTypes[type] : type;
        return this.values[index];
    }

    /**
     *
     * @param type {String/Number} type can be index integer or param's name
     * @param value {Number}
     */
    setValue(type, value) {
        let index = ((typeof type) === 'string')? this.paramTypes[type] : type;
        this.values[index] = value;
    }

    clear() {
        for (let i = 0; i < this.paramNum; i++) {
            this.values[i] = 0;
        }
    }

    /**
     *
     * @param adder {BasicParam}
     */
    addByParam(adder) {
        for (let i = 0; i < this.paramNum; i++) {
            this.values[i] += adder.values[i];
        }
    }

    /**
     *
     * @param scaler {BasicParam}
     */
    scaleByParam(scaler) {
        for (let i = 0; i < this.paramNum; i++) {
            this.values[i] += Math.floor(this.values[i] * scaler.values[i] / 100);
        }
    }

    /**
     *
     * @param type {String/Number} type can be index integer or param's name
     * @param value {Number}
     */
    addValue(type, value) {
        let index = ((typeof type) === 'string')? this.paramTypes[type] : type;
        this.values[index] += value;
    }
}
It works well when I test the game, but after I load a save data, the param of a character is not a BasicParam instance Any more, as is showed in the picture:
does this mean I cannot use an ES6 class? or there is a way to solve that.
 
Last edited:

mlogan

Global Moderators
Global Mod
Joined
Mar 18, 2012
Messages
15,354
Reaction score
8,533
First Language
English
Primarily Uses
RMMV

I've moved this thread to Learning Javascript. Please be sure to post your threads in the correct forum next time. Thank you.

 

Aloe Guvner

Walrus
Veteran
Joined
Sep 28, 2017
Messages
1,628
Reaction score
1,115
First Language
English
Primarily Uses
RMMV

Rholin

Warper
Member
Joined
Jun 26, 2015
Messages
3
Reaction score
1
First Language
Chinese
Primarily Uses
1.)
Why are you doing
Code:
$gameActors.actor('MELINA')
The parameter for that method should be a number of the actor ID, not a string of their name.

Reference:
https://forums.rpgmakerweb.com/index.php?threads/rpg-maker-mv-script-call-list.46456/
https://kinoar.github.io/rmmv-doc-web/classes/game_actors.html#actor

2.)
Show us where you assign the value to (actor).totalParam
the codes related are here:
Code:
System.Param.Game_BattlerBase_initMembers = Game_BattlerBase.prototype.initMembers;
Game_BattlerBase.prototype.initMembers = function() {
    this._basicParam = new BasicParam(null, this);
    this._homeParam = new BasicParam(null, this);
    this._totalParam = new BasicParam(null, this);
    this._tempPlusParam = new BasicParam(null, this);
    this._tempScaleParam = new BasicParam(null, this);
    System.Param.Game_BattlerBase_initMembers.call(this);
};

Object.defineProperties(Game_BattlerBase.prototype, {
    totalParam: {
        get: function() {
            if (SceneManager._scene instanceof  Scene_Battle) {
                return this._totalParam;
            } else {
                return this._homeParam;
            }
        }
    }
});
I override some functions (include $gameActor.actor()) so they behave in a different way. But I think this is not important for the question because the codes work well if I start a new game. The problem should be related to load save data method

Update: I found a solution and posted it in the main thread, thanks all the way!
 
Last edited:

Aloe Guvner

Walrus
Veteran
Joined
Sep 28, 2017
Messages
1,628
Reaction score
1,115
First Language
English
Primarily Uses
RMMV
Ah ok, I thought there could be an issue with getting a reference to the correct actor but if you overwrote Game_Actors.prototype.actor then that's fine.

Good catch, it's one of the few differences between the "class" keyword and the "old" way of creating a function constructor.

If you wanted to avoid eval, you could explicitly set the window object to have a reference to the constructor of your class:

Code:
window.BasicParam = class BasicParam { ... }
Another way would be to keep all of your custom classes that you need to get the constructors for in their own object, like this:

Code:
const myClasses = {
   BasicParam: class BasicParam { ... }
}
In this case "eval" is probably fine but generally you'll want to avoid it.
 

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

Latest Threads

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,868
Messages
1,017,066
Members
137,576
Latest member
SadaSoda
Top