Everything you need to know to get started with Moon.
28 May, 2015
This small guide will get you started creating a Moon Project.
tl;dr Sample Project
Moon is just a glorified mruby interpreter, with all its features as loaded in as mruby gems.
Moon requires quite a bit of setup in order to get started, remember its just an extension of mruby.
Moon::Engine already knows how to get Moon up and running with a Window and Input events.
main.rb would look like this
engine = Moon::Engine.new do |e, delta| # This block will be called each frame # Moon::Engine will always pass itself as the first parameter followed by the frame's delta time. end # This initializes OpenGL, creates the Window, does all other manner other Moonities. engine.setup # This will start the main loop, which will call the block above. engine.main
Luckily (again), you don’t have to write a bootstrap for each project you start, we already provide a bootstrap under moon’s scripts directory
Several symlinks are available in moon’s
These are shortcuts for their corresponding
moon-player is a nicely wrapped up bash script for calling
moon-mruby with moon’s
Its a good idea to add moon’s
bin path to your
If you want just a bit more control over moon, or you added some fancy extensions that need to be loaded, before, during or after Moon’s regular bootstrapping, you may just want to write one yourself.
If you’ve read the Getting Started, you’ll know that moon is a glorified mruby interpreter.
And the repository comes with a
bin/moon-player (and its variants).
moon-player is just a shell script which calls
moon-mruby which loads the
scripts/bootstrap.rb and it does its magic.
Well enough prep work.
Moon provides an Engine class which will initialize most of the boring and painful things.
One of the odd things about Engine is that its
initialize takes a block, this block will be used as the
step callback for your apps main loop (notice I used app, not game, because.. ok..).
engine = Moon::Engine.new do |e, delta| # e - the instance of the engine, in case you misplaced the one you created ;3 # delta - time elapsed since the last frame end
At this point you’re saying “Well, that wasn’t so hard”, and this is where I say “Sure, except creating an Engine != Initialized Engine”.
At this point, the engine has only been created and its
step callback set, OpenGL, GLFW and all the likes haven’t been setup as yet.
You’ll need to manually initialize GLFW, as for the reason, if you wanted to create multiple engines (FOR SOME REASON), it would re-initialize GLFW each time, while I do believe GLFW.init does nothing on multiple calls, it leaves a bad taste in your mouth.
So for the sake keeping your mouth minty fresh, YOU WILL initialize GLFW yourself, after that anything goes wrong,
is all your fault™.
GLFW.init # in good favour, we call GLFW.init before doing anything engine = Moon::Engine.new do |e, delta| # e - the instance of the engine, in case you misplaced the one you created ;3 # delta - time elapsed since the last frame end
In order to get the engine setup and its main window created, you’ll need to call
This will smash a few heads, roll a few dies, and magically obtain the black arts known as an OpenGL context for you, while somehow speaking to your somewhat broken Display Server (X11 I’m looking at you).
You can now do other things, such as chasing gophers around your yard, or blowing bubbles while sitting on a mountain, before finally calling the
Engine#main, at this point:
YOU HAVE FORFEITED ALL CONTROL TO MOON Given control to Moon tl;dr You are now at the mercy of Moon.
Don’t panic, the engine will return control once its main loop exits (either by an error or by
Engine#shutdown is used to destroy the window NOT stop the main loop (I’m saying this because I wrote it and went ahead and used
#shutdown instead of
#quit, so TAKE THIS FROM THE DEVELOPER.)
Once the engine returns your
yBox controller and your somewhat broken copy of
Lambda of Duty 6, you can now
shutdown and drink some beer.
begin engine.main ensure # ENSURE SHUTDOWN, yes, I said it engine.shutdown end
After that just let mruby reclaim the Engine for crushing into fine gems for future use by other objects.
All together the basic bootstrap looks like this: (ignoring my comments)
GLFW.init # load up your copy of Lambda of Duty 6 engine = Moon::Engine.new do |e, delta| end # Plug in your controller engine.setup # Let a rip begin engine.main ensure # possibly pull the controller and throw the yBox against the wall, or you got tired of all the bugs. engine.shutdown end # call it a day and go drink beer.
Now if you don’t mind, I have gophers to chase…
There is no hard or fast rule for Moon project structure, however if you use the default
it will require that you have a
tl;dr It should look something like this
my_project/ core/ load.rb resources/ shaders/ 120/ quad.vert quad.frag text.vert text.frag 330/ quad.vert quad.frag text.vert text.frag scripts/ load.rb
Reasoning behind core and scripts
This is actually a convention that came from the very beginning of the project.
core contained the Moon standard library, however that was later moved, but the structure remained.
On the other hand,
scripts were all the user scripts for the project.
Each directory contained a
load.rb, you can think of it as a
main.rb, that file was responsible for loading
Moon does not embed its shaders, reason?, we don’t have one actually, I guess debugging?
Anyway, you are required to copy the shaders from
assets/shaders, copy the
330 directories into your projects
These shaders are used by Moon’s Graphics classes, so if you aren’t using the
graphics module, you could just skip them.
Your first Project
Hello Goodbye World, because Hello is overrated, you’ll be creating a simple
Though you’ll need a font first, sorry, we (well mostly IceDragon) forgot to package a font with Moon.
From this point on, its assumed you’ll be using
moon-player to run and test your projects.
First up you’ll need a font, go swipe one off the interwebs, or just grab one from your local font directory or something.
You create a Font object by doing the following:
# signature font = Moon::Font.new(filename, size) # usage font = Moon::Font.new('resources/fonts/Arial.ttf', 18)
Customarily, you’ll put all assets/resources in
resources/ in a proper sub-directory, but that’s just us, feel free to go crazy with
uber-tastic-place-to-store-my-assets/things-that-go-on-the-screen/Arial.ttf, I ain’t stopping you.
Font is just a fancy Texture-like class, by itself it renders NOTHING. So to get your Font drawn on the screen, you’ll need a Text object.
text = Moon::Text.new(font, "my uber-tastic string!")
Now for a gotcha, if you looked in the bootstrap, you may have noticed that you don’t get any methods setup or termination, this may be considered in the future, but for now, just lazy initialize your stuff in
#step, or better yet, write your own bootstrap and share it with us.
def step(engine, delta) @text ||= begin font = Moon::Font.new('resources/fonts/Arial.ttf', 18) Moon::Text.new(font, "Goodbye, World") end @text.render(24, 24, 0) end
Assuming all went well in the world and your house didn’t explode because of a random segfault, you should see ‘Goodbye World’ in the top left corner of your window, in white.
But wait, I WANT COLOR!
Easy there, you can have your color, just pass a 3rd parameter to Text on creation.
# signature text = Moon::Text.new(font, string, options) # example text = Moon::Text.new(font, "Goodbye, World", color: Moon::Vector4.new(0, 1, 0, 1))
def step(engine, delta) @text ||= begin font = Moon::Font.new('resources/fonts/Arial.ttf', 18) Moon::Text.new(font, "Goodbye, World", color: Moon::Vector4.new(0, 1, 0, 1)) end @text.render(24, 24, 0) end
Now you must be screaming, “WHERE IS
Moon::Color?” the answer, there is none, there will never be one, get used to it;
Moon::Vector4 is now your
Congrats you now have a
Goodbye World program in Moon.
Text also accepts a few other options:
Moon::Text.new(font, string, color: Moon::Vector4, # default: Moon::Vector4.new(1, 1, 1, 1) outline: Integer, # outline size, 0 will disable outlines, anything higher will create an outline, default: 0 outline_color: Moon::Vector4, # default: Moon::Vector4.new(0, 0, 0, 1) line_height: Float, # default: 1.2 shader: Moon::Shader, # default: Moon::Shader.default_shader align: Symbol, # either :left, :right, or :center, default: :left )