Используйте Artemis ESF с JRuby

Я пытаюсь использовать структуру системы сущностей Artemis из JRuby. Вот код Java, который я пытаюсь преобразовать в JRuby:

import com.artemis.Aspect;
import com.artemis.Component;
import com.artemis.Entity;
import com.artemis.World;
import com.artemis.systems.EntityProcessingSystem;

public class MyGame {

    private World world;

    public MyGame() {
        world = new World();

        Entity e = world.createEntity();
        e.addComponent(new Position());
        e.addToWorld();

        world.setSystem(new ConsoleOutputSystem());
        world.initialize();
        for(int i = 0; i < 10; i++) {
            world.setDelta(60);
            world.process();
        }
    }

    public static void main(String[] args) {
        new MyGame();
    }
}

class Position extends Component {

    public int x;
    public int y;

    public Position() {
        this.x = 0;
        this.y = 0;
    }
}

class ConsoleOutputSystem extends EntityProcessingSystem {

    public ConsoleOutputSystem() {
        super(Aspect.getAspectForAll(Position.class));
        System.out.println("In system constructor");
    }

    @Override
    protected void process(Entity entity) {
        System.out.println("processing");
        System.out.println(entity.getUuid());
    }

}

Когда я выполняю это, вывод:

In system constructor
processing
9e8a24a8-b778-4926-b305-5a426a2f0ce1
processing
...

Метод ConsoleOutputSystem.process() вызывается десять раз. Вот мой код JRuby:

require 'artemis.jar'

java_import com.artemis.Entity
java_import com.artemis.World
java_import com.artemis.Component
java_import com.artemis.Aspect
java_import com.artemis.systems.EntityProcessingSystem

class MyGame 

  attr_reader :world

  def initialize

    @world = World.new()
    e = @world.create_entity()
    e.add_component(Position.new())
    e.add_to_world()
    @world.set_system(ConsoleOutputSystem.new())
    #@world.initialize
    @world.java_send :initialize
    10.times do
      @world.set_delta(60)
      @world.process()
    end
  end

end

class Position < Component

    attr_accessor :x, :y

    def initialize ()
        @x = 0
        @y = 0
    end

end

class ConsoleOutputSystem < EntityProcessingSystem

    def initialize()
      puts 'in system constructor'
      super(Aspect.get_aspect_for_all(Position))
    end

    java_signature 'protected void process(Entity)'
    def process(entity)
      puts 'process'
      puts entity.getUuid
    end

end


MyGame.new()

Выход:

in system constructor

Поэтому вызывается конструктор ConsoleOutputSystem, но не ConsoleOutputSystem.process(). Я попытался использовать @world.initialize и @world.java_send:initialize, и результат был одинаковым. Еще я попытался добавить java_signature 'protected void process(Entity)' в метод ConsoleOutputSystem.process().

Несколько других классов из пакета Artemis имеют защищенные методы с именем initialize(), но я не уверен, связано ли это с моей проблемой.

[РЕДАКТИРОВАТЬ]

Я сделал некоторый прогресс, так как я отправил вопрос. @world.java_send: инициализация работает и вызывается правильный метод. Что не работает, так это Aspect.get_aspect_for_all(). В Java ожидается Aspect.getAspectForAll()

Class<? extends Component> , Class<? extends Component>[]

в качестве аргументов. В JRuby ни один из них не работает в качестве аргумента Aspect.getAspectForAll():

Position
Position.class
Position.java_class
Position.java_proxy_class

Единственное, что сработало, - это создание экземпляра Position заранее и передача его класса в Aspect.getAspectForAll():

@position_class = Position.new().getClass()

Вот код, он работает, но кажется, что это похоже на клудж:

require 'artemis.jar'

java_import com.artemis.Entity
java_import com.artemis.World
java_import com.artemis.Component
java_import com.artemis.ComponentType
java_import com.artemis.ComponentMapper
java_import com.artemis.Aspect
java_import com.artemis.systems.EntityProcessingSystem

class MyGame 

  attr_reader :world

  def initialize

    @world = World.new()

    e = @world.create_entity()
    e.add_component(Position.new())
    e.add_component(Velocity.new())
    e.add_to_world()

    @world.set_system(ConsoleOutputSystem.new(@world))
    @world.java_send :initialize


    5.times do
      @world.set_delta(60)
      @world.process
    end

  end

end

class Position < Component

    attr_accessor :x, :y

    def initialize ()
        @x = rand(100)
        @y = rand(100)
    end

end

class Velocity < Component

  attr_accessor :v

  def initialize()
    @v = 1.43
  end

end

class ConsoleOutputSystem < EntityProcessingSystem

  attr_accessor :position_class, :velocity_class

    def initialize(world)

      @position_class = Position.new().getClass()
      @velocity_class = Velocity.new().getClass()

      puts "@position_class: #{@position_class}"
      puts "Position: #{Position}"
      puts "Position.class: #{Position.class}"
      puts "Position.java_class: #{Position.java_class}"
      puts "Position.java_proxy_class: #{Position.java_proxy_class}"

      super(Aspect.get_aspect_for_all(@position_class, @velocity_class))

    end

    def process(entity)

      puts 'process'
      puts entity.getUuid

      position = entity.get_component(@position_class)
      velocity = entity.get_component(@velocity_class)

      position.x += 1
      position.y += 1
      velocity.v += 1

      puts position.x
      puts position.y
      puts velocity.v
      puts '----------'

    end

end

game = MyGame.new()

Выход из

puts "@position_class: #{@position_class}"
puts "Position: #{Position}"
puts "Position.class: #{Position.class}"
puts "Position.java_class: #{Position.java_class}"
puts "Position.java_proxy_class: #{Position.java_proxy_class}"

является:

@position_class: org.jruby.proxy.com.artemis.Component$Proxy0
Position: Position
Position.class: Class
Position.java_class: com.artemis.Component
Position.java_proxy_class: org.jruby.javasupport.proxy.JavaProxyClass

Итак, моя проблема в том, как добраться до org.jruby.proxy.com.artemis.Component$Proxy0, не создавая экземпляр класса Position?

[РЕДАКТИРОВАТЬ 2]

Благодаря ответу Namek, вот код, который работает. Оно использует

@position_class = Position.java_proxy_class.java_class
@velocity_class = Velocity.java_proxy_class.java_class

поэтому мне не нужно создавать экземпляр класса JRuby, чтобы добраться до его Java-класса:

require 'artemis.jar'

java_import com.artemis.Entity
java_import com.artemis.World
java_import com.artemis.Component
java_import com.artemis.ComponentType
java_import com.artemis.ComponentMapper
java_import com.artemis.Aspect
java_import com.artemis.systems.EntityProcessingSystem


class MyGame 

  attr_reader :world

  def initialize

    @world = World.new()

    e = @world.create_entity()
    e.add_component(Position.new())
    e.add_component(Velocity.new())
    e.add_to_world()

    @world.set_system(ConsoleOutputSystem.new(@world))
    @world.java_send :initialize


    5.times do
      @world.set_delta(60)
      @world.process
    end

  end

end


class Position < Component

    attr_accessor :x, :y

    def initialize ()
        @x = rand(100)
        @y = rand(100)
    end

end


class Velocity < Component

  attr_accessor :v

  def initialize()
    @v = 1.43
  end

end


class ConsoleOutputSystem < EntityProcessingSystem

  attr_accessor :position_class, :velocity_class

    def initialize(world)

      @position_class = Position.java_proxy_class.java_class
      @velocity_class = Velocity.java_proxy_class.java_class

      super(Aspect.get_aspect_for_all(@position_class, @velocity_class))

    end

    def process(entity)

      puts 'process'
      puts entity.getUuid

      position = entity.get_component(@position_class)
      velocity = entity.get_component(@velocity_class)

      position.x += 1
      position.y += 1
      velocity.v += 1

      puts position.x
      puts position.y
      puts velocity.v
      puts '----------'

    end

end


game = MyGame.new()

1 ответ

Решение

Похоже, что ваша текущая проблема обсуждается здесь: http://jira.codehaus.org/browse/JRUBY-672

попытайтесь получить свой класс Java следующим образом:

Position.java_proxy_class.java_class

Другие вопросы по тегам