[XP] Trying to understand some code...

Started by Heretic86, May 17, 2012, 09:17:15 pm

Previous topic - Next topic

Heretic86

I've got a bit of code I am having some difficulty understanding.

  #----------------------------------------------------------------------------
  # * Generate registration of player moves to the caterpillar code
  #----------------------------------------------------------------------------
 
  # Constants - DO NOT EDIT
 
  MOVE_METHODS = ['move_down', 'move_left', 'move_right', 'move_up',
                  'move_lower_left', 'move_lower_right', 'move_upper_left',
                  'move_upper_right', 'jump',
                  'direction_fix_on', 'direction_fix_off']
 
  # Go through each method
  for method in MOVE_METHODS
    # Create the script for the specific method
    PROG = <<_END_
  def #{method}(*args)
    x,y = self.x, self.y
    super(*args)
    unless self.x == x && self.y == y
      $game_system.caterpillar.register_player_move(@move_speed, '#{method}', args, [self.x, self.y])
    end
  end
_END_
    # Run the script
    eval(PROG)
  end


I understand that it creates new def's on the fly, but what I want to do is to add more methods to the methods list.  Namely direction fix stuff.  The two included direction_fix elements in the array dont seem to be included.  What do I have to do for the script to recognize and include direction fix elements as things to also be eval'd which it isnt doing.

Source is from Zeriab's Caterpillar.
http://sites.google.com/site/zeriabsjunk/scripts-/caterpillar

The way the script works is that when the player takes a step, it records that action, then pases it along to each "cat actor' at the correct time.  What I want it to do is to include turning on or off direction fix for the player, but this code is over my head.

Help?
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

ForeverZer0

It just creates code dynamically at runtime. To put it simply, he is just creating text and having Ruby read it as source code.

Here would be a much simpler version:

eval("class Game_Player; attr_accessor :new_variable; end")

You run that, you will see that you can now set a variable using "$game_player.new_variable = @something".
Since Ruby is scripted, things aren't precompiled and you can actually build and create classes and variables dynamically and load it into Ruby's memory.

Here's an old little snippet I wrote long ago that does something similar using a metaclass.
# encoding: UTF-8

#==============================================================================
# ** Object
#------------------------------------------------------------------------------
# This class is the greatest ancestor of all Ruby objects.
#==============================================================================

class Object
#----------------------------------------------------------------------------
# * Define and get the object's metaclass
#----------------------------------------------------------------------------
  def metaclass
    class << self
      self
    end
  end
#----------------------------------------------------------------------------
# * Define attr_accessors for the object
#----------------------------------------------------------------------------
  def define_attributes(hash)
    hash.each_pair {|key, value|
      metaclass.send(:attr_accessor, key)
      send("#{key}=".to_sym, value)
    }
  end
end


This allows for setting a bunch of public instance variables on a object during runtime using a hash of key:value pairs. This is slightly different, though, since using a metaclass only has an effect on the instance, and not the class. The way above will make it so that new instances will have them attributes defined, while the method I posted will not.

Although metaprogramming allows for some cool things, its really not necessary 99% of the time, and can be prone to bugs if you don't implement it correctly. Even the above example just looks like he was making something fancy just to avoid typing out each one of them methods, I don't really see anything dynamic being added, and it even says not to edit.

Here would be an example of doing something dynamically. Say you want the user to be able to create their own actor parameters in addition to the default one, but you want them to be normally accessible methods, and not just an array of values or whatever. You could do this.

# Define your parameters here:
PARAMETERS = ['spd', 'mana', 'sneak']

# Now lets run the code...

PARAMETERS.each {|param|
eval("class Game_Actor; attr_accessor :#{param}; end")
}

actor = Game_Actor.new
actor.sneak = 45
puts actor.sneak








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