Scripter's Corner
There seems to be a growing amount of capable scripters around the forums, people who pour their heart and souls into well concocted delights of logic and arithmetic in the hopes to further the cause of video game designers and creators in general; yet, these people, this community, has no real way to share information between themselves. Workarounds, hacks, snippets, bug history, jokes, etc; we're slaves to the system, bound to our Hollywood (Submitted RGSS/2 Scripts forums) and our technical help center (RGSS Help forum), forced, like Sisyphus, to labor again and again, reinventing the wheel day after day, toiling under the unflinching stare of our monitors to fulfill other's needs (no, not like that you pervert!).
Well, I say, no more! This fancy introduction was my attempt at making you (un)comfortable, and hopefully I have (not)succeeded. So, after all this talk, I can already hear you yelling out into the cold, lonely night : "But what is the Scripter's Corner, etheon?".
It is, as I've said in a rather long and bizarre series of incoherent and overly descriptive sentences, a place where fellow scripters (coders, programmers, rubyists, Priests of the Why, etc.) can gather 'round and share their experiences. And by that, I mean anything, literally anything that could prove useful to others: your most recent discoveries, in-depth explanations of how certain classes work, tips on original and useful ways to use built-in classes and modules, code snippets, your own classes and modules which, although not scripts in themselves, can be useful to others. That, and much, much more. Found a bug, and then a work around? Post it! Made a small library that handles common physics, such as gravity, acceleration and force? Post it! Found a quick, simple way to determine whether or not there are any events currently running? By all means, post it!
Hopefully, by now, you have a fair idea of where I'm heading with this. This is a global effort, a community effort, which will persist only if everyone chips in a little of their work. I understand some of you might feel that your hard earned work is not to be shared, because it would be stolen, and I respect that; however, I believe that sharing information amongst ourselves can only bolster the global quality of the submitted scripts and, in the long run, can be nothing short of beneficial for the community.
Now, there are no real requirements. I'll be starting off the dance, and I hope more of you will join me. I'm looking at you, Yautja! :shades:
Note : When posting your libraries/classes/modules or snippets, please make sure to share with us not only the code, but how it can/should be used and such; programmers will only use something if it is useful (though non-useful stuff can still be interesting).
I'll start off with a little class I've been working on today : my own implementation of the simple CircularList.
Class : CircularList
A circular list is a data structure which is part of the List family. More importantly, lists are a type of collections, very much like arrays. For more on lists, please see Wikipedia.
Circular lists are, as I've said, data structures; in other words, they're useful collections to handle a variable amount of related data, such as strings, integers or objects. Since in Ruby everything is an Object, this matters little to us. The difference between circular lists and lists in general is that a circular list, although it has a beginning, has no real end; it wraps around and comes back at the beginning. Now, why would we need such a thing, you wonder; I needed it, for instance, to create a generic polygon class that would handle most transformations and calculations. As such, I stored the summits' coordinates (x,y) into a collection, and I needed it to wrap on itself (so that the last summit would be connected to the first).
Long story short, here's the code. Not very well commented, I'll grant you, but eh, sue me.
Usage : The class itself is fairly easy to use. I tried to keep a set of methods which are common to all collections, such as the .each, .length, .size and .delete methods. Usually, most method comments are self-explanatory, but in some case they might not be. The each method will work in an array like manner; it will not wrap around. That would've been an endless loop.
Instantiation of a list is done with the following :
The [object] part can be replaced by any type of object; it will be encapsulated within a Node class, which is an internal class of the CircularList class (it shouldn't be used elsewhere; at list, not until someone makes a List module). My node class goes both way; you can go forward or backward, as you please. Just don't use it directly; instantiation requires a reference to its list.
Method : events_running?
Someone asked the following question in the RGSS Help forums : "How do you check if there are any events currently running?"
I was quite puzzled by this, and after some research, I found a very, very simple solution, which was buried beneath layers of (weird) code.
It will return true if there are any events currently running; a better version, although with a slight overhead, would be :
Seems useless, but it would allow a scripter to add code before or after the following line, which might eventually be useful. Always think flexibility, kids!
Any questions, I'll be glad to help. I have a couple more classes and modules to share; for instance, I'm working on a basic Geometry module which will allow of some of the most common 2D shapes manipulations, including ellipses, (ir)regular polygons, circles, etc.
There seems to be a growing amount of capable scripters around the forums, people who pour their heart and souls into well concocted delights of logic and arithmetic in the hopes to further the cause of video game designers and creators in general; yet, these people, this community, has no real way to share information between themselves. Workarounds, hacks, snippets, bug history, jokes, etc; we're slaves to the system, bound to our Hollywood (Submitted RGSS/2 Scripts forums) and our technical help center (RGSS Help forum), forced, like Sisyphus, to labor again and again, reinventing the wheel day after day, toiling under the unflinching stare of our monitors to fulfill other's needs (no, not like that you pervert!).
Well, I say, no more! This fancy introduction was my attempt at making you (un)comfortable, and hopefully I have (not)succeeded. So, after all this talk, I can already hear you yelling out into the cold, lonely night : "But what is the Scripter's Corner, etheon?".
It is, as I've said in a rather long and bizarre series of incoherent and overly descriptive sentences, a place where fellow scripters (coders, programmers, rubyists, Priests of the Why, etc.) can gather 'round and share their experiences. And by that, I mean anything, literally anything that could prove useful to others: your most recent discoveries, in-depth explanations of how certain classes work, tips on original and useful ways to use built-in classes and modules, code snippets, your own classes and modules which, although not scripts in themselves, can be useful to others. That, and much, much more. Found a bug, and then a work around? Post it! Made a small library that handles common physics, such as gravity, acceleration and force? Post it! Found a quick, simple way to determine whether or not there are any events currently running? By all means, post it!
Hopefully, by now, you have a fair idea of where I'm heading with this. This is a global effort, a community effort, which will persist only if everyone chips in a little of their work. I understand some of you might feel that your hard earned work is not to be shared, because it would be stolen, and I respect that; however, I believe that sharing information amongst ourselves can only bolster the global quality of the submitted scripts and, in the long run, can be nothing short of beneficial for the community.
Now, there are no real requirements. I'll be starting off the dance, and I hope more of you will join me. I'm looking at you, Yautja! :shades:
Note : When posting your libraries/classes/modules or snippets, please make sure to share with us not only the code, but how it can/should be used and such; programmers will only use something if it is useful (though non-useful stuff can still be interesting).
I'll start off with a little class I've been working on today : my own implementation of the simple CircularList.
Class : CircularList
A circular list is a data structure which is part of the List family. More importantly, lists are a type of collections, very much like arrays. For more on lists, please see Wikipedia.
Circular lists are, as I've said, data structures; in other words, they're useful collections to handle a variable amount of related data, such as strings, integers or objects. Since in Ruby everything is an Object, this matters little to us. The difference between circular lists and lists in general is that a circular list, although it has a beginning, has no real end; it wraps around and comes back at the beginning. Now, why would we need such a thing, you wonder; I needed it, for instance, to create a generic polygon class that would handle most transformations and calculations. As such, I stored the summits' coordinates (x,y) into a collection, and I needed it to wrap on itself (so that the last summit would be connected to the first).
Long story short, here's the code. Not very well commented, I'll grant you, but eh, sue me.
Code:
class CircularList
 #-----------------------------------------------------------------------
 # Private Class : Node
 #-----------------------------------------------------------------------
 class Node
  #-----------------------------------------------------------------------
  # Public Instance Variables
  #-----------------------------------------------------------------------
  attr_accessor :forward, :back, :object
  #-----------------------------------------------------------------------
  # * Initialize
  #  list : a reference to the list it is part of
  #  object : the data associated with the node
  #  forward : the next node in the list
  #  back : the previous node in the list
  #-----------------------------------------------------------------------
  def initialize(list, object, forward = nil, back = nil)
   @list = list
   @object = object
   @forward = forward
   @back = back
  end
  #-----------------------------------------------------------------------
  # * Insert
  #  object : the object to insert
  #  node : the node after/before which to insert the object
  #  before : if TRUE, insert before, if FALSE, insert after; def : false
  #-----------------------------------------------------------------------
  def insert(node, before = false)
   # Insert before
   if before
    node.forward = self
    self.back, node.back = node, self.back
    node.back.forward = node
   else
   # Insert after
    node.back = self
    self.forward, node.forward = node, self.forward
    node.forward.back = node
   end
  end
  #-----------------------------------------------------------------------
  # * Dispose
  #  Disposes of self. Removes all references to self.
  #-----------------------------------------------------------------------
  def dispose
   @back.forward, @forward.back = @forward, @back
  end
  #-----------------------------------------------------------------------
  # * To S
  #  String representation of our node element.
  #-----------------------------------------------------------------------
  def to_s
   return @object.to_s if @object.respond_to? :to_s
  end
  #-----------------------------------------------------------------------
  # * ===
  #  Tests for object_id equality
  #-----------------------------------------------------------------------
  def ===(node)
   return (self.object_id == node.object_id)
  end
 end
 #-----------------------------------------------------------------------
 # Public Instance Variables
 #-----------------------------------------------------------------------
 attr_reader :start
 #-----------------------------------------------------------------------
 # * Initialize
 #  start : the first node
 #-----------------------------------------------------------------------
 def initialize(start = nil)
  @start = (start.nil?) ? nil : push(start)
 end
 #-----------------------------------------------------------------------
 # * Clear
 #  Clears the entire list and disposes of every node.
 #-----------------------------------------------------------------------
 def clear
  @start = nil
 end
 #-----------------------------------------------------------------------
 # * Empty?
 #  Returns TRUE if the list is empty, FALSE otherwise.
 #-----------------------------------------------------------------------
 def empty?
  return @start.nil? # Theoretically, if there is no head, there is no body.
 end
 #-----------------------------------------------------------------------
 # * First
 #  Returns a reference to the first element of the list.
 #-----------------------------------------------------------------------
 def first
  raise RuntimeError, "Current list is empty" if self.empty?
  return @start.object
 end
 #-----------------------------------------------------------------------
 # * Last
 #  Returns the last object in the circular list.
 #-----------------------------------------------------------------------
 def last
  raise RuntimeError, "Current list is empty" if self.empty?
  return @start.back.object
 end
 #-----------------------------------------------------------------------
 # * Push
 #  Pushes a new object on top of the list.
 #-----------------------------------------------------------------------
 def push(object)
  node = insert(object, @start, true) # Insert BEFORE our head
 Â
  # Set the new node as the start
  @start = node unless node.nil?
  return node
 end
 #-----------------------------------------------------------------------
 # * Append
 #  Appends an object at the end of the list.
 #-----------------------------------------------------------------------
 def append(object)
  node = (@start.nil?) ? @start : @start.back
  return insert(object, node) # Insert after our head's prior node
 end
 #-----------------------------------------------------------------------
 # * Insert
 #  object : the object to insert
 #  node : the node after/before which to insert the object
 #  before : if TRUE, insert before, if FALSE, insert after; def : false
 #-----------------------------------------------------------------------
 def insert(object, node, before = false)
  o = Node.new(self, object)
 Â
  # If the start is already placed, insert.
  unless @start.nil?
   node.insert(o, before)
  else
   # Since there is no start, clearly we must be set as such.
   @start = o
  Â
   # Link around to ourself!
   o.back = o
   o.forward = o
  end
 Â
  return o
 end
 #-----------------------------------------------------------------------
 # * Pretty Print
 #  Prints...prettily?
 #-----------------------------------------------------------------------
 def pretty_print
  retval = ""
  node = @start
 Â
  self.each { |node| retval << "#{ node }\n" }
  Â
  print(retval)
 end
 #-----------------------------------------------------------------------
 # * Each
 #  Iterate through each node.
 #-----------------------------------------------------------------------
 def each(&block)
  node = @start
  begin
   yield node
   node = node.forward
  end until node == @start
 end
 #-----------------------------------------------------------------------
 # * Each_Value
 #  Iterate through each objects, not node.
 #-----------------------------------------------------------------------
 def each_value(&block)
  node = @start
  begin
   yield node.object unless node.nil?
   node = node.forward
  end until node == @start
 end
 #-----------------------------------------------------------------------
 # * Extract
 #  object : the value (object) which is contained within a node
 #
 #  Finds the node whose object value is given.
 #  Returns the first ocurrance of said object.
 #-----------------------------------------------------------------------
 def extract(object)
  self.each { |node| return node if node.object == object }
  return nil
 end
 #-----------------------------------------------------------------------
 # * Delete
 #  Removes the node whose value is the object given.
 #-----------------------------------------------------------------------
 def delete(object)
  self.each do |node|
   if node.object == object
    # Is this the start?
    if node == @start
     @start = (node == node.forward) ? nil : node.forward
    end
   Â
    # The union won't get you out of this one!
    node.dispose
   end
  end
 end
 #-----------------------------------------------------------------------
 # * Length, alias size
 #  Returns the number of nodes in the list.
 #-----------------------------------------------------------------------
 def length
  retval = 0
 Â
  self.each { |node| retval += 1 }
 Â
  return retval
 end
 alias_method :size, :length
end
Usage : The class itself is fairly easy to use. I tried to keep a set of methods which are common to all collections, such as the .each, .length, .size and .delete methods. Usually, most method comments are self-explanatory, but in some case they might not be. The each method will work in an array like manner; it will not wrap around. That would've been an endless loop.
Instantiation of a list is done with the following :
Code:
list = CircularList.new([object])
The [object] part can be replaced by any type of object; it will be encapsulated within a Node class, which is an internal class of the CircularList class (it shouldn't be used elsewhere; at list, not until someone makes a List module). My node class goes both way; you can go forward or backward, as you please. Just don't use it directly; instantiation requires a reference to its list.
Method : events_running?
Someone asked the following question in the RGSS Help forums : "How do you check if there are any events currently running?"
I was quite puzzled by this, and after some research, I found a very, very simple solution, which was buried beneath layers of (weird) code.
Code:
$game_system.map_interpreter.running?
It will return true if there are any events currently running; a better version, although with a slight overhead, would be :
Code:
def events_running?
 return $game_system.map_interpreter.running?
end
Seems useless, but it would allow a scripter to add code before or after the following line, which might eventually be useful. Always think flexibility, kids!
Any questions, I'll be glad to help. I have a couple more classes and modules to share; for instance, I'm working on a basic Geometry module which will allow of some of the most common 2D shapes manipulations, including ellipses, (ir)regular polygons, circles, etc.