Get the latest news, exclusives, sport, celebrities, showbiz, politics, business and lifestyle from The VeryTime,Stay informed and read the latest news today from The VeryTime, the definitive source.

Embedding Images in Gosu Programs

42
Embedding Images in Gosu Programs

Games can rarely run from a single file. Even if all of the game's code fits in a single file, there's bound to be image and sound data that accompanies it. Traditionally, to distribute a game, you zip the code and data up in a zip archive and distribute this file. However, sending a zip file isn't very transparent, and you often need a file hosting service to host the zip file. You can't, for example, post the game on a forum in plain text, or on a pastebin.

The method outlined below allows you to embed your data files right into your Ruby script.

This article is part of a series. Read more articles about Rapid Game Prototyping in Ruby

How It Works

At the end of every Ruby file, you're able to provide data that isn't part of the script. Anything after the line reading __END__ is treated as data, and isn't parsed by the Ruby interpreter. This data can be read like a file by using the DATA variable. However, it's not quite as easy as dumping the file's data into this section.

First, you shouldn't put binary data in a file people open with text editors.

This generally makes a mess of people's screens, and the data will get mangled when the text editor tries to interpret line endings in the binary section. So, to start off, we need to encode this binary data in Base64. This is so called "ascii armor" and will protect this binary data from text editors.

Second, in order to store more than one file in this section, we need a way of referring to different parts of the data section. We're going to use YAML here, as it comes with Ruby and it's simple to use.

At the beginning of any program that uses this data, there's a line that reads $data = YAML.parse(DATA.read). This will parse the YAML stored in the DATA section, ready to be used from the $data global variable. Global variables are usually frowned upon, but since this is really designed for small, self-sufficient scripts, there's no reason not to use one here.

Finally, a small method is needed to turn these data sections into real files. The with_data method will decode the Base64-encoded data and write it to a temporary file, then pass the filename of that temporary file to a given block.

It's not the most efficient way of doing things, but it will work with any code that expects a file.

This article is part of a series. Read more articles about Rapid Game Prototyping in Ruby

The following Rakefile is provided to automatically compile all images from a directory into a Base64-encoded YAML file ready for use. In addition, it can also insert it directly into your script, replacing everything after the __END__ line with this Yaml data.

There are two Rake tasks you can use.
  • rake compile[directory] - This will take all the PNG files in a directory and create a Yaml file from them. It'll simply print this Yaml file out on the terminal. You can pipe it to a file, or copy and paste it into your script.


  • rake insert[directory,script.rb] - This Rake task is a bit more useful. It will compile the same Yaml file as above, but instead of printing it to the terminal, it will insert it into the script you passed in the parameters. It will read the script in, replace everything after the __END__ line with the Yaml file.

require 'base64'require 'yaml'require 'tempfile'require 'fileutils'def compile_directory(dir) store = {} Dir["#{dir}/*.png"].each do|png|File.open(png, "rb") do|f| b64 = Base64.encode64(f.read) store[File.basename(png)] = b64end end storeendtask :compile, [:directory] do |t, args| puts compile_directory(args.directory).to_yamlendtask :insert, [:directory, :file] do|t, args| store = compile_directory(args.directory) Tempfile.open('Rakefile') do|tmp|File.open(args.file) do|file| begin line = file.gets.chomp tmp.puts(line) end until line == "__END__"tmp.puts(store.to_yaml)end FileUtils.mv( tmp.path, args.file ) endend
This article is part of a series. Read more articles about Rapid Game Prototyping in Ruby

Once you have the files embedded in your script, it's time to use them. The example below uses them with Gosu::Image.new, which expects filenames. How do you get a filename from a file embedded in the DATA section? The with_data method will write the data out to a temporary file and pass it to a given block.

If you need to access this data manually, you can query the $data object and run Base64.decode64 with the data it returns.

This can be useful if the method can load directly from a string, or if the data is actually text data.

#!/usr/bin/env rubyrequire 'rubygems'require 'gosu'require 'yaml'require 'tempfile'require 'base64'$data = YAML.parse(DATA.read)def with_data(key,&block) Tempfile.open(File.basename(__FILE__)) do |tmp|tmp.binmodetmp.write( Base64.decode64($data[key].value) )tmp.close block.call(tmp.path) endendclass MyWindow
This article is part of a series. Read more articles about Rapid Game Prototyping in Ruby

Source...
Subscribe to our newsletter
Sign up here to get the latest news, updates and special offers delivered directly to your inbox.
You can unsubscribe at any time

Leave A Reply

Your email address will not be published.