Starting out with DragonRuby


After spending a week with DragonRuby, I really like it. I've never seen a toolkit/engine that uses its paradigm before - the media layer API (SDL in this case) is entirely hidden from you. All that's exposed is a data structure args into which you push data e.g. 

args.outputs.sprites << [ 120,  104, 32, 32, 'sprites/player_bullet.png' ]

Gone are the need to provide any function calls to set up a subsystem, or enumerate devices on the system, or flush/finalise data; or whatever else you'd otherwise need to take responsibility for just to get the flashing colours you want on the screen. After spending a couple of years with SDL2 and C++, this approach seems very limiting. But when your objective is to write a game that limitation may very well actually be an aid.
And when DragonRuby out-of-the-box will build artifacts for multiple platforms, this is a mighty way to just get your ideas onto the screen.

This post is just to capture some of the things I learned in starting out with DragonRuby on my personal Windows PC. None of this is the best way to do anything, but maybe it will help some who're also starting out...

Starting a new project


Assuming that you already do some coding and have git installed and a folder you like to keep projects in, first thing you may want to know is how to get a clean "first commit" project set up.
DragonRuby takes the approach of wanting you to keep its executables and libraries right alongside your code. So when you download DragonRuby from its itch page you'll see that it is just an archived folder - extract this folder, copy it into your projects directory, and rename it to whatever your project will be called - this is your new project!

Excluding DragonRuby from version control

If you are going to use a public version control repository to manage your project, you should not make DragonRuby available for free via your repository. Specifically you must not make the dragonruby-publish executable downloadable.

Here is my .gitignore:

# Files from Dragon Ruby distro
CHANGELOG.txt
CHEATSHEET.md
ctags-emacs
ctags-vim
dragon ruby README.md
dragonruby*exe
open-source-licenses.txt
README-raspberrypi.txt
samples/
tmp/
# Files from running Dragon Ruby
console_history.txt
.dragonruby/
builds/
exceptions/
logs/
# Files for itch.io butler
# TODO: These shouldn't even be here
butler.exe
butler.zip
butler-windows-amd64.zip
c7zip.dll
7z.dll


Probably this is not 100% right - many of the distro files can probably just be deleted rather than git ignored.

One file you will want to commit is VERSION.txt - this stores the build of DragonRuby you have. If you need to recreate your project exactly (given that the binaries are not stored in version control), this file tracks what build you need.


Start coding!

If you run dragonruby it will run the code in the mygame directory, which already contains example code. You can either start modifying this code; or create a new app directory and start coding in app/main.rb 

Learning DragonRuby

Once you start coding you will want some reference to work from. Some resources are:

The documentation at https://dragonruby-docs.readthedocs.io/en/latest

The example projects in the samples directory - there are examples of everything in here. I'd suggest not expecting to copy and paste large chunks though. Instead this is great reference for what's possible.

Search on Youtube and there are many great tutorial videos - https://www.youtube.com/results?search_query=dragonruby

Join the really nice community on discord: http://discord.dragonruby.org 

Ruby documentation - and one word of warning here is that googling for help with Ruby can be very misleading here for two reasons:

  1. DragonRuby is based on Ruby 2.1 which is relatively ancient - you need reference specifically for 2.1 e.g. https://docs.ruby-lang.org/en/2.1.0/
  2. A lot of Ruby help online is for "Ruby on Rails" - a specialised derivative of Ruby that is different enough that helpful tips for Rails will not work for Ruby. You might want to add -rails to google searches to cut out anything for Rails.

Building and publishing

The dragonruby-publish executable will both build your project for all targets (Linux, Mac, Windows, RaspberryPi, HTML5) and publish to Itch for you.

Working around publishing not working

For me, dragonruby-publish failed to publish to Itch. It failed to download the butler tool to upload to itch. I could get the same butler artifact from my web browser and also from curl in the same shell I was running dragonruby-publish in. I worked around this by creating the following release script:

# Fails to download butler, so only package
.\dragonruby-publish.exe --only-package
Compress-Archive -Update .\builds\spacegame-linux-amd64.bin .\builds\spacegame-linux-amd64.zip
Compress-Archive -Update .\builds\spacegame-linux-raspberrypi.bin .\builds\spacegame-linux-raspberrypi.zip
Compress-Archive -Update .\builds\spacegame-windows-amd64.exe .\builds\spacegame-windows-amd64.zip
./butler push .\builds\spacegame-linux-amd64.zip 68ST0X20/space-game:linux
./butler push .\builds\spacegame-linux-raspberrypi.zip 68ST0X20/space-game:raspberrypi
./butler push .\builds\spacegame-windows-amd64.zip 68ST0X20/space-game:windows
./butler push .\builds\spacegame-macos.zip 68ST0X20/space-game:macos

This script needs your current shell set up for butler pushes as per the butler documentation.

Adding a play-in-browser version of your game

DragonRuby and Itch almost make this free for you - to add your build directly to your game page:

  1. Edit your game on itch and set Kind of project to HTML (this is kind of confusing - this setting means you can have HTML5 running directly on the game page as well as your downloadable builds, not instead of).
  2. On the same Edit game page, upload the builds/gamename-html5.zip file for your project, and check the This file will be played in the browser checkbox.

Tips and Gotchas

Why did the Hello World app come back?!

Sometimes when you run dragonruby you will see the example Hello World game instead of your game. There seems to be several cases where if dragonruby encounters a problem it will default to generating the Hello World code in app/main.rb and it will run this in precedence to your game if that's in mygame. Just delete the app directory.

I think I've seen happen when running git commands while dragonruby is running - it maybe got confused by files it was watching on disk changing...

Poor performance when running game during development

dragonruby seems to write to disk a lot, so if your PC is not amazing spec or your project is not on your fastest hard drive, you may see jarring frame loss when testing your latest changes. If you can't help performance (e.g. move your project to an SSD drive) then you can cut some of the extra overhead by passing the --production option when running dragonruby. This will remove some of the development features the program was giving you, but will give performance close to what your built game will have.

Deleting expired objects

A pattern I often use in game code is to keep objects of a particular class (e.g. the player's bullets, the enemies on screen, stars scrolling through the sky) in an array, and each frame to cull any objects that are no longer needed.

e.g. in "Mega Space Game" stars are defined by a struct

Star = Struct.new(:x, :y, :fall_speed, :twinkle)

Stars are spawned by pushing them into the array args.state.stars

args.state.stars << Star.new(rand(1280), rand(720), 1 + rand(4), rand(4))

Each tick, stars fall down the screen:

args.state.stars.each do |star|
  star.y -= star.fall_speed
end

I want some way to remove stars that fall off the bottom of the screen. In modern Ruby there is the very useful delete_if:

# Delete if y < 0 i.e. off bottom of display
args.state.stars.delete_if { |star| star.y < 0 }

Nice, huh? Unfortunately since DragonRuby uses Ruby 2.1 delete_if isn't available. But an alternative is to call map! to set any invalid object to nil, then compact! to squash out any nil elements. My code for updating stars is then:

def update_starfield args
  # Make each star fall
  args.state.stars.each do |star|
    star.y -= star.fall_speed
  end
  args.state.stars.map! do |star|
    star.y > 0 ? star : nil
  end
  args.state.stars.compact!
  # Add new stars 
  if args.state.stars.length < args.state.number_of_stars
    (args.state.number_of_stars - args.state.stars.length).times do
      args.state.stars << Star.new(rand(1280), 720, 1 + rand(4), rand(4))
    end
  end
end

(you might notice - it could be possible to not delete any stars and instead move expired stars back to the top of the display - but consider other entities like enemies and bullets that just need to be deleted when they're done).

Hotloading

One of the fantastic features of DragonRuby is hotloading - if your game is running (via the dragonruby executable) then the moment you hit Save in your text editor, your saved code changes will be live in the running game!

This takes some getting used to - some saved changes will be immediately reflected in the running game. Some will behave weird. Some will not seem to affect the running game at all. If you're used to debugging, the lack of perfect reflection between your running game and your code will make sense. If not, just know that hotloading is amazing for tweaking some details like bullet speed, but as soon as the game doesn't seem to reflect your code you will probably want to restart dragonruby so you get a full reload of your code.

Files

spacegame-html5.zip Play in browser
Jun 18, 2020
spacegame-windows-amd64.exe 11 MB
Version 6 Jun 18, 2020
spacegame-linux-raspberrypi.bin 10 MB
Version 5 Jun 18, 2020
space-game-macos.zip 9 MB
Version 3 Jun 18, 2020
spacegame-linux-amd64.bin 10 MB
Version 6 Jun 18, 2020

Get Mega Space Game

Leave a comment

Log in with itch.io to leave a comment.