Ruby Shoes Tetris

Fri, Nov 7, 2014

I was inspired by a talk from @jasonrclark at this weeks @pdxruby that reminded us that the Shoes project is still alive and well. I had a little free time so I thought I’d make a tiny contribution and take a day to port over one of my simpler javascript games to Shoes.

Shoes was is a cross-platform Ruby desktop GUI framework aimed at beginners wanting to get into programming. For those of us who have been in the Ruby community for a while we might have assumed that Shoes died when _why left the community. However, from the shoesrb.com history…

_“Way way back in the day, there was a guy named _why. He created a project known as Hackety Hack to teach programming to everyone. In order to reach all corners of the earth, _why decided to make Hackety Hack work on Windows, Mac OS X, and Linux. This was a lot of work, and so _why decided to share his toolkit with the world. Thus, Shoes was born. Everybody loved Shoes. Many apps were made, and put into The Shoebox, which no longer exists. But, one day, why left. In his memory, Team Shoes assembled, and carried on making Shoes. They released Shoes 3 in late summer 2010.”

… and they are actively working on Shoes4.

So here’s a version of Tetris you can run with Ruby Shoes:

Installing Shoes4

For the most up to date instructions on how to install Shoes4 you should refer to the official project README. You’ll need:

Running Tetris

Once you have JRuby installed, you can clone the tetris-shoes repository and use JRuby to run the Shoes script:

$ git clone https://github.com/jakesgordon/tetris-shoes
$ cd tetris-shoes
$ jruby tetris.rb

NOTE: on OSX, with the current prerelease version of Shoes4, you might need to add the -J-XstartOnFirstThread option, e.g “jruby -J-XstartOnFirstThread tetris.rb”

Porting to Shoes

Porting the game to Shoes involved turning the engine into Ruby and extracting out the GUI specific parts (rendering and event handling) to use Shoes instead of the browser’s Canvas/DOM.

The majority of the engine is pure Ruby, and beyond the scope of this article - you can checkout the source for more details.

The Shoes specific code starts with a Shoes app that contains our game engine:

Shoes.app :title => 'Tetris', :width => WIDTH, :height => HEIGHT do

  game = Tetris.new

  # ...

end

Then we hook up keyboard event handling:

keypress do |k|
  case k
  when :left   then game.actions << :left
  when :right  then game.actions << :right
  when :down   then game.actions << :drop
  when :up     then game.actions << :rotate
  when :escape then quit
  end
end

… and use the Shoes #animate method to create a game loop:

last = now = Time.now
animate = animate FPS do
  now = Time.now
  game.update(now - last)
  # rendering goes here
end

… rendering for a tetris game is really simple, we need to use the Shoes #fill and #rect methods to create rectangles:

def block(x, y, color)
  fill color
  rect(x*DX, y*DY, DX, DY)
end

… and then use that method to render all of the occupied blocks, including the currently active piece:

game.each_occupied_block do |x, y, color|
  block(x, y, color)
end

game.current.each_occupied_block do |x,y|
  block(x, y, game.current.type[:color])
end

… and finally we need to check if the game has finished:

if game.lost?
  banner "Game Over", :align => 'center', :stroke => black
  animate.stop
else
  subtitle "Score: #{format("%6.6d", game.vscore)}", :stroke => green, :align => 'right'
end

Next up

Shoes is a nice, easy to use platform for building simple desktop applications and that includes simple games as well. It was pretty easy to port an existing game to Ruby and make it fit into the Shoes framework.

I’ll make a pull request to add tetris-shoes as an example in the official shoes4 repository and next time I have some free time I’ll maybe port over some of my other games

Related Links