Ruby game engine

(Frederico de Oliveira Linhares) #1

Hello!

I am writing a 3D game engine, instead of writing it in C++ and making a binding I am doing it directly in Ruby. I never saw anything similar so I don't know if is a good idea and if is going to work. Until now it's working.

In my engine I have a code similar to this:

Engine::init do
  character_mesh = Engine::Mesh.new("/path/to/mesh")
  Engine::run
end

The 'Engine::init' initialize systems like Vulkan before executing the code block and finalize those systems after the code block exit. The problem is, I must ensure that 'Mesh.new' can be called only after 'Engine::init' and also ensure the garbage collector free the 'Mesh' after the code block and before my code that finalize Vulkan. What is the best approach to do it?

Note: the Mesh and the code that initialize and finalize Vulkan was entirely implemented in C/C++. I am not using Ruby Rice, I don't feel I need it.

0 Likes

(Marvin Gülker) #2

I am writing a 3D game engine, instead of writing it in C++ and making
a binding I am doing it directly in Ruby

A noble goal. There exist some Ruby game engines (gosu comes to mind),
but I don't think they're 3D.

The problem is, I must ensure that 'Mesh.new' can be called only
after 'Engine::init'

Set a variable when it's called. The following example uses a
module-instance variable. Trying to call Engine::Mesh.new will cause a
RuntimeError exception.

    module Engine # Appearently Engine is a module for you?
      @initialized = false

      class << self
        attr_reader :initialized

        def init
          do_initialisation
          @initialized = true
          yield
        end
      end

      class Mesh
        def initialize
          raise "Engine not initialized" unless Engine.initialized
        end
      end

    end

Note your description and your given example do not fit together,
because when `Mesh.new' is called in your example while `Engine.init'
has not yet finished, as it's part of the `Engine.init' block (unless
you're doing some meta programming magic in `Engine.init' and do not
execute the block). I assume your example was what you really meant and
took that into account for my example above by setting `@initialized'
*before* calling `yield'.

and also ensure the garbage collector free the
'Mesh' after the code block and before my code that finalize
Vulkan.

Use an `ensure' clause to ensure Vulkan is finalised when the
`Engine.init' block terminates:

  def init
    do_your_initialisation
    yield
  ensure
    Vulkan.finalise
  end

This is syntactic sugar for fully writing out the begin/ensure/end
statement. Ruby tries to be not in your way and keep the code readable
(thanks, Matz).

As for controlling the Garbage Collector: don't. You can't ever fully
control it anyway from the Ruby side. It will free objects when it
thinks it's time to free them. You will need to take that into account
when writing `Vulkan.finalise'. There usually is a way that will work
without trying to cheat the Garbace Collector.

Note: the Mesh and the code that initialize and finalize Vulkan was
entirely implemented in C/C++. I am not using Ruby Rice, I don't feel
I need it.

Ruby's C interface is actually pretty nice. It's been a long time since
I last wrote a C extension, but I never felt uncomfortable with it.

···

Am 16. März 2019 um 01:58 Uhr +0000 schrieb Frederico de Oliveira Linhares:

--
Blog: https://mg.guelker.eu

0 Likes