kyonides 5 Posted January 24 (edited) This thread will be one of those basic tutorials that will start by telling you the basics of crafting scripts on your own. In the worst case scenario, you will be able to make minor edits without much help from actual scripters. Basic Concepts object - pretty much anything in Ruby and RGSS, including numbers to some degree. It is the basic building lego block. value - almost identical to object but it refers to what is actually returned by some script call, a method, etc. It is or might be contained by a variable. variable - x or y or z are common examples of variables used frequently in Ruby or RGSS scripts. They are the containers of any specific value / object. They can easily be treated as methods depending on how you have defined your custom class or module. method - sometimes also known as attribute, a basic component of a class or module. They are attached to its class or module. 1.to_s calls the convert to string method, turning it into "1" at once. Now you can use it on any window! class - a Class that can be initialized or constructed via the new method. module - a Module that is used as a container. It is not supposed to be used as a class for you cannot make any copies of it. It will always keep all of its internal variables intact till you close your game. Not even loading a different saved game will alter it by default. NOTE: Module itself is a class but one that cannot be initialized nor constructed by using new. All attempts to do such things will certainly fail. When Should You Use a Class or a Module? Pick a class if you need to make copies of tha object like Actors or Enemies or Items. Use or call a module if you want to use system wide functions that might alter your game somehow. The best example would be the Graphics module. Call Graphics.resize_screen(W, H) on RGSS3 (ACE) and you will be able to increase or decrease the window size a little bit. NOTE: $game_temp or Game_Temp class could have been easily be defined as a Game_Temp module for all of its methods and internal values are temporary by nature and you don't need multiple copies of it. When NOT to Use a Class You don't need to create a new class if an Array or Hash object can easily help you with storing its values. Module's Special Feature It is definitely true that you cannot initialize a Module, meaning that you will ever get a copy of it. Yet, you can easily mix it into a Class. From that moment all most of its variables and methods become the new methods of that specific Class. Let us take a look at the following example of how you are supposed to define a module and also a brand new class. module Test def running? true end end class Maker include Test end Did you see that include Test statement over there? It means that Test has become an integral part of Maker class. Now you can call it like this: klass = Maker.new klass.running? And it will return true as it current value. What is true? Anything that has been confirmed or exists, a truthy value. Am I getting philosophical here? Well, kind of. true represents what is really there, what can be found as many times as needed. What happens if it is a lie or is incorrect or does not exist at all? Then it would be false. Obviously false is the opposite of true just as much as a lie is the opposite of the truth. A Caveat Has Been Found! Ruby and RGSS have a weird but not so unusual feature in programming languages, namely the nil value. Basically, nil is its official non existing value, even if its a value on its own right. XD Curiously, it also works as a substitute for a false value in many cases. Whenever an object does not exist because it has never been called or defined as a variable or class or module, it is certainly equal to nil. Now comes the most intriguing feature that has been bugging you ever since you began reading this tutorial... What the hell is that stupid dot . doing there? Nope, it is not just a punctuation mark. It is a connection! It connects the method to its own class or method or variable or even to its number value. OK... What does def stand for? Short answer: definition. It allows you to define a class or module's method. And before you even ask it, know that the term end means, well, end! XD It marks the end of the century! OK, nope. It is the end of a method or class or module definition. That's all, folks! Edited January 27 by kyonides Share this post Link to post Share on other sites
kyonides 5 Posted January 27 (edited) The Lack of Interest into Fully Understanding a Programming Language Many but many scripters around even to this day tend to misuse a feature of Ruby just because they found something similar in the default scripts. This has been true ever since RMXP came out as the first engine with some scripting capabilities and still returns every so often in VX Ace. Defining a Class or Module As I told you before, there is a simple way to create a class. module MyModule end class MyClass include MyModule end And you can even include modules, not just one but many in a row! Just separate them by using commas. So what's wrong with it? Nothing. It has been correctly executed there. What I would like to criticize now is the lack of knowledge those scripters have shown over the years. It all begins with stuff like this. class MyCommandWindow < Window_Selectable end Here many people fall in a trap that won't normally cause any issues except when they do it once again! Yes, they repeat the same declaration over and over again every single time they define what we call the Parent Class or Super Class. What it means is that MyCommandWindow is the Child Class of Window_Selectable, making it a window with menu features preincluded by default, even if they had been created in Window_Selectable only. And guess what? Window_Selectable class is a Child Class of Window_Base and the latter is the Child Class of Window! As you can see the list can go way beyond your imagination, really it does. But why do they keep repeating the same mistake over and over again? That's because they lack some insight of Ruby inner workings like the C side of Ruby code. Yeah, Ruby is run on C functions. Every single Ruby Object is a special C struct. Spoiler What is a C struct? Well, it's like a precursor of a C++ or Ruby class, initially only found in C but it spread to C++ as well. I can't talk about non C related languages so... It pretty much has the same features as Ruby variables for you can easily access copies of your defined struct and its values in a similar fashion than Ruby, yes, with dots included. The difference is that they can also become pointers with its own connector instead of Values a la Ruby. Pointers are just memory references or addresses to a very specific point in, well, memory or RAM, that they have reserved for its own use. It is a small load of data to be passed to another struct pointer or any C function as an argument aka parameter. The way I'll explain this issue is the following: declaring the class or module serves 2 main purposes. Define the class or module and its parent class or module (as in a module nested inside another module). Do this once if they do have a parent class. Reopen the class or module. That's it! Ruby isn't like Java. The latter made it overly complicated to extend certain basic features like printing stuff on a shell or console. Ruby just has OPEN CLASSES! That's a nice feature that lets us add as much stuff as deemed necessary and alias (keep a reference to a preexisting method) a given method at will. Downside: It might allow many people to rely on monkeypatching default classes as a way not to create child classes or delegate them to custom classes. In CRuby you would use a function called rb_define_class("MyClass", rb_cObject) instead. Modules don't need a second parameter: rb_define_module("MyModule"). Internally it's used to determine if a class exists. Otherwise, it'll look for functions like rb_obj_alloc and stuff like rb_class_new and even an initializer., which can be your very own custom function or call your Ruby initialize method. A Ruby side initialize definition will certainly overwrite a C side one. So whenever you repeat the whole statement, you keep telling the Ruby system that it should now check the parent class once again! Why on earth!? It kept it in memory and won't forget it as long as the program is running. Thus, it makes no sense to insist on declaring that there. And what comes next is especially directed at newcomers and slightly experienced scripters: stop doing it or you might end up making a mistake like declaring the wrong parent class! This issue is similar to another one that keeps showing up in newcomers' codes, the excess of checks by calling too many if or unless or case statements to get to a single point where they simply need to change a variable's value, especially common whenever they need to toggle switches. But this topic might be something that should be handled in a separate post... Edited January 27 by kyonides Share this post Link to post Share on other sites
kyonides 5 Posted February 3 (edited) The Other Bad Practices Found in RGSS Scripts We all should know by now how to declare an if or unless conditional statement. Happy with a sweat Yet, there are people out there that do weird stuff while doing so. In some cases the culprit was the RMXP's default code. For those guys that entered the scene after RMVX or RMVX Ace came out, I have no excuse. Confused if variable == true print "It's true!" end if variable == false print "It isn't true..." end This is one of the most extreme cases seen so far. For some reason, the guy checks the same variable twice, once for a truthy value and another for its opposite value. It is terrible! Angry Just like in many other languages, there are other ways to check the same value appropiately, without repeating oneself. if variable == true print "It's true!" elsif variable == false print "It isn't true..." end There we can see how to define a second condition using elsif instead. It certainly means "else if" there. If we were checking for totally different values, that solution would be fine. Even so, we are only checking what is its actual boolean value and under such circumstance, there is an easier way to deal with it. if variable == true print "It's true!" else print "It isn't true..." end Yes guys! That is all you needed to do from the very beginning! Laughing Shocked But wait! There is more you need to learn here about those statements! if is_variable print "It's true!" else print "It isn't true..." end Grinning It is quite interesting how the code still works, don't you think? Thinking But why does it work here? Who Knows? There is an easy explanation. In Ruby, unlike C or C++, all objects return a truthy value if they are not equal to nil of the NilClass or false for obvious reasons. In C it would be quite common to see something like the following code: if (result) { return "You were successful!"; } else { return "You failed!"; } The negative way to declare that kind of statement would be: if (!state) { return "LoadError: Failed to load script."; } A ! bang, yes, a ! bang there means negative value or opposite value or simply false. And guess what? That does exist in Ruby as well! 😮 if !is_done print "In the works!" else print "Done!" end Of course, newcomers might need to include the equality operator and the true value like this == true but in the professional world that is not used at all. The only reason why you would ever, if ever, use it would be to test if an object is equal to true or false or nil in a threefold check. And this is extremely uncommon, guys! Happy with a sweat Toggling Switches So how can we apply that knowledge to changing the boolean value of a Game Switch? Thinking Just use the following code: $game_switches[1] = !$game_switches[1] A Curious But Nonsensical Idea Some time ago somebody wrote me a message telling me how dangerous it would be to do the following while using modules and classes. module Some ONEISTHERE = "Someone is there!" class Thing include Some end end OK, I got to say that it is idiotic per se, still, this person wanted me to warn you about it. The reasoning behind it was that it would create a terrible loop that should be avoided at all costs. Interesting conclusion. Thinking [Mad Scientist Mode ON] Let us test this theory, guys! Nope, as we can see in the picture above, that is CERTAINLY NOT the case there! What has happened was that we simply created a "new link" to the Constants already declared in the module above. The only thing we have achieved was to come up with a redundant way to get to the same old Constant. XD It was totally unnecessary for sure. =_=¡ [Mad Scientist Mode OFF] Edited February 3 by kyonides Share this post Link to post Share on other sites
kyonides 5 Posted April 19 When to Use the Module Class' include Feature I have seen many times that people kind of abuse of the :: scope operator when they are fiddling with modules. That inspired me to revisit the modules to make sure they stop repeating themselves like crazy. Basic Setup Modules module SomeUser module Config DEFAULT_FONT_SIZE = 20 DEFAULT_TITLE = "Some Label" end end So far there is nothing new to see here but everything changes Shocked once we start dealing with a specific Window class. Detective Let us take a look at some fake Window_TitleCommand Add-on. class Window_TitleCommand alias :some_user_config_win_ttl_comm_draw_item :draw_item def default_font_size SomeUser::Config::DEFAULT_FONT_SIZE end def draw_item(index) some_user_config_win_ttl_comm_draw_item(index) contents.font.size = self.default_font_size text = SomeUser::Config::DEFAULT_TITLE contents.draw_text(4, 26, contents_width, 24, text, 1) end end As you can see above, we had to use the :: scope operator several times in our scriptlet. Happy with a sweat Honestly, I got to tell you that it is not elegant at all. Confused The more Constants you include the worse it will look like. Let's make some modifications to the original code. class Window_TitleCommand include SomeUser::Config alias :some_user_config_win_ttl_comm_draw_item :draw_item def draw_item(index) some_user_config_win_ttl_comm_draw_item(index) contents.font.size = DEFAULT_FONT_SIZE contents.draw_text(4, 26, contents_width, 24, DEFAULT_TITLE, 1) end end Wunderbar! Shocked Wonderful! Now it looks quite neat! And we can even skip the creation of needless methods only to call the same long line of code we could find inside the default_font_size over and over again. There is a caveat, though. You should NOT do that if you are working on a class that inherits the methods you have altered there. This is especially true if at least one of its child classes does not need such modifications at all. I seriously Serious recommend you to only include the modules in Baby child classes and nowhere else unless you know what you are doing. Share this post Link to post Share on other sites
kyonides 5 Posted April 19 (edited) Assignment != Equality && Assignment != Identity && Equality != Identity Let us review what an assignment actually is. It simply means that you pick either a Constant or a variable and set a value to that object and not any other around it. (Well, you could still do it but you got to have a valid reason for it or else do not even try to do that!) The assignment operator is an = equal sign. variable = actual_value That means that whenever you use that variable or Constant, it will always return the last value you have assigned to that particular object. You should not alter a Constant's value, though. :S Equality stands for something that has the save value as another object, be it a Constant or a variable. Use two == equal signs to make the comparison between two objects that might be different or not. CONSTANT = 1 @variable = 1 CONSTANT == @variable #=> Returns true The === identity operator! And finally, we got the identity operator === to help us define if an object has been placed on both sides of a given comparison. Here you got to be careful because it is excesively strict when looking for any identical value or object. range = 1..8 range === 5 #=> Returns true range === range #=> Returns... false! range == range #=> Returns... true! Object.new === Object.new #=> Returns false, they are two different Objects with their own IDs. Whenever you are using the case when statement to double check if a give variable is equal to another, it will use the === identity operator by default. As we could see in the first example of the identity checks, the first test returned a true-ish value because it used the === operator with EVERY SINGLE VALUE of that Range object until it hit number 5. Honestly, you should use the == equality operator for if and unless statements mainly because there is no specific reason to do otherwise. When using the case when statement, make sure you will be comparing the same kind of objects like numbers or classes. It will fail if you made a mistake and tested the value of a variable, like number 5, against a class like Integer, even if number 5 is an Integer object on its own right. Other Operators By the way, the != operator simply means Not Equal. The !=== Not Identical operator does exist as well, but it would be quite weird for you to find a good use for it anywhere. The && double et symbol you could find on the title of this very same post simply means and. A Terrible But Good Looking Error That Can Make You Break Your Head You will not be able to tell why it is not working as intended because it will make you think everything is fine. variable == 100 || 50 Yeah, everything looks terrific and it NEVER throws any error at your face at all. Really guys, it never will. 100% guaranteed! Still, it is a huge mistake under most circumstances. The reasoning behind it is QUITE SIMPLE indeed. How do you know if the test is always working as intended if it never fails? Keep in mind that any object other than nil and false are treated as true by default. So tell me why is that a problem for any novice scripter? It is a huge problem because you wound up defining a conditional statement you never needed. I mean, if you always get a true-ish value back, why bother at all? You could simply remove it and the script would work as usually does. But I need it to reject certain requests because it did not hit the 100% accuracy I need in my skill, item consumption, etc. If that is true, then you better delete the "|| number" part at once. I cannot. I need it to also work if it hits the 50% mark... You get a yellow card for making such a noob mistake then. Actually, the only way that would work is to define the condition like I do it right below this very same line. variable == 100 || variable == 50 I would suspect you come from a different programming language that allow you to do that or you simply watched some video tutorial that was not Ruby specific at all. Stop mixing language syntaxes right there! Don't do it ever again! It is for your own benefit, anyway. Edited April 28 by kyonides var == n || m Share this post Link to post Share on other sites