JUMP INTO JAVASCRIPT PART 9

In which a year and a half later we finally look at game objects.

  • Trihan
  • 06/06/2019 02:02 AM
  • 475 views
It's been a year and a half. Some of you probably thought I was dead. But finally, finally, it's time. It's time to capture a wild piece of JavaScript, cut it open and poke around inside. It's time to...


Jump into Javascript

You'll have to be patient with me while I find my bearings; not having written a tutorial in over a year, I may be a bit rusty. But anyway, when last I signed off, we were FINALLY done with rpg_scenes. I said the next thing to look at would be rpg_objects, so without further ado...

Game_Temp

This class is used for temporary data, as the name suggests. Stuff you might need to keep track of but don't need to include in a save game. I'll hit the ground running since even after all this time I don't imagine I need to cover basic stuff like constructors any more.

Game_Temp.prototype.initialize = function() {
    this._isPlaytest = Utils.isOptionValid('test');
    this._commonEventId = 0;
    this._destinationX = null;
    this._destinationY = null;
};


So the initialize function is just setting up some class variables that will be used later. _isPlaytest is a flag that determines whether the engine is running in test mode or not (which is what allows stuff like phasing through tiles using ctrl and bringing up the debug menu with F9). It's set to the value of calling a function called isOptionValid in the Utils class, which we'll cover when we get to rpg_core.js. It passes in 'test' as a parameter, which is what will check for test play being active. We're also setting _commonEventId to 0, a variable that will track reserved common events. And finally, we're setting _destinationX and _destinationY to null, which are used to set the player's destination tile.

Game_Temp.prototype.isPlaytest = function() {
    return this._isPlaytest;
};


isPlaytest is a fairly simple function that just returns the value of the internal _isPlaytest variable. We've covered wrapper functions before but feel free to let me know in the comments whether you need a primer on this.

Game_Temp.prototype.reserveCommonEvent = function(commonEventId) {

this._commonEventId = commonEventId;
};


This function "reserves" a common event, which basically just queues it up to be processed once the engine is able to do so. It takes one parameter, commonEventId, which as the name suggests is the ID of a common event from the database. It sets the internal _commonEventId variable to the value of the passed-in parameter.

Game_Temp.prototype.clearCommonEvent = function() {
    this._commonEventId = 0;
};


Clearing a common event reservation is pretty simple; we just set _commonEventId to 0, which as we've just covered above is its default value.

Game_Temp.prototype.isCommonEventReserved = function() {
    return this._commonEventId > 0;
};


Another "check" function, isCommonEventReserved will tell us whether an event is reserved or not. It's a simple test: if the internal _commonEventId variable's value is greater than 0, then yes, we've reserved a common event. Otherwise no, we have not.

Game_Temp.prototype.reservedCommonEvent = function() {
    return $dataCommonEvents[this._commonEventId];
};


This function will return the actual common event object that the reserved ID represents. $dataCommonEvents is the variable which contains those objects, and is an array. We're accessing the element with an index equal to the internal _commonEventId value. Once we get into rpg_managers.js, we'll see how the $data variables are populated, but for now suffice to say it's getting its data from CommonEvents.json.

Game_Temp.prototype.setDestination = function(x, y) {
    this._destinationX = x;
    this._destinationY = y;
};


This function sets a destination tile for the player given two parameters, x and y. Quite simply sets the _destinationX and _destinationY internal variables to the supplied values.

Game_Temp.prototype.clearDestination = function() {
    this._destinationX = null;
    this._destinationY = null;
};


Clearing the destination is similarly straightforward: we're just setting the two variables back to their default value of null.

Game_Temp.prototype.isDestinationValid = function() {
    return this._destinationX !== null;
};


isDestinationValid is a test function which will tell you whether a valid destination is set, and all it does is returns whether _destinationX is not null. If it isn't, we'll return true; if it is null, we'll return false. Note that this does no checking on whether the destination is valid from a passability standpoint; all it's checking is whether the X variable has a value in it.

Game_Temp.prototype.destinationX = function() {
    return this._destinationX;
};

Game_Temp.prototype.destinationY = function() {
    return this._destinationY;
};


And finally we have a couple of wrapper functions for the internal destination variables, and they simply return those internal values.

That's it for Game_Temp! It's an incredibly extensible class, and you'll likely find that if you're adding additional features to your game that need tracked but not saved (and you aren't using your own proprietary classes) this is a good home for them.

Game_System

This class is responsible for system data, the nature of which we're about to go into.

Game_System.prototype.initialize = function() {
    this._saveEnabled = true;
    this._menuEnabled = true;
    this._encounterEnabled = true;
    this._formationEnabled = true;
    this._battleCount = 0;
    this._winCount = 0;
    this._escapeCount = 0;
    this._saveCount = 0;
    this._versionId = 0;
    this._framesOnSave = 0;
    this._bgmOnSave = null;
    this._bgsOnSave = null;
    this._windowTone = null;
    this._battleBgm = null;
    this._victoryMe = null;
    this._defeatMe = null;
    this._savedBgm = null;
    this._walkingBgm = null;
};


The initialize function is simple enough, just setting up several internal variables. _saveEnabled determines whether the player can save their game from the menu or not, _menuEnabled determines whether the player can access the menu from the map, _encounterEnabled determined whether random encounters can happen, and _formationEnabled determines whether the player can access the formation submenu. They all default to true.

_battleCount is the number of battles the player has been in, _winCount is the number they've been victorious in, _escapeCount is the number of battles from which they've fled, and _saveCount is the number of times they've saved. These all default to 0.

_versionId also defaults to 0, but it works in a somewhat unique way we'll look at shortly.

_framesOnSave is the number of frames that had elapsed in the game when it was saved. This is important because this is how "play time" is measured. The engine has no concept of actual time, so instead we divide the number of frames that have elapsed by 60 to get the number of seconds the game has been running (assuming the default rate of 60 FPS).

_bgmOnSave and _bgsOnSave store the BGM/BGS that were playing when the player saved. This is so what music and sound effects can be properly loaded after resuming the game.

_windowTone keeps track of...well, the tone of windows. _battleBgm tracks the currently BGM used in battles, _victoryMe tracks the victory theme, _defeatMe tracks the theme used in a game over, _savedBgm retains a BGM and _walkingBGM retains the map BGM. We'll see more of this in coming episodes as well, but for now all we need know is that they all default to null.

Game_System.prototype.isJapanese = function() {
    return $dataSystem.locale.match(/^ja/);
};

Game_System.prototype.isChinese = function() {
    return $dataSystem.locale.match(/^zh/);
};

Game_System.prototype.isKorean = function() {
    return $dataSystem.locale.match(/^ko/);
};

Game_System.prototype.isCJK = function() {
    return $dataSystem.locale.match(/^(ja|zh|ko)/);
};

Game_System.prototype.isRussian = function() {
    return $dataSystem.locale.match(/^ru/);
};


These functions check whether the game's locale matches a particular region. They should be pretty self-explanatory for the most part: isCJK is more of a catch-all that checks whether the local is Chinese, Japanese or Korean and will return true for any of the three.

Game_System.prototype.isSideView = function() {
    return $dataSystem.optSideView;
};


This function checks whether the battle system is set to side view, returning the value of the optSideView property of $dataSystem.

Game_System.prototype.isSaveEnabled = function() {
    return this._saveEnabled;
};

Game_System.prototype.disableSave = function() {
    this._saveEnabled = false;
};

Game_System.prototype.enableSave = function() {
    this._saveEnabled = true;
};


This set of functions checks whether the player can save their game, disables saving, and enables saving, by returning the value of or setting the value of the internal _saveEnabled variable.

Game_System.prototype.isMenuEnabled = function() {
    return this._menuEnabled;
};

Game_System.prototype.disableMenu = function() {
    this._menuEnabled = false;
};

Game_System.prototype.enableMenu = function() {
    this._menuEnabled = true;
};


This set is the same thing but for opening the menu.

Game_System.prototype.isEncounterEnabled = function() {
    return this._encounterEnabled;
};

Game_System.prototype.disableEncounter = function() {
    this._encounterEnabled = false;
};

Game_System.prototype.enableEncounter = function() {
    this._encounterEnabled = true;
};


Same for encounters...

Game_System.prototype.isFormationEnabled = function() {
    return this._formationEnabled;
};

Game_System.prototype.disableFormation = function() {
    this._formationEnabled = false;
};

Game_System.prototype.enableFormation = function() {
    this._formationEnabled = true;
};


...and for editing the battle formation.

Game_System.prototype.battleCount = function() {
    return this._battleCount;
};

Game_System.prototype.winCount = function() {
    return this._winCount;
};

Game_System.prototype.escapeCount = function() {
    return this._escapeCount;
};

Game_System.prototype.saveCount = function() {
    return this._saveCount;
};


These wrapper functions return the values of their respective internal variables to get the number of battles fought, battles won, battles escaped, and times saved.

Game_System.prototype.versionId = function() {
    return this._versionId;
};


This wrapper returns the internal version ID.

Game_System.prototype.windowTone = function() {
    return this._windowTone || $dataSystem.windowTone;
};

Game_System.prototype.setWindowTone = function(value) {
    this._windowTone = value;
};


This set of functions return and set the tone used for windows. windowTone will return either the value of _windowTone if it isn't null, or the windowTone property of $dataSystem otherwise. This ensures that the function will always return a value. setWindowTone takes one parameter, value, and sets _windowTone to that value.

Game_System.prototype.battleBgm = function() {
    return this._battleBgm || $dataSystem.battleBgm;
};

Game_System.prototype.setBattleBgm = function(value) {
    this._battleBgm = value;
};

Game_System.prototype.victoryMe = function() {
    return this._victoryMe || $dataSystem.victoryMe;
};

Game_System.prototype.setVictoryMe = function(value) {
    this._victoryMe = value;
};

Game_System.prototype.defeatMe = function() {
    return this._defeatMe || $dataSystem.defeatMe;
};

Game_System.prototype.setDefeatMe = function(value) {
    this._defeatMe = value;
};


This set of functions retrieve/set the battle BGM, victory ME and defeat ME. Similarly to the windowTone functioo, the retrieval wrappers will always return a value because if their internal variable doesn't contain a value, it will return the value from $dataSystem.

Game_System.prototype.onBattleStart = function() {
    this._battleCount++;
};

Game_System.prototype.onBattleWin = function() {
    this._winCount++;
};

Game_System.prototype.onBattleEscape = function() {
    this._escapeCount++;
};


These functions are technically "events", though JavaScript just uses functions for events too. They're called when a battle starts, a battle is won, or a battle is fled, and increases the appropriate internal variable by 1.

Game_System.prototype.onBeforeSave = function() {
    this._saveCount++;
    this._versionId = $dataSystem.versionId;
    this._framesOnSave = Graphics.frameCount;
    this._bgmOnSave = AudioManager.saveBgm();
    this._bgsOnSave = AudioManager.saveBgs();
};


The event that's called before saving the game does a few more things. First, _saveCount is incremented. Then _versionId is set to the versionId property of $dataSystem. Now that we're here, I'll explain that this value is randomly generated every time you save your game in the editor, and stored in System.json. _framesOnSave is set to the frameCount property of the Graphics class (which we'll see in more detail once we get to rpg_core.js). Finally, _bgmOnSave and _bgsOnSave are set to the result of calling the saveBgm and saveBgs functions of AudioManager, which we'll see when we get to rpg_managers.js.

Game_System.prototype.onAfterLoad = function() {
    Graphics.frameCount = this._framesOnSave;
    AudioManager.playBgm(this._bgmOnSave);
    AudioManager.playBgs(this._bgsOnSave);
};


The function called after loading a game does more or less the opposite of onBeforeSave: Graphics.frameCount is set to the value of the _framesOnSave variable, and the playBgm/playBgs functions of AudioManager are called, passing in _bgmOnSave and _bgsOnSave.

Game_System.prototype.playtime = function() {
    return Math.floor(Graphics.frameCount / 60);
};


As I mentioned before, by default MV runs at 60 frames per second. Therefore, the function that returns play time (the number of seconds the player has been playing for) returns the floor of the frame count divided by 60. I can't remember if I've covered it before, but just in case I haven't Math.floor is a function native to JavaScript which returns the rounded-down integer form of the number passed in to it. So say the game had been running for 32,456 frames. Divided by 60 that's 540.933, which Math.floor would return as 540.

Game_System.prototype.playtimeText = function() {
    var hour = Math.floor(this.playtime() / 60 / 60);
    var min = Math.floor(this.playtime() / 60) % 60;
    var sec = this.playtime() % 60;
    return hour.padZero(2) + ':' + min.padZero(2) + ':' + sec.padZero(2);
};


This function gets the display text for playtime, as shown on the menu. It's pretty straightforward: for hours we take the playtime divided by 60 (hours and minutes as a floating point) divided by 60 (hours). You know how time works, I'm sure. Minutes is the playtime divided by 60 MOD 60. Seconds is the playtime MOD 60. And then we return a string consisting of the hours, minutes and seconds, separated by colons, padded out with zeroes to 2 digits. padZero is a function defined in rpg_core.js, and we'll see exactly how it works once we get to that file.

Going back to our previous example, hour would be 540 / 60 / 60, which works out to 0.15 and Math.floor would return that as 0. Minutes would be 540 / 60 % 60. This will just return 9. Seconds would be 540 % 60, which is 0. So the string would be "00:09:00".

If you need a primer on modulus and why it's useful, basically it gives you the remainder after dividing two numbers. So 20 % 60 is just 20, since you can't divide 20 by 60. 80 % 60 is 20, since it divides once and then you have 20 left. You can see how this is useful when calculating time: if we have 80 minutes, we actually have 1 hour and 20, so modulus helps us break this down.

ame_System.prototype.saveBgm = function() {
    this._savedBgm = AudioManager.saveBgm();
};

Game_System.prototype.replayBgm = function() {
    if (this._savedBgm) {
        AudioManager.replayBgm(this._savedBgm);
    }
};

Game_System.prototype.saveWalkingBgm = function() {
    this._walkingBgm = AudioManager.saveBgm();
};

Game_System.prototype.replayWalkingBgm = function() {
    if (this._walkingBgm) {
        AudioManager.playBgm(this._walkingBgm);
    }
};

Game_System.prototype.saveWalkingBgm2 = function() {
	this._walkingBgm = $dataMap.bgm;
};


Finally we have a set of functions for saving and playing various BGMs. They should be pretty self-explanatory at this point: to save a BGM we call AudioManager.saveBgm and store the result in a given internal variable, and to replay a BGM we check whether the internal variable has a value and if so call replayBgm passing that variable in as the parameter. saveWalkingBgm2 just resets the walking BGM to whatever the map setting is in the editor.

That's Game_System done!

Game_Timer

This is a pretty short class, responsible for handling the built-in timer you can manipulate with event commands.

Game_Timer.prototype.initialize = function() {
    this._frames = 0;
    this._working = false;
};


The initialize function just dimensions two variables: _frames, which defaults to 0, and _working, which defaults to false. As the names suggest, these are to track how many frames the timer will run for, and whether the timer is currently "working" or active.

Game_Timer.prototype.update = function(sceneActive) {
    if (sceneActive && this._working && this._frames > 0) {
        this._frames--;
        if (this._frames === 0) {
            this.onExpire();
        }
    }
};


The update function for the timer takes one parameter, sceneActive. We've actually seen this in the update functions for Scene_Map and Scene_Battle, so you should already have an idea of where the value comes from. The function is pretty simple; if the passed-in sceneActive value is true AND the _working variable is true AND _frames is greater than 0, we decrement _frames. Then, if _frames is equal to 0, we call the onExpire function, which we'll get to in a sec.

Game_Timer.prototype.start = function(count) {
    this._frames = count;
    this._working = true;
};

Game_Timer.prototype.stop = function() {
    this._working = false;
};


The start and stop functions are pretty simple too. start takes one parameter, count, which is the number of frames you want the timer to run for. We set _frames to the passed-in count value, and _working to true to show that the timer is running. stop simply sets _working to false.

Game_Timer.prototype.isWorking = function() {
    return this._working;
};


The check function isWorking just returns whether _working is true or false, which will tell us whether the timer is started or stopped.

Game_Timer.prototype.seconds = function() {
    return Math.floor(this._frames / 60);
};


This function gets the number of seconds that have elapsed since the timer was started, by returning the floor of dividing _frames by 60

Game_Timer.prototype.onExpire = function() {
    BattleManager.abort();
};


onExpire is the function which is called when the frame count reaches 0, as we saw in update. It calls the abort function of BattleManager, which we'll see in detail when we get to rpg_managers.js but for now all you need to know is that it processes a battle ending.

So ends Game_Timer! One more class and I think I'll wrap it up for this episode.

Game_Message

This class handles the text window and display thereof. Since all of your dialogue, information message etc. will likely be done in that window, this is one of the most important classes in the engine.

Game_Message.prototype.initialize = function() {
    this.clear();
};


The initialize function just calls a function called clear, which looks like...

Game_Message.prototype.clear = function() {
    this._texts = [];
    this._choices = [];
    this._faceName = '';
    this._faceIndex = 0;
    this._background = 0;
    this._positionType = 2;
    this._choiceDefaultType = 0;
    this._choiceCancelType = 0;
    this._choiceBackground = 0;
    this._choicePositionType = 2;
    this._numInputVariableId = 0;
    this._numInputMaxDigits = 0;
    this._itemChoiceVariableId = 0;
    this._itemChoiceItypeId = 0;
    this._scrollMode = false;
    this._scrollSpeed = 2;
    this._scrollNoFast = false;
    this._choiceCallback = null;
};


...this! Well that sure is a lot of variables. _texts is an array of the messages which need to be displayed. _choices is an array of the strings which will be shown in a "show choices" window. _faceName and _faceIndex are for the filename and index of a faceset which will be displayed along with the text. _background is used to determine whether the window background is a solid window, a dim background or transparent; it defaults to 0, "window". _positionType determines whether the window is shown on the top, middle or bottom of the screen; it defaults to 2, which is "bottom". _choiceDefaultType determines the default highlighted choice in a choice window; it defaults to 0, which is actually choice #1. Choice #2 to #6 are 1-5, and "none" has a value of -1. _choiceCancelType is the same thing but for which choice will be chosen if the player cancels the window with ESC. _choiceBackground and _choicePositionType are more or less the same as the non-choice versions, with the exception that _choicePositionType denotes "left", "middle" and "right" rather than top, middle and bottom, and it defaults to 2 (right). _numInputVariableId is the ID of the variable an "input number" command will be stored in, and _numInputMaxDigits stores the number of digits the number entered can be. _itemChoiceVariableId is the ID of the item a player selects in a "select item" command, and _itemChoiceItypeId is the type of item the player is selecting: 0 is "Key item", 1 is "Hidden Item A" and 2 is "Hidden Item B". -1 is "Regular item". _scrollMode determines whether the text is scrolling up the screen or not and defaults to false; _scrollSpeed determines the speed of scrolling text and defaults to 2. _scrollNoFast determines whether the player can fast forward the text scroll by holding ENTER (defaults to false), and _choiceCallback is...a bit more complex, but we'll get to that soon. It defaults to null.

Game_Message.prototype.choices = function() {
    return this._choices;
};

Game_Message.prototype.faceName = function() {
    return this._faceName;
};

Game_Message.prototype.faceIndex = function() {
    return this._faceIndex;
};

Game_Message.prototype.background = function() {
    return this._background;
};

Game_Message.prototype.positionType = function() {
    return this._positionType;
};

Game_Message.prototype.choiceDefaultType = function() {
    return this._choiceDefaultType;
};

Game_Message.prototype.choiceCancelType = function() {
    return this._choiceCancelType;
};

Game_Message.prototype.choiceBackground = function() {
    return this._choiceBackground;
};

Game_Message.prototype.choicePositionType = function() {
    return this._choicePositionType;
};

Game_Message.prototype.numInputVariableId = function() {
    return this._numInputVariableId;
};

Game_Message.prototype.numInputMaxDigits = function() {
    return this._numInputMaxDigits;
};

Game_Message.prototype.itemChoiceVariableId = function() {
    return this._itemChoiceVariableId;
};

Game_Message.prototype.itemChoiceItypeId = function() {
    return this._itemChoiceItypeId;
};

Game_Message.prototype.scrollMode = function() {
    return this._scrollMode;
};

Game_Message.prototype.scrollSpeed = function() {
    return this._scrollSpeed;
};

Game_Message.prototype.scrollNoFast = function() {
    return this._scrollNoFast;
};


This block of functions is just a set of wrappers for retrieving internal variable values, so I've covered them all in one go. There's nothing more to say about them really.

Game_Message.prototype.add = function(text) {
    this._texts.push(text);
};


The add function takes one parameter, text (which is a string representing a message); we push the supplied value into the _texts array.

Game_Message.prototype.setFaceImage = function(faceName, faceIndex) {
    this._faceName = faceName;
    this._faceIndex = faceIndex;
};

Game_Message.prototype.setBackground = function(background) {
    this._background = background;
};

Game_Message.prototype.setPositionType = function(positionType) {
    this._positionType = positionType;
};

Game_Message.prototype.setChoices = function(choices, defaultType, cancelType) {
    this._choices = choices;
    this._choiceDefaultType = defaultType;
    this._choiceCancelType = cancelType;
};

Game_Message.prototype.setChoiceBackground = function(background) {
    this._choiceBackground = background;
};

Game_Message.prototype.setChoicePositionType = function(positionType) {
    this._choicePositionType = positionType;
};

Game_Message.prototype.setNumberInput = function(variableId, maxDigits) {
    this._numInputVariableId = variableId;
    this._numInputMaxDigits = maxDigits;
};

Game_Message.prototype.setItemChoice = function(variableId, itemType) {
    this._itemChoiceVariableId = variableId;
    this._itemChoiceItypeId = itemType;
};

Game_Message.prototype.setScroll = function(speed, noFast) {
    this._scrollMode = true;
    this._scrollSpeed = speed;
    this._scrollNoFast = noFast;
};


This block of functions is for setting the values of the various internal variables and should be pretty self-explanatory. In fact, the only one that isn't a straightforward "set the internal variable values to the ones passed in to the function" is setScroll, which also has a line which sets _scrollMode to true without using a parameter for its value. The reason for this is that if we're setting a scroll for the text, we can reasonably infer that we want the scroll mode variable to be true.

Game_Message.prototype.setChoiceCallback = function(callback) {
    this._choiceCallback = callback;
};

Game_Message.prototype.onChoice = function(n) {
    if (this._choiceCallback) {
        this._choiceCallback(n);
        this._choiceCallback = null;
    }
};


setChoiceCallback takes one parameter, callback, and stores is in the _choiceCallBack variable. The reason I've taken this one out separately from the other set functions is to explain that the argument we'll be passing to this function is, itself, a function. We won't see this in detail until we get to Game_Interpreter.

onChoice takes one parameter, n. If the _choiceCallback variable isn't null, we call _choiceCallback passing in n, then set _choiceCallback to null.

This is fairly complex compared to other things we've looked at, but basically because we passed a function as the callback parameter, and then set _choiceCallback to the same function, we can call the function that was passed in by invoking _choiceCallback. The parameter n is provided to onChoice when it's called in Window_Message, and then passed on to whatever function is contained in _choiceCallback. Once I get to the window classes, I'll explain in more detail exactly how this flow works and why it's done the way it is.

Game_Message.prototype.hasText = function() {
    return this._texts.length > 0;
};


The hasText function determines whether there are any messages waiting to be displayed, and returns the result of checking whether the length of the _texts array is greater than 0.

Game_Message.prototype.isChoice = function() {
    return this._choices.length > 0;
};

Game_Message.prototype.isNumberInput = function() {
    return this._numInputVariableId > 0;
};

Game_Message.prototype.isItemChoice = function() {
    return this._itemChoiceVariableId > 0;
};

Game_Message.prototype.isBusy = function() {
    return (this.hasText() || this.isChoice() ||
            this.isNumberInput() || this.isItemChoice());
};


These functions similarly check whether the window is in a given mode: isChoice will return true if _choices is longer than 0 elements; isNumberInput returns true if the number input ID is greater than 0, and isItemChoice will return true if the item choice variable ID is greater than 0. isBusy determines whether the message window is currently doing something, and returns true if the window has text to display OR the choice window is active OR the number input window is active OR the item choice window is active.

Game_Message.prototype.newPage = function() {
    if (this._texts.length > 0) {
        this._texts[this._texts.length - 1] += '\f';
    }
};


The newPage function adds a new page to the message window. First we check whether the length of _texts is greater than 0; if it is, we add '\f' to the element of _texts corresponding to the length of _texts minus 1, which basically means "the last element in the array". \f is a special character denoting "form feed" which basically clears the display so that whatever comes after it will be displayed in a fresh window. This is what allows multiple pages of messages to be displayed in one window "instance".

Game_Message.prototype.allText = function() {
    return this._texts.join('\n');
};


The allText function gets the entire set of pages to be displayed, and returns the _texts array joined by a \n character. Join is a built-in array function which creates a string consisting of each array element's value joined together by a given value (in this case a newline character). Note that if you call this without supplying an argument, the default value is a comma.

And that concludes Game_Message! The game object classes are generally fairly short, but they lay essential groundwork that will be needed in the window and manager classes which do the real legwork.

I think that'll be enough to chew on for now, but we'll be back soon! I'll hit the ground running next time with a look at Game_Switches. Until next time!

Posts

Pages: 1
Trihan
"It's more like a big ball of wibbly wobbly...timey wimey...stuff."
3029
Note that I screwed this up a bit and inadvertently covered the same classes I already did 2 years ago. In the process of writing the proper instalment.
Thank you for these. I am excited but slightly nauseous to do some jumping.
Pages: 1