Winkio's Scripting Tutorial

Started by winkio, October 30, 2011, 03:54:59 am

Previous topic - Next topic

winkio

October 30, 2011, 03:54:59 am Last Edit: November 07, 2011, 01:28:49 pm by winkio
First off, don't move this to the database until I finish writing it.

Winkio's Scripting Tutorial


Introduction

This tutorial is written for those that do not understand creating and editing Scripts in RMXP.  It is aimed at a beginner level, and emphasizes concepts and practical examples.  While this tutorial explicitly discusses RMXP and its scripting environment, RGSS, many of the concepts apply to other programming environments.




Section 1: What is Scripting?

At first glance, scripting may seem overwhelmingly complicated.  There are many lines of text and numbers with all sorts of symbols and odd spacing.  Some of the text is different colors as well.  Somehow, the whole mess creates a logical system in a game.  To explain this phenomenon, we will examine what scripting is at a basic level, and work our way up.

Scripting, much like writing, talking, and math, is a way of communicating information.  To grasp the concept, it may be easy to think of a script as a book or a speech.  In a book, an author uses written words to communicate a story.  In a speech, an author uses spoken words to communicate a persuasive idea.  In a script, and author uses digital words to communicate a logical system.

So what are digital words?  To keep up the analogy, written words are understood by people reading them, and spoken words are understood by people hearing them.  Digital words are understood by computers reading them.  Just as there are many languages for written and spoken words (English, German, Spanish, etc.), there are also many languages for digital words, such as C++, Java, and Python.  All these factors are combined into the definition of a digital language, or programming language.  In RMXP, the digital language we use is RGSS, which is a modification of Ruby.

Now we have defined the purpose of a digital language, we must define its mechanisms.  How exactly do digital words to communicate a logical system?  The answer is based on the concept of information.  Information is the basic quantity that is exchanged through all language, including written, spoken, and digital.  If I write or say the phrase 'there is a black cat,' I have just communicated the following information:


  • A cat exists

  • The cat is black



To communicate the same thing in digital language, it might look something like this:

kitty = Cat.new
kitty.color = Color.Black


While this example may seem obvious due to it's simplicity, we will soon observe the difficulty attached to communicating a complex idea such as having one person follow another.  Nevertheless, this example shows us that words of any type of language can be used to describe things.  In the examples above, they described the existence of a black cat.

Returning to the question of how exactly digital words communicate a logical system, we can answer it with our new definitions of information and description.  Digital words communicate a logical system by describing the system with information.  Now that we understand what scripting is all about, we can move on to learning the basics of writing a script.




Section 2: The Basics

We will start off this section by jumping right into a practical example.  Open up an RMXP project and open the Script Editor (F11).  On the left side of the window, right click on the item at the top of the list and click 'Insert' on the pop up menu.  A new blank script will appear.  Click on the right hand area of the window and type in the following code:

p 'Hello World'


Close the script editor and save the game.  Now run the game.  A popup window should display the message 'Hello World' before the game starts.

Subsection A: Methods
Spoiler: ShowHide


Now let's see what the script communicated.  The first part of the script is the single letter 'p'.  This p describes a predefined logical system that is part of the RGSS language.  What the 'p' system does at a basic level is display things in a popup window.  In this case, the 'Hello World' further describes the behavior of the p system by describing what will be displayed in the popup window.

In RGSS we call these systems such as p methods.  A method is a digital word and its definition that communicate a certain behavior.  They are very much like the verbs of written and spoken language.  For example, examine the sentence 'He jumps up'.  'He' is the object, 'jumps' describes the behavior that the object 'he' is doing.  'Up' describes the 'jumps' behavior.  In RGSS, the same statement may look something like this:

he.jumps(up)


This example displays the first three of the four common elements of a method:

1.  Name.  In this case, 'jumps' is the name of the method.  In the earlier example, 'p' was the name of the method.  Just as in spoken and written languages, it is used to refer to a method.
2.  Parameters, also referred to as Arguments.  In this case, 'up' is the only parameter of the method.  It is easy to image jumping some way other than up, such as left or back.  You could even jump high or low, quick or slow.  All of these would be possibly parameters for jump.  In the earlier example, 'Hello World' was the parameter of the p method, describing what would be displayed in the popup box.
3.  Object.  In this case, 'he' is the object, because 'he' is the thing that is doing the jumping.  Sometimes the object is understood from the context.  For example, I could say 'jump down from that ledge', and it would be understood that 'you' are the object.  Sometimes, the object is not required at all.  For example, I could say 'two plus three', and while plus indicates the behavior of addition, there is no specific object doing the adding, it is part of the language context.  We will explore objects in more detail later.
4.  Definition.  This defines what a method does using digital language.  Just as a word's definition is made up of other words, a method's definition is made up of other methods and digital words.

Returning to the 'Hello World' example, we can define what each part of the method is:
Name - p
Parameters - 'Hello World'
Object - none (context)
Definition - unknown

We say there is no object because we use the p method by itself, without a reference to an object.  In reality, this references the digital context of the script, which includes RGSS built in functions, in which p is included.

We also say that the definition is unknown.  We know that the p method displays its parameters in a popup box, but we do not have an exact digital description for the p method.  In other words, we do not have the digital words, or code, that define the behavior of p.


Subsection B: Variables
Spoiler: ShowHide


Now that we understand the concept of methods and what 'p' does in the script, we must understand what 'Hello World' is.  'Hello World' is raw information.  It represents a set of characters (letters in this case) that spell out 'Hello World'.  This type of raw information is called a variable.  A variable is a digital word and its value that communicates raw information.  They can be thought of much like nouns in spoken and written language.

There are two common elements of a variable:

1.  Name.  Similar to the method, the variable has a name which is used to refer to it.
2.  Value.  The raw information described by the variable.

In the example we saw, the name of the variable was 'Hello World', and the value of the variable was also 'Hello World'.  This is an example of a raw variable, where the name and the value are the same.  These simple variables are built into the digital context, and come in many forms, such as:


  • strings - 'Hello World'.  String variables contain a set of characters including letters, numbers, and symbols.  They are surrounded by quotes to indicate that they are characters and not numbers or names of other variables and methods

  • numeric - 3.5.  Numeric variables contain number values including positive, negative, and decimal.

  • boolean - true.  The only two boolean variables are 'true' and 'false' (never in quotes), and indicate a logical yes or no value.



There can also be abstract variables, which is when the name of the variable is different than the value of the variable.  A spoken example of this would be the color of a cat.  The name of the variable is 'color', but the value of the variable is 'black'.

To write code that communicates an abstract variable, the first step is to define it.  For this example in RGSS, it would be:

color = 'black'


This code says there is a variable with name color and value 'black'.  If we want to use the variable, we simply refer to the variable by name.  For example, try this code out in a new script:

color = 'black'
p color


Now the popup window shows 'black', the value of the variable named color.  You can even try more examples for the different types of variables:

color = 'black'
five = 5
yes = true
p color,five,yes


Subsection C: Reserved Words
Spoiler: ShowHide


If you have done any experimenting on your own, you may have noticed that errors occur when you name a variable (or method) true, end, def, if, class, module, anything that starts with a number, or anything that contains a period [.] or exclamation point ['], or any of numerous other things.  This is due to the existence of reserved words.  Reserved words are special words within a digital language, such as RGSS, that define the rules of the language.  They are sort of like the punctuation of written and spoken language.  As such, they define the structure of a script, so it is very important to pay attention to reserved words and make sure that they are in the correct places.

A good rule of thumb for method and variable names is as follows: start with a letter, and only use letters, numbers, and the underscore symbol [_] .  NEVER use spaces, as that will treat it as many separate names.  Instead, combine the words with either a capital letter or an underscore.  For example, instead of naming a variable 'black cat 1', name it 'blackCat1' or black_cat1'.


Subsection D: The Help File
Spoiler: ShowHide


If at any time you are confused about what a method does, what reserved words are, or have a question about RGSS in general, you can refer to the RMXP help file as a reference by pressing F1.  This is so important it has its own subsection.





Section 3: Details on Methods

Now that we understand the basics of a script, it should be apparent that methods are the most fundamental concept of scripting, as they communicate the behavior of the script.  In this section, we will explore methods in more detail, looking at return values, operators, and defining a method.  The core of any script will involve defining your own methods and calling on other methods that are either defined in a separate script or built into the RGSS language.

Subsection A: Return Values
Spoiler: ShowHide


Think about a method that adds two numbers.  In spoken language, I can say 'two plus three', and the listener will understand this as the quantity five.  The problem here is that 'two plus three' is not the name of a variable.  It is the adding method with parameters 'two' and 'three'.  The return value is information that is produced by a method.  Not all methods have a return value.  For example, I could have a paint_black method that changes the color of my cat to black.  There is no information being produced in this case, so there would be no return value.

So how are return values used in RGSS?  Let's say we wanted to generate a random digit (0-9).  We can use the built-in 'rand' method to do this, by calling rand(10).  The rand(n) function with parameter n generates a random integer i where 0 <= i < n, so rand(10) will generate a random digit 0-9.

p rand(10)


Great, we generated the value and displayed it.  What if we want to keep that value and use it later?  The answer is simple: since the return value is information, we can use it to define the value of a variable:

random_digit_1 = rand(10)


In fact, we can store many different random digits in different variables:

random_digit_1 = rand(10)
random_digit_2 = rand(10)
random_digit_3 = rand(10)
p random_digit_1 , random_digit_2 , random_digit_3


Subsection B: Operators
Spoiler: ShowHide


Going back to the addition example, how is the spoken statement 'two plus three' written in digital language?  The answer should look familiar:

2 + 3


We know that this code is referencing the add method with the parameters 2 and 3, but it doesn't look like anything we have encountered so far.  That is because the '+' is a special kind of method called an operator.  An operator is a method that is defined in a special way that allows ease of use.  In fact, we have already used the most common operator in the last section. The [=] operator references the set method, which finds the variable named by the first parameter and sets the value of this variable to the second parameter.  For example, take the following code:

five = 5


This code sets the value of the variable named 'five' to the number 5.

There are plenty of other operators:

Simple Math (addition, subtraction, multiplication, divison)
2 + 3
2 - 3
2 * 3
2 / 3


Simple Logic
(and, or, not)
true && false
true || false
!true


Comparison
(equal, inequal, greater, greater or equal, less, less or equal)
2 == 3
2 != 3
2 > 3
2 >= 3
2 < 3
2 <= 3


Advanced Math (modulo, exponent)
2 % 3
2 ** 3


Advanced Logic (bitwise and, bitwise or, tertiary)
2 & 3
2 | 3
true ? 2 : 3


Set
two = 2


Modified Set
(two += 3 is the same as two = two + 3)
two += 3
two -= 3
two *= 3
two /= 3
two %= 3
two **= 3


These are many of the common built in operators, but it is by no means a complete list.  You can even define your own operators, which will be discussed in the next subsection.  The important thing to remember is that operators are normal methods and follow all the same rules that we already know.


Subsection C: Multiple Methods
Spoiler: ShowHide


It is common to have multiple method references on a line.  For example, converting 50 degrees Fahrenheit to degrees Celsius, the line would look like:

tempC = 5 / 9 * (50 - 32)


Why are there parenthesis?  You may have heard of the order of operations in a mathematics setting before.  This is similar to the explanation for the script above, but not exactly the same.

In programming, a statement is a set of words that reference one method.  In RGSS, there is traditionally one statement per line, although you can have multiple statements on the same line if they are separated by semicolons [;].  While each statement only performs one method reference, the parameters of the method can reference additional methods.  We can examine this behavior in simple math:

Starting out simple, we have 3 + 2.  It's simply the add method with 3 and 2 as parameters.  However, we can add three numbers as well: 3 + 2 + 1.  This is obviously one statement, but it seems like it has two references to the add method.  In reality, it is being processed as the add method with 3 and 2 + 1 as parameters.  2 + 1 is a parameter but it contains a method reference, so it will get processed before the main method of the statement get's processed.  Thus the statement will follow these steps:

3 + 2 + 1
add(3, 2 + 1)
add(3, add(2, 1))
add(3, 3)
6


As you can see, 2 + 1 gets evaluated first.  This is how the order of operation in programming is set up, with the innermost parenthesis being processed first.  For example, if I add parenthesis to the last example, it will evaluate 3 + 2 first:

(3 + 2) + 1
add(3, 2) + 1
add(add(3, 2), 1)
add(5, 1)
6


Notice that the expressions inside parenthesis are evaluated first.  Since the only method used is addition, the order does not matter in this scenario.  However, let us now examine a more complex statement:

result = (2 + 3) * 4 - 5
result = add(2, 3) * 4 - 5
result = multiply(add(2, 3), 4) - 5
result = subtract(multiply(add(2, 3), 4), 5)
set(result, subtract(multiply(add(2, 3), 4), 5))


As you can see, this more involved mathematical statement is just a simple set method with addition, multiplication, and subtraction of numbers used to make the parameters.  When confused about the order of operations in a statement, it is useful to break it down into method form to observe what is actually happening.  See http://en.wikipedia.org/wiki/Order_of_operations#Programming_languages for a more complete list of the order of operations, which determines in what order operators will be processed.


Subsection D: Method Definitions
Spoiler: ShowHide


Now let's look at how to create our own methods.

For this example we will create a method that finds the average of three numbers.  First we will see the entire definition of this method, then we will go back and analyze it:

def average3(n1, n2, n3)
 return (n1 + n2 + n3) / 3.0
end


The first line of a method definition begins with the word 'def', which means that a method is being defined.  The next word is the method name, which in this case is 'average3'.  If the method has no parameters, then this is all that is needed in the first line.  However, in this case, we have three parameters, which we will call n1, n2, and n3.  We put these in parenthesis after the method name, and separate them by commas if there are more than one.

You will notice that the next line is indented.  This is because the word 'def' on the first line created a code block.  A code block in RGSS is a section of code and the logical structure that encases it.  It begins with the structure declaration and ends with the word 'end'.  The code inside the block is indented one tab in front of the code outside it.

In our example, the first line defines the start of a block and the third line defines the end of the block, with line 2 being the code contained in the block.  While there are often multiple lines contained within a block, in this case only one is needed.

Now looking at the second line, we see the statement

return (n1 + n2 + n3) / 3.0


The 'return' word references a method that sets the parameters on that line to the return value of the method, and then exits the method.  Due to this behavior, any code in the same code block as 'return' line that falls after the line that uses 'return' will not be processed, as the method will have been exited at an earlier point.  For example, any lines inserted between lines 2 and 3 in the code will have no effect whatsoever.

Now let's look closer at the second part of the line.  We notice that the parameters are being used in this line.  This is because inside the code block of a method definition, the parameters act as variables.  These variables have the same values as the parameters that are used when referencing the method, but are named differently.

Now onto the math.  At first glance it might seem too complicated.  To get the average of three numbers, all we do is add them up and divide by 3.  You may make the mistake of writing it like this:

return n1 + n2 + n3 / 3


This is wrong for two reasons.  First, we have to remember how multiple methods are processed.  In this case:

n1 + n2 + n3 / 3
n1 + n2 + divide(n3 / 3)
n1 + add(n2, divide(n3 / 3))
add(n1, add(n2, divide(n3 / 3)))


Only n3 is being divided by 3, the other two numbers are simply being added.  We can fix this by adding parenthesis:

(n1 + n2 + n3) / 3
(n1 + add(n2, n3)) / 3
add(n1, add(n2, n3)) / 3
divide(add(n1, add(n2, n3)), 3)


Great, now the whole thing is being divided by 3 just like we want.  It may seem like we are finished, but there is a small point that must be solved.  n1, n2, and n3 can be any numbers, either integers or decimals.  If they all the parameters are integers, then division will produce an integer result.  If we tried averaging the numbers 1, 2, and 4, we would expect 7 / 3 = 2.3333, when we would actually get 2.  This is one of the rules of integer division: when two integers don't divide evenly, the result will be rounded down (even if it is negative).  For example, if we tried averaging -1, -2, and -4, we would get -3 instead of -2.3333.

To fix this, we simply change 3 to 3.0, making one of the parameters decimal.  This will perform decimal division, which will produce the desired results of 2.333333 and -2.333333 for the sets of numbers above.

Now that we understand the method, we can try using it, by inserting the following script:

def average3(n1, n2, n3)
 return (n1 + n2 + n3) / 3.0
end

p average3(1,2,4),average3(-1,-2,-4)
p average3(rand(10),rand(10),rand(10))


This code defines the average3 method, displays the results for the sets of numbers above, and then averages three random digits.  There are a few things to keep in mind:


  • A method definition can be placed anywhere in a script, at the beginning, at the end, in the middle, or in an entirely separate script from the one that is referencing it.

  • A method definition will not run on its own, it must be referenced from code outside its definition code block



Subsection E: Optional Parameters and Alias
Spoiler: ShowHide


...


Subsection F: Modules
Spoiler: ShowHide


...





Section 4: Details on Variables

Subsection A: Arrays
Spoiler: ShowHide


...


Subsection B: Hashes
Spoiler: ShowHide


...


Subsection C: Objects
Spoiler: ShowHide


...





Section 5: Details on Reserved Words

Subsection A: Comments
Spoiler: ShowHide


...


Subsection B: Loops
Spoiler: ShowHide


...


Subsection C: Constructions
Spoiler: ShowHide


...





Section 6: Full Blown Scripting

put it all together




Author's Notes

Guide in progress, I will be continually adding to it until I finish it.

Blizzard

Looks good so far.

I think you may want to explain the concept of objects as well because the first section may be confusing without it (because of the code example).

Also, the begin-end block is not really necessary in section 2. It may confuse people about what it does so you should just leave it out IMO.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

Nice start, winkio.  I look forward to seeing it finished.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

winkio

I agree with you on the begin and end, I was going to use that to set people up to check for errors, but it's fine without it.

As you can see, I'm introducing methods first, and then working my way back to objects.  I find it a much more logical progression, because when scripting, you are primarily thinking about the behavior of the system, and what you want it to do, not the form of the system, and what you want it to look like.

ForeverZer0

I agree with winkio on that.
Personally I didn't understand all about being object oriented until after I learned  how to make a few scripts. I think that understanding is learned through experience.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

Hm... I find objects more intuitive as they are not as abstract as functions and programming flow. It's easier to understand the world in terms of objects and operations on those objects (i.e. methods) for a non-programmer (such having a class Car with the methods turnOn and turnOff).
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

October 30, 2011, 06:52:44 pm #6 Last Edit: October 30, 2011, 10:53:26 pm by winkio
Yeah, I know the approach you are talking about, and it makes sense, and is completely valid, but I think it causes people to focus too much on what programming is instead of on how to program.  Additionally, I think objects make more sense once you understand the ideas of methods and variables.

EDIT: I put a brief outline of the order I was planning.  You can see objects as a subsection of variables.  I like this order instead of objects first because objects are really the most complicated type of variable, so I think it makes sense to introduce them after introducing the simple types first.

Also, I was kind of on the fence about saving loops until after objects, but I think it will actually work out better because this order introduces all of methods and variables without having to worry about complexity.  Introducing concepts one by one as simple as possible should make learning to script a much more manageable experience.  I'm still thinking of adding a section on working with the default RMXP scripts, but I have to figure out how it would work and if it is really necessary.

Blizzard

October 31, 2011, 04:06:28 am #7 Last Edit: October 31, 2011, 04:07:35 am by Blizzard
If you're doing a bottom-up approach, you should leave objects for later and first make sure people understand variables, control-flow and loops already.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

I'll do some more thinking about the order of introducing objects.  What I was thinking with this order was doing bottom up with minimum complexity (methods, variables, objects), then going back and adding complexity (comments, loops, control flow, etc.).  I like leaving the complex stuff for last because then I don't need to introduce comments until they are needed so they won't be a burden or get in the way.  I also think it should provide a really solid understanding of the basic mechanics of programming, which will help when introducing the complex parts.