![]() |
![]() +- Save-Point (https://www.save-point.org) +-- Forum: Games Development (https://www.save-point.org/forum-4.html) +--- Forum: Tutorials (https://www.save-point.org/forum-19.html) +--- Thread: ![]() |
Ruby Scripting - kyonides - 08-29-2019 Quote:This topic is about Ruby Scripting What's ![]() It's a programming language. Originally it was just object oriented thus it has been great for OOP. Did you ever hear the term "spaghetti code"? It's a derogatory term for messy code and some people apply it to OOP languages whenever they wanna criticize them for making objects out of everything. Ruby is no exception. In version 1.8.x its base class was Object, since 1.9.x or 2.0.x it's been BasicObject. So yeah, everything is an object in Ruby (and RGSS and Gosu and so on). Is it Ruby's fault to be a messy bunch of code? Nope, it isn't. It's a scripter's fault actually. Your coding style will determine if you're able to become a scripter or programmer, not the language. You can pick any programming language that suits your needs or your business's but it's up to you to make something useful out of it. If you're bad in programming in C or C++, you can making a mess of a program as well. Is Ruby slow? Well, Ruby version 1.8.x was no roadrunner for sure but it was decent for small or medium size projects. 1.9.x offered us some improvement, still, the 2.x series are something to take into account for it's becoming faster and faster. 2.6.x even allowed us to experiment with MJIT, Ruby's version of JIT, by memoizing method calls while running scripts. Even so Ruby's been fast parsing text files. Rubygems allow Ruby to even deal with complex stuff like XML as well. Why should I pick Ruby? Again, that's up to you. Making the decision of making "small" games or Ruby on Rails / Sinatra apps, depends entirely upon your shoulders. Since we're on a forum dedicated to game making I'll assume you're interested in OOP and Ruby and you'll continue reading a series of post concerning this interesting topic. The Basics
I'm a lazy scripter ![]() ![]() Object Class
Since it's the main class in Ruby, fine, it was till BasicObject showed up, I'm gonna tell you about it. Whenever you run a script in a terminal window alias console or DOS depending on your Operating System, you're asking Object to deal with pretty much everything you've got to type or run there. Unless you create classes and modules, you're just dealing with the Object class. Object runs a main method, namely "main". If we compare this with ye old RM scripts, it's the most basic main method ever. Without it Ruby wouldn't run not even for a second. Does this mean that we need to create main methods in non RM scripts? Nope. Don't even try that! That's something that the RM series introduced to their niche, cultist group of emerging game developers. How you run your games or scripts depends on where you wanna run them. A Ruby on Rails or Sinatra web app would use something entirely different, I can guarantee you they have nothing in common with RM. How do I use the Object class? ![]() puts "Hello SavePoint!" ...was run as part of the Object class. (Even if puts actually belongs to the Kernel module...) What's that Kernel module you've mentioned here? ![]() hash = Hash(:m => 1) #=> { :m => 1 } Here Kernel module created a hash object for you. As an exception Hash is another method of the Kernel. Usually methods should be defined in lowercase. Still its purpose is to keep it simple for YOU. We better start discussing methods here. ![]() Methods
They are some of the basic contents of a class or module. If you ever need to define or modify some logic, use methods! ![]() my_concert = Concert.new my_concert.start ...and a concert would be held somewhere and would begin once all assistants took their seats. (I'm guessing here. ![]() There you could find a curious but important method for Classes. It's the new method. In Ruby and even in Crystal new initializes a copy of the Concert class. Why would we ever do that? That's because you don't expect to organize a single concert in human history, do you? ![]() In Ruby you call methods by connecting them to an object, either a class or an object, by typing a dot in between. Rarely you'd see some weirdos using :: instead, but just don't copy their weird style. ![]() There's something interesting about the new method you better learn about right now, you NEVER define it in scripts! You could only define it if you were working on a rubygem or Ruby extension if you really got some C programming skills to ever achieve such a goal. CRuby new method
From the Ruby side you never define new but you still have some sort of "replacement" called initialize. In Ruby you don't need to create an initialize method for modules since they should never be initialized anyway. Classes allow you to define it, but Ruby also provides you with a default initialize method in case you don't wanna create your own. Most people prefer to create their own initialize method anyway. ![]() initialize (called by CRuby rb_obj_call_init function) will be invoked by the new method which will pass its arguments down the line. SIDE NOTE Matz, Ruby's creator, didn't call initialize Ruby's constructor method in the original documentation he wrote many years ago that has been translated to English. Even so, people treat it as its constructor because it reminds them of C++ where a function with the class name will create the variables needed by the given class. Why does new or initialize matter here? ![]() value == 1 or print value == 1 And you'd get either a false value in any version of RGSS or an error message telling you value has not been initialized and it doesn't even know if that's a method or a variable if using a later version of ![]() Why is that happening? RGSS1 through RGSS3 DO allow you to use local variables without initializing them first. The problem comes when you port them to mkxp or HiddenChest or other modern and open source projects that run RGSSx games. They always use later versions of Ruby that removed that behavior, breaking back compatibility for sure. ![]() Objects You Should NEVER Initialize
Those would be a few classes indeed. They're true, false, nil, numbers and modules, of course! You'll get plenty of errors if you ever try to do that. Ruby classes are always open so you can initialize them as many times as you wish (and especially add them whatever you wanna include there). OK, if the script is protected or it's close source, you're out of luck... up to a certain point. You can still add stuff to them but it might not be linked to their original implementations because some of them might be coded in C or C++. Think about the Bitmap or Sprite class in RM series, they're good examples of what you can't completely modify unless you wanna mess with their built in functions and making them stop working out of the blue. ![]() Defining an initialize Method
Code: class MyClass There it is! ![]() We told Ruby to create a class called MyClass that you can build at will and it will get 2 default values for 2 specific instance variables, namely @some_variable and @some_boolean. They'll keep holding 0 and false values as long as your copy of your class exists. How did we define a class to contain our methods? By calling class and providing it with a class name that uses CamelCase. Well, it can just begin with a single capital letter and that would be good enough to create it. ![]() Don't forget!
![]() ![]() I mean, end all methods and classes and modules with a final end to close them.
![]() But I can't do anything with it! I tried and got nothing! ![]() Code: class MyClass Why didn't you reuse the script posted above? ![]() Warning! ![]() Don't mention the parent class there! There's no need for it! You only need to do that once! ![]() ![]() Huh? I wasn't planning to do that. What's a parent class anyway? ![]() Code: class BasicObject We could basically say that's how they were defined in Ruby. Your classes would already become Object class's children by default. Even so you can define something else as a class's parent class. The catch would be it'd exist by the moment you create the child class. Hit your head against the wall if you haven't. ![]() By the way those 2 methods I created a while ago are called getters in many languages. Why? Because you can only get their current value. ![]() But ![]() You remind me of a certain dreamer... ![]() Code: class MyClass That's all you need to do to create their setters! ![]() ![]() ![]() You're a mean scripter for sure! ![]() ![]() ![]() Code: class MyClass Nothing? ![]() Nope, got nothing to say. ![]() O_O Well, before I leave to grab some snack, I'll tell you something valuable. The first attr_ calls creates the methods for us, attr_reader is a method to create the first two methods you've seen above. attr_writer creates the last two of them. But there's a third one there! I have spotted it already! ![]() Yeah, my desperate detective ![]() ![]() ![]() I told you that you were really mean! ![]() Excuse me for saving it for the very last moment you'd need to pay attention to my blabbing. ![]() Happy Game Scripting Full Testing of Lag!
![]() RE: Ruby Scripting - kyonides - 08-30-2019 More About Parent Classes
Tonight I guess I should tell you a bit more about parent classes and why you need them. Do you really need them? ![]() Code: class Rect Do you see that? It's our basic Rect(angle) class! ![]() ![]() ![]() ![]() Right... ![]() ![]() Yeah, you could later come up with other classes like other shapes, namely Circle, Triangle, and so on. Honestly you can stick to rectangles only for most of your gaming needs. At the end, you won't deal with any other geometrical shape unless you start using something like OpenGL and start depending on your graphics cards capabilities. ![]() So how do you know when to subclass some bunch of code? Here's when you should do that! Code: class Person Do you know every single person share stuff in common? I guess so... ![]() Well, that could later become our first parent class! How so!? ![]() That's easy to explain! We know many people share traits like name, age, skin, eyes, hair, and so on. With this we can already create an object to represent a person like a student or coworker or site administrator or just some dreamer that complains about heat and many more! So what's next? ![]() ![]() Code: class Gamer < Person ![]() ![]() Yeah, I did! ![]() Go ahead! ![]() ![]() Code: class Lawyer < Person As you can see a lawyer, even if nobody likes them except for their own families ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() O_o? Are they!? Anyway, I've proven that we might need a basic parent class in case we might later define several descendants that will need to call stuff defined in the parent class. This pattern will save us from adding many checks in our code just to define when a person should turn on a TV set or open a briefcase or yell Objection! You wouldn't do that if you were just sitting on a seat like many other passengers while traveling on a bus or train or metro, would you!? ![]() Now we're gonna discuss what's super! ![]() ![]() ![]() ![]() ![]() Actually for Ruby none of them would be super. ![]() Yeah, none of them are, I do agree with Ruby on this. ![]() ![]() ![]() ![]() Code: class Siletrea < WannabeDragonfly Wait a second! ![]() ![]() ![]() ![]() ![]() ![]() ![]() By the way, just in case you include arrays or hashes in your classes, you'd usually need getters only. Most of the time you'd just change their contents, not the entire array or hash. Thus there's no need to define something you don't need. That will keep your code clean and won't ask for extra resources that are gonna get wasted anyway. ![]() How large can a class ever be? Err, again, that depends on your project and coding style. ![]() ![]() ![]() ![]() ![]() Warning!
Don't abuse of loops or you'll get stuck in no time!
![]() Happy Stack Overflow!
![]() RE: Ruby Scripting - kyonides - 09-03-2019 Modules
What are modules in ![]() What is that? ![]() ![]() Yeah, the most basic explanation on modules would be that they contain stuff. I know, you are going to tell me now that classes also contain their own stuff. ![]() Yeah, you could say that each module own its own boat and it keeps navigating the vast sea separated from all classes. It is not like it hates classes, it just can live and be invoked without them. Even so you can also mix them with classes in ![]() Code: module ChipFlavors We could add dozens of interesting chips recipes here but the point will remain the same. Our module, ChipFlavors, includes all chips flavor codes. This fact allows us to easily handle all of them in a single place without messing up with the actual classes that use them. Just imagine how tiresome it would become after a few years when we got like 50 different chips packages with different flavors. ![]() Actually for a machine it might be even better to just keep the module separate without mixing it in the Snack class. If you ever need to change codes, deprecate some and so on, you would only care about a module and not every single class every time you needed to update a vending machine. Today we have learned three things. We got modules, mixins and one that was obviously different and still got pretty much ignored, CONSTANTS. ![]() O_o? I am not! ![]() ![]() ![]() Do not say that! We are not breaking some rule, we are following one indeed! You see, Ruby cares about how you type stuff on your computer. Use lowercase and it will treat that word or compound as either a variable or a method. Use @ at and it will think it is an instance variable. Type @@ and it will become a class variable. Still, if you use $ dollar symbol, it will not believe it is an amount but a global variable. Anything starting with an uppercase letter will be considered to be an actual Constant. It is part of what we call a programming language’s syntax. You could say it is like its own set of grammar and punctuation rules. No matter if you respected your teachers at school or not, Ruby will force you to respect its rules! Go against what is common sense in the rubyist world and you will not get past that point ever. ![]() By the way, you mix in modules in classes by calling the include ModuleName right below that class name. You can include as many as deemed necessary. Just keep this in mind, use CONSTANTS to permanently store data as long as your program is active. Do Not Change Their Contents after defining them! I mean, do not ever think you can do stuff like changing their contents one hundred lines of code later. If you defined them in a specific way, keep them like that for the rest of its execution. Of course you can update it whenever you are maintaining its code while it is not running on any machine, but do it only then. If you just load it during its testing stage, it will not really matter. Just never do it while in its production stage (whenever you are already dealing with the “real world” audience). Then why did you mix lowercase and uppercase? O_O I did it because you can do so if you are defining a class or module. Use uppercase (and underscore once or twice) only if you are creating a class or module CONSTANT. I mean, when it belongs to that class or module. I have seen people nesting classes and modules at will. Why’s that? Err, well, you could say they are free to do so. For instance, you could define a single module and then lots of classes inside… like the RPG module in the maker series. Stuff like RPG::Actor and so on are a “living proof” of it. Double colon :: mean the connection there is between the container module and its inhabiting class. To be honest with you, you can do that with two different classes as well. There the difference would be that the first class might call the second class as some sort of helper class that might contain stuff you deliberately wanted to separate from the main class. RPG::Event and its subclasses are an excellent example here. The sections you can see in the event editor might belong to either the main or the secondary classes. This is why I cannot stop repeating myself. Everything depends on your coding style at the end. Is there anything else I might need to know about modules? O_o? I am uncertain if you really need to know this, but Module is a class. ![]() ![]() Guess what? There is something else you might need to learn about them. What is it? Modules can contain more than just CONSTANTS. You can place floating methods there as well. That is not an official term, it just attempts to teach you they are not officially part of that module. That’s impossible! You gotta be kidding me!! O_o? Nope, I am not. The main idea behind it is that you should be able to do the same you have done with CONSTANTS as with any method you would like to include in one or more classes where you will include that module of yours. So what happens to those methods after the mixin!? They kind of become part of that class’s list of methods. Yeah, you could not distinguish them from the rest if you print the whole list! That is what makes them run smoothly as if they had always been there! Are you saying modules will never own any methods ever!? Err, nope, I never said so. There IS a way to make it own any specific method. You see, so far we have only seen that methods are called by typing the def keyword followed by some method_name. Normally that means that method will belong to a class. To change that in a module, we can add something special there. It is the self keyword! Code: module MyModule Yes, it only belongs to that module now! In English it might be self evident what self actually means. For those speaking foreign languages (like your lazy servitor here), it might be strange to see how it is used. Honestly, it just means “I” or “me” own this method so call me first to access it properly. It is a simple replacement for that module’s name, meaning it will also work if you type that name instead. Since self is shorter and easy to understand, the convention is that you would just type self and not the module’s name there.
What if I’ve got plenty of module methods!? Do not worry then! There is a simple way to avoid typing all those dozens of egotistic self.
Use module_function in a separate line and all methods written below will become module methods by default. Again, I told you
![]() ![]() Kyonides Wrote:There is also another way to make those methods become singleton methods (belonging to that module). Keep in mind that such methods will NEVER become part of a class where you have mixed it in. You will still need to call it by typing MyModule.method_name every single time you need to trigger them there.
Right, I forgot to reveal another important fact about modules, you can call its module methods from anywhere! Once they have been properly defined, you can access them from any other script defined after that module has been defined. Happy ArgumentError Message Debugging Nights!
![]() RE: Ruby Scripting - kyonides - 09-06-2019 Numbers
Those Boring Integers and Floats
Nope, I am not talking about a weird TV show here. ![]() ![]() First of all, you got to know they all do not belong to a Number class, even if that would have been quite useful. Its actual name is the Numeric class. Internally Ruby offers you the Integer which is divided in Fixnum and Bignum without any way to let you ever change that. Still you can add or subtract numbers like you have always done in school. There is Float as well, which include all real numbers, those pesky values like 1.0 or 3.14159 and so on. There is no other number class. You can still enter binary or hexadecimal values but Ruby will internally print an integer instead. If you do not believe me, go try the IRB alias the ![]() ![]() ![]() + lets you sum up whatever you need to calculate, - is subtraction, * is multiplication and / lets you divide a number by another. % provides you with its modulo value (4 % 3 = 1 as its modulo). You can also combine them with the = equal sign at will. You can compare them with operators (mathematical symbols) like < or > or >= or <= or <=> or == or !=. <=> is the sort operator, while != is the unequal or not equal symbol. In Ruby you normally get Integers as a result unless both of them are Floats or you explicitly define the last argument as a Float with to_f method. you can convert a Float to an Integer with the to_i method. Actually you can even convert a character like 'A' to an Integer with to_i or hex or even ord depending on your version of the Ruby interpreter. Even so numbers in Ruby are kind of constant so you can assign 1 to 100 variables that whenever you change the value to one of them, the rest will not get affected at all, not even if you alter the original variable that was storing that number! ![]() Hello World!
The Most Boring Way to Start Programming
Yeah, it was inevitable! ![]() ![]() How do you say that in Ruby!? That is quite easy in Ruby and Cristal, you only need to do this: puts "Hello world!" And it will get printed in the ![]() ![]() How do I do the same in RM series? You would need to create a Window and its self.contents or a Sprite and its self.bitmap to do that. This is how you do that with Sprites. Code: @sprite = Sprite.new Here I did not use self.bitmap because I was already using a variable storing that @sprite. It is practically the same with a Window but you usually use one of its subclasses like Window_Base or Window_Command or a custom window class instead. You replace bitmap with contents. draw_text, guess what? It draws text on screen for you! ![]() ![]() ![]() Explanation on Bitmap and Window_Base's draw_text method
Code: @sprite.bitmap.draw_text(0, 0, 240, 24, "Hello world!") draw_text(x_coord, y_coord, max_width, max_line_height, text, optional_alignment) The optional alignment there can be either non explicit which is the same as its default value 0 (left). 1 would mean it will be centered taking in consideration the lines max_width. 2 means its right hand side will end at the max_width. puts "Happy Non Disposed Bitmaps!"
![]() RE: Ruby Scripting - kyonides - 09-09-2019 Regular Expressions in Ruby
Well, there are people out there that say that regular expressions or regex or regexp are no extension of a programming language but a language of its own, others might say it is some kind of DSL and so on. The truth about regular expressions that you should know about is that regex are not the same in every single language because there are oddities that only belong to a specific language or group of languages. Why are they called regular then? ![]() It is not because of something like a regular interval since it does not really look for it, even if we can ask it to return one or more occurrences of a certain string of text. It might be because you expect your favorite language to regularly look for them if you ever pass it a string. You could say it is a more complicated way of comparing stuff than usual, I mean, it is different to variable == 1 or another_variable == :symbol . Here you look for patterns. What do you mean with patterns? ![]() It would be stuff like /repeated/ or /[0-9]+/ or /[a-z]+/ and many more. Sometimes it is similar to comparing a string directly like in variable == 'repeated' but there also are times when you do not expect something THAT specific but a group of either numbers or characters or even a mix of them. So anything that relatively matches them would also become a valid finding for our matching system called regular expressions and its comparisons. This is something so common in programming that you always get shortcuts to some of these searches like /\d+/ for numbers (actually they are digits) or /\w+/ for characters. Even though you might want to look for general ways to find matches, sometimes you want to confirm they are something special like people's names. In such case you could do something like /[A-Z]\w+/ to attempt to find them, if people ever cared to capitalize their own names... ![]() ![]() ![]() ![]() What if I don't care about capital letters? ![]() In such case, you can do two things to forget about cases in strings. Either use string.downcase for lowercase or string.upcase for uppercase. Or just add an lowercase i to the end of the regex like in /\w+ \w+/i '12.478'.sub(/\d+.\d+/, 'Some Float') '12.478'.sub(/\d+\.\d+/, 'Some Float') That is a string that would get substituted or sub'ed by another string, namely 'Some Float' and both are the same, meaning you will get the exact same result, the string to replace the former. Since all floating point numbers (real numbers) are always written with a dot in Ruby, it does not matter if you pick any of those options. The problem with the first choice is that you could also type '12,478' and it would also replace it because a dot . in a regular expression means "any character" in a single slot or caret position. Still, Ruby would not convert it to a real number because it might think that only the first match (12) matters there, but it still can replace it completely with any string of your choice. If you are looking for temporary replacements, sub is the right method for you! sub! does the same job but it also changes the strings contents till the end of your method or application. ![]() Keep in mind that [ and ] are used as a way to group a number of candidates it will be looking for or get replaced later on. | that pipe or pipeline character (or whatever you want to call that weird symbol) means "or" and you can use it to specify that it might accept one pattern option or the other(s). ( and ) are useful if you only care to substitute or manipulate a group of characters that were specified therein. You get matches in general like this... $1, $2, $3 and so on. Of course if the previous matching variable was the last real match ever found, the rest will be equal to nil, meaning there was nothing else to be looking for. But how do I verify if it matches without modifying the string? ![]() ![]() if (condition) unless (condition) case number_or_string_or_symbol when regex1 # code when regex2 # code else # code end There else is valid as a default behavior in case there is no reason to trigger a previous option. It can be used in if, unless and case ... when statements. It got to be the very last option! ![]() By the way, unless is nothing but the negation of if. ![]() ![]() ![]() ![]() What do you do if what I am testing is neither a number nor a string from the very beginning? ![]() ![]() ![]() ![]() If you are dealing with classes, you can either call its name method or just its given name like in Scene_Map or Window_Base. ![]() ![]() One last thing... You might also know that =~ can be used for matches as well. Usually you place a string first and a regex later on. It will return a 0 if it is a real match or nil if you fail to find it. In that case you better do exactly what I did in my farewell message below. Then you would get an useful boolean test or true-false check! Happy Fake ('Captain J.U. Tyler' =~ /captain/i) == 0 Match!
![]() If anybody can ever believe he deserved to be a captain even of a spacecraft simulator.
RE: Ruby Scripting - kyonides - 06-05-2021 Variable & Constant Scope
Usually when learning OOP languages like ![]()
The only advantage the former offer is that they can be called from anywhere else via the :: scope operator. The latter need you to define a method to grant them some access from the outside world. ![]() Kyonides Wrote:I have seen people nesting classes and modules at will. Why’s that? So far it sounds quite straightforward, right? ![]() The truth is that it isn't. ![]() There's a catch! ![]() ![]() Basic Nesting Code: module Mod Specific Class Definition Code: class Mod::Classy ![]() But they are not identical!
![]() The truth is that the first one opens the module's scope first so you can add anything you can think off and later call it from anywhere inside that module or nested class without typing the whole address, i.e. you don't need to remind it of the Mod:: module name and the scope operator. The latter behaves in a different way. Since it specified the scope from the very beginning, you can't directly access the module's methods, constants, etc. without specifying the scope as well. So you'd either need to include Mod (which is weird) or use the scope operator every single time you ever plan to call the constants' or any other object's values. Why did this ever happen? ![]() The reason is simple. You narrowed down the scope to only keep direct access to that nested class Classy. If you had used the first declaration, the scope would have been opened to the whole module instead. This would also include what you had defined in a different script section on the RM editor. ![]() So choose the module or class scope wisely. ![]() By the way, Constants in ![]() ![]() The reasoning ![]() Happy Refactoring of Your Code!
![]() RE: Ruby Scripting - kyonides - 11-28-2021 Comparisons
In Ruby you have got 3 ways to compare a value of a CONSTANT or variable with any other value. if or unless statements (plus iterators (loops) like while and until) Code: if today == "Sunday" Here we were using the == equality operator. By the way, unless is a negative if statement. case statement Code: case $game_party.actors[0].name As you can see in the example above, it's a convenient way to test things. It even allows you to add more than a single value to every single when clause. You could say it's like defining an if statement in a very convenient way. But there's a catch! ![]() The comparison is always made based on the call to the === identical method. ![]() ![]() ![]() ![]() An if statement won't force you to use any specific operator for comparisons, you need to define them on every single line of code you're adding to your script. Enter ? Ternary : Condition What's a ternary condition? ![]() Well, it's quite simple indeed. It's like an abbreviated form of an if statement. It can also be found in other languages like C and C++. I guess you could find it useful if you need to test variables in order to find out if you set one value or another. You can also use it to call two distinct methods. Setting a Variable's Value Code: legal_status = age >= 21 ? "Adult" : "Minor" We used the >= greater than or equal to operator on the example above. As you have noticed, the variable legal_status will return an Adult or Minor status based on a character's age. Calling Different Methods Code: base_infiltrated? ? explode : business_as usual In this case we have included three different methods to test if a hypothetical base has been infiltrated by the enemy. ![]() If true, it will simply explode and ignore the third method. ![]() If false, people will ignore the routine check and keep working hard at the military base. ![]() Happy Boolean Return Values!
![]() RE: Ruby Scripting - kyonides - 05-02-2022 More About Defining Methods
As far as you have seen here, you can defining pretty much any method except for the new method. You would have to use the initialize method if you ever need to setup what values it will define every time it creates a copy of that class, meaning it becomes a new ![]() For more information on the new and initialize methods, please read the main post of this thread. There is something I have not told you that might confuse you if you come from other languages like C or C++. ![]() Until now you might have thought that you had always had to start with the class definition and the initialize method, if you ever needed it. Then you would have to define any other methods below the initialize or (scene class) main method. And that was fine. The thing is that ![]() I have got a reason why I am bringing this up right now. There is a slight advantage at defining certain methods and place them above the method that will call them later on. Internally it seems to be more convenient for ![]() Placing the callee after the caller method seems to make it a bit slower than the process I have described above. Here is an example of what I have been talking about: Code: class Window_Message In that hypothetical case we are defining substitute_actor_name before we even deal with fake_message_text_processing in the Window_Message class. So when the script ever calls and process that latter, it will jump upwards and execute the former and then fall back to fake_message_text_processing method without any issues. Then it will continue executing its contents, namely the draw_text method, to display a single line of text on screen. Recursive Methods
This type of method relies upon itself to keep processing data over and over again as if you had defined a loop or for loop or while loop or until loop. Code: class Window_Test < Window_Base In the case above we have defined a new Window_Test class that inherits basic methods from the Window_Base class. That will allow us to call the draw_text method at will. Later on we have also included a call to the very same method we are defining there. It was necessary to include a condition (the if modifier) to prevent it from recursively call itself for the rest of our lives. Otherwise we could have seen how the game gets frozen and some popup window showing up telling us that a stack overflow has occurred and the engine needs to close by force. So if we call recursive_method(5, 10) just once, it will print the value on screen 6 times in the same line. ![]() ![]() Well, not really. ![]() ![]() ![]() Happy Helper Method's Day!
![]() RE: Ruby Scripting - kyonides - 01-27-2023 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. Code: module MyModule 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. Code: class MyCommandWindow < Window_Selectable 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. C struct
The way I'll explain this issue is the following: declaring the class or module serves 2 main purposes.
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. That topic might be something that should be handled in a separate post... Happy Class Declarations!
![]() RE: Ruby Scripting - kyonides - 02-03-2023 The Other Bad Practices Found in RGSS Scripts
We all should know by now how to declare an if or unless conditional statement. ![]() ![]() Code: if variable == true 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! ![]() Just like in many other languages, there are other ways to check the same value appropiately, without repeating oneself. Code: if variable == true 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. Code: if variable == true Yes guys! That is all you needed to do from the very beginning! ![]() ![]() Code: if is_variable ![]() ![]() But why does it work here? ![]() 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: Code: if (result) { The negative way to declare that kind of statement would be: Code: if (!state) { 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! ![]() Code: if !is_done 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! ![]() Toggling Switches
So how can we apply that knowledge to changing the boolean value of a Game Switch? ![]() Just use the following code: 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. Code: module Some 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. ![]() ![]() 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. ![]() It was totally unnecessary for sure. ![]() ![]() Happy
![]() |