- Joined
- Apr 12, 2012
- Messages
- 7,985
- Reaction score
- 10,509
- First Language
- English
- Primarily Uses
- RMMZ
Since rpgmaker.net went down, so unfortunately have all my Slip into Ruby and Jump into Javascript articles. However, rejoice, sports fans! I'm bringing them all back right here. To prevent clutter, I will make each article its own reply to this thread. If you can think of a better way for me to do it, I am entirely ears. Without further ado, let's begin!
My goal is to offer a resource to budding RMXP/VX/VX Ace users who know that there's a scripting language there but don't have the first idea what it is or how to use it. Or people who DO have a first idea but aren't quite getting it.
However, before we can really get into the meat of what RGSS is and can do, it makes more sense to take a look at it from a wider viewpoint. So we're going to start with a bit of a primer on what, exactly, object-oriented programming is.
I could talk about classes and methods and properties and instance variables and inheritance and parameters and arguments until I'm blue in the face, but I know there are some people out there who wouldn't have a clue what I was on about. So we're going to make a cat instead.
If you're starting with a blank slate, you can't ask Ruby for a cat, because it has no idea what one is. Before we can make one, we need to provide a template from which all cats will be manufactured; a blueprint for a cat, if you will. In Ruby, this template is called a “class”:
This is one of the simplest classes you can write. It's the minimum amount of code required to be able to say “Hey Ruby, give me a cat please.” If at some point we find ourselves in need of a cat, it's simple: all we have to do is create a new instance of Cat with a unique name, like so:
We now have a cat, but it isn't a very exciting one because it just sort of sits there and doesn't do much. However, there is one thing it did that you couldn't see; it called its constructor method (“method” being Ruby's term for a subroutine or function)
The constructor method is a specially-named one which is always called “initialize” and is always called as soon as an instance of the class is created; if you don't provide one explicitly, there's a built-in one for all classes which Ruby will call for you, but this isn't always ideal if we want to do anything specific when we make a new cat. We'll come back to this later, so don't worry too much about it right now.
The main concern we have at the moment is that the cat can't breathe, which means it isn't going to live very long unless we give it some way to do so. Let's do that quickly before our pet expires:
There we go. Now any instance of a cat is able to breathe by calling this method when it's needed in the program. You call a method by entering the name of the instance, followed by a period, followed by the method name, like so:
And our moggy lives to see another day. However, as you can see it's still not the most exciting of pets...maybe we'd have more luck with a dog?
Uh oh. Rover's just informed us that he can't find a method called “breathe”, and he's rapidly turning blue. What went wrong?
Well a dog isn't a cat, so dogs can't really do anything that cats can. If we want Rover to breathe, we need to add the method to his class too:
There we go, much better. But Rover's just as boring as Tiddles. And the fact that we've replicated the exact same code bothers me. If only there were some way our cat and dog could share the breathing method between them...
Here's where class inheritance comes in. See, classes can be children of other classes, and the great thing is they will inherit all of the properties and methods of their parent. What do cats and dogs have in common? They're animals. What do all animals do? Breathe. So rather than replicating the breathe method for every animal in the world, it'll be much easier to let animals in general do the breathing and then pass it on to cats and dogs via inheritance. And we do that like so:
Excellent! Now we can do
And our pets have no respiratory problems whatsoever. We could even give ourselves a goldfish and as long as we specified that he's an animal too he can breathe like the rest. Of course, fish don't breathe quite the same way as cats and dogs, but that's a topic for later.
I feel quite sorry for poor Tiddles and Rover, so my next task is to give them a way to communicate with me. Let's see...
So now we can do:
And our output on the screen would be:
But wait. Inheritance isn't always a good thing...
Yeah, sometimes animals just need to have their own sounds. Let's fix this:
There we go, now dogs can only bark and cats can only meow. Our pets are able to communicate and breathe. They're starting to look much better already!
So tell me, how old is Tiddles? What? You don't know? Why not?
Well we haven't even told Ruby that our furry friends have ages. In fact it doesn't even know they're furry because we haven't told them about fur either. Things like this are called properties, and determine the kinds of data that can be held about the class.
So that we can answer the above question, let's give animals an age property. All animals have an age, so we might as well make it common to any animals we need. There are several ways to do this; I'll show you the least abusable way, then explain the alternative and tell you why it's a bad idea.
Oh man, that's a bit more complicated than we're used to so far, but don't worry, it's pretty simple. The “@” is basically telling Ruby that this variable is an “instance variable”--that is to say that every new instance of the class will have its own version. This means that Tiddles the cat will have an age independent from that of Felix the cat. If we didn't denote it as an instance variable then all cats would share an age, and that would just be chaos.
The new methods are there so that we can find out the age of a cat, or change its age if needed. So now when I ask you “How old is Tiddles?” you need only enter this in your program:
And the returned value will be the age of Tiddles. You can also do
And Tiddles will magically age to 5 years old.
This is, in my opinion, the best way to do this. What you could have done was this:
“attr_accessor”, “attr_reader” and “attr_writer” are essentially a shorthand way of doing the get and set methods we created in the previous example, but there's one important difference. attr_accessor basically means the variable can be read or written to at any time by anything anywhere. This might result in you accidentally changing a cat's age in a part of your program that has nothing to do with cats, and if you don't realise you've done it that's going to be a to find and debug later.
The way we did it was by creating what are known as “getter” and "setter" methods, which allow you to read and write instance variables but only from within their own class, limiting the circumstances under which one might change a variable's value without meaning to.
So now we have a parent class, Animal, which determines the things an animal is able to do. We might end up adding other methods to this like jump, swim, mate and so on. Then for the cat class, we might add catch_mice, scratch_human, land_gracefully...you get the idea.
You may have caught on to something I mentioned earlier when I said that some animals might not breathe the same way as others. Fish certainly don't breathe the same way cats do, but currently if you made fish an animal the program wouldn't know that. We'd have to do what's called “overloading” and give fish their own, unique way to breathe. We simply do that by redefining the breathe method in the fish class:
Now although fish inherit methods from Animal, we've told the program that they breathe differently from other types. Basically a method's functionality will be determined by the lowest level at which it's defined: methods in a specific class will take precedence over the parent, which will take precedence over the containing module (we'll cover modules later, don't worry).
And that's really all you need to know to be able to start recreating the world in Ruby! These concepts are the only things necessary to model the everyday things you see around you--and, indeed, kickass RPG systems. That's why you're here, right?
Recap:
In part 2 I'm intending to cover properties in more detail, including the different kinds of variable, and possibly go into parameters and arguments. If there's anything else you'd like an explanation on please let me know and I'll cover it either in part 2 or a later one.
------
Phew! The formatting needed some fixing from its original form, so I think I'm just gonna post these once a day rather than doing them all in one go. If you'd rather have them faster, though, I'm sure I can figure something out!
(Mods, if you could pin this, that'd be awesome, since it's intended as a replacement to the current pinned thread)
SLIP INTO RUBY PART 1 - OBJECT-ORIENTED WHA?
Part 1 of a series explaining Ruby and RGSS in a way you can understand.
Hello folks, and welcome to part 1 of...
My goal is to offer a resource to budding RMXP/VX/VX Ace users who know that there's a scripting language there but don't have the first idea what it is or how to use it. Or people who DO have a first idea but aren't quite getting it.
However, before we can really get into the meat of what RGSS is and can do, it makes more sense to take a look at it from a wider viewpoint. So we're going to start with a bit of a primer on what, exactly, object-oriented programming is.
I could talk about classes and methods and properties and instance variables and inheritance and parameters and arguments until I'm blue in the face, but I know there are some people out there who wouldn't have a clue what I was on about. So we're going to make a cat instead.
If you're starting with a blank slate, you can't ask Ruby for a cat, because it has no idea what one is. Before we can make one, we need to provide a template from which all cats will be manufactured; a blueprint for a cat, if you will. In Ruby, this template is called a “class”:
Ruby:
class Cat
end
This is one of the simplest classes you can write. It's the minimum amount of code required to be able to say “Hey Ruby, give me a cat please.” If at some point we find ourselves in need of a cat, it's simple: all we have to do is create a new instance of Cat with a unique name, like so:
Ruby:
tiddles = Cat.new
We now have a cat, but it isn't a very exciting one because it just sort of sits there and doesn't do much. However, there is one thing it did that you couldn't see; it called its constructor method (“method” being Ruby's term for a subroutine or function)
The constructor method is a specially-named one which is always called “initialize” and is always called as soon as an instance of the class is created; if you don't provide one explicitly, there's a built-in one for all classes which Ruby will call for you, but this isn't always ideal if we want to do anything specific when we make a new cat. We'll come back to this later, so don't worry too much about it right now.
The main concern we have at the moment is that the cat can't breathe, which means it isn't going to live very long unless we give it some way to do so. Let's do that quickly before our pet expires:
Ruby:
class Cat
def breathe
#insert code for inhaling oxygen and exhaling CO2
end
end
There we go. Now any instance of a cat is able to breathe by calling this method when it's needed in the program. You call a method by entering the name of the instance, followed by a period, followed by the method name, like so:
Ruby:
tiddles.breathe
And our moggy lives to see another day. However, as you can see it's still not the most exciting of pets...maybe we'd have more luck with a dog?
Ruby:
class Dog
end
rover = Dog.new
rover.breathe
Uh oh. Rover's just informed us that he can't find a method called “breathe”, and he's rapidly turning blue. What went wrong?
Well a dog isn't a cat, so dogs can't really do anything that cats can. If we want Rover to breathe, we need to add the method to his class too:
Ruby:
class Dog
def breathe
#code for breathing
end
end
There we go, much better. But Rover's just as boring as Tiddles. And the fact that we've replicated the exact same code bothers me. If only there were some way our cat and dog could share the breathing method between them...
Here's where class inheritance comes in. See, classes can be children of other classes, and the great thing is they will inherit all of the properties and methods of their parent. What do cats and dogs have in common? They're animals. What do all animals do? Breathe. So rather than replicating the breathe method for every animal in the world, it'll be much easier to let animals in general do the breathing and then pass it on to cats and dogs via inheritance. And we do that like so:
Ruby:
class Animal
def breathe
#code for breathing
end
end
class Cat < Animal
end
class Dog < Animal
end
Excellent! Now we can do
Ruby:
tiddles.breathe
rover.breathe
And our pets have no respiratory problems whatsoever. We could even give ourselves a goldfish and as long as we specified that he's an animal too he can breathe like the rest. Of course, fish don't breathe quite the same way as cats and dogs, but that's a topic for later.
I feel quite sorry for poor Tiddles and Rover, so my next task is to give them a way to communicate with me. Let's see...
Ruby:
class Animal
def breathe
#code for breathing
end
def meow
print “Meow!”
end
def bark
print “Woof!”
end
end
So now we can do:
Ruby:
tiddles.meow
rover.bark
And our output on the screen would be:
Code:
Meow!
Woof!
But wait. Inheritance isn't always a good thing...
Ruby:
tiddles.bark
rover.meow
Yeah, sometimes animals just need to have their own sounds. Let's fix this:
Ruby:
class Animal
def breathe
#code for breathing
end
end
class Cat < Animal
def meow
print “Meow!”
end
end
class Dog < Animal
def bark
print “Woof!”
end
end
There we go, now dogs can only bark and cats can only meow. Our pets are able to communicate and breathe. They're starting to look much better already!
So tell me, how old is Tiddles? What? You don't know? Why not?
Well we haven't even told Ruby that our furry friends have ages. In fact it doesn't even know they're furry because we haven't told them about fur either. Things like this are called properties, and determine the kinds of data that can be held about the class.
So that we can answer the above question, let's give animals an age property. All animals have an age, so we might as well make it common to any animals we need. There are several ways to do this; I'll show you the least abusable way, then explain the alternative and tell you why it's a bad idea.
Ruby:
class Animal
def initialize
@age = 0
end
def breathe
#code for breathing
end
def age
@age
end
def age=(val)
@age = val
end
end
Oh man, that's a bit more complicated than we're used to so far, but don't worry, it's pretty simple. The “@” is basically telling Ruby that this variable is an “instance variable”--that is to say that every new instance of the class will have its own version. This means that Tiddles the cat will have an age independent from that of Felix the cat. If we didn't denote it as an instance variable then all cats would share an age, and that would just be chaos.
The new methods are there so that we can find out the age of a cat, or change its age if needed. So now when I ask you “How old is Tiddles?” you need only enter this in your program:
Ruby:
tiddles.age
And the returned value will be the age of Tiddles. You can also do
Ruby:
tiddles.age=5
And Tiddles will magically age to 5 years old.
This is, in my opinion, the best way to do this. What you could have done was this:
Ruby:
class Animal
attr_accessor :age
def initialize
@age = 0
end
def breathe
#code for breathing
end
end
“attr_accessor”, “attr_reader” and “attr_writer” are essentially a shorthand way of doing the get and set methods we created in the previous example, but there's one important difference. attr_accessor basically means the variable can be read or written to at any time by anything anywhere. This might result in you accidentally changing a cat's age in a part of your program that has nothing to do with cats, and if you don't realise you've done it that's going to be a to find and debug later.
The way we did it was by creating what are known as “getter” and "setter" methods, which allow you to read and write instance variables but only from within their own class, limiting the circumstances under which one might change a variable's value without meaning to.
So now we have a parent class, Animal, which determines the things an animal is able to do. We might end up adding other methods to this like jump, swim, mate and so on. Then for the cat class, we might add catch_mice, scratch_human, land_gracefully...you get the idea.
You may have caught on to something I mentioned earlier when I said that some animals might not breathe the same way as others. Fish certainly don't breathe the same way cats do, but currently if you made fish an animal the program wouldn't know that. We'd have to do what's called “overloading” and give fish their own, unique way to breathe. We simply do that by redefining the breathe method in the fish class:
Ruby:
class Fish < Animal
def breathe
#insert custom code that only applies to fish
end
end
Now although fish inherit methods from Animal, we've told the program that they breathe differently from other types. Basically a method's functionality will be determined by the lowest level at which it's defined: methods in a specific class will take precedence over the parent, which will take precedence over the containing module (we'll cover modules later, don't worry).
And that's really all you need to know to be able to start recreating the world in Ruby! These concepts are the only things necessary to model the everyday things you see around you--and, indeed, kickass RPG systems. That's why you're here, right?
Recap:
- Classes are the “templates” used to create an object.
- Methods are the functions/subroutines that determine what the class can do.
- Properties are pieces of data that describe the class.
- Classes can be children of other classes, and will inherit any properties or methods the parent has in addition to its own.
- Properties can be read/written either by creating getter/setter methods, or designating them as one of “attr_accessor”, “attr_reader” or “attr_writer”. Note that attr_accessor will allow reading and writing, attr_reader will be read-only and attr_writer will be write-only.
- If a module, class or subclass have methods with the same name, the one that's lowest in the hierarchy will be used. Redefining a method that was already defined further up the chain is called “overloading”.
In part 2 I'm intending to cover properties in more detail, including the different kinds of variable, and possibly go into parameters and arguments. If there's anything else you'd like an explanation on please let me know and I'll cover it either in part 2 or a later one.
------
Phew! The formatting needed some fixing from its original form, so I think I'm just gonna post these once a day rather than doing them all in one go. If you'd rather have them faster, though, I'm sure I can figure something out!
(Mods, if you could pin this, that'd be awesome, since it's intended as a replacement to the current pinned thread)
Last edited:


