3

I've got all the tutorials up to beginner #5 translated and working, but I don't know Java well enough to know how to port the lines:

private ActionListener actionListener = new ActionListener() {
  public void onAction(String name, boolean keyPressed, float tpf) {
    if (name.equals("Pause") && !keyPressed) {
      isRunning = !isRunning;
    }
  }
};

private AnalogListener analogListener = new AnalogListener() {
  public void onAnalog(String name, float value, float tpf) {
    ...
  }
}

How might this work?

Jwosty
  • 3,497
  • 2
  • 22
  • 50
  • Wouldn't it be a good thing to make those translated tutorials available publicly? :) – Redoman Jan 11 '13 at 21:05
  • Oh, that probably would have; I just don't know where it even is on my computer if at all since it's been so long... – Jwosty Jan 15 '13 at 14:10

3 Answers3

1

As described in Calling Java from JRuby, you can use closure conversion, where blocks can be used to define a Java interface behaviour. Something like the following should work:

l = lambda { |name, pressed, tpf| running = !running if name == 'Pause' && !pressed }
input_managers.add_listener(l, ['Left', 'Right', 'Rotate'])
Sébastien Le Callonnec
  • 26,254
  • 8
  • 67
  • 80
  • I still can't get it to work; your way raises an error `org.jruby.exceptions.RaiseException: (TypeError) cannot convert instance of class org.jruby.RubyArray to class java.lang.String`. If I separate it out into individual args or call `to_java`, it doesn't execute the block. I've no idea what's wrong. – Jwosty Mar 22 '12 at 23:01
  • [Here's](https://gist.github.com/2166358) the file (it's loaded by another that sets up the classpath) – Jwosty Mar 23 '12 at 02:51
  • @Jwosty : can you try adding `@` to input manager, and then convert the array into comma-separated: `@input_manager.add_listener(l, 'Left', 'Right', 'Rotate')` The varargs might be the problem here. – Sébastien Le Callonnec Mar 23 '12 at 08:49
  • And here is the simple example I have used to come up with the code above: https://gist.github.com/2169349 – Sébastien Le Callonnec Mar 23 '12 at 10:33
  • It can't be converted to an instance variable because it's a method (did you mean `@input_manager = input_manager`?), and separating the arguments out doesn't seem to work either. – Jwosty Mar 23 '12 at 14:12
  • Close, but no cigar. I figured it out, but thanks for your help! :) – Jwosty Apr 05 '12 at 18:42
0

Ah, found the answer. Turns out, they were anonymous inner classes. In JRuby, you can just create a class that implements the Java interface like so:

class RBActionListener
  # This is how you implement Java interfaces from JRuby
  include com.jme3.input.controls.ActionListener

  def initialize(&on_action)
    @on_action = on_action
  end

  def onAction(*args)
    @on_action.call(*args)
  end
end

class HelloJME3
  # blah blah blah code blah blah blah

  def register_keys
    # ...
    ac = RBActionListener.new {|name, pressed, tpf @running = !@running if name == "Pause" and !pressed}
    input_manager.add_listener(ac, "Pause")
  end
end
Jwosty
  • 3,497
  • 2
  • 22
  • 50
0

I wrapped the action listener in a method that would return an object that includes ActionListener using JRuby's :impl method

def isRunningActionListener
  return ActionListener.impl do
    |command, name, keyPressed, tpf|
      case command
        when :onAction
          if name.eql?("Pause") && !keyPressed
            isRunning = !isRunning;
          end
      end
   end
end

you could also create your own ActionListener class that includes ActionListener...

class YourActionListener
  include ActionListener
  def onAction command, name, keyPressed, tpf
    #your code here
  end
end

creating your own class might be the better option as its a lot less verbose and easier to read and understand.