Archive for 1月, 2013

命令を組み合わせる

さてさて今度は、移動と、拡縮と、回転と、半透明化をデーカーに同時にさせることを考えてみよう。

まーた新しい命令が出てくるの?

と思った人はちょっと早合点。
今回新しい命令は1つも出てこない。
なぜなら既に紹介したMove、Zoom、Rotate、Opaque命令を使えば実現可能なことだからだ。

答えから示そう。
次のように書けばいい。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Move(to="画像", time=1000, x=200, y=200);
  Zoom(to="画像", time=1000, sx=200%, sy=200%);
  Rotate(to="画像", time=1000, angle=45);
  Opaque(to="画像", time=1000, alpha=50%);
}

ちょ、ちょ、ちょ、ちょっと待って!
重複した命令は中断されるって前回言ったじゃん!
………と思うかもしれない。

だがこれでいいのだ。
確かに重複した命令は中断されるのだが、それはあくまで”同じ種類の”命令が重複した場合の話だ。
実は……… “異なる種類の”命令はデーカーに同時に与えることができるのである。

論より証拠。
とりあえず実行してみよう。

YouTube Preview Image

デーカーに異なる種類の命令を同時に与えると、
デーカーはそれぞれの命令を同時に遂行する。
Move命令とZoom命令を同時に与えると「移動しながら拡縮する」
Rotate命令とOpaque命令を同時に与えると「回転しながら透明度を変える」
といった具合だ。

今回は4つの命令を同時に与えているので、
移動と、拡縮と、回転と、半透明化が同時に行われたというわけだ。
これは言い換えれば…

命令は組み合わせることができる

ということである。
時間をずらして命令の組み合わせることも可能だ。
さらにwait文と組み合わせて次のようなスクリプトを書いたらどうなるか、想像してみよう。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Move(to="画像", time=1000, x=200, y=200);
  wait 500;
  Zoom(to="画像", time=1000, sx=200%, sy=200%);
  wait 500;
  Rotate(to="画像", time=1000, angle=45);
  wait 500;
  Opaque(to="画像", time=1000, alpha=50%);
}

こんな奇妙な動きになる。

YouTube Preview Image

Move、Zoom、Rotate、Opaque命令はそれぞれ単体ではシンプルな動きしか表現できないが
組み合わせることで表現の幅が劇的に広がる。
単純な機能の『組み合わせ』で、複雑で多様な表現を実現するというこの考え方は、
Foooの重要な基本概念である。


デーカーを段階的に動かす

デーカーを動かすには、デーカーに命令すればよいことはわかった。
ではデーカーを右に移動させて、右への移動が終わったら下に移動させるといったように、
デーカーを段階的に動かすにはどうすればいいだろうか。

命令文は上から順番に実行されるわけだから…
右に移動させるMove命令を書いた後に、
下に移動するMove命令を書けばよさそうな気がする。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Move(to="画像", time=1000, x=200, y=50);
  Move(to="画像", time=1000, x=200, y=200);
}

これでデーカーが1秒かけて右に移動し、
さらに1秒かけて下に移動するようになりそうだ。
では実行してみよう。

Fooo_SerialMove_Exec1

デーカーは1秒かけて斜めに移動して止まった。
………Move命令を追加する前と変わらない動きだ。

バグか!?

いや、これはバグではない。
Foooの仕組み上必然的に起こる現象である。

Move命令がデーカーに移動しろと指示する命令であると説明したことを思い出して欲しい。
Move命令は『デーカーを移動する』命令ではなく、『デーカーに移動を指示する』命令なのである。
この違いは非常に重要だ。

このことは対象を指定するパラメータ名がtoという名前であることにも現れている。
デーカーの名前を指定するのだからパラメータ名はnameでもよさそうなものだ。

だが敢えてパラメータ名をto…「~へ」という名前にしているのは、
このパラメータが『命令の発行先』を意味するパラメータだからである。
そう、つまり

文字通り「~へ」なのだ。

(最もよく使うパラメータなので、できるだけ短い名前にしたかった…という理由もある)

つまり先のスクリプトは右に移動しろという命令を発行した後すぐに、
斜め下に移動しろという命令を発行しているということになる。
すなわち移動命令を重複して発行してしまっているわけだ。

デーカーは命令を重複して受け取ると、先に受け取った命令を中断して新しい命令に従う。
よって最初のMove命令は無視され、
後の命令だけが実行されて斜めに移動してしまうというわけである。

ではデーカーを段階的に動かすにはどうすればよいのだろうか。
答えは簡単だ。

待てばいい。

命令が重複してしまうのが問題なのだから、
最初のMove命令の動作が終わるのを待ってから
次のMove命令を発行すればよいのだ。

wait文

デーカーの動作を待つにはwait文を使用する。
wait文は指定時間だけ動作を待つことを意味する文だ。
命令文とは表記がやや異なる。
使い方は非常に簡単。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Move(to="画像", time=1000, x=200, y=50);
  wait 1000;
  Move(to="画像", time=1000, x=200, y=200);
}

これで最初のMove命令を発行して1秒待ってから、次のMove命令を発行するという意味になる。
実行してみよう。

Fooo_SerialMove_Exec2

期待通りの動きになった!

このようにwait文を使ってデーカーに命令を発行するタイミングをはかることで
デーカーにより複雑な動きをさせることが可能になるのである。


デーカーを拡縮・回転・透明化する

Move命令のほかにも、デーカーに指示できる命令はたくさんある。
他にどんなものがあるのか、順に見ていこう。

Zoom命令

Zoom命令はデーカーに「拡縮しろ」と指示する命令である。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Zoom(to="画像", time=1000, sx=200%, sy=200%);
}

to、timeパラメータはMove命令のソレと一緒だ。
sx, syパラメータにはそれぞれ横方向の倍率、縦方向の倍率を%で指定する。
(ちなみにsx, syという名前は、scale x, scale yの略)
実行してみよう。

Fooo_FormAction_Zoom

イメージデーカーが1秒かけて2倍に大きくなった。

Rotate命令

Rotate命令はデーカーに「回転しろ」と指示する命令である。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Rotate(to="画像", time=1000, angle=45);
}

to、timeパラメータはやはりMove命令のソレと一緒だ。
angleパラメータには回転角度を指定する。
実行してみよう。

Fooo_FormAction_Rotate

イメージデーカーが1秒かけて45度回転した。

Opaque命令

Opaque命令はデーカーに「不透明度を変えろ」と指示する命令である。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Opaque(to="画像", time=1000, alpha=50%);
}

to、timeパラメータについてはもう言わなくてもわかるだろう。
alphaパラメータには不透明度を%で指定する。
100%で完全に不透明、0%で完全に透明になる。
実行してみよう。

Fooo_FormAction_Opaque

イメージデーカーが1秒かけて薄く透明になった。

このように命令を使い分けることで、デーカーに様々な動作をさせることができる。


デーカーを移動する

画面に何かを表示するのに、いちいちデーカーを作らなくちゃいけなかったり
名前をつけなくちゃいけなかったり、なんだかちょっと面倒くさいな…
と思ったかもしれない。

面倒なのは、まぁ確かなのだが

こういう構造にしておくと、複雑な演出を簡潔に記述できるのである。
なぜ簡潔になるのか。
それはデーカーの動作をデーカー自身に任せることができるからだ。

──────現実で考えてみよう。
目の前に大きな壁がある。
壁の前にいるのは自分ひとりだけ。
壁には装飾が1つ貼り付けてある。

その装飾を動かそうとする場合、どうするだろうか。
装飾を手にとって、別の場所まで持っていけばいいだろう。
簡単な話だ。

しかし装飾が何個もあって、それぞれ同時に動かさないといけないとなったらどうだろう…
いくら手があっても足りない!
途方に暮れ…
そしてこう思うかもしれない。

「装飾が勝手に動いてくれればいいのに…」

装飾に車輪をつけ、機械仕掛けにして、目的の位置まで勝手に動くようにすればいい。
ちょっと大げさだが…
デーカーとは、まさにそんな大げさなことを実現してしまったものなのである。

これまでデーカーを部品だとか装飾だとか呼んで来たが、
実のところデーカーは単なる装飾ではない。
より高度な舞台装置… 言うなれば…

デーカーはロボットのようなものである。

デーカーには様々な命令をすることができる。
命令を受けたデーカーは、命令を自律的に遂行してくれる。
手取り足取り動かす必要はないのだ。

Move命令

ではデーカーにどんな命令をすることができるのか、具体的に見ていこう。
Move命令はデーカーに「移動しろ」と指示する命令である。


method Main()
{
  CreateImage(name="画像", image="画像.png", x=50, y=50);
  Enter(to="画像");
  Move(to="画像", time=1000, x=200, y=200);
}

toパラメータには対象となるデーカーの名前を指定する。
timeパラメータには動作の所要時間をミリ秒単位で指定する。
x, yパラメータには移動後の位置を指定する。
さっそく実行してみよう。

Fooo_Move_Exec

イメージデーカーが1秒かけて斜めに移動した。
このようにしてデーカーに対して移動命令を発行することで
デーカーの移動を簡単に実現できるのである。


『デーカー』

Foooは画面に表示する全てのものを部品として扱う。
部品には文章部品、画像部品、コマ部品、吹きだし部品などがある。

これはここまでに説明してきたことだが、
「ナニナニ部品」などといちいち呼ぶのはイマイチさまにならない。
そこでFoooではこれらの部品のことを…

『デーカー』と呼ぶ。

英語で書くと『Decor』。
“装飾”という意味だ。
画面を装飾するものといったニアンスである。

発音は正確には「デクォァール」といったカンジ。
一般的には「デカール」と日本語表記されるので、そちらの方が馴染みがある人も多いかもしれない。
「デーカー」と言う読み方をするのはFooo特有のものである。
なんでそんな読み方をするのかというと…

Decorをデーカーと読み間違えたからだ。

途中で間違いに気づいたのだけれど、
その後もそのままそう呼び続けて事実上名詞化してしまった。
とはいえ特有の概念の名前に一般的な単語を使うと、誤解を招きやすいという現象もあるので
怪我の功名というか…
逆にコレでいいんじゃないかと思っている。

後付だけどネ!

画像部品は、イメージデーカー(Image Decor)
文章部品は、テキストデーカー(Text Decor)
コマ部品は、フレームデーカー(Frame Decor)
吹きだし部品は、バルーンデーカー(Balloon Decor)

といった具合だ。
名詞化することで、ソレが何を指しているのかよりハッキリした気がしないだろうか。


コマと吹きだしを表示する

漫画独特の表現といえばコマと吹きだし。
Foooエンジンはもともとは『動く漫画』を作るためのゲームエンジンである。
そのため、漫画独特の表現を実現する専用の部品がある。

Decor_Frame CreateFrame命令

コマ部品を作成するのがCreateFrame命令だ。
Foooでは漫画のコマのことを『フレーム』と呼ぶ。
これは元々のシステムの名称に由来している。


method Main()
{
  CreateFrame(name="コマ", image="画像.png", x=50, y=50);
  Enter(to="コマ");
}

CreateFrame命令はCreateImage命令に似ているが、
画像に枠をつける機能がある。

x, yパラメータは部品の位置を指定するパラメータだ。
画像が左上にあると枠がわかりにくいのでx, yパラメータで位置を調整している。
x, yパラメータはほぼ全てのCreate系命令で共通して使えるパラメータでもある。

Fooo_DrawComic_Frame

ぼんやりとした枠がついているのがわかる。

Fooo_DrawComic_FrameZoom

Decor_Balloon CreateBalloon命令

吹きだし部品を作成するのがCreateBalloon命令だ。


method Main()
{
  CreateBalloon(name="吹きだし", text="hello, world", tail=-45, x=50, y=50);
  Enter(to="吹きだし");
}

CreateBalloon命令はCreateText命令に似ているが、
文章に吹きだし枠をつける機能がある。
tailパラメータには尾のつく角度を指定する。

Fooo_DrawComic_Balloon

吹きだしの素材は必要なく、形状は自動生成される。

Fooo_DrawComic_BalloonZoom

これらの部品を使うことで漫画のような画作りを簡単に行うことができる。
Foooエンジンの目指す『動く漫画』の姿がぼんやりと見えてきただろうか。


画像を表示する

基礎的な文法がわかったところで、今度は画像を表示させてみよう。
まず適当な画像ファイルをFooo.exeと同じ場所に用意しておく。

画像.png
Fooo_DrawImage_Image

前回述べた通り、Foooでは画面に表示する全てのものを部品として扱う。
Foooが扱える部品には前回使った文章部品のほかにも様々な種類がある。

Decor_Image CrateImage命令

画像を画面に表示させるには『画像部品』を使う。
画像部品を作成する命令はCrateImage命令だ。


method Main()
{
  CreateImage(name="画像", image="画像.png");
  Enter(to="画像");
}

実行してみよう。

Fooo_DrawImage_Exec

このようにFoooでは画面上に様々な部品を”作る”ことで、画作りをしていく。


スクリプトを細かく見てみよう

では”hello’ world”と表示するスクリプトがどういう内容なのか見ていこう。


method Main()
{
  CreateText(name="Text", text="hello, world");
  Enter(to="Text");
}

プログラミング言語に触れたことのある方は、
パッと見ただけで何をしているのかおおかた予想がつくだろう。
それもそのはず。

Foooスクリプトの文法は代表的なプログラミング言語である
C++言語をベースにしているのだ。

アドベンチャーゲーム用のエンジンなのに
C++に似てるってドユコト!?

っていうツッコミは後でお願いしますwww

method Main()

最初のmethod Main()は、スクリプトを実行すると最初に実行される部分を表している。
とりあえずは必ず書く必要がある”おまじない”のようなものだと思ってもらっていい。
そしてその後の { から } の間に、どんな処理を行うのか記述する。


method Main()
{
  // ここに処理を書く
}

処理内容には『命令文』を記述する。
{ } の中に書かれているCreateTextやEnterが命令文だ。
命令は上から書いた順番で実行される。

命令文の書式

命令文は次の書式で記述する。


  命令名();

命令文にはその命令の詳細をパラメータとして記述することができる。
パラメータの記法はC++とは異なり、名前付指定形式である。
これはwebページの記述言語であるHTMLでおなじみかもしれない。


  命令名(パラメータ名=パラメータ値);

パラメータはカンマ区切りで複数指定できる。


  命令名(パラメータ名=パラメータ値, パラメータ名=パラメータ値, ...);

Decor_Text CreateText命令

最初に書かれている命令文はCreateTextだ。


  CreateText(name="Text", text="hello, world");

CreateTextの直訳は「文章作成」。
そう、CreateTextはFoooエンジンに対して「文章を作れ」と指示する命令である。

なるほど…と思ったかもだが、しかしここでちょっと立ち止まって考えて見て欲しい。
よくよく考えると「文章を作れ」とは、なんとも違和感のある言葉であるではないか。
「文章を表示しろ」ではないのか。
実はこれが重要。

Foooエンジンは画面に表示されるすべてのものを
『部品』として扱う。

画面に何かを表示したい時は、まずFoooエンジンに部品を作らせる必要がある。
そう、CreateText命令は正確には「文章部品を作れ」と指示する命令なのである。

nameパラメータは新しく作る部品の名前を指定する。
名前は後で部品を操作するために必要なものだ。
ここでは部品に”Text”という名前をつけている。

textパラメータは文章内容である。

Enter命令

2つめの命令文は、Enterだ。


  Enter(to="Text");

Enterを直訳すれば「登場」…
EnterはFoooエンジンに「部品を表示状態にしろ」と指示する命令である。
CrateTextは部品を作るだけなので、Enter文で部品を表示状態にする必要がある。

「表示しろ」ではなく「表示状態にしろ」なことに注意して欲しい。
部品は表示するかどうかの状態を持ち、
表示状態である限り画面に表示され続けるのである。

toパラメータには命令の対象となる部品の名前を指定する。
対象は”Text”だ。

このようにして”hello world”と表示しているわけだ。
説明が随分と細かくなったけれど…
こんなシンプルなスクリプトを通してでも、Foooの特徴が少しばかり垣間見えて来たのではなかろうか。


Foooを実行してみる

とにもかくにもFoooエンジンを実行してみよう。
実行ファイルは”Fooo.exe”だ。

Fooo_0005_exe

ポチっとな♪

Fooo_0005_Exec

………何やらファイルの選択を求められる。
ここでは『Foooスクリプト』 ファイルを指定する。

Foooエンジンに何かをさせるにはFoooスクリプトを記述する必要がある。
Foooスクリプトファイルはただのテキストファイルだ。
適当にテキストファイルを作成して、前回書いた”hello, world”を書き込んでみよう。
ファイル名はなんでもいいのでとりあえず”Test.txt”にしておく。


// Test.txt
method Main()
{
   CreateText(name="Text", text="hello, world");
   Enter(to="Text");
}

さっきファイルの選択を求められたところで、この”Test.txt”を指定してやると…
こうなる。

Fooo_0005_Hello

ちょっと小さいので拡大。

Fooo_0005_HelloZoom

“hello world”と表示された!
,が表示されていないのだけれど、これにはちょっと理由がある。
それについては追々。

というわけで…

新世界へようこそ!


hello, world

“hello, world”とは、新しくプログラミング言語を学ぶ際に
おきまりのように最初に必ず出てくるサンプルプログラムのことである。
画面に”hello, world”と表示するだけのシンプルなプログラムだ。
「世界一有名なプログラム」とも言われる。
もともとはC言語の生みの親の一人であるカーニハン氏が使ったのが初出とされている。

この”hello, world”という言葉、自分はすごく好きだ。

直訳すれば 「こんにちは世界」 だが、
この言葉には 「新世界へようこそ」 といった意味がこめられているように思う。
コンピュータに初めて電源を入れると真っ暗な画面に最初にこの言葉が浮かび上がる…
そんなイメージでこの言葉を思いついたのではなかろうか。

──────はるか未来。
ジャンク山から朽ち果てたおんぼろアンドロイドを見つけ修理を始める。
そのアンドロイドが動いていたであろう時代のメモリーは既に失われていたが、
やっとのことで起動に成功する。
アンドロイドが再び初めて見る視界。
そのインナーモニターにはこう表示される。

“hello, world”

そんなシーンを思い浮かべるだけで胸が熱くならないだろうか?
ならない?

ううう、書きながら涙が…

前置きが長くなりすぎた…
というわけで、Foooスクリプトで”hello, world”を記述してみよう。


method Main()
{
   CreateText(name="Text", text="hello, world");
   Enter(to="Text");
}

簡単デスネ!

………
………………

そうでもない?