Game Development Community

dev|Pro Game Development Curriculum

Ruby Binding for TGEA

by Matthias Georgi · 01/23/2008 (6:04 pm) · 8 comments

After finishing a working implementation of my binding for the Ruby language, I'm gonna try now a tighter support using gccxml. After reading the post of Prairie Games and their work on the Python binding I was inspired to use the same route for generating wrappers for C++ classes.

My current implementation asks the Torque Scripting Environment for all defined classes, methods and fields and generates wrappers as script files, which call my binding code to interface with the Torque Engine. This has the drawback, that arguments and return values are converted to strings and my binding has to figure out, how to convert back and forth using the intermediate string representation.

This works quite well and has some kind of type safety in contrast to the Torque Scripting Language. I was able to convert all torque scripts to ruby scripts and the syntax is very nice to work with. Especially the scripts for the world editor got a lot clearer by using Ruby. A simple example will show you the advantages of using a full fledged scripting language. This is my implementation of the FileDialog GUI:

class FileDialogClass < GuiControl
  
  child_accessor :window, :okButton, :cancelButton, :dirTree, :textEdit, :fileList
  
  def_on(:add) do

    window.on(:close) do
      close
    end
    
    okButton.on(:action) do |sender|
      @callback.call selectedFile
      close
    end
    
    cancelButton.on(:action) do |sender|
      close
    end
  
    dirTree.on(:selectPath) do |sender, path|
      fileList.setPath(path, @filespec)
    end
  
    fileList.on(:select) do |sender, id, filename|
      textEdit.setText(filename)
    end
    
    textEdit.on(:return) do |sender|
      @callback.call(selectedFile)
      close
    end
  end
  
  def open(title = "Open File", button_text = "Open", filespec = "*.*", &proc)
    window.text = title
    okButton.text = button_text 
    @filespec = filespec
    @callback = proc
    Canvas.pushDialog(self, 99)    
    fileList.setPath(dirTree.getSelectedPath, @filespec)
  end
  
  def selectedPath=(file)
    dirTree.setSelectedPath file
  end
  
  def selectedPath
    dirTree.getSelectedPath
  end

  def selectedFile  
    "#{selectedPath}/#{textEdit.getValue}"
  end
  
  def close
    Canvas.popDialog(self)
  end
  
end

Essential was the implementation of the Event/Observer pattern, which simplifies the use of callbacks like onAdd. In Torque Script you are limited to one callback method for an event like onAdd. In my implementation you can attach more than one event listener to one instance or to the class itself. So you don't have to use namespaces, instead you attach the event listener to a particular instance, which should be done in the onAdd event handler, which gets called right after the creation of an object.

You may have noticed the child_accessor method. This one generates a accessor method for getting the child or descendant of a SimObject. This is cool, as you can avoid messing up the global namespace. You just use the internalName property of a child object and reach it via the accessor method.

So back to the GCCXML stuff. This is really exciting, as the xml format exposes the internal structure of a c++ program. I'm currently working on a small library, which parses the xml and makes the program structure accessible to the ruby world.

A simple Rakefile (like Make in Ruby) will transform the C++ classes to their xml representation and automatically generate wrapper code, which can be compiled by good old Visual Studio. This route allows a tight ruby binding avoiding the intermediate string representation. Furthermore all desired elements of the engine may be exposed to scripting and the burden of writing repetitive wrapper code is avoided.

If anyone is interested in ruby development, just let me know. I have invested a lot of time into this stuff (about 2 years) and like to share my experiences.

About the author

Integration of Torque and Ruby

Recent Blogs


#1
01/23/2008 (6:59 pm)
Awesome job Matthias, What a 1st blog!
#2
01/23/2008 (10:14 pm)
truly amazing.

any chance this will work with TGE (and on non Win systems)? :)
#3
01/24/2008 (3:42 am)
Thanks.

@Montgomery:
TGE should work fine, but It would require some merging of C++ code and removing some shader, material scripts.

I patched the engine on several places. First there were some little bugs in the engine code like wrong argument count for callbacks. A change was made in the GameConnection to avoid the ugly serverCmd* functions. Now the GameConnection itself dispatches the commmands and delegates to the server module, which in turn delegates to the corresponding module. Another change was made to the ActionMap class to issue the mouse/key callbacks to the ActionMap object itself to avoid global functions.

For non-win systems to work, ruby needs to be compiled, so you can distribute your own ruby executable. The engine must be compiled as dll extension, so a little change to the makefile is needed.

Porting and maintaining should be easier, once the componentized engine is available, as the code base is the same for TGEA and TGE.
#4
01/24/2008 (9:33 am)
Cool stuff!
#5
01/24/2008 (11:52 am)
That is just cool! Any chance of a ruby binding for TGB? ;)
#6
01/24/2008 (3:44 pm)
@Saiko:
I don't own the TGB engine, but as far as I know, TGB is based on the same scripting engine. So it would be possible, but would require rewriting of some scripts.
#7
05/13/2008 (12:12 pm)
This is really exciting stuff Matthias! I've been away from game dev for awhile and working mostly with Ruby so it's great to see that as I jump back into the Torque experience I can leverage what I've learned. I would love to talk Ruby and Torque with you if you're interested.
#8
06/02/2008 (1:24 pm)
Hi Brandon, just write me an email. Your email seems to be outdated.