Ruby+YAMLでゲームブック作成スクリプト(ソース付き)
ゲームブックを作ろうと考えたときに問題になるのが、パラグラフの管理(ランダムに置き換えたりとか)というわけで、
昔、パラグラフ管理ソフトを作ったのですが、最近またゲームブック作りたい熱が出てきているので、
そのソフトのプログラムを見てみると・・・
うーん、やっぱりややこしいなぁ。
というわけで、ゲームブックのソースをYAMLで書いて、Rubyで処理するようにしてみたら・・・。
うわっ、思ったより簡単やった・・・。
これを使うと、ゲームブックの元が以下のようなYAMLファイルで出来てしまいます。
head: ending: エピローグ title: なんやわけわからんけど、ゲームブックです preface: | まえがき paragraph: - label: pg01 number: first text: | 右へは#{label[:pg02]}へ、左へ行は#{label[:pg03]}へ、 真ん中へは#{label[:pg05]}へ。 - label: pg02 text: 何もなかった。#{label[:pg01]}へ。 - label: pg03 text: あれ? なんか「14」とか書いてるよ・・・#{label[:pg04]}へ。 - label: pg04 number: 4 text: ごめんなさい! ゲームオーバー! - label: pg05 number: last text: おめっとさん ending: エンディング postscript: あとがき
コレを変換すると、こうなります。
[アドベンチャーゲームブック] なんやわけわからんけど、ゲームブックです [まえがき] まえがき - 1 - 右へは3へ、左へ行は2へ、 真ん中へは5へ。 - 2 - あれ? なんか「14」とか書いてるよ・・・4へ。 - 3 - 何もなかった。1へ。 - 4 - ごめんなさい! ゲームオーバー! - 5 - おめっとさん [エピローグ] エンディング [あとがき] あとがき
このように変換できます。
簡単なものなので、ランダムかどうかわかりにくいけど、ちゃんとパラグラフが入れ替わっています。
また、パラグラフ番号の固定とかもちゃんとできるようになっています。
スクリプトを↓に載せておきます。
引数は、元のYAMLファイル名だけです。
気軽にバンバン使っちゃってください。
(勿論、無保証で、トラブルとかの責任は負わないので、そこんとこヨロシク!)
#YAML+Rubyでゲームブック作成 #2007.5.20 Cyross Makoto $KCODE = "UTF8" require 'yaml' require 'kconv' $VNUM = "2.00" $VDATE = "2007.5.20" class MakeParagraphManager @@heads = {"title" => "アドベンチャーゲームブック", "preface" => "まえがき", "opening" => "オープニング", "ruling" => "ルール解説", "backstory" => "背景", "ending" => "エンディング", "postscript" => "あとがき"} def initialize(args) raise Exception.new("No args. you should set gamebook script filename!") if args.length == 0 @filename = args.shift @gb_data = YAML.load_file(@filename) @paragraph_size = @gb_data["paragraph"].length @paragraph_hash = Hash.new end def exec process_const if @gb_data["const"] randomize_paragraph output end def process_const chash = @gb_data["const"] ks = chash.keys ks.each{|k| chash[k.intern] = chash[k] } end def randomize_paragraph parray = Array.new(@paragraph_size) @paragraph_size.times{|n| parray[n] = n + 1} pdata = @gb_data["paragraph"] pdata.each_with_index{|p, i| if p["number"] pn = p["number"] pn, p["number"] = 1, 1 if pn == "first" pn, p["number"] = @paragraph_size, @paragraph_size if pn == "last" raise Exception.new("No args. you should set gamebook script filename!") if (pn < 1 || pn > @paragraph_size) parray[i] = nil end } parray.compact! pdata.each{|p| next if p["number"] v = rand(parray.size) p["number"] = parray[v] parray.delete_at(v) } pdata.each{|p| @paragraph_hash[p["label"].intern] = p["number"] } unless parray.empty? @paragraph_size.times{|n| pn = n + 1 ar = pdata.find_all{|p| p["number"] == pn } next unless ar raise Exception.new("Paragraph number is overlaped! : #{pn} ") if (ar.size > 2) } end @gb_data["paragraph"].sort!{|a, b| a["number"] <=> b["number"] } end def output label = @paragraph_hash const = @gb_data["const"] head = @gb_data["head"] File.open(@filename+"gb.txt", "w"){|f| f.print format("title")+"\n" if @gb_data["title"] f.print format("preface")+"\n" if @gb_data["preface"] f.print format("opening")+"\n" if @gb_data["opening"] f.print format("ruling")+"\n" if @gb_data["ruling"] f.print format("backstory")+"\n" if @gb_data["backstory"] @gb_data["paragraph"].each{|p| f.print "- "+p["number"].to_s+" -\n\n" txt = p["text"].to_s.toutf8 f.print eval("\""+txt+"\"")+"\n" f.print "\n" unless txt =~ /\n$/ } f.print format("ending")+"\n" if @gb_data["ending"] f.print format("postscript")+"\n" if @gb_data["postscript"] } end def format(name) str = nil str = @gb_data["head"][name] if @gb_data["head"] str ||= @@heads[name] return ("["+ str + "]" + "\n\n" + @gb_data[name]).toutf8 end private :randomize_paragraph, :output, :format end m = MakeParagraphManager.new(ARGV) m.exec
解説とかは、別の機会に。