RMRK RPG Maker Creation => RPG Maker General => General Scripting => Topic started by: D&P3 on August 13, 2012, 09:25:00 AM
Title: A few questions about scripting
Post by: D&P3 on August 13, 2012, 09:25:00 AM
I kinda went into Ruby scripting using what I already know from other languages, I have noticed that loops don't seem to work the way that I imagine they should.
while( fCurrentFrame <= 600.0f ) { fDeltaTime = GetFPS(); // Which may or may not give you an error depending on what library you are using. fCurrentFrame += iFrameIncrement * fDeltaTime; // Which essentially slows down the FPS to 60 }
That would work just the same as a wait command in RPGMaker, it will wait for 10 seconds.
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- loop do @currentframe += 1 end until @currentframe >= @framewaitamount #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- loop do @currentframe += 1 end unless @currentframe < @framewaitamount #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- loop do @currentframe += 1 end if @currentframe >= @framewaitamount #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
I was also using While and For loops, but it really didn't work at all. Stepping through the code using the print keyword reveals that the count continues much further than the set amount. And once the loop ends, the count is shown to be 600 ???
I'm not sure why this loop doesn't seem to work with Ruby, is it doing something different than what the loop does in C++?
I have resolved that problem by using Graphics.wait(@framewaitamount)
But I'm still curious.
I also have an issue with my Actor Death BGM script (and before anyone mentions it, yes I have changed it from playing a BGM to an ME already :P)
#============================================================================== # Actor Death BGM & Common Events # Version: 1.0 # Author: DiamondandPlatinum3 # Date: July 31, 2012 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Description: # This script will allow you to play a BGM when one of your actors die in # battle. It'll also allow you to use a common event when it occurs. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #------------------------------------------------------------------------------ # Instructions: # # - Place this script in the materials section, above Main. # # - Edit the editable region options # # - Set your common events to do what you want them to do (in the database) # If you don't want any common event to run for any specific actor - set the value to zero. # #============================================================================== class Scene_Battle < Scene_Base def actor_death_bgm_play(which_actor) #integer variable
#========================================================= # EDITABLE REGION #========================================================= @death_bgm = "Town5" # Set to nil if you don't want any bgm to play upon death @bgm_volume = 100 @bgm_pitch = 100 @framewait_amount = 100 # Set to zero if not using any bgm
#------------------------------------------------------- @common_event_id_to_run = [ 0, # Don't touch this line #------------------------------------------------------- 10, #Actor1's Common Event to run if incapacitated 11, #Actor2's Common Event to run if incapacitated 12, #Actor3's Common Event to run if incapacitated 13, #Actor4's Common Event to run if incapacitated 14, #Actor5's Common Event to run if incapacitated 15, #Actor6's Common Event to run if incapacitated 16, #Actor7's Common Event to run if incapacitated 17, #Actor8's Common Event to run if incapacitated 18, #Actor9's Common Event to run if incapacitated
#========================================================= ]# END OF EDITABLE REGION #=========================================================
#------------------------------------------------- # Play Actor Death BGM #------------------------------------------------- Audio.bgm_play("Audio/BGM/" + @death_bgm, @bgm_volume, @bgm_pitch) unless @death_bgm == nil Graphics.wait(@framewait_amount) $game_temp.reserve_common_event(@common_event_id_to_run[which_actor]) $game_system.battle_bgm.play end
#------------------------------------------------- # Check Actors for Incapacity #------------------------------------------------- def check_actors_for_incapacity @actor_array = [$game_party.members.size] for actor in $game_party.members @actor_array[actor.id] = actor.state?(1) actor_death_bgm_play(actor.id) if @actor_array[actor.id] end end
#------------------------------------------------- # Display Added States #------------------------------------------------- alias play_bgm_on_actor_death process_action_end def process_action_end(*args) play_bgm_on_actor_death(*args) check_actors_for_incapacity end end
Basically at the moment, it plays the death BGM on an actor when they die but plays it on that same actor yet again when the function is called once more (you can imagine how annoying that might be if you have three dead actors and you hear the death BGM play after every single action).
I have thought of using two boolean arrays to achieve my aim, but that seems kind of wasteful and I'm sure there is an easier and more efficient way
#------------------------------------------------- # Check Actors for Incapacity #------------------------------------------------- def check_actors_for_incapacity
# Instance arrays, this will not work as intended! # I'm just using it as an example
@adbactor_array = [$game_party.members.size] @adbdead_actors = [@adbactor_array.size] for actor in $game_party.members
# Define whether Actor is dead or not @adbactor_array[actor.id] = actor.state?(1)
# Call the Death BGM Function actor_death_bgm_play(actor.id) if @adbactor_array[actor.id] && !@adbdead_actors[actor.id]
# Set the boolean after the function is called, so that it will play the BGM at least once @adbdead_actors[actor.id] = adbactor_array[actor.id]
end end
Any suggestions on what I should do to achieve my aim here? :) Thanks everyone.
Title: Re: A few questions about scripting
Post by: Zeriab on August 13, 2012, 05:07:00 PM
Your problem is a syntactic matter and the very dynamic nature of Ruby. I highly recommend checking out the syntax nicely described here: http://www.zenspider.com/Languages/Ruby/QuickRef.html#control-expressions
To help you understand what your code does let me rearrange the code: (The resulting abstract syntax tree is probably the equivalent)
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- until @currentframe >= @framewaitamount loop do @currentframe += 1 end end #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- unless @currentframe < @framewaitamount loop do @currentframe += 1 break; end end #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- if @currentframe >= @framewaitamount loop do @currentframe += 1 break; end end #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
You are using the following constructs:
expr if bool-expr expr unless bool-expr expr until bool-expr
To help you understand let me show you how you can implement the loop method like this:
What you would want to use is one of the following expressions:
while bool-expr [do] body end
until bool-expr [do] body end
begin body end while bool-expr
begin body end until bool-expr
In terms of actually waiting a frame you can use Graphics.update or Graphics.wait. The latter is equivalent to: (Taken from the help file, not tested for typoes)
def Graphics.wait(duration) duration.times do Graphics.update end end
For the second issue I suggest that you make your changes to where the code for handling battler death actually resides rather than trying to introspect after each action. (Hint: Search for die. (Ctrl+Shift+F for searching all sections))
*hugs*
Title: Re: A few questions about scripting
Post by: D&P3 on August 13, 2012, 05:28:43 PM
Simple and easy enough to understand, thanks a lot for your help Zeriab. ;8 I appreciate it :)
Title: Re: A few questions about scripting
Post by: Zeriab on August 15, 2012, 03:37:44 PM
I'm glad I helped you understand it ^_^ Let me know if there is else you have trouble with. You can also try poking my student (Modern Algebra)
*hugs*
Title: Re: A few questions about scripting
Post by: D&P3 on January 15, 2013, 10:13:51 PM
I have a few more now:
When I use an alias, I just alias the method name like so:
Title: Re: A few questions about scripting
Post by: LoganF on January 15, 2013, 10:38:27 PM
I'm not sure if there's any benefits or detriments to using one or the other with alias. Preliminary research seems to say that it makes it look more Ruby like to use symbols. It's also more apparent as opposed to using what was called "naked words". Another seems to say that because you are using them like labels as a way to refer to the names rather than directly referencing them. Visually, I prefer the symbol format, especially in VX Ace since the names come up in that yellow/orange colour.
I've also taken more to using alias_method(old_name, new_name) as well. Not sure why, just something of a personal preference. Whilst I can't say I know whether using them with or without the colons is good or bad, I can at least bring something in regards to alias vs alias_method with one of those having something to do with scoping. This might be useful for that: http://www.ruby-forum.com/topic/135598
The asterisk in Ruby isn't to do with deferencing like it is in C++ (I initially believed this too, so you aren't alone). In Ruby, it allows for variable length argument lists, which is also the name for it maybe. For example (original code found from the link below):
def varargs(arg1, *rest) "Got #{arg1} and #{rest.join(', ')}" end varargs("one") » "Got one and " varargs("one", "two") » "Got one and two" varargs("one", "two", "three") » "Got one and two, three"
alias :old_method :new_method def new_method(*args, &block) old_method(*args, &block) end
We do this because we might not be sure, or we don't really care maybe, about the arguments coming in. The original method might not take arguments, but what if some other script aliased the old method and he did want some things passed in. We aren't building our script with theirs in mind, but we want to increase compatibility. Using a variable length argument, like *args, achieves that.
Ruby doesn't have a Boolean object type. It has two types in place of that: TrueClass and FalseClass. When you use the keyword 'true' or 'false' it is a keyword that references an object of the respective type (true is a TrueClass, false is a FalseClass). When you come to checking the object type with the .is_a? method, you will have to check for it being a TrueClass object or a FalseClass one. What I do, sometimes, is a make a method that I might call #is_bool?(variable) that will return true if it's either a TrueClass or FalseClass, or false otherwise. It's not great, but it does the trick.
Title: Re: A few questions about scripting
Post by: D&P3 on January 16, 2013, 03:44:46 AM
I did not think there would be a difference between the two, still thought I'd ask. The colour scheme does seem to make symbols more appealing to the eye though :)
I knew what it was doing, however it was a thrill to do some revision based on your words :) According to the link you provided, it seems the term for it is 'Variable-Length Argument Lists' just as you suggested. I will think of it as so, since I have never seen that used outside of method arguments.
I did not know that 'true' & 'false' were seperate entities on their own, that's surprising. I think I'll stick with the '!!boolean == boolean' since I'd find it more readable and pleasing to the eyes that way.