Creation Asylum Banner
X   Site Message
(Message will auto close in 2 seconds)

Welcome Guest ( Log In | Register )

"If you havent failed yet, try again"

Dubealex
Quick Jump: The AsylumV | EntertainmentV | Game MakingV | Creative ForumV | Technology & ComputersV | TranslationsV

3 Pages V   1 2 3 >  
Reply to this topicStart new topic
> RGSS & Ruby Lessons - Chapter 2, Take the leap into RGSS scripting now !
Rating 5 V
Dubealex
post Nov 7 2005, 09:39 PM
Post #1


Administrator of this Asylum
Group Icon
Group Icon


Admin

Member No.: 1
Posts Liked: 48 *
Joined: 8-November 04
Posts: 2,704
-->
From: Longueuil, Canada

RPG Maker Level:
Master

Class Title:
Writer, Scripter & Designer

Last.fm ID: Dubealex

Country:



RGSS & Ruby Lesson - Chapter 2

:icon_fleche_ff3: You need to have read Chapter 1 before reading Chapter 2.

:icon_fleche_ff3: Remember the RGSS Reference on the main website-- It contains many info, even regarding If Statement and the likes.

edit: I fixed a little error I did with Else if stamement. Sorry.

The basic structure of a RGSS (Ruby) code was explained in Chapter 1. We learned how to do ATTR, how objects communicate and how to create simple class and objects.

In Chapter 2, we will learn all the basic components that you must be able to use in order to create your very own scripts. Those components are stuff like "For..Loop", "If Statement", "Case" and "Variable Managements". We will go through each of them individually, and we will create small programs showing off how each components work, and we will finish this chapter with some script example (exercise) that uses many components at once.

We will also learn how to manipulate many important component in RGSS, like the relation between a Scene and a Window, and how to do a Scene and a Window. We will thus create our own scene and display data in it. We won't do a complete CMS with menus and selectable items now, this will come in Chapter 3. (Otherwise this chapter would have been really too huge...)

1- Variables & Constants

In every program, you need variables and sometimes you need contants. To save space and time in this chapter, if you don't feel confortable with variables, I suggest you go read my Variable Tutorial named "RMXP Variables Demystified" and come back here once you read it.

Local Variables
A local variable begins with a lowercase letter. This kind of variable can be used only within the method it was created in. In the following sample, both local variable exist only within their method, they do not conflict each others.

Sample:

CODE
class Local_Variable
  
  def method_1
    local_variable=2
  end
  
  def method_2
    local_variable=3
  end
  
end


Instances Variables
An instance variable begins with a @ and must be created inside a method. This kind of variable can be used in any method contained in the same class. In the following sample, the instance variable created in method_1 is equal to 2, and we change it to 4 in method_2. An instance variable is global within a class, it exist for all the method inside that class.

Sample:

CODE
class Instance_Variable
  
  def method_1
    @instance_variable=2
  end
  
  def method_2
     @instance_variable=4
  end
  
end


Class Variables
A class variable begins with two @@ and must be created anywhere in the class, as long as it's not inside a method. It is recommended to put them below the class name definition. A class variable is shared among all objects of a class and all method from that class can use it. In the following example, we created a class that counts the number of objects it created so far.

Sample:

CODE
class Class_Variable

  @@class_variable=0
  
  def initialize
    @@class_variable+=1
  end

end


Global Variables
A global variable exist in the entire program, once created, it can be used in any other class. In the following sample, we created a global variable in a class, and we add 1 to it in another class.

Sample:

CODE
class Global_Variable_1
  
  def initialize
    $global_variable=0
  end

end

class Global_Variable_2
  
  def initialize
    $global_variable+=1
  end

end


Constants
A constant is a "container" that contains a certain value, it should not be changed; but in Ruby, you can... But only from within the class in which you changed it, the value stored in a constant always remains the one you set in it's definition. In the following sample, I created 3 class to show how constant can be used.

Sample:

CODE
A_CONSTANT=100

class Constant_Test_1
  ANOTHER_CONSTANT=50
  
  def initialize
   print ANOTHER_CONSTANT
   print A_CONSTANT
  end

end

class Constant_Test_2
  
  def initialize
    print Constant_Test_1::ANOTHER_CONSTANT
    print A_CONSTANT
  end

end

class Constant_Test_3
  A_CONSTANT+=1
      
  def initialize
    print A_CONSTANT
  end

end


First, we created a global constant named "A_CONSTANT" and we set it to 100. You also saw that a global constant is defined outside a class; it will be useable in every class of your program. In the first class, we created a class constant, that is useable from within the class... But you can use it from another class when you use the right syntax. In the second class we actually accessed the constant we created in the first class. The syntax rule is the following:

CODE
Class_Name::CONSTANT_NAME


Using this syntax, you can define a constant inside a class, do whatever you want to it, and be able to access it from another class. In the third and last class sample, we actually add 1 to our global constant "A_CONSTANT", and we print it's content, which gives us 101. Try to execute all those class one after the other, and repeat it 2 times... I.E: Do this in a event Call Script:

CODE
Constant_Test_1.new
Constant_Test_2.new
Constant_Test_3.new
Constant_Test_1.new


As you can see, the constant "A_CONSTANT" is equal to 101 only when you call Constant_Test_3.new, and it stays at 101 because it always uses the static value found in "A_CONSTANT", which is 100. Simply put, a constant is constant, it doesn't really changes. Remember that a constant should not be created/modified inside a method.

2- Conditional Statements

In this section you will learn how to do "If Statement", "Case Stements", and so on. I already explained the basics of those syntax in the RGSS Reference, here's a link to it. You should go there, read it all, and come back here to read the details and see real script sample:

-> Go on the main website and go in RGSS Reference - Ruby Syntax.

When you do conditional statement, always remember to uses double sign, I.E:

CODE
if my_variable=0      # <-- ISN'T CORRECT
if my_variable==0    # <-- IS CORRECT


A full list of sign to used in conditions can be found in the page given in the link above. There is multiple way of doing those conditions in Ruby, and I will give you some example that will give you the same result if run.

If Statements

Sample A:

CODE
class If_Statement_1
  @@a_class_variable=10
  
  def initialize
    @@a_class_variable+=1
    a_local_variable=13
    
    if @@a_class_variable==a_local_variable
      print "Yay, we are equal !"
    else
      print "Arg, it's not fair !"
    end  
    
  end

end


If you run 4 times this class, I.E: Do this in a call script:

CODE
If_Statement_1.new
If_Statement_1.new
If_Statement_1.new
If_Statement_1.new


You will get the message "Yay, we are equal !" at the third window; since we add 1 to our class variable each times you call that class, and the condition check if our class variable equals our local variable. So, the process that RMXP does when you call it 4 times is the following:

[First Time]
@@a_class_variable=10+1 --> gives 11
a_local_variable=13

The IF statement compare the two, and they aren't equal. The if statement thus execute the ELSE actions and show that message.

[Second Time]
@@a_class_variable=11+1 --> gives 12
a_local_variable=13

The IF statement compare the two, and they aren't equal. The if statement thus execute the ELSE actions and show that message.

[Third Time]
@@a_class_variable=12+1 --> gives 13
a_local_variable=13

The IF statement compare the two, and they are now equal. The if statement thus execute it's main body actions, and show the right message on screen.

[Forth Time]
@@a_class_variable=13+1 --> gives 14
a_local_variable=13

The IF statement compare the two, and they aren't equal anymore. The if statement thus execute the ELSE actions and show that message.


Sample B:

CODE
class If_Statement_1
  @@a_class_variable=10
  
  def initialize
    @@a_class_variable+=1
    a_local_variable=13
    
    if @@a_class_variable==a_local_variable then print "Yay" else print "Arg" end
  end  
  
end


This sample shows that you can write the If Statement in one single line if you want to. It can be useful for small condition. Here's 2 other sample with the same effect, but without the else handler:

Sample C:

CODE
class If_Statement_1
  @@a_class_variable=10
  
  def initialize
    @@a_class_variable+=1
    a_local_variable=13
    
    print @@a_class_variable
    if @@a_class_variable==a_local_variable : print "Yay"  end
  end  
  
end


Here you can see that we can replace THEN by a semicolon : Those are synonims. We print the content of @@a_class_variable and we see that we print the message "Yay" only if it equals 13. So, as I said, it's useful for small stuff like this. You can also write that condition like this:

Sample D:

CODE
class If_Statement_1
  @@a_class_variable=10
  
  def initialize
    @@a_class_variable+=1
    a_local_variable=13
    
    print @@a_class_variable
    print "Yay" if @@a_class_variable==a_local_variable
  end  
  
end


In this sample, we can omit the END keyword, so it's even smaller. We inversed both component in the condition. So we will print "Yay" ONLY if @@a_class_variable is equal to a_local_variable. So, now you know there are many different ways of doing condition, and we will use them later in our more advanced example.

You can also use ELSE IF keyword to add condition into your If Statement, you aren't limited to one ELSE handler as in an event Conditional Branches... RGSS is programming, so it's more powerful and more flexible. Here some example:

Sample E:

CODE
class If_Statement_1
  @@a_class_variable=10
  
  def initialize
    @@a_class_variable+=1
    a_local_variable=13
    
    if @@a_class_variable==a_local_variable
      print "We Are Equal !"
       elsif @@a_class_variable==12
        print "I Equal 12 !"
         elsif @@a_class_variable != a_local_variable
          print "We aren't equal !"
    end
  end  
  
end


As you can see, the trick with Else If is to remember to use elsif and not Else If.

Using Else If will force the program to take one of the choices in the If Statement, and never two at once. Otherwise, when @@a_class_variable would equal 12, we would have seen 2 messages, we would have seen "I Equal 12 !" and "We Aren't Equals", but the If Statement shows the first one that returns to be true, and skip the others. If you want to do this, you can simply do all your else if as new If Stamement, the program will thus check them all, and execute only those who happen to be true. Like this`:

CODE
class If_Statement_1
  @@a_class_variable=10
  
  def initialize
    @@a_class_variable+=1
    a_local_variable=13
    
    if @@a_class_variable==a_local_variable
       print "We Are Equal !"
    end
    if @@a_class_variable==12  
       print "I Equal 12 !"
    end
    if @@a_class_variable != a_local_variable
       print "We aren't equal !"
    end  
  end
  
end


If you run this, you will see that when @@a_class_variable equals 12, two messages are shown, "I Equal 12 !" followed by "We Aren't Equal". However, in much case where you would use else if, it's better to use a Case Statement, explained below.

Case Statement

A case statement is used to check the content of a given variable, and list a group of actions that will happens at each given value. This is used a lot in Scene and Menus. We will still uses the exact same sample as above, we our class_variable:

Remember, you must change the names you used in your Call Script to the class name, in this section, it's Case_Statement_1.new

Sample A:

CODE
class Case_Statement_1
  @@a_class_variable=0
  
  def initialize
    @@a_class_variable+=1
    
  case @@a_class_variable
    when 1
      print "I am 1"
    when 2
      print "I am 2"
    when 3
      print "I am 3"
    else
      print "What Am I ?"
    end  
  
  end
  
end


If you read my RGSS reference as I said above, you should not have any problem understanding the sample I just gave. As you can see, it really look nicer with a Case Statement than with else if. Once again, remember that a semicolon can replace the THEN keyword in conditional statement, so you can make your code smaller using this:

Sample B:

CODE
class Case_Statement_1
  @@a_class_variable=0
  
  def initialize
    @@a_class_variable+=1
    
  case @@a_class_variable
    when 1: print "I am 1"
    when 2: print "I am 2"
    when 3: print "I am 3"
    else  print "What Am I ?"
  end  
  
  end
  
end


We can also make "Ranges", a range is defined by specifying a start value and an end value, with points in the middle. (We will talk more about range later.)

Basic Range Rules:

CODE
START..END    -->Include the END value
START...END   -->Exclude the END value


So, you can use those "Range" in your case statement, like this:

Sample C:

CODE
class Case_Statement_1
  @@a_class_variable=0
  
  def initialize
    @@a_class_variable+=1
    
  print @@a_class_variable
  case @@a_class_variable
    when 1..3: print "I am between 1 and 3"
    when 4..6: print "I am between 4 and 6"
    when 7..9: print "I am between 7 and 9"
    else  print "What Am I ?"
  end  
  
  end
  
end


To test this, simply add more Case_Statement_1.new to your Call Script. 10 is enough to see all the test. You can also uses specific condition list, seperated by comas, like this:

Sample D:

CODE
class Case_Statement_1
  @@a_class_variable=0
  
  def initialize
    @@a_class_variable+=1
    
  print @@a_class_variable
  case @@a_class_variable
    when 1,3: print "I am wether 1 or 3"
    when 4,6: print "I am wether 4 or 6"
    when 7,9: print "I am wether 7 or 9"
    else  print "What Am I ?"
  end  
  
  end
  
end


In this sample, the program check if the value found inside @@a_class_variable is one of those listed at each "when" keyword. So, (in this case) a comas (,) is like an OR keyword. Remember that you can also uses other thing instead of numbers (integers), like text (strings), like this:

Sample E:

CODE
class Case_Statement_1
  @@a_class_variable="a"
  
  def initialize
    @@a_class_variable.next!
    
  case @@a_class_variable
    when "b": print "I am B"
    when "c": print "I am C"
    when "d": print "I am D"
    else  print "What Am I ?"
  end  
  
  end
  
end


In this sample, we do a .next! command, that is used to increment a string to it's next logical value depending on the character found at the extreme right of the string.

Example:

a_string="ab"
a_string.next!
--> a_string now equals "ac"

another_string="name102"
another_string.next!
--> another_string now equals "name103"


So, back to our Case sample, we see that it's working with string too. I won't list all the others conditional statement, as Unless, While and Until, they are explained in my RGSS Reference, and by reading the If Statement and the Case Statement from this lesson, I'm sure you can understand them pretty well.

3- Loop

Once again, in the link given above (The RGSS Reference), there is a good For..Loop reference. Here's a working sample, once again using the same kind of code shown in previous sample:

Sample A:

CODE
class For_Loop_Sample
  
  def initialize
    a_local_variable=0
    
    for i in 1..10
      a_local_variable+=1
      print a_local_variable
    end  
    
  end
  
end


This will add 1 to "a_local_variable" and print it's content 10 times... from 1 to 10, including 10. Remember the Range rules I explained above, it's the same rule in a for loop. So if we would have written "0...10" instead of "1..10", it would have given us the exact same results.

Some of you may be confused by the i in the line... What the hell is that i for ? What I like to say is that the i stand for "Iteration", as Iteration is repeating. Here's an extract from the RGSS Reference:

QUOTE
[...]A For Loop will execute it's body (actions) until it reaches the end value. The For Loop actually "iterate" the actions found in its body and store the numbers of iteration in the variable i. We can use any numbers or string (text) as start and end value. This will create the For Loop range. A range is defined using points (..) or (...). Using two points, as in the example above will make a range starting from the start value and ending at the end value, including the end value. Using 3 points (...) will exclude the end value. [...]


I won't list all the possible syntax for a For..Loop, as I did them in the RGSS Reference, just go check it out. Your i value can be used to create condition from within your for..loop or to use as reference. Check the following example:

Sample B:

CODE
class For_Loop_Sample
  
  def initialize
    
    for i in 1..4
       print $game_actors[i].name
    end  
    
  end
  
end


In order to test that example, you need to have your 4 first hero defined in RPG Maker. Basically, our i value is equal to the value in the range where we are at, and increment at each loop. Here's what is the process that RMXP did:


[First Iteration]
i=1
--> We print name of hero ID#1 (i being a variable, $game_actors[ i].name is now known as $game_actors[1].name)

[Second Iteration]
i=2
--> We print name of hero ID#2 (i being a variable, $game_actors[ i].name is now known as $game_actors[2].name)

[Third Iteration]
i=3
--> We print name of hero ID#3 (i being a variable, $game_actors[ i].name is now known as $game_actors[3].name)

[Forth Iteration]
i=4
--> We print name of hero ID#4 (i being a variable, $game_actors[ i].name is now known as $game_actors[4].name)


You can see that this kind of code is used a lot in RMXP, especially in Window_MenuStatus, where RMXP list the actors datas in a For..Loop. Just remember that you can use variable in the range, as this will have the same effect as the sample shown above:

Sample C:

CODE
class For_Loop_Sample
  
  def initialize
    a_loacal_variable=1
    another_local_variable=4
    
    for i in a_loacal_variable..another_local_variable
       print $game_actors[i].name
    end  
    
  end
  
end


4- Inheritance

You will have to understand the power and the structure of Ruby inheritance before trying to understand how exactly a window and a scene works. You can make a class "inherit" methods and other data (variables) from another class. Class working with inheritance are called SubClass and SuperClass in Ruby; this can also be known as ChildClass and ParentClass. Here's an example:

Sample A:

CODE
class Inheritance_Sample_1
  
  def initialize
    @a_local_variable=1    
  end
  
end  


class Inheritance_Sample_2 < Inheritance_Sample_1
  
  def initialize
    super
    print @a_local_variable
  end
  
end


To test it out, simply do a Call Script in an event, and write this in it:

CODE
Inheritance_Sample_2.new


To make a class inherit from another, you write a < symbol aside it's name, followed by the name of the class you want to be the SuperClass. In our sample, "Inheritance_Sample_2" is the SubClass and "Inheritance_Sample_1" is the SuperClass. Which means we can access stuff from Inheritance_Sample_1 from Inheritance_Sample_2 if used correctly.

You can see the keyword "super" in our initialize method in the class "Inheritance_Sample_2"; what does this do ? Well, it simply execute the method in the SuperClass that has the same name as the one in which we wrote the "super" syntax. Meaning that we used "super" in the initialize method, this will have the effect of executing the initialize method of the SuperClass, in our case it's "Inheritance_Sample_1" --> here's the process that RMXP did with that code:

[Receives the .new command]
-Execute the initialize method of Inheritance_Sample_2
-Found a "super" keyword.
--> Check what is the SuperClass; found that it is Inheritance_Sample_1
- Execute the initialize method of the SuperClass Inheritance_Sample_1
--> The initialize method of Inheritance_Sample_1 set @a_local_variable=1
- The program then continue in the initialize method of Inheritance_Sample_2
--> @a_local_variable is now equal to 1
- We print @a_local_variable on screen
[End of program]


Here's a diagram to better visualize what I mean:

Attached File  inheritance1.jpg ( 32.19k ) Number of downloads: 1083


So, as you can see, if we do a super keyword, it execute the method in the SuperClass, as putting a "super" keyword in method_a of the SubClass will execute the method_a of the SuperClass.... And so on.

You can also use the "super" keyword with arguments, as explained in Chapter 1, this can be seen in every Window class of RMXP; will be explained in section 5 below.

5- Scene And Window

RPG Maker XP interfaces are built with Scene and Window. Each scene is composed of many windows. The way it works is like having a lot of little blocks on a table, and we arrange the blocks a certain way to built what we desire. The table is the scene, and the blocks are the windows. So, it's logical to built a block before we can do a scene.... So let's do a window now:

Creating a window

The basic of a window is simple, you may have seen it in all the Window_ script in the default RMXP Script Editor. We will built a new window called "My_Window". To test it when you're done, simply do a Call Script in an event and write this in it:

CODE
My_Window.new


My_Window code:

CODE
class My_Window < Window_Base

  def initialize
    super(0, 0, 200, 200)
  end
  
end


*I'm aware of the fact that the window disapears after a while; it's normal, it's because of Scene_Map; we did not told Scene_Map to update that window. We'll talk about that later. Let's just built a simple window for now:

As you can see, this have the effect of creating a window on the top left corner of the screen. Here's the syntax:

super(x position, y position, width size, height size)

As you have learned in section 4, inheritance, "super" is used to execute a method in the SuperClass. Our window have Window_Base as SuperClass, so let's take a look at the initialize method of Window_Base:

Window_Base Initialize method:

CODE
def initialize(x, y, width, height)
    super()
    @windowskin_name = $game_system.windowskin_name
    self.windowskin = RPG::Cache.windowskin(@windowskin_name)
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.z = 100
  end


This is invoked each time you do a window, this defined it's sizes and position, it's windowskins and such other attributes. What is important to look at is the following line:

def initialize(x, y, width, height)

As explained in Chapter 1, those are Attribute Receivers (as I call them), so by using our "super(0, 0, 200, 200)" in the code of our window, RMXP actually did this:

[Super keyword interpreted...]
- Read arguments sent with "super"
--> In Window_Base, we set the following attribute with the data sent with super:
-> x=0
-> y=0
-> width=200
->height=200
--> The window is created
-Back to our window code
[End of program]


This window is plain... It's empty. Let's write something in it.

My_Window Code (+Text):

CODE
class My_Window < Window_Base

  def initialize
    super(0, 0, 200, 200)
    self.contents = Bitmap.new(width-32, height-32)
    self.contents.font.name = "Arial"  
    self.contents.font.size = 24
    self.contents.draw_text(0, 0, 200, 32, "Yay, some text !")
  end
  
end


3 lines are necessary to add text. You must specify a font name, a font size, and write the text itself. Let's explain those line:

self.contents = Bitmap.new(width-32, height-32)
This tells that the content of our window should be of the "Bitmap" type (Bitmap is defined within RMXP, not in the Script Editor). This allow to write text in the window, basically. The argument we send is the size of that bitmap area. Usually, we set it equal to the window size, hence width and height. (Remember, width and height are defined in the SuperClass, and we set them with our super line above.)

Wanna know the big dark secret of the minus 32 ? I.E: width-32 ? It's because that arrow will appears pointing that data can still be viewed; this is probably because the bitmap is genuily larger than the window... dunno. We could have written (200-32, 200-32), it would have given the same result. (This could also be the reason of the text being cut-off in the borders of the window).

The 2 other lines are straight forward.

self.contents.draw_text(0, 0, 200, 32, "Yay, some text !")
This line actually defines your text. The arguments you send in the parenthesis are the same as with the creation of a window. i.e: (x position, y position, width size, height size). The last argument is simply the text to draw in the window.

*I am also aware that when looking at the Window code by default in the Script Editor, the text is actually drawn in another method, usually called "refresh". This is useful only if the content of the window will change as the window is shown. In other words, it is relevant to code it like that in Window_PlayTime, but not really in Window_Gold.

Now that we are able to create a basic window, we can try to built a scene that will show, let's say, 3 windows. Window #1 will show the playtime, the gold held and the map ID on which you are. Window #2 will list the hero present in your party one above another, and window#3 will show stats for the hero in your party.

(Take note that there isn't any window command (menu) in that scene yet. This will come later.)

Here's the basic layout of what we want to achieve:

Attached File  scene_sample.jpg ( 46.21k ) Number of downloads: 2544


*OK ! I know, it's plain, it's ugly and kind of useless design... But we just want to know how to code a scene, without too many thing at the same time. Don't worry, I will explains how to work with selectable menu, even with multiple selectable menu, in chapter 3.

Creating Window #1

The first window is the window on the top that shows the playing time, the gold held and the map ID. This is the simplest window to code. You could put all three window code and the scene in the same page in the script editor, but as this is a lesson, it's better to create a page for each window, and another for the scene, that way you won't get confused in all the code. So, first thing first, create a new page and call it Window_1 and add this code in it:

(Important: You must add the page below the page containing the SuperClass of any script you do. This means that our window will work as long as they are below Window_Base. --> What I always do is add new custom script just above MAIN, all the time.)

Window_1 Code:

CODE
class Window_1 < Window_Base

  def initialize
    super(0, 0, 640,100)
    self.contents = Bitmap.new(width-32, height-32)
    self.contents.font.name = "Arial"  
    self.contents.font.size = 24
    refresh
  end
  
  def refresh
    self.contents.clear
    self.contents.font.color = text_color(6)
    self.contents.draw_text(0, 0, 100, 32, "PlayTime:")
    
    #CODE TO SHOW PLAYTIME (Copied from Window_PlayTime)
    @total_sec = Graphics.frame_count / Graphics.frame_rate
    hour = @total_sec / 60 / 60
    min = @total_sec / 60 % 60
    sec = @total_sec % 60
    text = sprintf("%02d:%02d:%02d", hour, min, sec)
    self.contents.font.color = normal_color
    self.contents.draw_text(100, 0, 120, 32, text)
    #END OF CODE TO SHOW PLAYTIME
    
    self.contents.font.color = text_color(6)
    self.contents.draw_text(250, 0, 50, 32, "Gold:")
    self.contents.font.color = text_color(0)
    self.contents.draw_text(305, 0, 100, 32, $game_party.gold.to_s)
    
    self.contents.font.color = text_color(6)
    self.contents.draw_text(400, 0, 100, 32, "Map ID:")
    self.contents.font.color = text_color(0)
    self.contents.draw_text(480, 0, 100, 32, $game_map.map_id.to_s)
  end
  
  def update
    if Graphics.frame_count / Graphics.frame_rate != @total_sec
      refresh
    end
  end
  
end


As you can see, I seperated the script in 5 differents blocks, and I will explains those block lines by lines.

BLOCK 1:

1 def initialize
2 super(0, 0, 640,100)
3 self.contents = Bitmap.new(width-32, height-32)
4 self.contents.font.name = "Arial"
5 self.contents.font.size = 24
6 refresh
7 end



This is the initialize method, with what you have already read in this chapter, and in chapter 1, you should be able to know what is going on in this block. Line 1 to 5 were explained in above sections, so I won't repeats myself. The 7th line simply calls the "refresh" method, that is defined below.

BLOCK 2:

1 def refresh
2 self.contents.clear
3 self.contents.font.color = text_color(6)
4 self.contents.draw_text(0, 0, 100, 32, "PlayTime:")

5 #CODE TO SHOW PLAYTIME (Copied from Window_PlayTime)
6 @total_sec = Graphics.frame_count / Graphics.frame_rate
7 hour = @total_sec / 60 / 60
8 min = @total_sec / 60 % 60
9 sec = @total_sec % 60
10 text = sprintf("%02d:%02d:%02d", hour, min, sec)
11 self.contents.font.color = normal_color
12 self.contents.draw_text(100, 0, 120, 32, text)
13 #END OF CODE TO SHOW PLAYTIME
[...]


This is the first block that begins the method refresh. The first thing we do is clear the content of the window... why the heck do we want to do that in the first place ? Well, it's because we will refresh the content of that window in our later scene to show the play time running; and we do not want the text to show over and over again, or else it would get messy.

Line 2: self.contents.clear actually take care of that.

Line 3 and 4 were explained in above sections, they take care of showing the text "Playing Time:" in the window, at the desired location. The only thing that I haven't yet shown is line #3: self.contents.font.color = text_color(6). This line specify the color used to draw the text. The number between parenthesis at the end represent the color ID defined in Window_Base starting at line #39. (I.E: They are the same color ID used in messages event, using \c[ID].)

The code to show the playing time start at line 5. This code is the same as in Window_PlayTime, except for the location of the time in the window. If you wonder what is all that giberrish in the code, I will clear it out:

Line 6: @total_sec = Graphics.frame_count / Graphics.frame_rate

This create a new variable named @total_sec, and makes it equals to the total frame count that occured in the game divised by the frame per seconds (The frame rate - FPS). Basically, it can be converted like that:

- 12450 Frames has been counted since the begining of the game.
- The FPS (Frame Rate or Frame Per Second) is 30.
- If you want to know the numbers of seconds, you do 12450/30=415 --> 415 sec.

So, basing ourselves on that new seconds variable, we can define a number of minutes and a number of hours, since we all know that there are 60 seconds in a minutes, and 60 minutes in an hour.

Line 7: hour = @total_sec / 60 / 60

This line thus calculate the number of hours played. If we take the example from above, it would give us that result:

-> 415 / 60 / 60 = 0.115 --> 0 hour.

RMXP gives us 0 as an asnwer since it's using Integers in the equation; and Integers does not allow decimals. We'll talk about maths in chapter 3.

Line 8: min = @total_sec / 60 % 60

Ok, this is the line that may have confused you... What on earth is the use of the % ? Well, it does a modulo (known as mod). I already explained what was a modulus (modulo, mod) in my RMXP Variable Demystified. Here's an extract of it:

QUOTE
The modulus is the ramainder of a division. If we divide 17 by 3 on a calculator, its answer would be "5.666666667", but this anwser has nothing to do with modulus.

The mod function is defined as the amount by which a number exceeds the largest integer multiple of the divisor that is not greater than that number. Here's how it's working:

17 mod 3 = 2
Because 17 / 3 = 5 remaining 2, wich means that 17 = 3 * 5 + 2

Try this: Take a calculator and divide 17 by 3, it will give you 5.666666667.
Now, take only the full integer 5 (don't take what is after the decimal). Multiply 5 by 3, and it gives you 15. Then what remains from 17 - 15 ? Exactly, 2. This makes the 17 mod 3 = 2 take all it's sense.


So, this means that 60 modulo 60 would equals 0, since 60/60=1, and that 1 has no remaining value. All that means that this little line will reset the minutes variables to 0 when it has reached 60.

So, keeping our example, here's what it logically gives us:

(415 / 60) mod 60 = 6.916 --> 6 minutes (RMXP doesn't floor the value.)

I do not have to explain line 9, it's the same thing as line 8, but to count the number of seconds.

Line 10: text = sprintf("%02d:%02d:%02d", hour, min, sec)

sprintf is used to format a string (A text variable) using format code. What is between the quote marks " " are the format code. A format code is actually composed of "flag characters" and "field type". The flag character will set the view format of the resulting string, and the field type will specify how to interpret the argument sent into sprintf. Each implementation of sprintf begins with a % sign, and every other symbols added into a format code that isn't known as wether a "field type code" or a "falg character code" is shown as is in the resulting string. The argument sent in sprintf are listed after the format code, seperated with comas. The number of argument sent must be equals to the number of format code used (begins with a %). So, let's see what this line actually did:

We created "text", that is a local variable as explained in section 1, and we set it equal to the result of our sprintf command. Let's see each format code:

%02d
This is the first one, and the 2 other are identical. How does this work ? Well, the % sign tells the program that what follows is a format code. "0" is a "flag character" that is used to set the view format. 0 is to add the number 0 (zero) before the string instead of spaces, and the following number "2" tells the program to write 2 zeros. Just try to change this 2 by a 3, and you will see 3 zeros in your Window_PlayTime menus. The letter "d" tells the program to interpret the argument we will send as decimal numbers. Then, we wrote :, and since this isn't a code, it's written in the string as is.

So, this means that we format a new string that will look like that:

00:00:00

Yay, it's a clock ! There are many other format code, you can found them on the web, a website containing them can be found on my website links sections.

You can see that after the quote marks come the 3 other local variable we created on line #7, 8 and 9 (hour, min, sec). Here's a small diagram, and we can go to the next line:

Attached File  sprintf.jpg ( 31.15k ) Number of downloads: 1048


Line 11 to 13 were also explained in earlier section and chapters, they show the text we just formated with our sprintf. Let's jump to the next block:

BLOCK 3:

1 self.contents.font.color = text_color(6)
2 self.contents.draw_text(250, 0, 50, 32, "Gold:")
3 self.contents.font.color = text_color(0)
4 self.contents.draw_text(305, 0, 100, 32, $game_party.gold.to_s)


This should not be too hard, it was, once again, already explained. I need only to explain a small thing about line #4.

Line 4: self.contents.draw_text(305, 0, 100, 32, $game_party.gold.to_s)

The .to_s at the end of the variable is to convert it into a string, so we can draw it as text. If we try to put a variable containing numbers there, an error will pop up saying "Cannot convert Fixnum into String". So we tell the program to convert it in the code, and it thus work fine.

I don't have to explain the next block, as it is the same thing as block 3; it just shows the map ID instead of the gold held. So let's jump to the last block, update:

BLOCK 5:

1 def update
2 if Graphics.frame_count / Graphics.frame_rate != @total_sec
3 refresh
4 end
5 end
6 end


This is our update method. As you can see, this method isn't used from within our window, it will be used by our Scene later on. The method update of our window most exist, because we will make it update in our scene. Window that doesn't have to be updated as they are seen don't need any update method. You will see what I mean when we will code our Scene later on. But let's explain the lines anyway:

(I'll skip the line that you are supposed to understand now, because chapter 1 and the earlier section of chapter 2 should have teached you those lines.)

Line 2: if Graphics.frame_count / Graphics.frame_rate != @total_sec

This is an If Statement as described earlier. And if you have read my RGSS Reference as I told eariler, you will know that != means "Not Equal To". So, what we do in that IF is the following:

We divise the total amount of frames that occured in the game by the frame rate (this gives us the total amount of seconds, as explained above), and we check if that answer is equal or not with our variable @total_sec (which contains the total amount of sec that was created when we show the window for the first time.) If it's not equal to it, we call the refresh method, and thus we clear the content, and recalculate the new time, and show it once again. So, this update method check if the time has changed, and when it does, we show the new time.

Creating Window #2

The second window is the one to the left, which list the hero in your party, with their class beneath them. Add a new page and name it Window_2.

Window_2 Code:

CODE
class Window_2 < Window_Base
  
  #BLOCK 1
  def initialize
    super(0, 0, 200,380)
    self.contents = Bitmap.new(width-32, height-32)
    self.contents.font.name = "Arial"  
    self.contents.font.size = 24
    
    #BLOCK 2
    for i in 0...$game_party.actors.size
      x = 0
      y = i * 90
      actor = $game_party.actors[i]
      self.contents.font.color = text_color(6)
      self.contents.draw_text(x, y, 200, 32, $game_party.actors[i].name)
      self.contents.font.color = text_color(4)
      self.contents.draw_text(x, y+32, 200, 32, actor.class_name)
    end
  end

end


This window contains less code, it's because it draw the text in a for loop. I won't explain BLOCK #1 as it was already explained in above sections. Let's jump once again to our next block:

BLOCK #2:

1 for i in 0...$game_party.actors.size
2 x = 0
3 y = i * 90
4 actor = $game_party.actors[ i]
5 self.contents.font.color = text_color(6)
6 self.contents.draw_text(x, y, 200, 32, actor.name)
7 self.contents.font.color = text_color(4)
8 self.contents.draw_text(x, y+32, 200, 32, actor.class_name)
9 end
10 end
11 end


Line 1: for i in 0...$game_party.actors.size

As shown earlier, this is our for loop. The .size command is a ruby command to know the size of an array, or a string. If you read my RMXP Variable Demystified, you'll know what is an array and such. $game_party.actors is an array variable containing the hero present in your party. Remember that an array index start at 0, not at 1, which means that the first hero in your party doesn't have the party ID#1, it have the party ID#0. So, this for loop actually iterate itself starting at 0, and finish at the amount of hero present in your party, excluding the last number. (Remember the range rules with the ... and .. points.) --> Why exclude the last number ? Here's why:

(This example take into consideration that 4 hero are present in your party)

[For Loop Start]
- We check the size of game_party.actors
- We have 4 party members, it thus equals 4
--> We will do 4 iteration in the for loop.

[First Iteration - 1/4]
- i=0
- refers to the game_party actor ID#0 (the first one)

[Second Iteration - 2/4]
- i=1
- refers to the game_party actor ID#1 (the second one)

[Third Iteration - 3/4]
- i=2
- refers to the game_party actor ID#2 (the third one)

[Forth Iteration - 4/4]
- i=3
- refers to the game_party actor ID#3 (the forth and last one)


As you can see, ID0 is your first hero in the party. If we would have used 2 points in our range to include the last number, it would have given a loop that does 1 iteration that should not be done. (i.e: The array index start at 0, so look at this:)

index 0 = Hilda
index 1 = Arshes
index 2 = Eliette
index 3 = Dubealex

We thus have an array with a size that equals 4. (I hope you got it.)

Line 2 and 3: x = 0 -- y = i * 90

Remember that we are still inside the for loop body, which means we will do what is there multiple times. The first one is easy, x=0, this create a local variable and set it to 0. We will use that x variable later to place all our text at coordinate x (which is 0). If you change that 0 by another value, you will see that all the names will appears elsewhere in the window.

The second one, y = i * 90, again create a local variable y that we will again use to place the text in the y coordinates. The trick in that part is that we want each name to appears above another, not in the same spot ! Since we now know that our variable i contains the iteration value (as I said earlier), we can thus use that. We multiply it by 90, if you put another value in place of 90, you will simply see more space between each name, or less space, depending on which value you put there. So, here's an explanation of this process:

[First Iteration]
- i=0
- x=0
- y= i * 90
--> i equals 0, so 0 * 90 equals 0.
- We will draw the first name at coordinates [0,0] ([x,y])

[Second Iteration]
- i=1
- x=0
- y= i * 90
--> i equals 1, so 1 * 90 equals 90.
- We will draw the second name at coordinates [0,90] ([x,y])

[Third Iteration]
- i=2
- x=0
- y= i * 90
--> i equals 2, so 2 * 90 equals 180.
- We will draw the third name at coordinates [0,180] ([x,y])

[Forth Iteration]
- i=3
- x=0
- y= i * 90
--> i equals 3, so 3 * 90 equals 270.
- We will draw the forth name at coordinates [0,270] ([x,y])


Line 4: actor = $game_party.actors[ i]

This line is to save space below, it wasn't a "necessary" line. But it's useful as it makes the line below smaller and more easy to understand. We also do not have to repeat the full variable name over and over again. Here's what it do:

It create a local variable name actor, and set it as being $game_party.actors[ i].
(Remember that i is the party hero ID.) --> Then, in later lines, you can just use line like actor.name to refer to $game_party.actors[ID].name, which is a long line to type, isn't ?

Line 6: self.contents.draw_text(x, y, 200, 32, actor.name)

As explained earlier, we now draw the text of our hero's at coordinates x (which is 0), and coordinates y (that is calculated at each new iteration). And we can use actor.name instead of the full variable name, to save time and space in the script.



If the worst hasn't happened yet, it is because you have not tried everything yet.






Go to the top of the page
 
Thanks+Quote Post
Dubealex
post Nov 7 2005, 09:43 PM
Post #2


Administrator of this Asylum
Group Icon
Group Icon


Admin

Member No.: 1
Posts Liked: 48 *
Joined: 8-November 04
Posts: 2,704
-->
From: Longueuil, Canada

RPG Maker Level:
Master

Class Title:
Writer, Scripter & Designer

Last.fm ID: Dubealex

Country:



Line 8: self.contents.draw_text(x, y+32, 200, 32, actor.class_name)

This line is similar to line 6, except for our y coordinates. We do y+32 because we want the class names to be written below the hero's name. (Remember, to go higher in the Y coordinate, you must lower the value, and to get lower, you must augment the value... I know it can be confusing at first.) We set 32 since we have text height of 32 everywhere, and it fits right. If you customize your script, you will have to put values that fits with your fonts and menus.

Ok, that's it for this window. It wasn't that complicated, once you get the hang of it, isn't so ?

Creating Window #3

The third and last window is the window to the right, the one that contains the heros attributes. This one looks like the window #2, but with a twist... We will use an if statement inside the for loop to make the hero appears in 2 column instead of all above another. So, just add another page in the script editor, and name it Window_3:

CODE
class Window_3 < Window_Base

  #BLOCK 1
  def initialize
    super(0, 0, 440,380)
    self.contents = Bitmap.new(width-32, height-32)
    self.contents.font.name = "Arial"  
    self.contents.font.size = 24
    
    #BLOCK 2
     for i in 0...$game_party.actors.size
      x = 0
      y = i * 150
      if i >= 2
        x=250
        y -= 300
      end      
      actor = $game_party.actors[i]
      self.contents.font.color = text_color(6)
      self.contents.draw_text(x, y, 200, 32, actor.name)
      offset_x=contents.text_size(actor.name).width+10
      self.contents.font.color = text_color(4)
      self.contents.draw_text(x+offset_x, y, 200, 32, "Lv: " + actor.level.to_s)
      draw_actor_hp(actor, x, y+32)
      draw_actor_sp(actor, x, y+64)
      draw_actor_exp(actor, x, y+96)
    end
  end
  
end


Information about block 1 was explained in previous lessons. So I will skip to block 2:

Line 1: for i in 0...$game_party.actors.size

This will make a "for loop" starting at 0 and stoping at the size of our current game party, which is a max of 4 by default. THe game party info are stored as an array and thus start at 0, this is why the first hero in the party is known as 0, and the last as 3.

Line 2: x = 0

Here we define x as being 0 so the listing can start at the far left of the screen.

Line 3: y = i * 150

This line define the vertical position, and since we are doing a for loop, Y is defined as being the value of our loop (where we are at in the cycle) multiplied by 150 to let enough space to put the info we want for our hero.

Line 4: if i >= 2

This line is the If Statement. This is only this little if statement that allows us to have 2 column of stats instead of one. To better explain it, I will show you the complete If body, not just the first line:


4 if i >= 2
5 x=250
6 y -= 300
7 end


So, line 4 check if our i variable is bigger or equal than 2, and if it does, it will do what is inside the If body. Remember, when our i value is equal to 2 (or bigger) it's because 2 hero's where processed already. We wanted 2 hero in one column, and another 2 heros in another column. So when i equals 0 or 1, it is the 2 first hero to draw. When it's equals to 2 or 3, it the 2 last one.

Line 5: x=250

So, if 2 hero were already processed, we don't want the 2 other to be drawn at the same spot, so we change the X cooridnate to 250, which will draw our 2 last hero to the right of the first.

Line 6: y-=300

This line does almost the same thing as line 5. It modify the y value, but the fact is that we want the hero to have the exact same spacing between them, but since our i value is already at 2 when we do this, we must subtract the extra 300 that we got so we can draw the 2 other hero at the top of the new column. Here's a process sample for those who did not get that right:

[First Iteration]
- i=0
- x=0
- y= i * 150
--> i equals 0, thus 0 * 150 = 0 (y=0)
- Check the if statement, it return false, i isn't bigger or equal to 2.
--> New coordinates to draw text are [0,0]
[etc]

[Second Iteration]
- i=1
- x=0
- y= i * 150
--> i equals 1, thus 1 * 150 = 150 (y=150)
- Check the if statement, it return false, i isn't bigger or equal to 2.
--> New coordinates to draw text are [0,150]
[etc]

[Third Iteration]
- i=2
- x=0
- y= i * 150
--> i equals 2, thus 2 * 150 = 300 (y=300)
- Check the if statement, it return true, i IS bigger or equal to 2.
--> We enter the If Statement body and execute the actions in it...
- x=250 (Change the value inside x to 250)
- y-=300
--> y equals 300, thus 300-300=0 (y=0)
--> New coordinates to draw text are [250,0]
[etc]

[Forth Iteration]
- i=3
- x=0
- y= i * 150
--> i equals 3, thus 3 * 150 = 450 (y=450)
- Check the if statement, it return true, i IS bigger or equal to 2.
--> We enter the If Statement body and execute the actions in it...
- x=250 (Change the value inside x to 250)
- y-=300
--> y equals 450, thus 450-300=150 (y=150)
--> New coordinates to draw text are [250,150]
[etc]


So, as you can see, we just create 2 aligned columns ! Let's jump to the other lines. Line 8 to 10 were already explained earlier...

Line 11: offset_x=contents.text_size(actor.name).width+10

This line create a local variable named "offset_x", that will be equals to the width of the name of the hero that we have drawn plus 10 (so there a bit of space between what we will write there...) This will be used when drawing the Level of the hero. Basically, we wants the Level to be drawn just aside of the hero's name, but since hero's name can be of many different sizes, we must use a variable to set the x position of the level text. contents.text_size(actor.name).width is a command that allow you to know the width of a text. We specify which text between the parenthesis, and we choose a attribute after the last point. To know the height, we just replace width by height.

Line 13: self.contents.draw_text(x+offset_x, y, 200, 32, "Lv: " + actor.level.to_s)

This is the line that write the Level of the heros. So, as you can see, we have set it's x position by adding our "offset_x" value to the existing x position. That way, the level is always aside the names. Remember the .to_s command... The level is an integer, we must convert it to a string before writing it.


Line 14: draw_actor_hp(actor, x, y+32)

Ok, if you are asking yourself where the "variable" draw_actor_hp come from, you are mistaken. draw_actor_hp is in fact a method name, since we have argument between parenthesis aisde it. But wait a minute... Where is that method ? It's not in our Window_3 code ? Well... Remember inheritance ? We have set Window_Base as the SuperClass of Window_3, so that method is bound to be inside Window_Base, isn't ? Let's check it out ! Let's open Window_Base, and run a search for "draw_actor_hp" ... Found it ? Here it is:

(I hate those jap giberrish comments.... anyway...)

Window_Base -> draw_actor_hp method code:

CODE
def draw_actor_hp(actor, x, y, width = 144)
# ??? "HP" ???
self.contents.font.color = system_color
self.contents.draw_text(x, y, 32, 32, $data_system.words.hp)
# MaxHP ???????????????
if width - 32 >= 108
hp_x = x + width - 108
flag = true
elsif width - 32 >= 48
hp_x = x + width - 48
flag = false
end
# HP ???
self.contents.font.color = actor.hp == 0 ? knockout_color :
actor.hp <= actor.maxhp / 4 ? crisis_color : normal_color
self.contents.draw_text(hp_x, y, 48, 32, actor.hp.to_s, 2)
# MaxHP ???
if flag
self.contents.font.color = normal_color
self.contents.draw_text(hp_x + 48, y, 12, 32, "/", 1)
self.contents.draw_text(hp_x + 60, y, 48, 32, actor.maxhp.to_s)
end
end


This is where all is coded... well, this code actually set the colors of the HP, set all the formatting. So, if you need to adjust stuff in your game, go there and have fun with the customization ! Back to our window now:

All the other lines actually calls method from Window_Base to draw the HP, SP and Exp of our heros on the screen. There's really nothing more to it. We simply add some value to our y position, so they can be all above the others.

It's now the time to create our magnificent scene... :clap:

Creating Our Scene

Now that we have 3 window working right, we need a scene to show them on screen. Remember when I was talking about a table and blocks... The table is your scene, and you can arrange your blocks as you please on that table. If you look at your window code, you will notice that we only set their width and height, we never specified any X and Y position. i.e:

CODE
def initialize
super(0, 0, 440,380)

#(x position, y position, width size, height size)


It's because we will place those window where we desire in our scene. That way, if you wanted to have the Window_1 at the bottom, you can by modifying the scene, not the window. It's better that way, it's a better development habit.

Ok, with that said, let's create our table... arg... our scene ! Just add a page in your script editor, and name it Scene_Chapter_2.

Scene_Chapter_2 code:

CODE
class Scene_Chapter_2

#BLOCK 1
def main
   @window_1=Window_1.new

   @window_2=Window_2.new
   @window_2.y=100

   @window_3=Window_3.new
   @window_3.x=200
   @window_3.y=100

#BLOCK 2
   Graphics.transition
   loop do
    Graphics.update
    Input.update
    update
    if $scene != self
     break
    end
   end

#BLOCK 3
  Graphics.freeze
   @window_1.dispose
   @window_2.dispose
   @window_3.dispose
  end

#BLOCK 4
def update
   @window_1.update
   if Input.trigger?(Input::B)
     $game_system.se_play($data_system.cancel_se)
     $scene = Scene_Map.new
   end
  end

end


BLOCK 1:

1 def main
2 @window_1=Window_1.new

3 @window_2=Window_2.new
4 @window_2.y=100

5 @window_3=Window_3.new
6 @window_3.x=200
7 @window_3.y=100


This the begining of our main method for our scene. Ok... Why isn't there a method named initialize as in almost all other class... Why do a scene have a method called main instead of initialize ? Well, it's all up to Entrebrain, look in the MAIN script (to the very bottom), you will see that code around line #18:

CODE
while $scene != nil
    $scene.main
  end


As you can see, they check for .main (method main), so if you just play with it, and write "pepsi" instead of "main", it would give you "$scene.pepsi". Of course, now all your scene would not work anymore. You would need to go in all of them, and change their method main by pepsi, and voil? ®? But let's stick to what's there by default, main is pretty descriptive of what it does...

Line 2: @window_1=Window_1.new

Remember Chapter 1 ? We talk about objects and stuff like that, so you should know by now that we just created a new object name @window_1 that is of class Window_1. So, now we can manipulate our window_1 as we want, without affecting the real window.

Line 3 and 5 just does the same thing, but they "spawn" window 2 and 3 instead. Then we have lines 4, 6 and 7. Those lines specify our x and y position for the window we want. Wait a sec there... If you remember correctly chapter 1, we have said that to use something like @object.method, we need that method defined in the class of that object... And @window_2.x calls a method named x; this method isn't in our Window class. Let's look in Window_Base, it's SuperClass... Nope, it's not there. Let's then look in the SuperClass of Window_Base, which is Window...Oups, we don't have access to this class. The Window class is the class that built the in-game interface of RPG Maker XP. There is a lot of low-level code in there, thus Enterbrain just implemented it into RPG Maker, and we don't have access to it. But the method x is inside that Window class. You can simply open the help file of RMXP and go to the right section to see all the method inside Window. Just open it, and go in the SEARCH tool, type in Window, and choose the relevant section. The list is right there. You can translate it with Babel Fish.

With all that said, we simply configured our window where we want them, and that's all.

BLOCK 2:

1 Graphics.transition
2 loop do
3 Graphics.update
4 Input.update
5 update
6 if $scene != self
7 break
8 end
9 end


Line 1: Graphics.transition

This line make the scene appears. Once again, it's all interpreted by stuff already coded. This is why RGSS is simpler than Ruby, it's a scripting language. You can use already maded components. If you omit that line, the scene still works, you will just not see it on screen.

Line 2: loop do

This line start a loop, somewhat like a for loop, but it will repeat itself until the keyword "break" is met. In this case, we break the loop if the scene isn't the same as the scene you are viewing. This is done by the If Statement on line #6. This loop will start when you open the scene, and will always repeats itself.

Line 3: Graphics.update

This will update the graphics on screen, if you omit that line, you won't see any modification made to the window after the scene was first drawn. This mean that if you delete that line, you won't see the Playing Time running.

Line 4: Input.update

This update the input command the player can do in the game. This make sure that RMXP is always looking for a keypress made by the player. If you omit that line, you won't be able to use any interactivity in your scene.

Line 6, 7 and 8 were explained above, it's our If Statement checking if the scene is changed. If it's changed, we must stop that loop.

BLOCK 3:

1 Graphics.freeze
2 @window_1.dispose
3 @window_2.dispose
4 @window_3.dispose


This part is still inside our main method, this part take care of getting rid of our window when we exit the scene. You may be wondering why the window are disposed only when we exit, even if the main method is the first to be executed when you open a scene ? Well, it's because of the Loop. Just like a for loop, what comes after the loop in the code will be executed only when the loop is completed or stopped. So, all that code after the loop will be executed only when we will break that loop in the If Statement; as explained above.

Line 1: Graphics.freeze

This line take care of making a "transition" between both scene. Because in RMXP, while you play, you are always in a scene or in another. So, when you exit a scene, that line makes sure that the scene you were in actually fade out and do not dissapear instateneously (Did I write that word well ??). If you delete that line, you will see what I mean.

Line 2,3 and 4 actually take care of disposing of the window, so they aren't there anymore when you exit the scene. It will destroy the object we have created. That's why you may get errors if you try to access a window that have been previously disposed... You can't access an object that doesn't exist... It's purely logical.

This time we can found the method "dispose" in Window_Base, here it is:

CODE
def dispose
  # Jap Comments
  if self.contents != nil
    self.contents.dispose
   end
   super
end


As you can see, that method only take care of getting rid of the content of the window, and there should be more stuff going on. So, once again, the code that is really responsible for disposing a window is in Window, not accesible by us. And you can clearly see that this dispose method call "super", meaning it's calling the method "dispode" in it's SuperClass, which is Window... The dark and mysterious class of RMXP.

BLOCK 4:

1 def update
2 @window_1.update

3 if Input.trigger?(Input::cool.gif
4 $game_system.se_play($data_system.cancel_se)
5 $scene = Scene_Map.new
6 end
7 end
8 end


This block is our update method, which is called in our main loop as explained above. That's is what makes the update method repeats itself over and over again.

Line 2: @window_1.update

As explained in chapter 1, this will execute the update method of our class Window_1... Simply because we have defined @window_1 as being an object of class Window_1 in our main method. Now you know why we coded an update method in our Window_1 earlier. So, to refresh your memory, we add an if statement in this method, that check if the total second has changed. If it does changes, it then calls refresh and re-draw the time in the window. Since the update method of our scene is looping, the update method of our Window_1 is also looping... and so on. Pretty cool isn't ?

As you can see, we don't need any update for the 2 other window, we don't plan on modifying their content while the scene is open.

Line 3: if Input.trigger?(Input::cool.gif

This is another If Statement, in all it's glory, that is checking the input made by the player. Know that Input:: is in fact a module implemented inside RMXP, we still don't have access to it. If that If Statement becomes true, meaning that IF the playing press the B key (Which is the Escape, X or the NumPad 0 key on the keyboard by default. You can change that in the menu while you play by pressing F1.)

Line 4: $game_system.se_play($data_system.cancel_se)


This line will play an SE (Sound Effect) when you leave the scene. This is purely for aesthetic purposes. But I will explain how it's working anyway, as almost everything in RMXP works the same, if you understand that, you will understand almost everything else.

$game_system is an object created when you start a game. It's created in Scene_Title, in the main method, here it is:

CODE
$game_system = Game_System.new


So, everything that you can do with that object is defined in it's class, which is Game_System, as I explained in my Chapter 1. So, by filtering all the method inside Game_System, you can have a broader idea of what you can with it. So, in that particular line, we are invoking the se_play method, that is requiering an argument, which we specified in the parenthesis. (All of this was in Chapter 1 anyway.) So, if we search in Game_System to found that method, we will found that:

CODE
def se_play(se)
   if se != nil and se.name != ""
    Audio.se_play("Audio/SE/" + se.name, se.volume, se.pitch)
   end
  end


This will play the SE. Take a look at how it's working, and you may have to follow the traces given by the objects/class names. You can thus try to understand anything by yourself. Become a "code hunter". Everything leave a trace, just follow it.

Example: You see se.name in the If Statement... where does it come from ? Well, you can tell that it's a local variable by the way it's written, and since there is a point and a command after it, it should means it's an object, isn't ?

Well, you aren't that far off, but in this very case, it's a bit darker. To know what is se.name and how it's working, you must first know that se is actualy the argument receiver of our method se_play. So, we need to check what we sent as argument... Let's see:

CODE
$game_system.se_play($data_system.cancel_se)


Okay, we sent $data_system.cancel_se as argument. What is $data_system ? Once again, it's an object, it's followed by a point. So check in Scene Title, you will see it's definition once again, and you will be able to know what it is. Here:

CODE
$data_system = load_data("Data/System.rxdata")


Oh boy, now we are going far far away. $data_system refer to the System.rxdata file found in your Data directory of your project. WHat does this file contains ? Well, when you open your datase in RMXP, the last tab is named System, well, that file stores all the stuff you set in that section. Which means that each tab in the database has it's rxdata file... So that's it, se.name is inside System.rxdata, our search ends here.

(Well, to be honest, I just improvised all this little "code hunt" section, and I think it's cool to learn, so I will do another tutorial called "Code Hunt" that will give tricks like that.)

Line 5: $scene = Scene_Map.new

This line actually change the scene. Once again, $scene is an object, the first occurance of it's definition is in MAIN, it define $scene as being of class Scene_Title.

So, now, to conclude this chapter, you just have to test play that scene to test it out. Make sure all your 3 Window and your Scene are in your Script Editor, and make a call script in an event with that in it:

CODE
$scene=Scene_Chapter_2.new


That will start the scene. To exit the scene, you press Escape.

In chapter 3 we will tackle some more advanced stuff. We will learn how to add a selection menu, and how to work with multiple selection menu in the same scene. We will also learn important component of Ruby, like how to do Alias and more advanced stuff, so your script can be more powerful.

I hope you like that tutorial, it took a hell lot of time to do... lol (I'm tired... I'm exhausted. Let's post that on the board, and relax for a while... by !)



If the worst hasn't happened yet, it is because you have not tried everything yet.






Go to the top of the page
 
Thanks+Quote Post
Supreme Pie Ninj...
post Nov 8 2005, 05:19 AM
Post #3


Version 2.0
Group Icon


I'm Awesome !!

Member No.: 88
Posts Liked: 0 *
Joined: 13-December 04
Posts: 7,175
-->
From: Canada™

RPG Maker Level:
Expert


Country:



Wow...that's nice!

Good job as always!
Go to the top of the page
 
Thanks+Quote Post
datriot
post Nov 8 2005, 05:21 AM
Post #4


God
Group Icon


God

Member No.: 1,693
Posts Liked: 5 *
Joined: 24-September 05
Posts: 1,514
-->
From: Leeds, United Kingdom

RPG Maker Level:
Not Applicable

Class Title:
First Knight of the Order of the Pie

Country:



OMG, this must be like the longest tutorial ever created!
Thanks again for another lesson of greatness and stuff. tongue.gif

Wait a sec....I read this ages ago....why am I replying to it now.....wierd.....

This post has been edited by datriot: Nov 8 2005, 05:21 AM
Go to the top of the page
 
Thanks+Quote Post
Dubealex
post Nov 8 2005, 09:40 PM
Post #5


Administrator of this Asylum
Group Icon
Group Icon


Admin

Member No.: 1
Posts Liked: 48 *
Joined: 8-November 04
Posts: 2,704
-->
From: Longueuil, Canada

RPG Maker Level:
Master

Class Title:
Writer, Scripter & Designer

Last.fm ID: Dubealex

Country:



lol, this isn't a new tutorial, it's the RGSS lessons chapter 2 -- The other topic was corrupted and I could not fit all the text in the post... :eusa_whistle:

And by the way, it took a long time, but I fixed all my tutorials to remove the weird characters (A) and stuff that occured because of the transfer to the new server.

C ya !



If the worst hasn't happened yet, it is because you have not tried everything yet.






Go to the top of the page
 
Thanks+Quote Post
phantom7s8
post Nov 9 2005, 04:20 PM
Post #6


X-Treme
Group Icon


Master

Member No.: 660
Posts Liked: 0 *
Joined: 18-May 05
Posts: 238
-->
From: Massachusetts

RPG Maker Level:
Expert

Class Title:
Artist, Mapper, Writer, other stuff.



Well that definitly gonna be fun readin through that.
And wasnt that last part in the 3rd tutorial last time?



IPB Image

IPB ImageIPB ImageIPB ImageIPB ImageIPB ImageIPB ImageIPB ImageIPB Image
Go to the top of the page
 
Thanks+Quote Post
Dubealex
post Nov 9 2005, 06:57 PM
Post #7


Administrator of this Asylum
Group Icon
Group Icon


Admin

Member No.: 1
Posts Liked: 48 *
Joined: 8-November 04
Posts: 2,704
-->
From: Longueuil, Canada

RPG Maker Level:
Master

Class Title:
Writer, Scripter & Designer

Last.fm ID: Dubealex

Country:



Nope, chapter 3 is about understanding menus.



If the worst hasn't happened yet, it is because you have not tried everything yet.






Go to the top of the page
 
Thanks+Quote Post
mazey
post Nov 15 2005, 09:45 AM
Post #8


Newbie
Group Icon


Newbie

Member No.: 1,993
Posts Liked: 0 *
Joined: 15-November 05
Posts: 1
-->

RPG Maker Level:
Good




Great tutorial!
I'm just wondering, i found parts of chapter 3 on google, but not the whole chapter. Are you going to post it in the forums, or is it allready posted here?

Edit: Forget it. I Found Chapter 3..

This post has been edited by mazey: Nov 15 2005, 09:50 AM
Go to the top of the page
 
Thanks+Quote Post
Satiel
post Feb 18 2006, 03:30 PM
Post #9


Kristof von Metal
Group Icon


God

Member No.: 2,295
Posts Liked: 2 *
Joined: 7-January 06
Posts: 1,286
-->
From: Austin, Texas

RPG Maker Level:
Novice

Class Title:
Music Video Master

Country:



Thanks again for this tut. It rocks!



YouTube Channel: http://youtube.com/user/ChallengeAcceptedInc
It's radical.

Go to the top of the page
 
Thanks+Quote Post
crazydude1423
post Mar 1 2006, 09:33 PM
Post #10


Newbie
Group Icon


Newbie

Member No.: 2,676
Posts Liked: 0 *
Joined: 28-February 06
Posts: 27
-->

RPG Maker Level:
Fair




I can't find the Ruby Syntax topic and the link in the tut. is missing. Where can I find it? :strach:



IPB Image
IPB Image
Go to the top of the page
 
Thanks+Quote Post
Dubealex
post Mar 5 2006, 08:18 PM
Post #11


Administrator of this Asylum
Group Icon
Group Icon


Admin

Member No.: 1
Posts Liked: 48 *
Joined: 8-November 04
Posts: 2,704
-->
From: Longueuil, Canada

RPG Maker Level:
Master

Class Title:
Writer, Scripter & Designer

Last.fm ID: Dubealex

Country:



its in the Main SIte menu at the top-right of the forum, it's called "RGS reference"



If the worst hasn't happened yet, it is because you have not tried everything yet.






Go to the top of the page
 
Thanks+Quote Post
en_ryu
post May 1 2006, 05:57 AM
Post #12


Newbie
Group Icon


Newbie

Member No.: 3,061
Posts Liked: 0 *
Joined: 1-May 06
Posts: 1
-->

RPG Maker Level:
Good




I just read your scripting tutaorial, both chapters, and I kinda understood most of it, but i have a more specific question. How would you write the line of a sript so you can change the character graphic? I know how to do it in events, you just go 'Move Event', then 'Change Graphic'm but I want to do it in a script. Can you please tell me?
Go to the top of the page
 
Thanks+Quote Post
RPG_GameDesigner
post Jul 3 2006, 02:40 AM
Post #13


Newbie
Group Icon


Newbie

Member No.: 3,674
Posts Liked: 0 *
Joined: 25-June 06
Posts: 26
-->
From: San Antonio, TX

RPG Maker Level:
Good

Class Title:
writer, eventer, & mapper



Very awesome set of tutorials!!! I've been wanting to learn how to script with ruby for RMXP for a while now but it's been hard to find any good tutorials for it. After reading these two, I'm getting the hang of it big time! I really appreciate these tutorials.







Go to the top of the page
 
Thanks+Quote Post
RPG_GameDesigner
post Jul 11 2006, 11:29 AM
Post #14


Newbie
Group Icon


Newbie

Member No.: 3,674
Posts Liked: 0 *
Joined: 25-June 06
Posts: 26
-->
From: San Antonio, TX

RPG Maker Level:
Good

Class Title:
writer, eventer, & mapper



I never really understood how to make the window stay up for more than a split second. And how do you make it to where it won't close until you press a button??? I know it has something to do with scene map.

This post has been edited by RPG_GameDesigner: Jul 12 2006, 04:56 PM







Go to the top of the page
 
Thanks+Quote Post
VonDoggy
post Oct 12 2006, 10:26 AM
Post #15


One of the Returned
Group Icon


Celestial

Member No.: 4,646
Posts Liked: 3 *
Joined: 6-September 06
Posts: 3,316
-->
From: Life

RPG Maker Level:
Fair

Class Title:
Mother of a Beautiful Girl

Last.fm ID: gemini8859

Country:



I can't find the RGSS reference you're talking about. I found an RGSS Reference section in the script archive, but it's not the way you describe. It's just a few lists of syntaxes to cahnge some system things suck as armor, weapons, items, etc...



It is truly amazing how long the internet will keep some images alive.
Go to the top of the page
 
Thanks+Quote Post
You Win
post Nov 4 2006, 01:28 AM
Post #16


Expert
Group Icon


Expert

Member No.: 3,056
Posts Liked: 0 *
Joined: 30-April 06
Posts: 108
-->
From: Malaysia

RPG Maker Level:
Good

Class Title:
Story maker, Database n Event maker, Mapper.



A little bit confuze, but still.. it is a good tutorial.

I just want to know if it is posible to make the window appear by pressing esc?



No one is better than everyone. So lets work together.
IPB Image

Share the pain, half the pain
Share the happiness, double the happiness

IPB Image

Go to the top of the page
 
Thanks+Quote Post
Unessential
post Nov 9 2006, 08:43 PM    Mood:   Annoyed
Post #17


Newbie
Group Icon


Newbie

Member No.: 5,228
Posts Liked: 0 *
Joined: 9-November 06
Posts: 5
-->

RPG Maker Level:
Good




Alright, I copied your code for the basic 200x200 window and it wouldn't work.

I placed it at the bottom page and I copied and pasted directly.

whenever I try and call the window I got:

"?????? Name Error ??????
uninitialized constant interpreter:: [classname]"

(in this case My_Window)

So instead I called Window_Base directly like this:

Window_Base.new(0,0,200,200)

and that worked fine. Does anybody have any idea why I am getting that error message in the first instance. and if not can anyone tell me what it means? It's kind of hard to debug when I can't understand those error messages.

This post has been edited by Unessential: Nov 9 2006, 08:46 PM
Go to the top of the page
 
Thanks+Quote Post
Spidey
post Nov 10 2006, 07:14 AM
Post #18


Spider-Mod
Group Icon
Group Icon


Moderator

Member No.: 1,136
Posts Liked: 7 *
Joined: 13-July 05
Posts: 5,175
-->
From: Israel

RPG Maker Level:
Master

Class Title:
Eventer/Scripter

Country:



What's the code exactly?


Go to the top of the page
 
Thanks+Quote Post
Unessential
post Nov 11 2006, 04:17 PM
Post #19


Newbie
Group Icon


Newbie

Member No.: 5,228
Posts Liked: 0 *
Joined: 9-November 06
Posts: 5
-->

RPG Maker Level:
Good




this code

QUOTE
class My_Window < Window_Base

def initialize
super(0, 0, 200, 200)
end

end
Go to the top of the page
 
Thanks+Quote Post
Sheol
post Nov 12 2006, 12:24 PM
Post #20


God
Group Icon


God

Member No.: 1,130
Posts Liked: 0 *
Joined: 12-July 05
Posts: 1,375
-->

RPG Maker Level:
Good


Country:



I think you pasted your code after Main, when it must be before Main.
Go to the top of the page
 
Thanks+Quote Post

3 Pages V   1 2 3 >
Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 



- The Staff Team Lo-Fi Version Time is now: 5th December 2020 - 10:33 AM