CALL METHODS OF OTHER CLASSES
Posts
Pages:
1
I have a problem. I'm learning RGSS and for practice im implementing all rm2k lost options in XP. The problem is that i don't know exactly how to call methods out of the actual class.
I have a "Other" class that have many new methods, like correction critical for weapon, or another based in Actor/Class, etc.. well, methods that i have to call in many other scripts.
example:
#This is the call i'm making now , in Game_Battler 3
$Other.critic_weapon(@attacker,@critical)
And this the called method class:
class Other
def critic_weapon(attacker, critical)
if attacker.weapon_id == 1
print "critic mod"
critic += 5
return
this is the error message
no method error, undefined method critc_weapon for nil: Nil class
I have a "Other" class that have many new methods, like correction critical for weapon, or another based in Actor/Class, etc.. well, methods that i have to call in many other scripts.
example:
#This is the call i'm making now , in Game_Battler 3
$Other.critic_weapon(@attacker,@critical)
And this the called method class:
class Other
def critic_weapon(attacker, critical)
if attacker.weapon_id == 1
print "critic mod"
critic += 5
return
this is the error message
no method error, undefined method critc_weapon for nil: Nil class
You're calling an instance function like a static function: Instance functions require an instance of the object to call the function while a static function doesn't need any of that shnazz stuff.
Example of an instance function:
class Rock
def initialize(_round)
@round = _round
end
def isRound?
return @round
end
end
Invoking:
# some code
rock = Rock.new(true)
rock.isRound?
# more code
You can't call isRound? without an instance of the class object. The instance function wouldn't make any sense because it wouldn't now what rock's @round it's returning. You're asking an individual object to execute one of its functions with its internal parameters and any passed arguments. This is generally what you want to do most of the time.
Now a static function can be called anywhere by anyone (does Ruby have function protection?) at anytime. Example!
class Sun
def Sun.Brightness
return 9000
end
end
Invoking:
# some code
Sun.Brightness
# more code
You don't need an instance of the Sun object to call the Brightness function of the Sun class. There is a disadvantage: A static function can't reference any instance variables of a class (see: Anything prefixed with a single @, @@'s are static to a class and can be used by an instance and static function and the variable is the same thing across all calls). Generally not recommended unless you know what you're doing (in which case you know when to use static functions and when not to) since they break any object-oriented style that programming languages like Ruby try and support.
Now for totally NOT answering your question!
Now that all that instance/static mumbo jumbo is out of the way, you're doing it wrong. RMXP is incredibly sloppy at points and determining if an attack was a critical is one of them. Its hard coded in the middle of a function with no regard for allowing an easy way to override its chance of critical hit algorithm (Line 58 of Game_Battler 3). If you want to make any changes to the critical rate algorithm without a minor architecture change you need to inject your code in there. Note that you have to check if the attacker is a Game_Actor or not (the class used for PCs, it extends the Game_Battler class aka the Game_Actor class has everything the Game_Battler does plus its own variables+functions)
I'd suggest changing how the system works a bit. Replace that useless Line 58 with something like:
if rand(100) < attacker.crit_rate - defender.crit_def
And in Game_Battler add two new functions: crit_rate and crit_def
These would return the default crit rate and crit defense of a battler which would be set in a class variable like @crit_rate and @crit_defense plus any modifiers you want to apply. Game_Battler's don't have any equipment so what you want to do is create the crit_rate/defense functions in the Game_Actor class so you can get to a PC's weapon/armour.
Something like...
# Adding a new function to Game_Actor
class Game_Actor < Game_Battler
# Calculate the critical hit rate of this character
def crit_rate
crit = super() # Call the base class crit_rate in the Game_Battler class
crit += 5 if @weapon_id == 1 # If the actor has weapon ID 1 equipped, inrease crit rate by five
return crit # Return the new crit rate
end
end
Also "Veriance" (items tab). Whoops typo on Enterbrain's part.
holy walls of text. If I explained anything poorly or if you want an example or anything let me know.
Example of an instance function:
class Rock
def initialize(_round)
@round = _round
end
def isRound?
return @round
end
end
Invoking:
# some code
rock = Rock.new(true)
rock.isRound?
# more code
You can't call isRound? without an instance of the class object. The instance function wouldn't make any sense because it wouldn't now what rock's @round it's returning. You're asking an individual object to execute one of its functions with its internal parameters and any passed arguments. This is generally what you want to do most of the time.
Now a static function can be called anywhere by anyone (does Ruby have function protection?) at anytime. Example!
class Sun
def Sun.Brightness
return 9000
end
end
Invoking:
# some code
Sun.Brightness
# more code
You don't need an instance of the Sun object to call the Brightness function of the Sun class. There is a disadvantage: A static function can't reference any instance variables of a class (see: Anything prefixed with a single @, @@'s are static to a class and can be used by an instance and static function and the variable is the same thing across all calls). Generally not recommended unless you know what you're doing (in which case you know when to use static functions and when not to) since they break any object-oriented style that programming languages like Ruby try and support.
Now for totally NOT answering your question!
Now that all that instance/static mumbo jumbo is out of the way, you're doing it wrong. RMXP is incredibly sloppy at points and determining if an attack was a critical is one of them. Its hard coded in the middle of a function with no regard for allowing an easy way to override its chance of critical hit algorithm (Line 58 of Game_Battler 3). If you want to make any changes to the critical rate algorithm without a minor architecture change you need to inject your code in there. Note that you have to check if the attacker is a Game_Actor or not (the class used for PCs, it extends the Game_Battler class aka the Game_Actor class has everything the Game_Battler does plus its own variables+functions)
I'd suggest changing how the system works a bit. Replace that useless Line 58 with something like:
if rand(100) < attacker.crit_rate - defender.crit_def
And in Game_Battler add two new functions: crit_rate and crit_def
These would return the default crit rate and crit defense of a battler which would be set in a class variable like @crit_rate and @crit_defense plus any modifiers you want to apply. Game_Battler's don't have any equipment so what you want to do is create the crit_rate/defense functions in the Game_Actor class so you can get to a PC's weapon/armour.
Something like...
# Adding a new function to Game_Actor
class Game_Actor < Game_Battler
# Calculate the critical hit rate of this character
def crit_rate
crit = super() # Call the base class crit_rate in the Game_Battler class
crit += 5 if @weapon_id == 1 # If the actor has weapon ID 1 equipped, inrease crit rate by five
return crit # Return the new crit rate
end
end
Also "Veriance" (items tab). Whoops typo on Enterbrain's part.
holy walls of text. If I explained anything poorly or if you want an example or anything let me know.
Thanks for this large response. I don't understand Obect Oriented languages very well, i only know C programing. Now im learning ruby directly for that. But i have some other questions:
-Acceding the $data variables is bad or something? i say because it would be more easier no?
-I'm going to give enemies also a critical option like 2k. I created a e_crit_rate and e_crit_def in game battler, and then i call them with the same method with super() in Game_Enemy. It's this OK or there are a better way?
-If i call a class (ex: wep = Game_Battler.new) what are the consecuences? the class chargues in "wep" no? then if its a low level variable will end quick. And if i only want to chargue one method of a large class, its optimal to make this?
if attacker.is_a?(Game_Actor)
if rand(100) < attacker.crit_rate - target.e_crit_def
end
else
if rand(100) < attacker.e_crit_rate - target.crit_def
end
end
Also, the last question... how attacker.crit_rate does? maybe im limited by C, where always you give variables with ().
-Acceding the $data variables is bad or something? i say because it would be more easier no?
-I'm going to give enemies also a critical option like 2k. I created a e_crit_rate and e_crit_def in game battler, and then i call them with the same method with super() in Game_Enemy. It's this OK or there are a better way?
-If i call a class (ex: wep = Game_Battler.new) what are the consecuences? the class chargues in "wep" no? then if its a low level variable will end quick. And if i only want to chargue one method of a large class, its optimal to make this?
if attacker.is_a?(Game_Actor)
if rand(100) < attacker.crit_rate - target.e_crit_def
end
else
if rand(100) < attacker.e_crit_rate - target.crit_def
end
end
Also, the last question... how attacker.crit_rate does? maybe im limited by C, where always you give variables with ().
author=gerkrt link=topic=3525.msg70920#msg70920 date=1239884521No, if something is going to be accessed all over the place and be between the scripts and map data (like the $data classes). If you want to add a new function that increases a character's crit rate based on their weapon, it makes no sense to make a function static since you need an instance of the battler's object to check if it has the nessesary weapon equipped anyways so it's best to simply make it an instance function which also enforces some level of type checking (sine Ruby has weaker typing than C++, but on the other hand nothing is stopping you from trying an invoking an instance function on an object since that is a run time error instead of a compile time error due to Ruby's weak typing)
-Acceding the $data variables is bad or something? i say because it would be more easier no?
Example:
Static invocation
get_crit_rate(attacker)
Instance invocation
attacker.get_crit_rate
If you prefer the static way, go ahead and use it. I shouldn't be dictating the 'proper' way of doing something if it's what you prefer and you'll be the one writing and maintaining it. Pick whatever you prefer!
(I just really prefer the second way :) )
author=gerkrt link=topic=3525.msg70920#msg70920 date=1239884521
-I'm going to give enemies also a critical option like 2k. I created a e_crit_rate and e_crit_def in game battler, and then i call them with the same method with super() in Game_Enemy. It's this OK or there are a better way?
There is which I cover in the next part (I didn't answer these questions in order so my post is messy).
author=gerkrt link=topic=3525.msg70920#msg70920 date=1239884521Technically you should never create a new Game_Battler, you should create a new Game_Actor/Game_Enemy since creating a Game_Battler won't actually load anything. Now if you call 'wep = Game_Actor.new(0)', wep will be the actor and you can get stuff like what they have equipped. There is a performance issue with reloading an object with all that actor data when you don't need it and there's already an instance of it floating around in $game_actors (if the class in question doesn't already have a reference to it already).
-If i call a class (ex: wep = Game_Battler.new) what are the consecuences? the class chargues in "wep" no? then if its a low level variable will end quick. And if i only want to chargue one method of a large class, its optimal to make this?
if attacker.is_a?(Game_Actor)
if rand(100) < attacker.crit_rate - target.e_crit_def
end
else
if rand(100) < attacker.e_crit_rate - target.crit_def
end
end
Looking back on this, it sounds like I'm contradicting myself. Sorry for confusing you and please take anything I say about 'coding styles' with static or instance whatevers as just a possible alternative.
As for your code snippet, due to how inheritence works with classes most of that is unnessesary. Game_Actor and Game_Enemy extends Game_Battler so it inherits all of its functions and Ruby is smart enough to know that if the attacker is a Game_Actor, it will call its version of a function instead of the Game_Battler even if they have the same name and arguments. You could have:
if rand(100) < attacker.crit_rate - target.crit_def
And Ruby will call the correct functions based on the attacker and target's class. All you'd need to do is define crit_rate/def in Game_Battler and Game_Actor.
Example:
class Game_Battler
def crit_rate
return 5
end
end
class Game_Actor
def crit_rate
crit = super
crit += 5 if @weapon_id == 1
return crit
end
end
If attacker is a Game_Actor, Ruby will call the Game_Actor's crit_rate function (which in turn cals the Game_Battler function via super). If attacker is a Game_Battler or a Game_Enemy, Ruby will call the Game_Battler's crit_rate.
author=gerkrt link=topic=3525.msg70920#msg70920 date=1239884521You don't need to specify () to indicate that you're trying to call a function in Ruby. attacker.crit_rate could be a function or a variable (in Ruby you can even have assignments be a function! Something like 'def crit_rate=(newCritRate)' is a valid function header and calling something like 'attacker.crit_rate = 10' would call that function). I think the one exception is when coding the contents of a class, you can't call a function just by specifying its name as Ruby will assume you're talking about a local variable.
Also, the last question... how attacker.crit_rate does? maybe im limited by C, where always you give variables with ().
Example!
class Object
def function1
return 1
end
def function2
return 2
end
def function3
x = function1 # This will NOT call function1, x will be assigned the value of the not-yet-created variable function 1
y = this.function2 # This WILL call the function
z = function1() # As will this
end
end
There isn't any issue if you do add () with every function call you want to make though, there's nothing to stop you and it doesn't do any harm. It's one of the more trivial differences between Ruby and C++.
Pages:
1














