SLIP INTO RUBY - UNDER THE HOOD PART 3: GAME OBJECTS
Delve into the wondrous intricacies of the Game_Temp, Game_System and Game_Timer classes! A day early even! Because I love you.
- Trihan
- 03/30/2015 10:22 PM
- 11346 views
Hello again sports fans! It's time for the nitty-gritty. Getting more under the hood than the hood. It's time...for GAME OBJECTS! And also
There are 31 Game Objects classes in RGSS3; I'm going to cover 3 of them per issue for 10 issues, and then give Game_Interpreter its own entry as it's really, really, really, really, really big. Really. Really. Big. Like, 1413 lines of code big. If it turns out that I have 3 in a row that aren't really that much content I might combine 6 into one update, but we'll see how it goes.
Game_Temp
Game_Temp handles temporary data that isn't needed in a save file, and is referenced by the global variable $game_temp.
First, the instance variables:
common_event_id is used to store the ID of the currently-reserved common event. We'll see more about this when we get to Game_Interpreter. fade_type stores the type of fade that occurs when the player is transferred to a new map, which again we'll see in more detail in Game_Interpreter.
Really simple initialize method; all it does is set both instance variables to 0.
Setter method for common_event_id. Takes the ID of the reserved common event as the parameter.
Clear method for common_event_id, and simply sets it to 0.
Returns true if common_event_id is greater than 0. (you'll notice that a convention in RGSS3 is for "check" methods which return a boolean to have a name ending in a question mark, which is actually quite good practice)
Getter method for common_event_id, though rather than returning the variable's value it looks up the common_event_idth element of $data_common_events, which is a global variable containing all the data on common events in the database.
And that's it! They get more exciting, promise.
Game_System
Game_System handles system data, and is referenced by the global variable $game_system.
As always, first we look at the instance variables:
SUPER MEGA SURPRISE LESSON GAIDEN
You'll have noticed by now that a lot of instance variables are defined as symbols, and that they are generally attr_accessor or attr_reader. There's also attr_writer, but that's less common. This is basically a shorthand way of creating not only an instance variable for the symbol, but also a getter and/or setter method, meaning you can read or write to the variable outwith the class.
To explain a little more clearly, currently you can do something like "$game_system.save_disabled = false" because it's an attr_accessor. Change it to an attr_reader or remove the line entirely and the game will crash with a NoMethodError or something similar.
Anyway, let's look at what we've got here.
save_disabled, menu_disabled, encounter_disabled and formation_disabled are exactly what they say on the tin: they determine whether the player is allowed to save, access the menu, fight battles or change party formation.
battle_count keeps track of how many battles the party has fought. save_count keeps track of how many times the game has been saved. version_id tracks the version number of the game. version_id is a built-in attribute of RPG::System, and is a random number used for update checks, which is changed every time you save your game.
Just initialising the instance variables. The booleans are initialised to false, the integers to 0. There are also some non-attr variables: window_tone, which contains the tone used for windows; battle_bgm, which contains the BGM used in battle; battle_end_me, which contains the victory theme; and saved_bgm, which contains the previously-playing BGM.
Determines whether the game is in Japanese mode: this will always be true in the Japanese version of the editor, and false otherwise.
Getter method for window tone. Returns window_tone if it contains a value, or the window tone from $data_system (the default that was set in the database) otherwise. The former will only be true if you call $game_system.window_tone= directly or use the "Change Window Color" event command.
Setter method for window_tone.
Getter method for battle_bgm; works on the same principle as the window tone.
Setter for battle_bgm.
Getter for battle_end_me.
Setter for battle_end_me.
This method is called before the game is saved. First, the save count is increased by 1. The version ID is updated and the number of frames which have elapsed is stored in @frames_on_save. Finally, the BGM and BGS are saved to their respective variables.
Called after a game is loaded. Sets the number of elapsed frames to the value saved and starts playing the saved BGM/BGS.
Gets the amount of time played in seconds by dividing the number of frames which have elapsed by the frame rate in frames per second.
Returns a string of the playtime in hours, minutes and seconds (hours being playtime divided by 60 divided by 60, minutes being playtime divided by 60 mod 60, and seconds being playtime mod 60). The sprintf format ensures two significant figures, so single digits are preceded with a leading zero.
Simple method which stores the most recently played BGM in its instance variable.
Method for resuming a saved BGM if one exists.
And that's it for Game_System!
Game_Timer
This class, funnily enough, is the one that handles timers. It's referenced by the global variable $game_timer.
At initialisation we have two instance variables: count, which is the value of the timer in FRAMES; and working, which is a boolean determining whether the timer is running or not.
Update is called every frame. If the timer is running (@working is true) AND @count is greater than 0, we reduce @count by 1. If @count is now 0, we call on_expire.
Simple method for starting a timer. The number of FRAMES is supplied and assigned to @count, and @working is set to true.
Stopping a timer is even simpler: we just set @working to false.
Checker method, will return true if @working is true.
Method for determining the seconds left on the timer. As @count is a value in frames, we divide by the frame rate to determine the actual number of seconds. For example, if the frame rate is 60FPS and we have a 30-second timer, @count will initially be equal to 1800. Calling $game_timer.sec will return 30 (1800 / 60).
This is the method which is called when a timer expires, and simply aborts battle.
...wait, what? I say again.
Yep! I don't think this is particularly common knowledge, but if you start a timer in battle it will AUTOMATICALLY end battle once the timer expires! If you wanted a timer that didn't end battle, you would have to edit this method.
And so ends another edition of Slip into Ruby. Next week, we're going to cover Game_Message, Game_Switches and Game_Variables! And since the latter two are really super short, we'll probably throw in a couple more.
As always, any and all feedback is welcomed and appreciated. I do this for you guys, after all.
Until next time.
There are 31 Game Objects classes in RGSS3; I'm going to cover 3 of them per issue for 10 issues, and then give Game_Interpreter its own entry as it's really, really, really, really, really big. Really. Really. Big. Like, 1413 lines of code big. If it turns out that I have 3 in a row that aren't really that much content I might combine 6 into one update, but we'll see how it goes.
Game_Temp
Game_Temp handles temporary data that isn't needed in a save file, and is referenced by the global variable $game_temp.
First, the instance variables:
attr_reader :common_event_id # Common Event ID attr_accessor :fade_type # Fade Type at Player Transfer
common_event_id is used to store the ID of the currently-reserved common event. We'll see more about this when we get to Game_Interpreter. fade_type stores the type of fade that occurs when the player is transferred to a new map, which again we'll see in more detail in Game_Interpreter.
def initialize @common_event_id = 0 @fade_type = 0 end
Really simple initialize method; all it does is set both instance variables to 0.
def reserve_common_event(common_event_id) @common_event_id = common_event_id end
Setter method for common_event_id. Takes the ID of the reserved common event as the parameter.
def clear_common_event @common_event_id = 0 end
Clear method for common_event_id, and simply sets it to 0.
def common_event_reserved? @common_event_id > 0 end
Returns true if common_event_id is greater than 0. (you'll notice that a convention in RGSS3 is for "check" methods which return a boolean to have a name ending in a question mark, which is actually quite good practice)
def reserved_common_event $data_common_events[@common_event_id] end
Getter method for common_event_id, though rather than returning the variable's value it looks up the common_event_idth element of $data_common_events, which is a global variable containing all the data on common events in the database.
And that's it! They get more exciting, promise.
Game_System
Game_System handles system data, and is referenced by the global variable $game_system.
As always, first we look at the instance variables:
attr_accessor :save_disabled # save forbidden attr_accessor :menu_disabled # menu forbidden attr_accessor :encounter_disabled # encounter forbidden attr_accessor :formation_disabled # formation change forbidden attr_accessor :battle_count # battle count attr_reader :save_count # save count attr_reader :version_id # game version ID
SUPER MEGA SURPRISE LESSON GAIDEN
You'll have noticed by now that a lot of instance variables are defined as symbols, and that they are generally attr_accessor or attr_reader. There's also attr_writer, but that's less common. This is basically a shorthand way of creating not only an instance variable for the symbol, but also a getter and/or setter method, meaning you can read or write to the variable outwith the class.
To explain a little more clearly, currently you can do something like "$game_system.save_disabled = false" because it's an attr_accessor. Change it to an attr_reader or remove the line entirely and the game will crash with a NoMethodError or something similar.
Anyway, let's look at what we've got here.
save_disabled, menu_disabled, encounter_disabled and formation_disabled are exactly what they say on the tin: they determine whether the player is allowed to save, access the menu, fight battles or change party formation.
battle_count keeps track of how many battles the party has fought. save_count keeps track of how many times the game has been saved. version_id tracks the version number of the game. version_id is a built-in attribute of RPG::System, and is a random number used for update checks, which is changed every time you save your game.
def initialize @save_disabled = false @menu_disabled = false @encounter_disabled = false @formation_disabled = false @battle_count = 0 @save_count = 0 @version_id = 0 @window_tone = nil @battle_bgm = nil @battle_end_me = nil @saved_bgm = nil end
Just initialising the instance variables. The booleans are initialised to false, the integers to 0. There are also some non-attr variables: window_tone, which contains the tone used for windows; battle_bgm, which contains the BGM used in battle; battle_end_me, which contains the victory theme; and saved_bgm, which contains the previously-playing BGM.
def japanese? $data_system.japanese end
Determines whether the game is in Japanese mode: this will always be true in the Japanese version of the editor, and false otherwise.
def window_tone @window_tone || $data_system.window_tone end
Getter method for window tone. Returns window_tone if it contains a value, or the window tone from $data_system (the default that was set in the database) otherwise. The former will only be true if you call $game_system.window_tone= directly or use the "Change Window Color" event command.
def window_tone=(window_tone) @window_tone = window_tone end
Setter method for window_tone.
def battle_bgm @battle_bgm || $data_system.battle_bgm end
Getter method for battle_bgm; works on the same principle as the window tone.
def battle_bgm=(battle_bgm) @battle_bgm = battle_bgm end
Setter for battle_bgm.
def battle_end_me @battle_end_me || $data_system.battle_end_me end
Getter for battle_end_me.
def battle_end_me=(battle_end_me) @battle_end_me = battle_end_me end
Setter for battle_end_me.
def on_before_save @save_count += 1 @version_id = $data_system.version_id @frames_on_save = Graphics.frame_count @bgm_on_save = RPG::BGM.last @bgs_on_save = RPG::BGS.last end
This method is called before the game is saved. First, the save count is increased by 1. The version ID is updated and the number of frames which have elapsed is stored in @frames_on_save. Finally, the BGM and BGS are saved to their respective variables.
def on_after_load Graphics.frame_count = @frames_on_save @bgm_on_save.play @bgs_on_save.play end
Called after a game is loaded. Sets the number of elapsed frames to the value saved and starts playing the saved BGM/BGS.
def playtime Graphics.frame_count / Graphics.frame_rate end
Gets the amount of time played in seconds by dividing the number of frames which have elapsed by the frame rate in frames per second.
def playtime_s hour = playtime / 60 / 60 min = playtime / 60 % 60 sec = playtime % 60 sprintf("%02d:%02d:%02d", hour, min, sec) end
Returns a string of the playtime in hours, minutes and seconds (hours being playtime divided by 60 divided by 60, minutes being playtime divided by 60 mod 60, and seconds being playtime mod 60). The sprintf format ensures two significant figures, so single digits are preceded with a leading zero.
def save_bgm @saved_bgm = RPG::BGM.last end
Simple method which stores the most recently played BGM in its instance variable.
def replay_bgm @saved_bgm.replay if @saved_bgm end
Method for resuming a saved BGM if one exists.
And that's it for Game_System!
Game_Timer
This class, funnily enough, is the one that handles timers. It's referenced by the global variable $game_timer.
def initialize @count = 0 @working = false end
At initialisation we have two instance variables: count, which is the value of the timer in FRAMES; and working, which is a boolean determining whether the timer is running or not.
def update if @working && @count > 0 @count -= 1 on_expire if @count == 0 end end
Update is called every frame. If the timer is running (@working is true) AND @count is greater than 0, we reduce @count by 1. If @count is now 0, we call on_expire.
def start(count) @count = count @working = true end
Simple method for starting a timer. The number of FRAMES is supplied and assigned to @count, and @working is set to true.
def stop @working = false end
Stopping a timer is even simpler: we just set @working to false.
def working? @working end
Checker method, will return true if @working is true.
def sec @count / Graphics.frame_rate end
Method for determining the seconds left on the timer. As @count is a value in frames, we divide by the frame rate to determine the actual number of seconds. For example, if the frame rate is 60FPS and we have a 30-second timer, @count will initially be equal to 1800. Calling $game_timer.sec will return 30 (1800 / 60).
def on_expire BattleManager.abort end
This is the method which is called when a timer expires, and simply aborts battle.
...wait, what? I say again.
Yep! I don't think this is particularly common knowledge, but if you start a timer in battle it will AUTOMATICALLY end battle once the timer expires! If you wanted a timer that didn't end battle, you would have to edit this method.
And so ends another edition of Slip into Ruby. Next week, we're going to cover Game_Message, Game_Switches and Game_Variables! And since the latter two are really super short, we'll probably throw in a couple more.
As always, any and all feedback is welcomed and appreciated. I do this for you guys, after all.
Until next time.
Posts
Pages:
1
They follow the same principle. You can do
just as easily as unless.
Ruby is one of the few languages that supports this syntax of putting your condition after the line of code to execute.
if $game_switches[#]
just as easily as unless.
Ruby is one of the few languages that supports this syntax of putting your condition after the line of code to execute.
Yay! Seems I was never too far off in the first place.
But aren't there other ways for boolean checks, such as if, else and elsif?
lol 'elsif' - for whatever reason, I think of 'Keebler Elves' when I see that term.
But aren't there other ways for boolean checks, such as if, else and elsif?
lol 'elsif' - for whatever reason, I think of 'Keebler Elves' when I see that term.
That's it! Though personally I'd just do
I try never to use explicit method calls for boolean checks if all I'm doing is checking for truth, implicit true for the win!
BattleManager.abort unless $game_switches[#]
I try never to use explicit method calls for boolean checks if all I'm doing is checking for truth, implicit true for the win!
You'd use != for not equal to.
When you click the "code" tag it asks you what the language is. If you enter "ruby" it'll automatically colour the code for you.
When you click the "code" tag it asks you what the language is. If you enter "ruby" it'll automatically colour the code for you.
author=Trihan
No, if you wanted to do it non-implicitly you'd do
BattleManager.abort unless $game_switches[#] == true
How do you get the code to come up in those colors?
Or is it a manual edit?
Of course, the ==...implicitly equal to. I'm guessing that Ruby doesn't like =/= for inequal.
No, if you wanted to do it non-implicitly you'd do
BattleManager.abort unless $game_switches[#] == true
def on_expire
BattleManager.abort unless $game_switches[#].true
end
That's neat.
Hmm...
You can do just $game_switches[*] as a condition and it'll implicitly understand that you want to check it returns true for the value of the element, or if the switch class had a true? method defined you could do $game_switches[*].true?
Method calls will always have a dot between the name of the method and the object calling them.
Method calls will always have a dot between the name of the method and the object calling them.
author=TrihanYou can do angle brackets by enclosing them in angle brackets in your post. :)def on_expire BattleManager.abort unless $game_switches[#] end
I think what's breaking it is that "true?"; $game_switches has no such method, and you appear to be missing a dot to make it a method call anyway.
I'm guessing that I misinterpreted how if a switch is on, it's read as 'true' in the syntax. Missing the dot, where exactly?
$.game_switches [#] (?)
Kinda feelin' the novice burn...
def on_expire BattleManager.abort unless $game_switches[#] end
You can do angle brackets by enclosing them in angle brackets in your post. :)
I think what's breaking it is that "true?"; $game_switches has no such method, and you appear to be missing a dot to make it a method call anyway.
This is likely a huge necropost, but since no one else has posted their thoughts, I may as well.
I always thought it annoying(!) when the battle ended due to the timer being zero.
Once, I tried to change the method by adding
'unless $game_switches (#) true?' (without the quotes and with brackets in place of parentheses because these forums hate brackets)
to the end of BattleManager.abort ...
That made Ruby throw a fit.
I always thought it annoying(!) when the battle ended due to the timer being zero.
Once, I tried to change the method by adding
'unless $game_switches (#) true?' (without the quotes and with brackets in place of parentheses because these forums hate brackets)
to the end of BattleManager.abort ...
That made Ruby throw a fit.
Pages:
1