Proof of Concept: Ruby in RMMV - A Simple HUD Demo

Discussion in 'Useful Development Tools' started by Chocobo, Feb 19, 2019.

  1. Chocobo

    Chocobo Villager Member

    Messages:
    29
    Likes Received:
    47
    First Language:
    German
    [​IMG]
    Last weekend I came to stumble across the Opal project that allows Ruby code to be run in the browser by transpiling it into JS. I was hooked to find out if it can work in RMMV -- and by that I mean more than just a hello world program.

    As a preamble:
    There already was a thread with a demo of the RMMV running Ruby about 2 years ago. But the concept was different. It required the end user to have Ruby installed and set up and would only work on a computer. Also, the code wouldn't have been able to interact with the JS objects, so things like a HUD wouldn't have been possible.

    This demo project is runnable on a computer, a web browser or a mobile device, without the user having to install anything. So the normal RMMV deployments all work. Furthermore, Opal's JS bridging allows for two-way Ruby/JS interaction.

    Without further ado, here's a video of the running demo:


    And here is the Ruby code of the two HUDs:
    Code:
    #==============================================================================
    # ** Variable_HUD
    #------------------------------------------------------------------------------
    #  This class shows a HUD that displays a variable and an icon.
    #==============================================================================
    
    class Variable_HUD < Window_Base
       def initialize(iconID, varID)
        @iconID = iconID
        @varID = varID
        
        x = 816/2 - window_width/2
        
        # Calling the base constructor
        super! x, 0, window_width, window_height
        
        refresh
       end
      
       def window_width
         128
       end
     
       def window_height
         64
       end
     
       # Get the variable value
       def value
         $gameVariables._data[@varID] || 0
       end
     
       # Draw the contents
       def refresh
        self.contents.clear
        self.contents.fontSize = 24
        
        drawIcon(@iconID, 0, 0)
        self.contents.drawText(self.value, 0 + 36, 0, 32, 32, 'right')
       end
    
      # Display the window and attach to the scene
      def show
        $scene.hud = self
        $scene.hud.openness = 0
        $scene.addWindow(self)
        
        open!
      end
    end
    
    #==============================================================================
    # ** Super_HUD
    #------------------------------------------------------------------------------
    #  This class shows a HUD that displays some random stuff.
    #==============================================================================
    
    class Super_HUD < Variable_HUD
      def initialize
        # Needed when a method from the JS base class should be overriden
          override :standardBackOpacity
    
        super 99, 100
        
        self.height = 100
      end
     
      # Methods from the Ruby base class can be overriden as usual
      def value
        @varID + rand(100)
      end
     
      def standardBackOpacity
        # Super calls can be made with _super attached to the base method
        o = standardBackOpacity_super
        return o / 2
      end
    end
    
    #---------------------------------------------------------------------------
    
    # Overriding the update method of Scene_Map.
    # In JS -- too lazy right now to figure out the Ruby code :~)
    %x{
        var mapUpdateVHUD = Scene_Map.prototype.update;
        Scene_Map.prototype.update = function()
        {
            $sceneMap = this;
            if (this.hud)
                this.hud.$refresh();
            
            mapUpdateVHUD.call(this);
        }
    }
    
    In the index.html, there are the following added script tags:
    HTML:
            
            <script src="ruby/opal.js" onload="Opal.load('opal')"></script>
            <script src="ruby/native.js"></script>
            <script src="ruby/opal-parser.js" onload="Opal.load('opal-parser')"></script>
        
            <script type="text/javascript" src="js/libs/pixi.js"></script>
            <script type="text/javascript" src="js/libs/pixi-tilemap.js"></script>
            <script type="text/javascript" src="js/libs/pixi-picture.js"></script>
            <script type="text/javascript" src="js/libs/fpsmeter.js"></script>
            <script type="text/javascript" src="js/libs/lz-string.js"></script>
            <script type="text/javascript" src="js/libs/iphone-inline-video.browser.js"></script>
            <script type="text/javascript" src="js/rpg_core.js"></script>
            <script type="text/javascript" src="js/rpg_managers.js"></script>
            <script type="text/javascript" src="js/rpg_objects.js"></script>
            <script type="text/javascript" src="js/rpg_scenes.js"></script>
            <script type="text/javascript" src="js/rpg_sprites.js"></script>
            <script type="text/javascript" src="js/rpg_windows.js"></script>
            <script type="text/javascript" src="js/plugins.js"></script>
            
            <!-- Ruby files go here -->
            <script type="text/ruby" src="ruby/ruby-definitions.rb"></script>
            <script type="text/ruby" src="ruby/HUD.rb"></script>
            
            <script type="text/javascript" src="js/main.js"></script>
    First, the Opal scripts. At the end, two Ruby files are included. The first one defines globals, helpers and some behaviors so that the HUD code can be written like it is. Also, the RMMV "script" command gets overwritten so that it evaluates Ruby code instead of JS code.

    The Variable_HUD class inherits from the Window_Base JS class (bridging). Everything else is more or less just "normal HUD stuff", apart from the last lines. The syntax %x{...} lets you run JS code; there the update method is aliased and overriden (this should be doable in pure Ruby as well). Also note that the super call to the JS base class in Variable_HUD requires the special syntax with an appended exclamation marks. Lastly, note that if you want to override methods from the base JS class, you need to use a special override call (see Super_HUD constructor).
    On a closing note, I want to mention that this should just serve as a proof of concept. Running Ruby code like this will be significantly slower than running the direct JS code. Also, there's probably a lot more work to do in order to be able to write bigger plugins.

    You can find the demo project (< 2 mb) in the attachments.
     

    Attached Files:

    #1

Share This Page