福澤テクノロジー

おっさんプログラマーが、主に技術的な話をするブログ。

ALCS(仮) の使いどころ

ゲームでは、登場人物がしゃべったり、ナレーションを流すようなシーンがあるが、文字の色やサイズを変えたりメッセージの表示速度を動的に変えたりする演出をよくする。
スクリプトレベルでは、メッセージを全角文字、コマンドを半角文字で表現したり、
HTMLのタグのようにコマンドを埋め込んでおき、コンバータによりコマンド解析を行なう場合が多いんじゃなかろうか。もしくは、スクリプトが実行時に構文解析を行なうとか。

こんな表示をしたいとする。フォントを大きくした所では、メッセージ表示速度も遅くしたい。


霞の目ネペンテス液を入れろと言ったら
入・れ・ろ・ッ!

これを実現させる架空スクリプト:

name(霞の目)
「color(RED)ネペンテス液color(BLACK)を入れろと言ったら
font(BIG);delay(1000)入・れ・ろ・delay(200)ッ!」

この架空スクリプトは、文章を出力する事を主眼としたゲーム専用言語を想定している。
全角文字列は文字出力コマンドであり、半角文字列は機能を実行するコマンドである、と考えればいい。
スクリプト言語としては、汎用性に乏しすぎる。
メッセージ出力に特化しすぎていないで、もっと汎用的な機能を持った言語で、かつメッセージを主体としたゲームでも書きやすい言語がいい。


Rubyのような汎用的なスクリプト言語でそれを実現させるにはどうするか。
せっかくのスクリプト言語なのだから、文字列中のコマンドはその場で直接スクリプトに実行させればいいじゃん! という発想で作ったのがHayat言語のsayCommand機能だ。

霞の目「{赤}ネペンテス液{黒}を入れろと言ったら
      {大}{delay(1000)}入・れ・ろ・{delay(200)}ッ!」

"「" がsayCommand機能開始で、 "」" までがデータの列として扱われ、sayCommand()メソッドに次々と送られていく。
sayCommand()メソッドは、送られてきたデータに従って文字を出力したりサイズ変更や色変更などの機能を実行する。


ALCSは、言語仕様に影響を与えずに、リテラルだけで同様の事を実現できる。

霞の目.say %p[#{赤}ネペンテス液#{黒}を入れろと言ったら
  #{大}#{delay(1000)}入・れ・ろ・#{delay(200)}ッ!]

%pリテラルは、%Wとは異なり #{...} を展開して文字列化したりしないで、Procオブジェクトとして配列の1要素とする。だから受け取った側で実行タイミングをコントロールできる。

これを実働させるスクリプトは、例えばこんな感じになる。

黒 = ""
赤 = ""
青 = ""

小 = ""
中 = ""
大 = ""

$char_wait = 200

def color(x)
  # change font color
  print "[#{x}]"
end

def size(x)
  # change font size
  print "(#{x})"
end

def delay(x)
  $char_wait = x
  print "<#{x}>"
  nil
end

def dispStr(str)
  str.each_char do |c|
    # sleep($char_wait / 1000)
    print c
  end
end

class Person
  def initialize(name)
    @name = name
  end

  def say(alcs)
    print "#{@name}"
    alcs.each do |m|
      case m
      when Proc
        x = m.call
        case x
        when "", "", ""
          size(x)
        when "", "", ""
          color(x)
        else
          # other function
        end
      else
        dispStr m
      end
    end
    print "\n"
  end
end


霞の目 = Person.new("霞の目")

霞の目.say %p[#{赤}ネペンテス液#{黒}を入れろと言ったら
  #{大}#{delay(1000)}入・れ・ろ・#{delay(200)}ッ!]

実行結果:

霞の目「[赤]ネペンテス液[黒]を入れろと言ったら
(大)<1000>入・れ・ろ・<200>ッ!」

文字色やサイズなどを実際に変えるのは大変なのでprintでごまかしているけど、どう動作するのかは十分把握できると思う。

上記スクリプトは、ALCSを実装した魔改造バージョンのmrubyで実際に動きます。

git clone -b alcs git://github.com/FUKUZAWA-Tadashi/mruby.git

%pリテラルではなく、ALCS Here-document を使う場合はこうなる。

霞の目.say <<<EOH
#{赤}ネペンテス液#{黒}を入れろと言ったら
#{大}#{delay(1000)}入・れ・ろ・#{delay(200)}ッ!
EOH

長文のナレーションのような所で使いやすいかと思う。