AIRNovel 開発者向け情報

窓の杜さんでAIRNovel連載記事
初めての方はこちらから読むのも良さそうです。

はじめに

  • ノベルゲーム作りは初めてで、何から手を付ければいいやら……
    まずはこの頁を上から順番に、ゆっくり読んで、実際に動かしてみて下さい。
    「こうしたらどうなるかな?」→「できた!」と楽しんで頂ければ幸いです。
  • AIRNovelの概要についてはこちらをご覧下さい。
  • 瀬戸愛羅さんの解説サイト【AIRNovelをさわろう!】もご参照下さい。

まずはお試し

サンプルを動かす準備  こちらのページで「INSTALL NOW」をクリックすると、自動的に「Adobe AIR ランタイム」と「サンプルゲーム 桜の樹の下には」がインストールされます。

 インストールしてみて、どんな触り心地か触れてみて下さい。
 Adobe AIRランタイムはこちらでも配布されています。
 AIRNovelゲームやサンプルアプリの実行可能なOS・ハードウェア環境は、Adobe AIRの必要システム構成に準拠します。
短編「桜の樹の下には」 例えば自作の小説本を出版するとします。
その際、パルプの生成方法、紙の刷り方、印刷技術、装丁デザインの勉強等までする必要があるでしょうか?
本来小説を書くというのは、紙とペンを用意し、書き始めることだけのはずです。
良い小説を書くために「小説の書き方本」を読みあさり、知らない事を勉強する方向へ労力を注ぎ、胃を壊すぐらいコーヒーを飲みたいのではないでしょうか?
同じように、まずはあなたの愛機のテキストエディタで原作を書くことに専念して下さい。


●ではどうやって本にするのか?
今ここに一冊の本があります。
梶井基次郎 原作の短編ノベルゲーム「桜の樹の下には」です。
実はこれは鉛筆で書かれています。
まずはこの本を消しゴム掛けして、元の文章をあなたの原作に書き換えてしまいましょう。
本を作るところから、始める必要はありません。
これはもちろんたとえ話ですが──同じようにして、あなたの本が完成するのです。

作品を書いているうちに装丁を考えたり、紙質や手触りに凝ったりしたくなるかも知れません。
その時は初級・中級・上級へと読み進めていって下さい。
今度は小説を書く楽しみではなく、本を作る楽しみが待っています。


●消しゴムの掛け方 〜あるいはスクリプトファイルの書き換え方〜
まずは文字コードUTF-8を開けるテキストエディタを用意して下さい。
改行コードはLF固定で。
「桜の樹の下には」を愛機にインストールし、インストール先ディレクトリをご覧下さい。
●Windows:Program Files¥UnderCherry 下
 (デスクトップのUnderCherryショートカット右クリック→[ファイルの場所を開く]でも可。最近はProgram Files(x86)かも)
●MacOSX:アプリケーションフォルダ内、UnderCherry.appの「パッケージの内容を表示」→Contents/Resources/とディレクトリを下った所
●Linux:/opt/UnderCherry/share/

以下のディレクトリ構造が確認できましたか?



scenarioディレクトリ内にあるss_000.anはスクリプトファイルといいます。 これをテキストエディタで開いてみて下さい。
以下のような内容です。(タグの色分けはされていないと思いますが)

そのまま「桜の樹の下には」を起動し、「最初から」を押すと
物語の冒頭が以下のように表示されます。

これを変更してみましょう。
ss_000.anの文章末尾「!」を「?」に変更して下さい。

「桜の樹の下には」を終了し、再度起動して同じ箇所を見ると、
以下のようになっています。

このように、公開されているスクリプトを自由に書き換えて
自分だけのノベルゲームが作れるのです。

「桜の樹の下には」のスクリプトを参考にし、改変し、AIRNovelの理解に役立てて下さい。

 完成したあなたの作品。スクリプトが見られて困るなら、スクリプトや画像を暗号化して見れなくする機能もあります)

※この改変は「桜の樹の下には」をネットで自動更新すると上書き更新されてしまいます。
これは“自分のプロジェクト”を作る事で回避する事が出来ます。
→to be continued ...

自分のプロジェクトを作ってみよう

ANBooksのインストール  開発環境やサンプルを実行するにあたり、便利なアプリを無料公開しています。
 ANBooks というアプリです。ネイティブ版でWindows版・Mac版があります。
 以下のリンクから【ANBooks.(exeかdmg)】をダウンロードし、インストールして下さい。

 起動すると、以下のような画面が表示されると思います。
(画面はMac版。Windows版もほぼ同じイメージなので省略します)
 (ファイル名の数値はバージョンで、大きい物が新しい版です。このページが公開されて以降もどんどん更新されると思われ、アプリ起動時に自動更新の確認がありますので、OKを押して下さい)

 また実行には前述の「Adobe AIR ランタイム」が必要ですが、サンプルゲームが実行出来ていればランタイムは準備済みです。
新プロジェクトを作る  AIRNovel の新しいプロジェクトを作ってみましょう。
 新たな作品や実験アプリ、プラグインなど、全てはここから始まります。
 わずかな操作で簡単に雛形を生成出来ます。

 左上の【メニュー】を押し、【新規作成】をクリックします。

 プロジェクト名を入力するダイアログが現われます。
 まずはシンプルなプロジェクトを作成しましょう。
 適当な名前を入力し、【シンプルなプロジェクトを作成】をクリックします。

 aaプロジェクトが新規作成されました。


 クリックすると作品詳細画面へ移り、作品の詳細が表示されます。

 【最初から読む】をクリックすると、ゲームが始まります。
(正方形のウインドウです。もう一つはメッセージや警告などのメッセージ表示です)
 非常にシンプルですが、れっきとした AIRNovel エンジンで動いているゲームです。
 クリックすると次のページに進みます。
 いつでもコントロール(MacではCommand)キーとEndキーを同時押しで、詳細画面に戻ります。

 このように簡単に新プロジェクトを作ることが出来ます。
新プロジェクトの中身 「桜の樹の下には」ほど本格的で複雑なものでなくても、前項で作ったプロジェクトのように小さな規模でも AIRNovel システムは動作します。
 シンプルな例を見る事で本質の理解が進むので、小さくてもしっかり動いている例を見てみましょう。

 ここでは新プロジェクトの中身を覗いてみましょう。
 詳細画面の上部、【aaプロジェクト】をクリックします(右横に「○に三」アイコンがある)
 Windowsではエクスプローラー、MacならFinderが開きます。

 フォルダが開きます。(画面はMac)
 ここではプロジェクト名と同じ「aa」フォルダになり、これが新たに作ったプロジェクトそのもの全てです。


 以下はディレクトリ構造の詳細解説です。
 ポイントとして、以下の5点があります。それぞれ呼び名があります。
  1.config.anprj      …… プロジェクトファイル
  2.icon フォルダ、icon.jpg …… アイコン素材(icon.jpgは ANBooks に表示されます)
  3.mat フォルダ      …… 素材フォルダ(数や名前は自由に変更可能)
  3-1.mat/main.an      …… スクリプトファイル(これも自由に変更可能)
  3-2.mat/ 下のその他     …… 素材ファイル(絵や音声など)
その他 build.xml、prj-app.xml、SDK フォルダなどありますが、ANBooksが使用し、みなさんは基本的に触りません。説明は割愛します

 どんな AIRNovel ゲームでも、必ずこれらの要素で構成されています。
(絵などを表示しない場合、素材ファイルは必ずしも必要ではありません)

 一つずつ見ていきましょう。
*.anprjファイルの書式  config.anprj の中を見てみましょう。
 これはテキストエディタで開く事が来出るXMLファイルです。
 あなたのゲームにおける AIRNovel への設定は、ここに記述します。
(XMLの仕様上、値は必ず「"」クオーテーションマークで囲って下さい)

 以下に詳細を記述しますが、適度に読み飛ばして下さい。ここで全てを理解する必要はないです。設定はここに書くのだな〜ぐらいで。

config.anprj(UTF-8, LFで開く・保存)
<?xml version="1.0" encoding="UTF-8" ?>
<config>
	<first_script fn="main"/>
	<save_ns name="com.fc2.blog38.famibee.anbooks_made.aa" localpath="/"/>

	<search>
		<path dir="mat" />
	</search>
	<coder len="0x360"/>
	<window width="300" height="300"/>
	<anbook title="aaプロジェクト"
			creator="著作者は未指定です"
			cre_url="https://twitter.com/#!/ugainovel"
			publisher="出版者は未指定です"
			pub_url="http://famibee.blog38.fc2.com/"
			detail="anbooks自動生成のプロジェクトです"/>
</config>
ゲームという「一つのプロジェクト」の設定は全てここに書くのですが、
ANBooksというツールを使う以上(よほど高度な設定をしない限り)このファイルを直接触る事はありません。

例えば作品詳細画面の右上、【編集】をクリックすると……


そのまま編集出来るようになります。
ここに値を記入すると、ANBooksが config.anprj やその他ファイルをいい感じに書き換えます。


参考のために以下にそれぞれの意味を記しますが、流し読みで結構です。
【こんな設定が有る】んだな、【設定はこの config.anprj ファイル】だな、ぐらいを知っていれば。

●first_script要素
  必須です。必ず一つ指定します。
  fn属性 …… 最初に起動するスクリプトファイル

●save_ns要素
  必須です。必ず一つ指定します。
  name属性 …… 扱うセーブデータを一意に識別するキーワード文字列。
          自由な文字列で結構ですが、別のゲーム同士が被らないよう配慮して下さい。
          これさえ変更しなければ、どれだけスクリプトを改編しても違うプロジェクトでも
          同じデータを扱います。配布URLを含める事を推奨。
          (上記は逆順ドメイン+ランダムな文字列)
   localpath属性 …… (これの第二引数。とりあえず記述しておいてOK)

●search要素
  必須です。必ず一つ指定します。複数のpath要素を囲む事が出来ます。
  AIRNovel はここに指定されたフォルダに対し、素材やスクリプトなどを探しに行きます。
  新プロジェクトでは mat フォルダ一つですが、数や名前を自由に変更可能です。英数字を推奨します。
  ここに書かれていないフォルダはプロジェクトに含まず無視します。

  ●path要素
    必須です。必ず一つ以上指定して下さい。
    サーチ対象のパスを指定。これにより「mat/main.an」でなく「main.an」という風にディレクトリ指定を省く事が出来る機能です。
    この機能があるため、別のディレクトリに同じファイル名のファイルの存在は許されません。
    dir属性 …… ディレクトリを指定

  ●pathfile要素
    Flashとしてブラウザ実行する際に参照するパスファイルを指定します。
    fn属性 …… パスファイル(.txt)を指定。暗号化(.txt_)も可能。省略時は「path.txt」
  ※新プロジェクトには不要なため含まれていません。

●coder要素
  ファイルをプレイヤーに見せたくない暗号化で、スクリプトは丸ごと暗号化します。(暗号化ファイルは、拡張子の最後が「_」(半角アンダーライン)になります)
  しかし画像や音声ファイルは量が多い&ファイルサイズが大きいため前の方数バイトだけ暗号化する方針です。(ファイルの前のほうには重要な情報が入っていて、それで致命的に暗号化出来ますので)。その「前からなんバイト」を指定できます。
    len属性 …… 画像や音声ファイルを前からなんバイト暗号化するのか指定
     先頭からの復号化処理対象バイト長。省略時は0、全て復号化。

●window要素
  アプリケーションウインドウについて指定します。
  指定できる属性は AIRNovel スクリプトの[window]タグと同等です。
  省略した場合は1024x768 dotサイズ、[window]タグと同様になります。

●anbook要素
  主に ANBooks 詳細画面に表示されている情報です。
  title属性 …… 作品タイトルを指定します。
  creator属性 …… 著作者を指定します。同人ならペンネーム。
  cre_url属性 …… 著作者URLを指定します。ツイッターやメール、サイトなど。無ければ省略します。
  publisher属性 …… 出版社を指定します。同人ならサークル名。
  pub_url属性 …… 出版社URLを指定します。無ければ省略します。
  detail属性 …… 内容紹介。端的に記入します。
※アイコンは icon.jpg を差し替えます。ANBooks に表示されます。


 以下は新プロジェクトには含まれていませんが、同様に指定できる要素です。
 追記しても結構です。

●log要素
  プレイヤーが読んだ文章を読み返せる機能、履歴について指定します。
    max_len属性
     …… 記憶する文字数を指定。(省略時1024)
        ルビ文法などにより実際はこの数値よりやや少なめになります。

●init要素
  ゲームの初期状態について指定します。
    bg_color属性
     …… どのレイヤやプラグインよりも背後にある背景色を指定。(省略時0x000000……黒)
        画像レイヤを表示していくと見えなくなりますが、起動直後からレイヤ表示までのアプリ
        画面が気になる場合に有効です。
    tagch_msecwait属性
     …… 通常文字表示待ち時間(未読/既読)のデフォルト値(10ms)を変更する。
    auto_msecpagewait属性
     …… 自動文字表示、行クリック待ち時間(未読/既読)のデフォルト値(3500ms)を変更する。


例えば、以下のように変更する事が出来ます。(フォルダやファイルは別途用意する)
<?xml version="1.0" encoding="UTF-8" ?>
<config>
	<first_script fn="start"/>
	<save_ns name="com.fc2.blog38.famibee.99878e72-e417-4007-b75f-c9a006a74fef"/>

	<search>
		<path dir="bgimage" />
		<path dir="bgm" />
		<path dir="fgimage" />
		<path dir="image" />
		<path dir="others" />
		<path dir="rule" />
		<path dir="scenario" />
		<path dir="sound" />
		<path dir="system" />
		<path dir="video" />
	</search>
	<window width="1024" height="768"/>
	<init bg_color="0xFFFFFF"/>
	<coder len="0x360"/>

	<debug filterLevel="0" monitor="true" init_time="true" render_dt="true"/>
</config>
●debug要素
  デバッグ情報の出力について指定します。
  リリース時には要素ごと削除(かコメントアウト)すべきです。

  monitor属性
   …… trueを指定すると、FPS、FRT(フレームのレンダリング所用時間)、メモリ使用量などを
      リアルタイムグラフ表示します。
  init_time属性
   …… trueを指定すると、最初の[s]タグが呼ばれるまでの所要時間を計測し出力します。
  render_dt属性
   …… trueを指定すると、レイヤ毎の描画間隔を出力します。
初めてのanスクリプト  実際にプロジェクトを変更してみましょう。
 mat フォルダ内にある「main.an」をテキストエディタで開いて下さい。
 ※文字コードはUTF-8、改行コードは LF 固定です。文字コード・改行コードを間違うミスに注意。

 以下のように[lay 〜(略)〜]直後に適当に空間を空けて、入力してみて下さい。

こんにちはエアノベル世界[l]

 これをゲームとして実行します。変更を保存し、
 先ほどのように【最初から読む】をクリックすると、ゲームが始まります。


このように表示されたら成功です。ようこそ AIRNovel へ!
(フォントはOSや環境に左右されます)
(また、作品一覧表示する冒頭の「ANBooks書庫」画面で右クリックしても同じ処理をします。場合によってはこちらのほうが楽かも知れません)

初級テクニック

スクリプト文法・入門編  スクリプトってなんでしょう?

 AIRNovelにおけるスクリプトとは、
 テキストファイルに書いた「小説」に、「タグなどの命令」を書き加えたものです。
小説 + タグなどの命令 = スクリプト
 具体的な例としては、(もし前から順番に読んでいなさるのなら)初めてのanスクリプトで作ってもらったスクリプトファイルが、立派な例になります。
(再掲)

[add_lay layer=mes class=txt]
[add_lay layer=upd class=grp]
[lay layer="mes" visible=true b_alpha=0 r_size=12 r_align="121" layout='blockProgression="rl" lineHeight="36" paddingTop="15" paddingRight="15" fontSize="24" color="0xffffff"']

 こんにちはエアノベル世界[l]


 例で言うと「小説」は「こんにちはエアノベル世界」という文字の部分です。
「タグなどの命令」は「[」と「]」の半角文字の大括弧に挟まれた、英語や数字や記号の部分です。
 タグは言うなれば魔法の呪文。
RPGなら暗い洞窟を明るく照らしたり、仲間の体力を回復したり、扉の鍵を開けたり。
呪文は一つ一つに意味があり、役割があります。便利で頼りになる道具です。
でも瀕死の仲間を明るく照らしたり、扉の体力(?)を回復したりしても意味はありません。
タグの使い道を正しく理解し、よりよいノベルゲーム制作という冒険を進めましょう。
「タグなどの命令」は一見ややこしく難しそうに見えます。
 ですが、「今すぐ」「全てを」理解する必要はありません。

タグリファレンスというカンニングペーパー、辞書があります。
 タグを使いこなすのに、「あんなタグがあったな」となんとなく憶えておけば、あとはタグリファレンスという辞書を引きながら記述していけばよいのです。


 前括弧の「[」直後の英文字列に注目してください。
 一行目は「add_lay」ですね。これを今後は「タグ名がadd_layだ」と言い、「add_layタグ」と呼び、今後この文章(AIRNovel 開発者向け情報)では[add_lay]と書きます。
 これだけ憶えて置いてくださいね。
 同様に[lay]、最後に[l]。

 さて、そうすると何だかややこしそうな上の例も、たった三つのタグがあるだけ、と言う事に気付きます。
 まず[add_lay]。
 やたらめっぽう長くてややこしそうな「おまけ」が付いてる[lay]。
「おまけ」が全然ない、最短の[l]。

「おまけ」は、「属性」と呼びます。
 一つの働きをするタグに、細かい指示をする記述の事です。
 属性って色んなものにありますよね。
 呪文にも「タイプは炎系。力の源は闇。攻撃力は25。水棲生物に強い」
 女性キャラクターなら「年齢は十四歳。メガネは必須! 髪色は黒髪、背はちょっと高めなのを気にしている。スリーサイズはそれぞれ……」
 某ラーメン屋なら「アブラナシヤサイカラメマシニンニクスクナメ」

 [add_lay]は、「属性layerは文字列mes」「属性classは文字列txt」と記述されています。
 タグ一つ一つの説明は、タグリファレンスという辞書みたいな資料に載っています。
(載っていない場合は、「マクロ」という誰かが作った呪文です)
 この[add_lay]と言う呪文は、「(AIRNovelに)レイヤを追加する。」のです。(レイヤについては別項で)

 タグリファレンスを片手に見ていくと、こういう働きになります。
  レイヤを追加しなさい。
  レイヤ名はmes、でね。
  レイヤは文字レイヤでね。
  
 言葉の意味が今分からなくても、タグとはどういうものか、タグの書き方がざっくりつかめればOKです!


 ここで実際にタグの動作を見てみましょう。
 最初に作ったサンプルを、横書きにしてみます。

 この辺の指定はタグリファレンス[lay]の(文字レイヤ)の表にある、【layout 属性】に説明が書いてあります。(最新タグリファレンスと微妙に違ったらご愛敬)
(文字レイヤ)
属性必須省略時値域・型コメント
layoutn現在値String 文字レイヤのレイアウトを指定する。
文法はFlex SDK 4のTLF (Text Layout Framework)・TextFlowのXML指定による。
このlayoutという属性の中にTLF属性群を入れ子状に記述する。
例えば、blockProgressionで縦書き・横書きを指定できる。
設定しないTLF属性は現在値を継続する。
初期値は空(から)、全くの未指定。

駆使すると、「文字表示領域矩形内に自動で文字を並べる」事なども出来ます
 三行目の「blockProgression="rl"」を「blockProgression="tb"」に変更します。

リファレンスガイドには【有効な値は、BlockProgression.RL、BlockProgression.TB、FormatValue.INHERIT です。】と書いてありますが、指定すべき値は「関連する API エレメント──flashx.textLayout.formats.BlockProgression」の下の方、【定数の詳細】にある「rl」や「tb」です。
(たぶん行の並び、「Right-Left」→「Top-Bottom」の略称)

 少し左に寄りすぎていますね。あと横書きなら画面下の方に置くのがスタンダードです。文字表示位置をずらしてみましょう。
 現在、「paddingTop="15" paddingRight="15"」という指定により図の部分にパディング(余白)を空けています。


 これを「paddingTop="215" paddingLeft="15"」に変更します。

 ちょうどいい位置に表示されるようになりました。

 これは以下のような余白を入れた結果です。

レイヤとは スクリプト文法・入門編の続きです。

レイヤとは?
透明の下敷きのようなものです。
幾つか種類があり、
「文字レイヤ」は文字を表示するのが得意です。
 原稿用紙のように整然と文字を並べたり、ルビを表示したり。
 ちょっと不思議ですが、「ボタンのように押せる画像」もこのレイヤが担当します。
 タグではなく、全角文字を書いておくと一文字ずつ表示されていきます。

「画像レイヤ」はjpg・png等の画像、swfというフラッシュアニメの表示が得意です。
 ノベルゲームでは立ち絵と呼ばれる人物の絵や、
 一枚絵と呼ばれる画面いっぱいのイラスト、
 はたまた漫画のコマのように小さなカットを表示したり、
 表示した絵の場所を変更する事が得意です。

 サンプルゲーム「桜の樹の下には」の例を詳細に見ていきましょう。


 この場面では文字レイヤが一つ、画像レイヤが二つ使われています。

 画像レイヤを一つ使って最背面の「緑と渓流」の画像を表示し、


 その上に重ねた、もう一つの画像レイヤで画面中央に「ウスバカゲロウ」の小さなカットの画像を表示しています。

 更に上に重ねた文字レイヤで、「白い半透明の四角」と「黒い文字」を表示しています。
※青三角の改ページクリック待ち記号も文字レイヤ上ですが、詳しくは別項に譲ります。

「重ねた」と言いましたが、これはスクリプト文法・入門編で出てきた[add_lay](レイヤを追加する)でレイヤを「作り」つつ、上へどんどん積み重ねていく事が出来ます。

 イメージが掴みやすいように、実際のプロジェクトのレイヤ構造を見てみましょう。
 aaプロジェクトの詳細画面を開き、【最初から読む】を「右クリック」します。いつもと逆ですね。デバッグ情報を多めに表示するモードです。


 サンプルのクリック待ち(1ページ目、的な)トコで停まったとき、「ターミナル」に色々表示します。
 一番下の【レイヤ構造3D】をクリックすると、サンプルプロジェクトaaのレイヤ構造を簡易3D表示します。

 半透明四角がレイヤです。周辺をドラッグすると回転出来ます。
「mes」レイヤの前に、「upd」レイヤがあるようですね。
 スクリプトを見ると……
 冒頭1行目で「add_lay」タグにより「mes」レイヤを作り、
 その後2行目で(その上に)「upd」レイヤを作っています。
一度重ねたレイヤの「重なり順」は変更できますが、「今どれが一番前だっけ!?」と混乱するのであまり変えない方がいいでしょう。
変更しない前提でレイヤの使い道を考えたり、レイヤの画像を差し替えたりしていきます。
レイヤはメモリや処理速度の許す限り、何枚でも重ねる事が出来ます。
が、ゲームをプレイする人のマシンがあなたの愛機ほど高性能のものとは限らないので、
文字レイヤ1枚+画面全体を覆う背景画像レイヤ1+その他画像レイヤ3=5枚、ぐらいで
やりくりするのが賢明です。


「桜の樹の下には」のスクリプトを覗いてみましょう。
anprjファイルにあるように、このアプリに於いて最初に起動されるスクリプトファイルは「main.an」です。
短編「桜の樹の下には」の項を参考にしてスクリプトファイル「main.an」を開くと、冒頭に以下の記述があります。
[add_lay layer=base class=grp]
[add_lay layer=0 class=grp]
[add_lay layer=1 class=grp]
[add_lay layer=2 class=grp]
[add_lay layer=mes class=txt]


レイヤに「base」「0」などの「レイヤ名」を付けつつ、画像レイヤや文字レイヤを[add_lay]していますね。

今度は「ss_000.an」の該当部分を見てみます。(このノベルゲームの本文はこのスクリプトに書いています)
テキストエディタの文字列検索で「ウスバカゲロウ」を探してみてください。

[fg fn="ウスバカゲロウ" layer=0 left="&(const.flash.display.Stage.stageWidth -640)/2" top="&(const.flash.display.Stage.stageHeight -400)/2"]
それは渓の水が乾いた磧《かはら》へ、小さい水溜を残してゐる、


[fg]はタグではなく独自のマクロ(別項で述べます)であり、タグリファレンスには載っていませんが、
ここでは「レイヤに画像を表示する」働きをするものだとしておいてください。
ここで重要なのは、以下の二つの属性です。
  fn="ウスバカゲロウ" ……「ファイル名が『ウスバカゲロウ』の画像ファイルを」、
  layer=0 ……レイヤ名「0」のレイヤ(この場合、画像レイヤ)に表示する。
という風に、レイヤは「レイヤ名」でどのレイヤかを特定し、「レイヤの種類」に応じた処理をさせていきます。
レイヤには裏表がある
初級編で一番難しい話をします。良く睡眠を取り、疲れていない時に読んで下さい!

●単純に絵を表示したいのなら、以下の記述で表示できます。
[add_lay layer=絵 class=grp]
[lay layer=絵 fn="ans.jpg" visible=true]


[add_lay]……画像レイヤを追加し、(レイヤ名は「絵」)
[lay]……レイヤに以下の設定をする。
  (layer=絵) レイヤ名が「絵」のレイヤに、
  (fn="ans.jpg") ファイル名が「ans.jpg」の絵を表示し、
  (visible=true) レイヤ表示設定(visible)を真(true)にする──レイヤを表示します。
画面が真っ暗だとか、レイヤが表示されない場合、
大抵は表示する絵を指定していない(透明の下敷き=表示されるものがない)か、
「visible=true」を忘れている場合が多いです。
ちなみに、消したい時はvisible=falseです。

●もう一つ、フェードイン・フェードアウトするように絵を表示する方法があります。
上記の方法だと、(画像ファイルのロード完了次第)瞬時に表示されます。
ただ、これで人物表示を行うと「いかにも絵を出してます」という感じであまり良くありません。
人物の立ち絵や滑らかな背景変更をさせるため、トランス、という機能について説明します。

実はレイヤには表ページと裏ページがあり、[add_lay]すると裏表同時に生成されています。
(今までの話は、表ページのみを操作対象としていました)
ロードした画像、レイヤの位置や大きさなどの属性は、それぞれ全く独立して存在しています。

表が文字レイヤで裏が画像レイヤ、という事は出来ません。
常に裏と表は同じ種類のレイヤです。
ただし、裏ページは絶対に表示されません。表ページだけが表示されます。
ではなぜ裏ページ、というものがあるのか?
それはゲームプログラミングの世界で「ダブルバッファ」と呼ばれる技法を実現するためです。
例えば、以下の記述をします。
[lay layer=絵 page=back fn="ans.jpg" visible=true]
[trans layer=絵 time=1000]
[wt]

1.([lay])まず「絵」レイヤの裏ページに絵を用意しておきます。
  この作業を「見えない裏ページ」で行う事で、絵を用意している最中の舞台裏を
  プレイヤーに見せずに済みます。このための裏ページ、「ダブルバッファ」なわけです。
2.([trans])次に「絵」レイヤの表ページをどんどん透明に(フェードアウト)していき、
  逆に裏ページをどんどん不透明に(フェードイン)していきます。
  (裏表ページが逆のフェード動作をするため、クロスフェードと言います)
  これで滑らかに絵が表示されます。
3.クロスフェードが終了すると、まるで表ページが裏ページのように隠れ、
  裏ページが表ページのように表示されています。
  この時点で、裏と表のページが入れ替わっています。
4.最後に、表示されている元裏ページ(新表ページ)から非表示の元表ページ(新裏ページ)へ、
  レイヤの情報がコピーされます。画像レイヤなら全ての画像、swfアニメが対象です。
  文字レイヤのみ、文字のフォーマットなどほとんどの情報がコピーされますが、
  文字本文やルビだけはコピーされず、元表ページのテキストは消去されます。
5.([wt])トランスの終了を待って、次のスクリプトを処理します。

2.と3.の一連の動作をトランス、と言います。表と裏を交換するという意味合いです。
表ページは文字通り表舞台。裏ページは準備をする舞台裏、といったところです。

純粋な意味での交換ではなく、交換して元裏から元表へのコピーが自動で処理されますが、
これは新表ページと同じ状態への差分的な変更、というケースが多いためです。


立ち絵の表情を変化させる時など、裏表ページとトランスを有効に使いこなすのは重要なテクニックです。
使用できる素材ファイル AIRNovelで使用できるファイル形式は以下の通りです。拡張子で示します。

画像・動画ファイル
  png、jpg、swf、アニメーションgifやpng(画像拡張プラグインでサポート)
  png_など上記ファイルの暗号化版

スクリプトファイル
  an、an_(〃)

音声・効果音・BGMファイル
  mp3、mp3_(〃)、ogg、ogg_(〃)、
  m4a(現状 m4a のみ暗号化は未サポート)

ムービーファイル
  flv、flv_(〃)、f4v、f4v_(〃)、mp4、mov、3gp、3g2
  ※iOSではflvのみ

動的ライブラリ(プラグイン)・組み込みフォントファイル
  swf、swf_(〃)
フォルダの追加削除  画像や音声素材が増えてきたら、matフォルダだけでは困りますよね……

 フォルダの追加・変更は全くの自由です。
 フォルダを追加・削除した場合は【ANBooks 書庫】に一旦戻り、詳細画面に戻って下さい。
 そして【プロジェクトフォルダ設定】を開きます。フォルダやファイルについて、プロジェクトの一部とするかどうかを設定出来ます。

●「無視」…………AIRNovelが見なくていいモノはこれを選択します。
●「含める」………AIRNovelが見るべきならこれを選択します。
        (anbookパッケージに含めません)
●「anbookだけ」…anbookパッケージ(かなり後で後述)「にも」含める場合。
         AIRNovelから見える意味合いもあります。

 ※プロジェクトの一部であると後々、実行形式パッケージにした際に一緒に梱包されちゃいますので、素材フォルダは含めない「無視」にして下さい。
 ※iconナントカは意味合いが決まってますので、灰色で変更出来ないようにしています。
注意点があります。
入ってるフォルダが違っても、同じファイル名のファイルは許されません。AIRNovelがエラーとします。
 これはフォルダ名を書かなくても(どこに入っているか知らなくても)いいようにしたい、というスクリプトの書きやすさを求める仕様から来ています。
[lay layer=絵 page=back fn="ans" visible=true]
※「ans」→「ans.jpg」→「mat/ans.jpg」の略、のような。
 フォルダ分けと同じ事がしたい場合は「xxx_xyz.png」などとファイル名を工夫して下さい。

・また、フォルダは1階層だけサポートしています。
 フォルダの中にフォルダ、は無しです。
(テンプレのconfigは特殊。理由は上級者向けなので割愛)

・また、以下のフォルダ名は使用できません。
font …… フォントファイルを入れるため。(別項で説明)
icon …… アイコンファイルを入れるため。(中の画像素材は自作ゲーム用に編集できます)
SDK …… ビルド用のAIRNovelソースファイルを入れておくため
Work …… テンプレートが色々オマケファイルを入れておくため
ジャンプしてみる スクリプトを書いていると、とても長くなりがちです。
章ごとに別のスクリプトに分けると管理がしやすい場合もあります。
選択肢毎に、別ルート毎に分けると作業がしやすい人も居るかと思います。
そんな時にはスクリプトから別のスクリプトへと処理を「ジャンプ」する機能を活用しましょう。
選択肢やサブルーチン、マクロなどにも関わる重要なテクニックですので、是非理解して下さい。

例えば、以下のようなmain.anを実行したとします。
(main.an)──ジャンプサンプル

[add_lay layer=mes class=txt]
[lay layer="mes" visible=true r_size=12 r_align="121" layout='blockProgression="rl" lineHeight="36" paddingTop="15" paddingRight="15" fontSize="24" color="0xffffff"']

こんにちはエア

[jump fn="first.an"]


main.anを処理したAIRNovelは「こんにちはエア」という文字を表示した後、
[jump fn="first.an"]というタグ処理に取りかかります。
これは「first.an」というスクリプトファイルをサーチパスから探し(存在しない場合、エラーとなります)、
処理をfirst.an冒頭から始めます。

first.anは、例えば以下のようなものを用意しておきます。
(first.an)──ジャンプサンプル

ノベル世界[l]


すると画面上には「初めてのanスクリプト」と全く同じ表示が成されます。

(こんにちはエアノベル世界)
実際にはスクリプトを跨いでいますが、AIRNovelは特に気にしません。


●ラベルについて
さて、ジャンプ先はもっと事細かに指定する事も出来ます。ラベル、と言います。 以下のようなmain2.anを実行したとします。
(main2.an)──ラベルサンプル

[add_lay (略)]
[lay (こっちも略)]

こんにちはエア

[jump fn="first2.an" label=*gogo]

(first2.an)──ラベルサンプル

ノベル
*gogo
世界[l]



(こんにちはエア世界)
「ノベル」が表示されません。なぜでしょう?

この例では「first2.anスクリプトファイルの、*gogoというラベルにジャンプ」します。
「ノベル」を飛び越して*gogoから処理を継続したので、表示されなかったわけです。
これが[jump]というタグの働きです。

*gogoがラベルです。先頭の*(半角アスタリスク)は必須ですが、名前は自由に付ける事が出来ます。
ラベルそのものは何も処理しません。ただジャンプ先を示すだけです。
もちろん、ジャンプ元とジャンプ先では、同じラベル名を使用する必要があります。


●サブルーチンについて
最後に、ジャンプと似て非なる「コール」について知っておきましょう。
ジャンプはジャンプしたっきり、行ったっきりですが、
コールは簡単に元の場所に戻る仕組みが用意された特殊なジャンプです。
(main3.an)──コールサンプル

[add_lay (略)]
[lay (略ですって)]

こんにちは
[call fn="sub.an" lbl=*gogo]
ノベル

世[call fn="sub.an" lbl=*gogo]界[l]

(sub.an)──ラベルサンプル

世界
*gogo
エア
[return]



(こんにちはエアノベル世エア界)
[call]でコールすると、[return]でコールした次の位置へと戻る事が出来ます。
例のようにラベルも使えます。
余談ですが、このようにメインルーチン(main3.an)に対するサブ、と言うような意味合いで、
sub.anのようなスクリプトファイルを「サブルーチン」などと呼んだりします。
[call]先で更に[call]する事が出来ます。その際必ず、[call]した数だけ[return]するようにして下さい。
余談その二ですが、[return]で戻るためには当然AIRNovelが戻り先を憶えておく必要があります。
その容れ物の事を「コールスタック」なんて呼んだりします。
コールの戻り先を積んでおく箱、というような意味合いです。
書店に置かれた平積みの本のように、底にある最初に積んだものは最後にしか取り出せません。
ただ本と違って、一冊下から抜き出すなんて事は出来ません!
選択肢を作る 一本道の小説風のノベルゲームもありますが、物語の分岐点で読者に選択をゆだねるタイプのアドベンチャーゲームもあります。
そのような選択肢を作る方法を解説します。

表示した文字をWebページのようにリンクにする「文字リンク」……[link]
表示した画像をリンクにする「ボタン」……[button]

これらを必要な分だけ並べ、最後に[s]で停止させます。基本的にはこれだけです。
[link label=*a1]選択肢1[endlink]
[link label=*a2]選択肢2[endlink]
[button label=*a3 pic="ボタン絵"]
[s]

*a1
(選択肢1の文章)

*a2
(選択肢2の文章)

*a3
(選択肢3の文章)

文字リンクのサンプルがありますので、こちらのスクリプトファイルも参考にして下さい。
画像リンクは「櫻の樹の下には」のタイトル画面が参考になります。
タグ リファレンスを読もう 「他にはどんな事が出来るの?」と興味津々な方は、
AIRNovel タグ リファレンスをざっと眺める事をお勧めします。

ここまで読んで来れたあなたなら、きっと理解できるはず。


基本的に[l]や[r]、
「桜の樹の下には」マクロですが[plc][fg]、
まずこの四つを理解すればノベルゲームは作れます。
マクロについては後述。
スクリプト文法・詳細編 ここまで説明したスクリプト文法以外に、以下のものがあります。
初級編みたいに易しくじっくりは説明しませんが、読めばなんとなく分かるものもあると思います。
全てをここで憶えようなんてせず、時々見たり参考にするつもりで充分です。

全角文字……文字として、一文字ずつ表示する。
タブ文字……無視します。文字を右(横書き時)や下(縦書き時)に寄せたい場合は全角空白を使用して下さい。
改行文字による改行……無視します。改行させたい場合は[r]を使用してください。

タグ……「[」と「]」の半角大括弧に挟まれたもの。
タグ名……前括弧「[」直後から始まり、半角空白かタブ文字か「]」まで続く一単語。

属性……タグの中にある、タグ名以外の要素。
    半角空白やタブ文字で区切っていくつも書ける。タグがサポートしない属性は無視される。以下の種類がある。
      1.属性が全くない場合。
      2.属性名+「=」(半角イコール)+属性値。
      3.「*」(半角アスタリスク)。

属性名……英数、「_」(半角アンダーバー)、日本語の自由な組み合わせ。
     ただし「タグ名」という属性にはタグ名そのものの文字列が入っている。
属性値(リテラル)……true、false、null
           ※リテラル……特殊な意味を持つ単語、みたいなものです。
属性値(文字列)……「"」(半角クオーテーションマーク)「'」(半角シングルクオーテーションマーク)で囲う。
          ただし文字列に半角空白を含まない場合はクオーテーションを省略できる。
         「x=0xFF」は「0xFF」という文字列を与える。
属性値(変数)……文字列冒頭に「&」(半角アンパサンド)を記述する。
         「x="&a"」「x=&a」などとする。
         「x=&"a"」は不可。
属性値(式)……「x="&a + b"」「x=&a+b」などとする。
         「a=&"a + b"」「a=&a + b」は不可。(後者は半角空白入りの文字列により)
         「x=&0xFF」は「0xFF」を式として解釈した結果の「256」という数値を与える。
属性省略値……属性値直後に「|」(半角縦線)で区切り、もう一つ属性値を繋げて書ける。
          これは前の属性値はnullの時、後ろの属性値を採用する小さなIF文、三項演算子のようなもの。
          「x=mp:x|0」と記述すると、
            mp:xが非nullなら……xはmp:x、
            mp:xがnullなら……xは0となる。
属性省略値(null指定)……属性省略値は条件にかかわらず必ず値がセットされる事になるが、
          条件次第で「属性値は指定されなかった」事に出来る指定。すなわち、
          「x=mp:x|null」と記述すると、
            mp:xが非nullなら……xはmp:x、
            mp:xがnullなら……xは「指定されなかった」「記述されていない」事にできる。
          
          ※mp:xがnullならnullにしたい場合、「x=mp:x」または「x=mp:x|"&null"」と記述する。

コメント……「;」(半角セミコロン)以降から改行までをコメントとし、処理しない。
ラベル……行頭から「*」(半角アスタリスク)+英数字ラベル名。ラベル名直後は改行を推奨。
     ラベルそのものは何もしないが、[jump][call]でこのラベル名を指定し、スクリプトファイルのこのラベルの位置へとジャンプ・コールすることができる。
変数名……スコープ+「:」(半角コロン)+クラス+変数名。

中級テクニック

ノベルをテンプレで作ろう 「基本はもう充分、いい加減ノベルゲームを作らせてくれ!」
 ごもっとも、ではそろそろ制作に入りましょう。

 最初に作ったテンプレート(小さな黒正方形画面のプロジェクト)から本格的なノベルを造り上げる事も出来ますが、それは大変すぎます……。
 ここでもテンプレートから基本のノベルゲームを生成し、そのカスタマイズと行きましょう。

 例によって【新規作成】を開きます。


 ところであなたの作品は縦書きですか? 横書きですか?
 前述の通りいくらでも変更出来るのですが、確認しておきたいと思いまして。
 というのも、ノベルゲームのテンプレートとなる作品が別れているので、最初に選んでしまおうと。

 以下が用意されたテンプレート一覧です(2014/10/05 時点)
 ●シンプルなプロジェクトを作成……
  300 x 300 ピクセルサイズのウインドウで動く、最低限のスクリプトと素材で構成されたプロジェクト。技術的な実験などを行ないたい時などに便利。

 ●「空を飛べたら Win Mac版」を元に作成……
  「横書き」のサンプルプロジェクト。デスクトップOS向け。
  素材はウインドウサイズサイズ1024 x 768を想定。

 ●「桜の樹の下には Win Mac版」を元に作成……
  「縦書き」のサンプルプロジェクト。デスクトップOS向け。
  素材はウインドウサイズサイズ1024 x 768を想定。

 ●「桜の樹の下には iPhone版」を元に作成……
  iPhone/iPad 向けプロジェクト。素材は画面サイズ800 x 480を想定。
  他のiOS向けとの違いは主に素材サイズ。

 ●「〃 iPhone Retina対応版」を元に作成……
  iPhone/iPad 向けプロジェクト。素材は画面サイズ800 x 480と960 x 640を想定。
  他のiOS向けとの違いは主に素材サイズと、Retina対応。素材も高解像度専用の「_saveload@2x.jpg」などを含む。

 ●「〃 iPad版」を元に作成……
  iPad 向けプロジェクト。素材は画面サイズ1024 x 768を想定。
  他のiOS向けとの違いは主に素材サイズ。

 ●「〃 Android版」を元に作成……
  Android 向けプロジェクト。素材は画面サイズ800 x 480を想定。

 ●シンプルなプラグインを作成……
  プラグイン製作用。詳細は「プラグインの自作」を。
 ここではテンプレート「空を飛べたら」で行きましょう。
 プロジェクト名「Your」を入力し、「空を飛べたら」をクリックします。


(テンプレート素材を自動ダウンロードしてから、)追加されます。


【最初から読む】等で実行すると、ノベルゲームが起動します。
 色々触ってみて下さい。





 これはあなたがいくら改造しても大丈夫なプロジェクトです。
 ファイルの様子を見ると……

 このように様々なフォルダに素材が入っています。
 なんとな〜くアルバム、背景などフォルダ名で中身が解るようになっていますが、実際に中を見てみると分かりやすいでしょう。
テンプレを少し解説  サンプルゲームのスクリプト、(デフォルトの状態では)最初に実行される「main.an」を通して、何をしているかを解説していきます。
 一つ一つ噛み砕いていけば、きっと理解出来ます。
 ご自分の作品へとカスタマイズしていく際の参考にして下さい。
最新の main.an では機能追加などで内容や行番号が微妙に変わっているかも知れませんが、お酌み取り下さい。
 キーボードのF5、W、F8などの機能についての解説もあります。全てスクリプトで実現しています。
(ので、不要ならコメントアウトすべきです)

(main.an -- 1/4)
最新は多分ちょっと違います……。

行 1〜5:必要なレイヤを追加
行 7〜8:必要なプラグインを追加。どちらも system/ フォルダ下にある。
    _notice……フルスクリーンにしたときなどに出る通知表示
    plgTweensy……レイヤーやプラグインにトゥイーンアニメを加える

行 10:「wキー」を押すと、いつでも「*toggle_full_screen」をコール。
    「*toggle_full_screen」ではフルスクリーンモード・ウインドウモードを切り替える処理がある。(main.an にある。後述)
行 11〜12:「カーソルキー右(左)」を押すと、次(前)のボタンへフォーカスを移動する。
行 13:(デフォルトではコメントアウトだが)[voice]マクロにより最後に再生された音声を、再度再生する。
行 14:「pキー」を押すと、いつでも画面のスナップショットを撮る。
行 15:「F5キー」を押すと、いつでも実行中のスクリプト(イベントが利くのはクリック待ちや[s]なので、正確には実行停止中)をリロードする。
    ただし、それ以外のスクリプトはリロードしない点に注意。
行 16:「F7キー」を押すと、いつでも[stats]を実行。
行 17:「F8キー」を押すと、いつでも[dump_val]を実行。
行 18:(デフォルトではコメントアウトだが)起動直後に必ずアプリ更新をチェックしたい場合、この辺で[update_check]を実行する。

行 20:scenario/sub.an をコール。主にゲームで使うマクロ定義。
行 21:system/_yesno.an をコール。主にゲームで使うマクロ定義。
行 23:一文字マクロ定義。スクリプトに「@」と書くだけで「[l]」と書いたのと同じにする。簡略表現。
行 24:一文字マクロ定義。スクリプトに「\」と書くだけで「[plc]」と書いたのと同じにする。簡略表現。
行 27:「escキー」が押されていない場合のみ、前回終了した本文の位置から再開する。タイトルなどはタイトルから。


(main.an -- 2/4)

行 30:タイトル処理、始まりのラベル
行 32:タイトル開始にあたって必要な処理を行なう(マクロを呼ぶ)。
行 40:タイトルBGMを再生。
行 41:(デフォルトではコメントアウトだが)「;」を消すと変数を全てクリアする。インストール直後のような、初期状態のテストに便利。

行 43:タイトルメニュー処理、始まりのラベル(現状、ジャンプの目印としては特に使ってない)
行 44〜47:背景だけ指定して、他のレイヤは空にする。

行 49:文字レイヤmesをクリア。
行 50〜53:文字レイヤmes(の裏ページ)にボタンを追加

行 55:裏ページを表ページにクロスフェード
行 56:クロスフェードが終わるまで待ち、終わったら次へ。
行 57:スクリプト停止。予約したイベント発生を待つ。
    起こり得るイベントは直前に追加したボタン四つか、行 10〜17で予約したグローバルイベント([event global=true …])。


(main.an -- 3/4)

行 60〜88:ボタンの処理。詳細は割愛。
    ここへはコールで飛んできている点に留意。[return]するだけで行 57に戻る。


(main.an -- 4/4)

行 10〜17で予約したグローバルイベントのコール先。詳細は割愛。
変数の使い方。変数の型 変数は数値や文字列を入れておく、バケツのようなものです。
ギャルゲーならどれだけその子に好かれたか、好感度などの値を保存したいですね。
もしくは読み進めた履歴テキストも、AIRNovelが変数に入れています。
そのように変数は様々な「値」を入れておいたり、後で取り出して使う事が出来るものです。


変数は変数名をつけて区別します。これによりAさんの好感度を入れたバケツと、Bさんの好感度を入れたバケツを区別したり出来るわけです。

変数名は以下の書式です。
《スコープ》+「:(半角コロン)」+《クラス》+「.(半角ピリオド)」+《名前》+《取得方法》

《スコープ》……
  変数名の前に付けると、値が保存される期間を制御できます。
  スコープが異なる変数は別の変数です。

  指定できるのは「tmp」「sys」「mp」「save」のいずれか。コロンと共に省略するとtmp扱い。
    tmp …… 一時変数。値はアプリ終了時に消滅。雑用向き
    sys …… システム変数。設定すると恒久的に値が保持される。全てのセーブデータにおいて共有する。達成率など向き
    mp …… マクロの引数。値はそのマクロ定義が終了すると消滅
    save …… セーブ変数。セーブデータ毎に値が保持される

《クラス》……
  「(指定しない)」「const」のいずれか。ピリオドと共に省略すると指定しない扱い。
  通常の変数は指定しないが、constを指定した場合は
  「最初に一度だけ代入でき、以降は参照のみ可能。二回目以降の代入をするとエラー」となる。
  内部設定など参照専用の組み込み変数によく使用される。

《名前》……
  半角英数、日本語、半角ピリオドを組み合わせて変数の名前を指定する。
  変数宣言は無し、いきなり使用できる。(初期値は不定、必ず初期化しましょう)
  配列などはサポートしないが、以下は全て同値と見なす文法があり、擬似的な連想配列として扱える。
    hA.ar12
    hA['ar12']
    hA['ar1' + '2']
    hA['ar1' + 2]
    hA['ar' + BB]  (BBは変数、値='12')
    hA['ar$BB']  (BBは変数、値='12')
    hA['ar#{BB}']  (BBは変数、値='12')

《取得方法》……
  「(指定しない)」「@str」のいずれか。
  @strを指定した場合は文字列として取得する。
  指定しないと「出来るだけ数値として」取得する。


具体的な例を見てみましょう。
1+2の計算をして結果を「tmp:ret」という変数に入れる場合は、以下のように記述します。以下はどちらも同じ意味です。
[let name=tmp:ret text="&1 + 2"]
[let name=ret text="&1 + 2"]

一行で全て書かず、複数の変数を駆使する事も出来ます。
[let name=a text=1]
[let name="b" text=2]
[let name=ret text="&a + b"]

[let]を使わない、より簡潔な記述文法があります。(ver 3.18以降)
&a=1
&b=2
&ret = a + b
(詳細はタグリファレンス[let]の項を参照)
変数の演算。使える演算子 AIRNovelで使える演算子は、以下の通りです。
使える対象……
・数値は「0」「3.333」「0xffffff」などの数字や、数値が入った変数。
・文字は任意の文字列や、文字列が入った変数。
・Boolean は true か false。
算術演算子
演算子結果使える対象
+足し算1+2【結果は3】
"1" + "2"【結果は"12"】
数値、文字
-引き算1-2【結果は-1】数値
*掛け算1*2【結果は2】数値
/割り算5/2【結果は2.5】数値
¥割り算をしてから小数点以下を切り捨て5¥2【結果は2】数値
%割った余り5%2【結果は1】数値

比較演算子(結果は全て Boolean になります)
演算子結果使える対象
==値が等しければtrue数値、文字、Boolean
!=値が等しくなければtrue数値、文字、Boolean
>左辺の方が値が大きければtrue数値
<左辺の方が値が小さければtrue数値
>=左辺の方が値が大きければtrue数値
<=左辺の方が値が小さければtrue数値

論理演算子(結果は全て Boolean になります)
演算子結果使える対象
!否定。値の前に付ける。値がtrueのときfalse、falseのときtrueBoolean

条件演算子
演算子結果使える対象
exp1 ? exp2 : exp3exp1 が true なら exp2、
false なら exp3 を返す
Booleanexp1 は Boolean、
exp2・exp3は 数値、文字、Boolean
演算子の優先順位……
【優先順位が高い】
!
*   /   ¥   %
+   -
>   >=   <   <=
==   !=
||   &&
?:
【優先順位が低い】
※演算子の優先順位を変えるかっこ【()】も使えます。
組み込み変数・定数 AIRNovelが値を設定している変数や定数もあります。AIRNovel起動直後から使えます。
const.an.〜、an.〜という名前はAIRNovelが使いますので、皆さんは新規に作成しないで下さい。以下の表にあるモノを使うのは全然OKです!

constでない変数は、設定するとその値がシステムに反映されます。
例えば「[let name=an.auto.enabled text=true]」は自動読みすすみモードを有効にします。
変数名(tmpスコープ)値域・型コメント
an.auto.enabledBoolean自動読みすすみモードかどうか
an.skip.all【追加】Booleanfalse(初期値)なら既読のみをスキップ
an.skip.enabledBoolean次の選択肢(/未読)まで進む が有効か
an.chkFontMode【追加】Boolean組み込みフォントチェックを行なうか
文字を表示しようとした際、必要なフォント・或いは字形情報が組み込まれていない場合、背景色を赤くし警告する。
デフォルト値=false
※(注意)
・ビルド実行版のみ使えます。
仮想環境実行とリリース版ではtrueに出来ないようになっています。
(前者はフォントが読み込めない為、後者はリリース版においてフォントで不手際があった際、大変見苦しい事態になる為)
an.tagL.enabledBoolean頁末まで一気に読み進むか(l無視)
const.an.breakPluginNameString表示中のクリック待ち画像・swf名
const.an.dlgUserOKBooleanダイアログでユーザーが積極的な選択(OKやフォルダ選択)を行なったか。キャンセルをしなかったか。[import]などで設定する
const.an.eventArgStringボタン等イベント時、そのボタン定義時に指定された値
const.an.eventArg.html.idStringクリックされたHTML要素のid属性値
const.an.html.(HTML要素のid属性)String[let_html]などで最後に取得したHTMLタグに挟まれた文字列
const.an.isFirstBootBooleanゲームがインストールされてから、初めての起動か
const.an.isKidokuBooleanこの変数を参照した位置は既読か。参照「後」必ず既読になる点に注意
const.an.isRetinaBooleanRetinaディスプレイやAndroidなどモバイルで画面サイズとゲーム画面サイズが合わず、画像や素材を拡大しているか。
const.an.js.(変数名)String[let_html]などで最後に取得したJavaScript変数の結果
const.an.key.alternateBooleanALTキー(MacならOptionキー)が押されているかが押されているか
const.an.key.backBooleanback 〃
const.an.key.commandBooleancommand 〃
const.an.key.controlBooleancontrol 〃
const.an.key.endBooleanend 〃
const.an.key.escapeBooleanescape 〃
const.an.last_page_textStringそのページの履歴テキスト(《》文法もそのまま)
const.an.lay.(レイヤ名)Booleanレイヤが[add_lay]され存在するか
const.an.lay.(レイヤ名).urlString(HTMLレイヤのみ)HTMLが読み込まれているか(そのHTMLファイル名)を示す
const.an.lay.(レイヤ名).(foreかback).alpha【追加】Integerレイヤの不透明度
const.an.lay.(レイヤ名).(foreかback).heightIntegerレイヤの縦幅。ただし画像レイヤの場合、画像読込後でないと0
const.an.lay.(レイヤ名).(foreかback).visibleBooleanレイヤが表示されているか。visible属性の値を返す
const.an.lay.(レイヤ名).(foreかback).widthIntegerレイヤの横幅。ただし画像レイヤの場合、画像読込後でないと0
const.an.lay.(文字レイヤ名).fore.b_alphaNumber背景の不透明度
const.an.lay.(文字レイヤ名).fore.cursor_rowInteger現在のカーソル行数
const.an.lay.(文字レイヤ名).fore.max_rowIntegerページあたりの表示行数
const.an.mouse.middleBooleanホイールボタンが押下されているか
const.an.onLauncher【追加】Boolean疑似実行環境か
const.an.plg.(プラグイン名)Booleanプラグインがロードされたか
const.an.plg.(プラグイン名).visibleBooleanプラグインが表示されているか。visible属性の値を返す
const.an.retinaRateNumberRetinaディスプレイやAndroidなどモバイルで画面サイズとゲーム画面サイズが合わない場合、画像や素材を何倍(実数)に拡大しているか。
const.an.unzip.(ファイル名).mes【追加】String[unzip]の状態メッセージを示す
const.an.unzip.(ファイル名).state【追加】String[unzip]の進捗を示す
const.an.update_check.errorIDInteger[update_check]エラーコード
const.an.update_check.stateString[update_check]の状態。
const.an.update_check.subErrorIDInteger[update_check]エラーサブコード
const.an.vctCallStk.length【追加】Integerコールスタックの深さ([call]するたびに増)
const.an.xmlConfig.window.heightIntegerconfig.anprj に設定した画面サイズ横幅
const.an.xmlConfig.window.widthIntegerconfig.anprj に設定した画面サイズ縦幅
const.Date.getTimeNumberUTC経過時間(世界協定時刻(UTC)、1970年1月1日0時0分0秒からのミリ秒数)を取得
const.flash.desktop.NativeApplication
.nativeApplication.applicationDescriptor.filename
Stringアプリケーション記述ファイル(*-app.xml)に記述したfilenameの値
const.flash.desktop.NativeApplication
.nativeApplication.applicationDescriptor.version
Stringアプリケーション記述ファイル(*-app.xml)に記述したversionの値
const.flash.desktop.NativeApplication
.nativeApplication.applicationDescriptor.versionLabel
Stringアプリケーション記述ファイル(*-app.xml)に記述したversionLabelの値
const.flash.desktop.NativeApplication
.nativeApplication.applicationDescriptor.versionNumber
Stringアプリケーション記述ファイル(*-app.xml)に記述したversionNumberの値
const.flash.desktop.NativeApplication
.nativeApplication.runtimeVersion
Stringこのアプリをホストしているランタイムのバージョン番号
const.flash.display.Stage.displayStateStringウインドウ・フルスクリーン状態(flash.display.StageDisplayStateを参照)
const.flash.display.Stage.frameRateIntegerアプリの描画フレームレート。この値は[window]で変更できる
const.flash.display.Stage.fullScreenHeightIntegerフルスクリーンサイズに移行したときに使用されるモニターの高さ
const.flash.display.Stage.fullScreenWidthIntegerフルスクリーンサイズに移行したときに使用されるモニターの幅
const.flash.display.Stage.stageHeightInteger アプリウインドウの縦幅。この値は[window]で変更できる。
また、Androidなどモバイルで画面サイズとゲーム画面サイズが合わない場合に自動拡大縮小される場合があり、const.an.xmlConfig.window.height と必ずしも同じ値にならない。
const.flash.display.Stage.stageWidthInteger アプリウインドウの横幅。この値は[window]で変更できる。
また、Androidなどモバイルで画面サイズとゲーム画面サイズが合わない場合に自動拡大縮小される場合があり、const.an.xmlConfig.window.width と必ずしも同じ値にならない。
const.flash.system.Capabilities.isDebuggerBoolean FlashやAIRシステムがデバッグ用の特別なバージョンか
●ANBooks疑似環境実行時──true
●ANBooksビルド実行時、「ant」実行時──true
●「*.air」などのパッケージ──false
const.flash.system.Capabilities.languageStringコンテンツが実行されているシステムの言語コード
const.flash.system.Capabilities.osString現在のオペレーティングシステム
const.flash.system.Capabilities.pixelAspectRatioString画面のピクセル縦横比を指定
const.flash.system.Capabilities.playerTypeStringランタイム環境のタイプ
const.flash.system.Capabilities.screenDPIString画面の1インチあたりのドット数(dpi)解像度をピクセル単位で指定
const.flash.system.Capabilities.screenResolutionXInteger画面の最大水平解像度
const.flash.system.Capabilities.screenResolutionYInteger画面の最大垂直解像度
const.flash.system.Capabilities.versionStringFlash Player又はAdobe® AIRのプラットフォームとバージョン
const.flash.utils.getTimerNumberVM起動経過時間(仮想マシンが起動してからのミリ秒数)を取得
const.Stage.deviceOrientationStringデバイスの現在の方向(iOSでは冒頭、unknown)
const.Stage.mouseXIntegerマウス水平座標
const.Stage.mouseYIntegerマウス垂直座標
const.Stage.orientationStringステージの現在の方向
const.Stage.supportedOrientations.defaultBoolean通常向きが、デバイスでサポートされている方向か返す。
const.Stage.supportedOrientations.rotatedLeftBoolean左に90度回転した向きが、 〃
const.Stage.supportedOrientations.rotatedRightBoolean右に90度回転した向きが、 〃
const.Stage.supportedOrientations.upsideDownBoolean上下逆さ向きが、 〃
const.Stage.supportsOrientationChangeBooleanステージの方向の変更(およびデバイスの回転)をサポートしているかどうか。現在モバイルデバイスのみ
const.StageOrientationEvent.afterOrientationStringステージ方向と同じ値(初期NULL)
const.StageOrientationEvent.beforeOrientationStringステージ方向の前回値(初期NULL)
flash.desktop.NativeApplication.nativeApplication
.systemIdleMode
String(主にiOSなどモバイル端末が)アイドルモードに移行するのを防ぐか。keepAwake、normal(デフォルト)を指定。(詳細)
変数名(sysスコープ)値域・型コメント
sys:an.auto.msecLineWaitInteger未読テキストの改行待ち時間(ミリ秒)
sys:an.auto.msecLineWait_KidokuInteger既読テキストの改行待ち時間(ミリ秒)
sys:an.auto.msecPageWaitInteger未読テキストの改ページ待ち時間(ミリ秒)
sys:an.auto.msecPageWait_KidokuInteger既読テキストの改ページ待ち時間(ミリ秒)
sys:an.skip.modeString スキップモード。an.skip.enabled = trueの際、改行待ちや改ページ待ちをスキップするかどうかの動作を指定する。
"l" …… 改行待ち=する、改ページ待ち=する
"p" …… 改行待ち=しない、改ページ待ち=する
"s" …… 改行待ち=しない、改ページ待ち=しない
(初期値="s")
sys:an.tagCh.canskipBooleanテキストをクリックなどでスキップ可能か
sys:an.tagCh.doWaitBoolean未読テキストにウェイトを掛けるか
sys:an.tagCh.doWait_KidokuBoolean既読テキストにウェイトを掛けるか
sys:an.tagCh.msecWaitInteger未読テキスト待ち時間(ミリ秒)
sys:an.tagCh.msecWait_KidokuInteger既読テキスト待ち時間(ミリ秒)
sys:const.an.sound.BGM.volume0.0〜1.0BGMの基準音量(buf="BGM"の効果音)[volume]で変更できる
sys:const.an.sound.SE.volume0.0〜1.0効果音の基準音量(buf="SE"の効果音)[volume]で変更できる
sys:const.an.sound.SYS.volume0.0〜1.0システムの基準音量(buf="SYS"の効果音)[volume]で変更できる
sys:const.an.ss.※.height1〜〃 画像データの縦幅
sys:const.an.ss.※.size
(※は[snapshot fn="ss:/※"]と保存時指定した画像名)
1〜[snapshot]で保存した画像データのバイト数
sys:const.an.ss.※.width1〜〃 画像データの横幅
sys:const.flash.display.Stage.nativeWindow.x画面左上を(0, 0)とする座標アプリウインドウの座標。[window]で変更できる
sys:const.flash.display.Stage.nativeWindow.y
sys:flash.media.SoundMixer.soundTransform.volume0.0〜1.0アプリ全体の基準音量
sys:TextLayer.Back.Alpha0.0〜1.0バック不透明度。テキストウインドウの背景の濃度。0.0で透明、1.0で不透明。
変数名(saveスコープ)値域・型コメント
save:an.break.height1〜 クリック(改行)待ちマークのサイズを指定。デフォルト値のnullで直前の文字サイズに。
'no_chg'で元素材のまま変更しない(2014年までのAIRNovel仕様)
ただし'no_chg'と数字の組み合わせだと、縦横比を変えないよう数字サイズに合わされる。
save:an.break.width1〜
save:an.doRecLogBooleanテキストを履歴に記録するか
save:an.userFnTailStringこの変数に指定した語尾を追加したファイル名のファイルが、あるなら使う(初期値='')
save:const.an.fnBgmString演奏中のBGMファイル名
save:const.an.layer.(レイヤ名).enabledBoolean文字レイヤごとのイベント発生有効無効を取得する。[enable_event]で変更できる値。初期値true。
save:const.an.loopBgm【廃止2017/02/25】Boolean最後の[playse][playbgm]で指定された loop属性の値
save:const.an.mesLayerStringデフォルト文字レイヤ。レイヤ指定を省略した時はこの値が使われる。[current]で変更できる
save:const.an.scriptFnString処理中のスクリプトファイル名
save:const.an.scriptIdxInteger処理中のスクリプトインデックス(行番号ではなく内部トークン単位)
save:const.an.sLogString履歴テキスト
save:const.an.sound.(バッファ名).fn【追加2017/02/25】Stringそのバッファで最後に再生した音声ファイル名
save:const.an.sound.(バッファ名).ret_msミリ秒最後の[playse][playbgm]で指定されたループ戻り位置
save:const.an.sound.(バッファ名).volume0.0〜1.0(実数)最後の[playse][playbgm][fade系][volume]で指定された目標音量
以下はマクロ内でのみ存在する
変数名(mpスコープ)値域・型コメント
mp:(引数名) マクロを呼んだときの引数
[鮪 text=まぐろ]
なら、mp:textに「まぐろ」という値が入っている。
マクロ内のタグやマクロの引数のみ、%text という表記も出来る
mp:const.an.macro_nameString処理中のマクロ名
mp:const.an.me_call_scriptFnStringマクロの呼び元スクリプト名を示す変数
式の評価と条件分岐  変数の中身を値や他の変数と比較し、その結果によって処理をしたり、しなかったりする事が出来ます。
 これは非常に重要なテクニックで、変数の使い道の半分はこのためにあります。
 例えば変数「tmp:好感度」が75の時、
[title text="割と好かれてる" cond="tmp:好感度 >= 50"]
という文を処理した時、cond属性の文字列に対し「式の評価」が行なわれます。
 変数の値を考えると「75 >= 50」です。「>=」に注目すると「75は50より大なり・大きいか、同じ」なので、式は成立します。
これを「式の評価が真」または「true」と言います。
「>=」は演算子といいます。色んな種類があります。
・a >= b は「aとbは同じ値・または aがbより大きい なら真」→日本語でいう「aはb以上」
・a > b は「aよりbが小さい なら真」(aとbは同じ値 は負)→日本語でいう「aはbより大きい」
・a <= b は「aとbは同じ値・または aよりbが大きい なら真」→日本語でいう「aはb以下」
・a < b は「aよりbが大きい なら真」(aとbは同じ値 は負)→日本語でいう「aはb未満」
・a == b は「aとbは同じ値」
・a != b は「aとbは違う値」(違っていれば、大きくても小さくても構わない)

cond属性はあらゆるタグやマクロに必ずある属性で、「式の評価が真の場合のみ、そのタグ(マクロ)を実行する」という働きがあります。
 よって[title]によりアプリウインドウのタイトル文字列が設定されます。


 別の場合、例えば「tmp:好感度」が49の時には[title]は処理されません。式が成立しないからです。
これを「式の評価が偽」または「false」と言います。

 このように「式を評価」し、処理を変える事をプログラム言語的に「条件分岐」と言います。


 よりダイナミックに処理の流れを変える、条件分岐方法があります。
[jump][call]に対しcond属性で式の評価を行なうのです。
 条件が成立したときだけ[jump][call]するわけです。


 さらに高級言語によくある、if文もあります。
 [if][elsif][else][endif]をサポートしています。

 例えば以下のように記述すると、
[if exp=false]

[elsif exp=true]

[else]

[endif]
 文字レイヤに「ろ」と表示されます。
 それぞれのタグの並びはこの通りで無ければなりませんが、[elsif]は必要ならいくつあってもいいし、なくてもいいし、[else]も不要ならなくてもいいです。

 [if][elsif]などの区間を、「ifブロック」と呼びます。
 ifブロックではラベルの記述「*xxxx」以外なら全ての記述が出来ます。
 タグやマクロ、[jump][call]によるジャンプやコールも可能です。

IF文サンプル(別ページで開く
立ち絵表情差分  立ち絵は表情差分の無い一枚のpngファイルで用意する事も出来ますが、 Photoshopをお持ちならそのままのレイヤ構造で表示したいと思います。
立ち絵表情差分サンプル(別ページで開く

立ち絵顔差分は以下の手順で行ないます。
まずはお手軽な、Photoshop 所有環境の方。
ここではサンプルとして、立ち絵表情変化サンプルを使用します。ダウンロードして開いて下さい。
 ANBooksがゲームを起動します。画面は広いですが同じサンプルが起動します。これを目標として素材を作ります。

1.psdファイルを制作する。
  psdファイルを制作する。身体とのっぺらぼうの顔、目や口を別レイヤにしておく。
 サンプルファイル「tool_face.zip/絵師/蓑浦.psd」を使用します。
 Photoshopで開いてみると、こんな感じです。

2.レイヤ毎にpngファイルを出力する。
3.スクリプトで差分画像の登録[add_face]を行なう。
これらを自動化するツール「ANFace」があります。
 以下の画像クリックでツールをダウンロードし、インストールして下さい。

 起動し、「蓑浦.psd」をドラッグ&ドロップします。
 すぐに「faceフォルダ」にpng群と必要なanスクリプトを出力します。

 ほとんどの場合このままで良いのですが、ここで注意点を。
 レイヤをpngとして切り出す際、「絵以外の部分の空白をなるべく最小化する処理」を行ないます。
 一番下のレイヤを「身体」「ボディ」として扱い、一番下レイヤだけその処理を行なわないのです。
 が、サンプルは身体レイヤが二つあります(和装、洋装)。この場合の対応方法を。

「和装」「洋装」を入れたフォルダにすればOKです! まとめて「ボディ」として扱います。

また、Windowsで許されないファイル名があるため、ANFaceは以下の処理を行ないます。
●レイヤ名に「¥/:*?"<>|」が含まれる場合は「_」に置換する。
●レイヤ名がWindowsのシステム予約語ファイル名(CON、PRN、AUX、NUL、CLOCK$、COM1~9、LPT1〜9)の場合に後ろに「_」を追加する。
●レイヤ名の先頭や末尾にある「.」「 」「 」を「_」に置換。

※「</Layer 」で始まるフォルダ名・レイヤ名は避けて下さい。内部的に正常な処理が行えません。(まずそんな名にしないと思いますが)

4.自動生成された「anファイル」をゲーム中で[call]で呼ぶ。
(サンプルなら、main.an9行目の[call fn="face蓑浦"])

5.スクリプトで使用する。具体的には、
  画像レイヤに対する[lay]タグのface属性に、[add_face]で定義したnameをコンマ区切りで重ねたい順に指定する。
  
  [fg fn="蓑浦_和装" face="蓑浦_口_普通,蓑浦_眼_普通,蓑浦_眉_普通"]
  なら、「蓑浦_和装」の上に「蓑浦_口_普通」を重ね、「蓑浦_眼_普通」を重ね、「蓑浦_眉_普通」を重ねる。
 このようにAIRNovelではたいていの場合、png・jpgなどの画像ファイルとswfアニメファイルの区別無く使えます。
 gifアニメみたいですね(gifそのものは未サポート)。画像とFlashの垣根はほぼ無いわけです。
 swfファイルはAdobe Flashやフリーのツールで制作できます。

(参考)
電子演劇部 立ち絵まばたきをswfファイルで
電子演劇部 ツール:レイヤ切り出し.jsx


Photoshopをお持ちでない方。

1.pngファイルを制作する。
2.スクリプトで差分画像の登録[add_face]を行なう。
  差分画像の表示縦・横位置は、人物など基本となる画像の左上を(0, 0)とし、そこからの相対座標で指定します。
3.以降は上記「Photoshop所有環境の方」と同様です。
自分だけの命令・マクロを作る マクロとは、「タグを寄せ集めて新しいタグを作る」事が出来る機能です。
初めから使えるタグと区別するためにマクロ、といいますが、
使う段に至っては使い心地は全く同じです。

マクロは簡単に作成できます。既存の最も簡単なマクロを例に解説します。
以下は「桜の樹の下には」スクリプト「sub.an」にて定義されているマクロです。

タグ[macro][endmacro]で囲まれた部分がマクロの処理です。
この定義文を一度通ると、以降の行で[lr]と記述する事でその場に
[l][r]
と記述したのと同じ事になります。

[lr]と書けると、初めからあったタグと何ら使い心地が変わりませんね。
このようにタグや他のマクロをまとめ、新たなマクロを作る事が出来ます。


さて、タグには属性がありましたね。マクロにも属性を使用する事が出来ます。

「*」(半角アスタリスク)を指定する事で、[se]マクロに指定された属性を全てそのタグやマクロに渡す事が出来ます
例えば [se fn="音" buf="Sound"]というマクロは……
[stopse fn="音" buf="Sound" cond="mp:fn == null"]
[playse fn="音" buf="Sound" cond="mp:fn != null"]
と記述したのと同じ事になります。

ちなみに、cond指定があります。これはタグと同じく「条件が真、Trueのときのみ有効。実行する」という意味です。
「mp:fn」の「mp:」は「マクロに渡された属性」という意味です。
nullは「属性が指定されていない場合の値」です。
例では「fn="音"」──すなわち「mp:fn == "音"」であり、「mp:fn != null」です。
よって、最終的には
[playse fn="音" buf="Sound"]
と記述したのと同じ動作をします。


「マクロに渡された属性」はもう一つ書き方があって、

という記述は
[txt_lay_v_left * l="&mp:l"|366]
と同じです。%(半角パーセント)を使う方が簡潔ですね。

また例では属性と数値が、|(半角縦線)を挟んでいます。
これはマクロの属性が省略された場合のデフォルト値指定で、前がnullなら後ろの値を採用する仕組みです。
[txt_lay_v_center]
は、
[txt_lay_v_left l=366]
と同じ事になります。
プラグインの導入 *.swfファイル(small Web format、Flash制作ツールで生成したもの)をAIRNovelにロードし、裏表ページのないレイヤとして、あるいは自作タグを拡張する事が出来ます。
この場合のswfファイルをプラグインと呼びます。

プラグインの制作にはFlashやActionScript 3.0の知識が必要ですが、
プラグインを使うだけならその必要はありません。
ここでは、配布しているサンプルplgTweenを例に使い方を説明します。
(クリックでサンプルページへ)

 まずはplgTweenサンプルanbookファイルをダウンロードし、開いて下さい。


 上のサンプルと同じく、灰色四角の「Ans」が画面四辺をバウンドしつつなぞっています。
  実は動く「Ans」は matフォルダ内のans.jpgで、普通の画像ファイルです。

 サンプルのフォルダを見てみましょう。

 anファイルがたくさん有ります。これは単にサンプルが五つ入っているだけで、アニメするのにたくさんanファイルが必要なわけでは有りません……。
 バウンドした ans.jpg 、そして plgTweensy.swf というものがあります。これがプラグインです。

 サンプルに含まれる、「最初に呼び出すスクリプト」WaitTweensy.an を見てみましょう。

1行目でプラグインを読み込んでいます。
2行目で画像レイヤを追加。
(関係ないモノを少し飛ばして……)
6行目で画像を読み込んでいます。
(分かりやすくするために「ans.jpg」と拡張子も書いていますが、出来れば省略するのをお勧めします。暗号化すると拡張子が変わるので)

 後は順次処理を行ない、18行目[jump]で8行目 *loop に戻るのを繰り返します。
 さて、9行目に[tsy]というタグが現われました。しかしタグリファレンスにそんなタグはありません。マクロ? いえ、それ以前のどこにもマクロ定義していません。

 そう、プラグインがタグを追加したのです。
 プラグインにはそれが出来るのです。
これは公式プラグインですのでマニュアルを用意しています。
レイヤなどにTweenアニメを行なうタグです。
AIRNovel プラグイン リファレンス [tsy][wait_tsy]

(参考)
電子演劇部 アニメ機能「Tweensyプラグイン」




 swf ファイルってなんだろう? 疑問が湧いてきませんか。
 表情差分ではまばたきアニメに使えるし、プラグインとしても使える。

 実は「桜の樹の下には」サンプルの改行・改ページの▲のクリック待ちアニメもswf アニメファイルです。
 クリック待ちアニメを差し替えるにはそれぞれ「breakline.swf」「breakpage.swf」ファイルを上書きします。

 アニメするだけのswfファイルは公式のFlash Pro(お高い)やフリーソフトでも制作出来ますし、無料素材として配布されている場合もあります。(使用規約は要チェック)

 もう一つ、今度は「プラグイン plgTween.swf ファイル」により「プラグインとして読み込んだアニメ swf ファイル」を「Tweenアニメ」してみましょう。
 plgTweenプラグインは、他のプラグインまでアニメ出来るのです。(表示するモノがあれば、ですが)
トゥイーンアニメを行なうサンプル(別ページで開く

 動く時計が少し回転して止まったと思います。
 swf 自身のアニメと、Tweenアニメが無関係に独立しています。
 動く時計はmatフォルダ内のanalogclock02.swfで、プラグインとして読み込んだFlashアニメファイルです。

 サンプルpluginTweenに含まれる、PluginTweensy.anの中を見てみましょう。
 2行目の[loadplugin]で「動く時計アニメswf」を「プラグイン」として読み込み、
 7行目の[plugin]でウインドウ中央付近(350, 250)に移動し、プラグインを表示状態にしています。
 プラグインの表示だけならこの二行で説明完了です。(8行に[waitclick]を記述するとよく分かります)

 ──プラグインでは無いアニメswfファイルをプラグインとして読み込む!?
 あまり深く考えず、こういう事も出来るというぐらいでサラッと流して下さい。
 主に裏表のレイヤが不要だったり、ActionScriptにより複雑な表示処理を行ないたい場合の手段で、大変特殊で高度な例です。


 1行目の[loadplugin]で「[tsy]を追加する」プラグインを読み込み、
 10行目の[tsy]では「動く時計アニメswfプラグイン」を2秒かけ、イージングはBack.easeInOutで、0〜90度のランダムで回転させます。
イージングとは変化量の増加のさせかたです。ここでは説明を割愛します。ease要素で指定します。
同じく10行目の[waitclick]でクリックを待ちます。
逆に plgTweensy.swfはタグを拡張するだけなので、[plugin]を使用しない事も小さなポイントです。


 このように、プラグインを使うだけならフォルダにswfを起き、[loadplugin]で読み込むだけです。(必要に応じて[plugin]など)
 タグを拡張するプラグインの場合は添付される資料やサンプルを見ながらスクリプトを記述していきます。
(plgTweensy.swfが追加するタグ、そしてその使い方はサンプルやソースファイルをご覧下さい)

 タグを拡張するプラグインを制作したい場合は「プラグインの自作」を参照してください。

上級テクニック

ビルドの準備をしよう  今まではスクリプトファイルを編集した後、
「ANBooks で【最初から読む】をクリックして実行する」という開発方法を紹介してきました。

 ただ、この実行環境では様々な制約があります。
・埋め込みフォントを使えない。
・開発環境と違うOSにおいて、日本語ファイル名を上手く使えない。
・Win/Mac/Linux/iOS/Androidなどインストール形式(.air、.ipa、.apk)のアプリを製作できない。

 以上の制約を受けず制作するには、ビルド出来る環境を整える必要があります。
 そんなに難しいわけではなく、Javaランタイム(JDK)環境が必要なだけです。さっそくやってみましょう。

 左上の【メニュー】を押し、【ビルド環境設定】をクリックします。

 以下のような【ビルド環境設定】が表示されます。


【Flex SDK設定】をクリックして開いて下さい。


【Flex SDKパス】に、Flex SDKというライブラリをどこに置くかを設定します。
 インストール直後にはデスクトップに置く指定ですが、誤操作を防ぐために他の場所へ移すことを強くお勧めします。
 Cドライブ直下に空フォルダを作り、そこへのファイルパスを指定します。
Flex SDK を置くパスに、半角空白を含んではいけません。
 Windows なら「C:¥FlexSDK」、Mac なら「/Library/flex_sdk/」などがいいでしょう。
 入力したら、【妥当性チェック】をクリックします。

 設置パスが問題なければ、上図のように【設定完了】になります。

 最後に【自己署名ファイル】の作成です。
設定不要になりました。


 さて、動作チェックを行ないましょう。
 プロジェクトの詳細画面に入り、「【ant】ターミナルでビルド&実行」をクリックして下さい。


 おや、「Java/Ant環境設定が済んでいません」等とメッセージが。
(都合によりWindowでのスナップショットです)
(Macの場合はダウンロードページが開きます)


 デスクトップにショートカットが出来ている。指示通りダブルクリックで実行する。
(Macの場合はありません)


 処理が走る。ブラウザを開くから、JDKをインストールしてくれと次の指示が。


 JDKへのリンクをクリック。(JREではなくJDKを)


「Accept License……」をクリックし、開発Windows環境に合わせ、32bit(Windows x86)または64bit(Windows x64)版を選んでクリック。


 exeがダウンロードされるので、開いてインストールを進める。この画面で「閉じる」を選んでいいです。(途中の「ソース」もインストールは不要)


 再びデスクトップのショートカットを実行すると、Antの環境設定に進む。(ANBooksの【ビルド】ボタンをクリックしても、ショートカットを実行するよう促されるので間違えないと思います)


 設定が終了したら黒いウインドウが閉じ、デスクトップからショートカットも消える。


 改めて【ビルド】の「【ant】コマンドラインでビルド&実行」等を行なうと、各種設定を行ないしばらく待たされ、ビルドが成功しプロジェクトが実行される。
(待たされるのはこの一度のみ。他のプロジェクトを作ってももう待たされない)


 これは ANBooks からの起動とは違い、AIRNovel エンジンを「ビルド」し、「Ant から起動」したものです。
 今後はこの「ビルド」する方法で高度な開発が出来るようになります。(組み込みフォントを生成したり、リリース用のairファイルを生成したり)
 素材やスクリプトを修正してはビルドしていきます。
(これまでの ANBooks を使った実行も引き続き可能です)

RC4暗号化と復号化
ANBooksを使用する方は特に読まなくても大丈夫です。
 スクリプト・画像・音声・プラグインファイルは、そのままではユーザーに丸見えです。(以前「システムのディレクトリ構造」で実際に中を見ましたね)

 ここではAIRNovelに組み込まれているRC4暗号でファイルを暗号化し、AIRNovelにのみ見える形にする方法を説明します。
(どんな暗号にも絶対安全はありません。ご了承ください)

任意ファイルをRC4暗号化するソフト(ANCoder)」を使用して説明します。インストールして下さい。

 起動すると上図のような画面になります。
 何か適当な画像ファイルをドラッグ&ドロップしてみて下さい。

 その画像があったフォルダに、暗号化したファイル(拡張子の最後が「_」(半角アンダーライン))が生成されます。(例:a.pngならa.png_)
 これは「hoge」という暗号キーで画像ファイルを暗号化したものです。

 この画像ファイルはどんな画像閲覧ソフトや機能でも見れなくなっています。確認してみてください。(拡張子から「_」を取っても見れません)


 次にこの暗号化したファイルから元の画像ファイルを生成します。これを復号化と言います。

 暗号化したファイルをさらにドラッグ&ドロップしてみて下さい。
「_」が二つついたファイルが生成されます。

 二つの「_」を削除し、(最初の画像ファイルと名前がぶつかるので)ファイル名も変える(例えば b.png)と、閲覧できる画像ファイルである事が判ります。
RC4暗号は暗号キーと復号キーが同じになる暗号技術です。
またRC4において暗号化と復号化は同じ処理です。
つまり「hoge」で暗号化したファイルは、「hoge」で元のファイルに戻せるのです。
 最初のファイルと暗号化→復号化したファイルの内容は、完全に同じ物です。

RC4はストリーム型で処理も高速とはいえ、復号化にはそれなりの時間が掛かります。
必ずしも暗号化が不必要なファイルは暗号化しない事もテクニックの一つです。
(例えば[trans]のrule画像、埋め込みフォントswfなど)

 また画像・音声ファイルは構造上、先頭から数百バイトを暗号化するだけで致命的に暗号化されます。ファイルサイズも大きくなりがちなため、AIRNovelや関連ツールでは「画像・音声ファイルは先頭数百バイトだけ暗号化する」という動作をします。
 その際、先頭から何バイトを復号化するかを指定できます。「*.anprjファイルの書式」を参照し活用してください。
普通はデフォルトのままで、変える必要がないと思います。
自動暗号化処理  ゲームが大規模になるとANCoderで一つ一つ暗号化するのも大変です。
 ANBooksなら大量の素材も手軽に暗号化処理を行なえます。
ビルド環境設定を済まして下さい)

 暗号化が行える(暗号化する必要がある)のはプロジェクトフォルダ内の素材のみです。
 サンプルプロジェクトでは、mat フォルダがそれに当たります。
 スクリプトと画像ファイルが入っていますね。

・iconフォルダはアイコンが入っているだけです。
・SDKフォルダはビルドの際に必要なだけで、配布されません。

【実行形式パッケージ〜】−【素材暗号化】をクリック。


 素材暗号化についての設定が現われます。
【フォルダ単位の暗号化】で「mat/」をクリックする。

「する」になったら設定完了です。


 上部に戻り、ビルドして下さい。
(よく見るとターミナルに暗号化の様子が出力されています)


 ゲームが起動します。暗号化する前と動作は同じですが、
 フォルダを見ると「_」が付いた暗号化ファイルになっています。


 元の素材はどこ? ──自動的に場所を移しています。
「Work/before_anc/mat」にあります。

 ここの素材を変更し、ビルドすると自動的に暗号化→ビルド起動します。


 トグルスイッチを押して、ビルドするだけ。簡単ですね。
ゲーム制作中は素材を変更するたびに暗号化処理をしていると作業が待たされると思いますので、リリース前頃にそろそろ暗号化して作業しようかな、という感じかも知れませんね。


 この処理の暗号化キーは、さっきの【素材暗号化】にあります。
 試しにトリプルクリックなどで全選択してコピーし……


 暗号化バイト数を「0x360」、画像ファイル(拡張子「png_」)をドロップ。

「0x360」は設定ファイル「config.anprj」に「<coder len="0x360"/>」と記述された「先頭から何バイトを暗号化・復号化するか」の値です。

 生成された復号化ファイル(拡張子「png__」)の拡張子を「png」にすると、元の画像に戻ります。

復号キーの隠蔽
この項は上級者向けです。初心者は読み飛ばしてもOKです!

 暗号化ファイルを用意したとして、AIRNovelは復号キーさえ判れば復号化できます。
 復号キーはAIRNovelソースファイルに記述する必要があります。
 (プロジェクトフォルダ)/SDK/an_sdk/com/fc2/blog38/famibee/AIRNovel/cripter.as を見て下さい。

cripter.as(必ずUTF-8, LFで開く・保存、コメント行は省略)
	import com.fc2.blog38.famibee.converter.CriptRC4;

	private static const	_o:CriptRC4	= new CriptRC4("〜省略〜");
	private static const	_:Function	= _o.cript;
上記で「〜省略〜」とある部分に、ANBooksが復号キーを記述しビルドします。それにより復号キーを組み込んだAIRNovelのswfファイルが生成され、暗号化した素材ファイルを復号化出来るわけです。


 ただ、公開されたcripter.asのままでは復号キーが平文で含まれてしまいます。
 cripter.asを改造する事でより厳密に隠蔽する事ができます。(Action Script 3.0の理解が必要です)

 上記例の4行目、暗号化処理への関数参照さえ用意すればAIRNovelが認識できます。
例えば以下のようにします。
	import com.fc2.blog38.famibee.converter.CriptRC4;

	private static var	_c:CriptRC4	= null;

	private static var	_:Function	= function (data:ByteArray, len:uint=0):ByteArray {
		_c = new CriptRC4(/* 〜平文以外の方法、処理などで復号キーを指定〜 */);
		
		_ = _c.cript;	// 関数参照を書き換え。もうnew CriptRC4()の必要なし

		return _(data, len);
	}


 できれば暗号化スクリプト以外は実行できないようソースファイルの変更が必要です。
 例えばmain.anというファイルを作られたら、いくらでも画像閲覧できてしまいます。(config.anprjに指定した時。画像のファイル名はフォルダを覗けば見える)

 簡単な方法としては「LoadMng.as」のEXT_URLLOADERから非暗号化拡張子を削除します。
static	public const	EXT_URLLOADER	:String	= "an_|txt_|txt";
 他の方法としては、変数 full_path が暗号化スクリプトかどうか調べる等の処理を入れる方法もあります。
 この形なら AIRNovel 本体ソースファイルを触らずに済みます。(addition_script.as というソースファイルはその為の位置づけです)
「addition_script.as」に以下を追加します。
// 暗号化スクリプトしか実行させない。
// エラーメッセージは解析ヒントになるので出さない。
if (full_path.substr(-1) != "_") throw("");
traceタグとデバッグ
 AIRNovelでは[trace]にて文字列をデバッグ表示に出力(ANBooksにも)出来ます。これにより変数の中身や、ifブロックの処理の流れがわけ分からなくなったときに、追いかけやすくなります。
 [trace]を便利に使えるようになる頃には、上級者の仲間入り!
プラグインの自作
この項は上級者向けです。初心者は読み飛ばしてもOKです!
プラグインを作ってみましょう。
 動的ライブラリとしてAIRNovelの機能を拡張し、可能性を広げるものです。
これにはActionScript3.0とFlex・AdobeAIRライブラリについての知識が必要になります。
またAdobe社のセキュリティ方針により、Stageオブジェクトなどにアクセスできないなど一部制限があります。

 左上メニューの【新規作成】をクリックで、一番下にある【シンプルなプラグインを作成】して下さい。
 ここではプロジェクト名例として「abc」とします。


 必要な素材をダウンロードしてから新規プロジェクトが一番上に追加されます。

 これは「最初から読む」出来ません。ビルド専用です。(プラグインをビルドする必要があるため)
 さっそくビルドしてみるのもいいでしょう。


 これはどういうプラグインなのか、まずは使っているスクリプトから見てみましょう。
「mat/main.an」から見てみます。

 6行目で「plgAbcプラグイン」を読み込み、
 13行目で[hogehoge]タグの「値という名の属性」に「変数 v の中身」を渡していますね。
 14行目は「&ret&」で「変数 ret の中身」を&&文法で文字表示しています。
 16行目はコメントどおり、変数 v を更新しています。
 あとは永久ループです。

 このサンプルプラグインは、sourceフォルダにプラグインのActionScriptソースが用意されています。
 初めから「[hogehoge]タグを追加する処理」が入っています。入力と出力のよいサンプルとなるでしょう。

 以下はプラグインのAS3ソースファイルです。
 [hogehoge]タグという「何もしない」タグをAIRNovelに追加します。

plgAbc.as(必ずUTF-8, LFで保存)
/*
 * plgAbc
 * AIRNovel用 プラグイン
 *	〜機能説明〜
 */
package {
	import flash.display.Sprite;

	public final class plgAbc extends Sprite {
		private var	AnLib		:Object		= null;

		public function plgAbc() {super();}
		public function init(hArg:Object):Boolean {
			AnLib = hArg.AnLib;
			if (AnLib == null) {hArg.ErrMes = "AnLib == null"; return false;}

			// 追加する自作タグ名とその処理関数
			if (! AnLib.addTag("hogehoge", hogehoge)) {
				hArg.ErrMes = "addTag [hogehoge] err.";
				return false;	// 追加失敗ならfalse
			}

			return true;	// 追加成功ならtrue
		}

		// 処理関数
		private function hogehoge(hArg:Object):Boolean {
			// 自作タグ処理を記述
			var v:Number = AnLib.argChk_Num(hArg, "値", 10);
				// [hogehoge 値=3] なら、
				// 属性「値」から値を受け取り、ActionScript変数vに3を入れる
				// argChk_Num()の三つめの「10」は省略時のデフォルト値
			
			++v;	// +1してみる
			
			AnLib.setVal("ret", v);	// AIRNovelの変数retに計算結果を入れる

			return false;
				// 通常はfalseで終了。
				// trueならスレッド終了を待つが、より理解が深まってから使うべし
		}
	}
}
 ビルドするとplgAbc.swfファイルが生成されます。
 [loadplugin]でAIRNovelに読み込むと、[hogehoge]タグが使えるようになるわけです。
 小さなサンプルスクリプトを作って試すと、トライ&エラーのサイクルが小さく早く廻るのでお勧めです。

 あとはこのソースファイルをテンプレートとし、あなたの独自プラグインを作成してください。

 できればプラグインを公開して、皆の財産として共有しましょう。
 ソース公開時は、出来ればMITライセンスでお願いしたく思います。

 公開済みのプラグインも参考にして下さい。
  ●AIRNovel プラグイン リファレンス
  ●電子演劇部 タイル塗りつぶしプラグイン
  ●電子演劇部 画像スクロールプラグイン
  ●電子演劇部 文字表示拡張プラグイン「plgMultiTxt」
  ●電子演劇部 文字入力プラグイン「plgTxtIn」
  ●電子演劇部 特殊効果「plgTweensyFXプラグイン」
  ●電子演劇部 乱数機能「plgSFMTプラグイン」
  ●電子演劇部 画面揺れ機能「plgQuakeプラグイン」
  ●電子演劇部 フィルター機能「plgASFilterプラグイン」
  ●電子演劇部 アニメ機能「Tweensyプラグイン」
  ●電子演劇部 動的ライブラリ「Papervision3Dプラグイン」


●動的ライブラリの内部処理について
 [loadplugin]タグの内部処理ではflash.display.Loaderにより画像やswfファイルをロードします。
(ちなみに画像をロードした場合はflash.display.Bitmap、
 swfファイルはflash.display.MovieClipとしてオブジェクトが生成されます)
 その際、ロードしたオブジェクト(普通MovieClip)に「init」というメンバがあれば以下の形式の関数と見なし、コールします。
 plgAbc.asにあるinit関数がそれです。
public function init(hArg:Object):Boolean {...}
  hArg……[loadplugin]の引数や、
      AnLibメンバにAIRNovel内部関数へのポインタ
  戻り値……ActionScript Thread Library待ちの必要があるか。
      画像ロード待ちなど、必要以外はfalseを推奨。通常false。
<連想配列hArgのAnLibメンバの内容>
hArg.AnLib = {
   getVal : function(後述)  // 変数の値を取得する
  , setVal : function(後述)  // 変数に値を代入する
  , callTag : function(後述)  // タグやマクロを呼び出す
  , addTag : function(後述)  // タグを追加する
  , addEvent : function(後述)  // イベントを追加する
  , putErrMes : function(後述)  // エラーメッセージを出力する
  , argChk_Num : function(後述)  // 実数チェック
  , argChk_Boolean : function(後述)  // Booleanチェック
  , searchPath : function(後述)  // サーチパス内からファイルパスを探す
  , getLayerDO : function(後述)  // レイヤDisplayObject取得
  , getPluginDO : function(後述)  // プラグインDisplayObject取得
  , getSnapshot : function(後述)  // スナップショット取得
  , waitCustomEvent : function(後述) // 自作イベント待ち
  , buildBmpFilter : function(後述)  // BitmapFilterを生成する
  , getSwfVersion : function(後述)  // swfVersionを取得
  , getIsAIR : function(後述)    // 実行環境はAIRか
  , addPicFormat : function(後述)   // 画像拡張プラグイン処理を行なう
};
// 変数の値を取得する
function getVal(arg_name:String):Object {...}
  arg_name……変数名(→[let]変数名書式)
  戻り値……取得した変数の値
// 変数に値を代入する
function setVal(arg_name:String, val:Object):void {...}
  arg_name……変数名(→[let]変数名書式)
  val……代入する値
// タグやマクロを呼び出す
function callTag(name:String, hArg:Object):Boolean {...}
  name……タグ名
  val……タグ引数、キー名と値の連想配列
  戻り値……ActionScript Thread Library待ちの必要があるか。
// タグを追加する
function addTag(tag_name:String, tag_fnc:Function):Boolean {...}
  tag_name……タグ名
  tag_fnc……タグ処理関数
    タグ処理関数は以下の形式で無ければならない。
    function (hArg:Object):Boolean {...}
      hArg……追加したタグに渡された引数。キーと値の連想配列
      戻り値……ActionScript Thread Library待ちの必要があるか。
            画像ロード待ちなど、必要以外はfalseを推奨。通常false。
    
  戻り値……true:タグ追加成功
// イベントを追加する
function addEvent(ed:DisplayObject, type:String, hArg:Object):Boolean {...}
  ed……FlashイベントをListenするDisplayObject
  type……Flashイベント名(KeyboardEvent.KEY_DOWN等のイベント定数)
  hArg……以下の内容の連想配列
      <hArgメンバの内容>
      hArg = {
         fn :〜  // イベント発生時にジャンプする先のスクリプトファイル。
        , label :〜  // この辺の値は[event]を参照
        , call :〜  // 〃
        , del :〜  // 〃
        , global :〜  // 〃
        , key :〜  // イベント詳細。keydownイベントで「どのキーが」押されたのか、など。
        , fnc :〜  // イベント発生時にコールする関数。関数形式は以下の通り
            function (e:Event):void {...}
      };

[s]待機時にFlashイベントをトリガにしてActionScript処理を行える。
ただし一つのオブジェクトへのイベントは最大一つまで。
直接ActionScript処理をしたい場合以外はcallTagで[event]すれば事足りる。
// エラーメッセージを出力する
  メッセージを出力するだけで、アプリを停止しない。
  デバッグ表示に出力する
function putErrMes(mes:String):void
  mes……エラーメッセージ文字列。

※デバッグのため、デバッグメッセージ出力にも利用できそう
// 実数チェック
  連想配列のメンバが実数かどうかチェックする
function argChk_Num(hash:Object, name:String, def:Number):Number {...}
  hash……連想配列
  name……チェック対象メンバ名
  def……連想配列に存在しない場合のデフォルト値。
      NaNを指定し連想配列に存在しない場合、
      必須メンバ不足としてエラーメッセージ&アプリ停止
  戻り値……取得した変数の実数値
// Booleanチェック
  連想配列のメンバをBooleanとして判定する
function argChk_Boolean(hash:Object, name:String, def:Boolean):Boolean {...}
  hash……連想配列
  name……チェック対象メンバ名
  def……連想配列に存在しない場合のデフォルト値
  戻り値……取得した変数のBoolean値
ActionScript3.0でそれぞれの型を Boolean 型に変換した場合の値は以下のようになります。
  Undefiend → false
  Null → false
  Boolean → 変換前のオブジェクトと同じ
  Number → 0 または NaN は false、それ以外の値は true
  String → 空文字列は false、それ以外の値は true
  Object → true
この関数は以上のルールに加え、例外的に"false"という文字列入力に対し「false」を返します。
// サーチパス内からファイルパスを探す
  サーチパスはAIRNovelプロジェクトファイル「〜.anprj」に列挙したもの。
  見つからない場合はエラーメッセージ&アプリ停止
function searchPath(fn:String, ext:String = null):String {...}
  fn……ファイル名。拡張子は省略可能
  ext……サーチ対象拡張子群。「|(半角縦線)」で区切ると複数可能
  戻り値……見つかったファイルパス

※サーチパスという機能により複数ディレクトリを跨って検索されるため、
 同じファイル名+拡張子のファイルが別ディレクトリに存在していると
 意図した動作をしない。システム動作対象外
// レイヤDisplayObject取得
  レイヤ名からDisplayObjectを取得する
function getLayerDO(name:String, isFore:Boolean):DisplayObject {...}
  name……取得するレイヤ名
  isFore……取得するのは表ページか
  戻り値……取得したDisplayObject
// プラグインDisplayObject取得
  プラグイン名からDisplayObjectを取得する
function getPluginDO(name:String):DisplayObject {...}
  name……取得するプラグイン名
  戻り値……取得したDisplayObject
// スナップショット取得
  画面のスナップショットを取得する
function getSnapshot(bmd:BitmapData, hArg:Object):void {...}
  bmd……取得したスナップショットを書き込むBitmapData
  hArg……以下の内容の連想配列
      <hArgメンバの内容>
      hArg = {
         layer :〜  // スナップショットを取得する対象のレイヤ名
        , page :〜  // 〃対象のページ。foreかback。
      };
  hArg.layer……スナップショットを取得する対象のレイヤ名
        (半角カンマ区切りで複数レイヤを指定可能)。
        省略時はレイヤ全て(プラグイン含まず)。
        「plg:プラグイン名」と記述する事でプラグインも指定できる。
  hArg.page……〃対象のページ。foreかback。
  戻り値……取得したDisplayObject
// 自作イベント待ち
  自作プラグインで使用。イベント待ちとキャンセルを実現する
function waitCustomEvent(onBreak:Function, edComp:IEventDispatcher, canskip:Boolean = true):Boolean {...}
  onBreak……待機中断イベント処理
  edComp……完了イベントディスパッチャ
  canskip……クリックやキーボードでウエイトをキャンセルできるか
  戻り値……ActionScript Thread Library待ちの必要があるか。
// FilterFactory生成
  引数を与えるだけでBitmapFilterを生成する。
  AIRNovel本体のFilterFactory.build()を使わせるため、
  フィルタを使用するプラグインでAIRNovel本体と文法を揃えられる
function buildBmpFilter(hArg:Object):BitmapFilter {...}
  hArg……生成するフィルタの初期値([trans]を参考に)
  戻り値……生成したActionScript BitmapFilterオブジェクト
  (AIRNovel本体のFilterFactory.build()そのものをコール)
// swfVersionを取得
function getSwfVersion():uint {...}
  引数……なし
  戻り値……取得したswfVersionの値
// 実行環境はAIRか
function getIsAIR():Boolean {...}
  引数……なし
  戻り値……実行環境がAIRならtrue
// 画像拡張プラグイン処理を行なう
function addPicFormat(ext:String, getDo:Function, ba2pic:Function, hArg:Object):void {...}
  ext……追加サポートする拡張子
  getDo……ひとまずすぐ返す表示オブジェクト(速さ勝負、初期化してなくていい)
  function ba2pic():void {...}……ファイルデータから内容を生成する処理
     do:DisplayObject……getDoでひとまず返したObj、これをこの関数で初期化
     ba:ByteArray……該当拡張子ファイルデータ、これからgetDoで返した内容を生成
     fncComp:Function……生成後にコール
  戻り値……実行環境がAIRならtrue
  hArg……その他引数

ここまでが[loadplugin]の役割で、以降は動的プラグイン側の処理が中心です。

コールされたプラグイン側はその際に「初期化処理」や「独自タグ追加処理」などを行い、 本体の機能を拡張する事が出来ます。
サンプルプラグインのソースファイルが理解の参考になると思います。
  →動的ライブラリ「Papervision3Dプラグイン」
  →アニメ機能「Tweensyプラグイン」
埋め込みフォントの使い方  ゲームの雰囲気に合わせてフォントを変えたい──。
 ノベルゲームの「文字」は食事でいえば「ご飯」にあたる重要なもの。そこに注目するのは当然の欲求ですね。

 埋め込みフォントを使うとOSやユーザー環境に縛られず、あらゆるプラットフォームにおいて同字体、同字形で文字表示できるようになります。

 「フォントファイル」を「font」フォルダに置き、
【フォントswfビルド】し、
【ビルド実行】で表示を確認……するだけです。(AIRパッケージも同様です)

注意:
● サポートするフォントファイル拡張子は「ttf、otf、ttc」です。
ANBooks の【ビルド環境設定】を済ましておく必要があります。
フォントは組み込んでの使用が許諾されるもののみ使用してください。
●【疑似環境実行】では埋め込みフォントが反映されません。
 【ビルド実行】、あるいはAIRアプリ化する必要があります。

 ここでは「KFひま字」(by KF STUDIO)をAIRNovelにて使用する方法を説明します。

 1.まずKF STUDIOサイトからフォントファイルをお借りし、手に入れて下さい。(KFhimaji.otfです)
 そしてプロジェクトフォルダに(無ければ)「font」フォルダを作り、そこへ置いてください。

 フォントをOSにインストールすると、組み込みがきちんと出来ているのか、きちんと出来ていないのにOSが補ってくれているのか分からなくなります。
 Macなら、開発中だけでも標準アプリFont Bookにて【使用停止】(切)にしておいて下さい。

 2.【フォントswfビルド】をクリックします。



 3.【ビルド実行】するとあらゆる文字のフォントが「KFhimaji」になっている。(ボタンは画像なのでそのまま)




 b1.別のフォントを試してみましょう。
 「かんじゅくゴシック」をお借りしましょう。ダウンロード・解凍し、かんじゅくゴシック.otfファイルをfontに置きます。
(フォントファイルが一つだけになるようにして下さい)


 b2.【フォントswfビルド】【ビルド実行】するとフォントが「かんじゅくゴシック」になっている。
 (ゲーム全体のフォントを変えたあとは「最初から読む」で確認して下さい)




ポイント:
 スクリプトに表示文字が増えるたびにフォントファイルを再度ビルドするのは面倒です。
 開発中は一度「フォントswfビルド(全文字を含む)」で全ての文字情報を含んだフォントファイルを生成しておき、開発に集中するのも手です。
 リリース直前に一度、(最低限の文字で)ビルドを行なうわけです。




 さて、全体のフォント変更方法は分かりました。
 次に部分的に変更したい方法について説明します。

 c1.使用したいフォントファイルを、fontに追加。(ここでは先の「KFhimaji」を使用)


 c2.フォントを変えたい箇所のスクリプトを開き、タグでフォントについての記述を追加します。方法は以下の二種です。
  ●[lay] の layout属性内にフォント名を指定。(使いどころ:ページ単位で変更するイメージ)
  ●[span] の layout属性内にフォント名を指定。(使いどころ:一時的な場所で使うイメージ)

 ここでは、[span]を使用してみましょう。一時的に「KFhimaji」フォントを使用し、「かんじゅくゴシック」に戻します。
(改行は不要です。見やすくしただけです)
 桜の樹の下には
[span layout='fontFamily="KFhimaji"']
屍体
[span layout='fontFamily="かんじゅくゴシック"']
が埋まつてゐる![plc visible=false]

 c3.一部分だけフォントが反映されました。
 注意:縦書きで点や丸の様子が変な場合
  フォントが縦書きに対応していないためです。(画像例は「ロゴたいぷゴシックコンデンスド」)
 注意:エラーになる場合
  フォントファイル名でエラーになる場合があります。
  例えば「GenEi-P-Heavy_ver8」だと、ファイル名に「-(半角ハイフン)」が入っていると一部環境でトラブルが起こりますので、「GenEiGo.ttf」などと変名します。(Androidでは日本語ファイル名がトラブルになります)

※もし「かんじゅくゴシック」に「屍体」という文字の字形情報が含まれていない場合、以下のようにカンマ区切りで書くことも出来ます。
 カンマ区切り指定は、前から順番に字形情報を探しに行き、見つからなければ次々に探していきます。
 桜の樹の下には
[span layout='fontFamily="かんじゅくゴシック, KFhimaji"']
屍体が埋まつてゐる![plc visible=false]
 ※埋め込みフォントは一番前のモノのみ準備されます。


 また、以下のようなフォント指定機能があります。

●;#USE-FONT (フォントファミリー名)
 例);#USE-FONT IPAexゴシックcff
 スクリプトのこの指定行以降は、指定したフォント「だけ」を使用する指定。
 さらにこの後に「;#USE-FONT」指定をすることが何度でも出来る。
 フォントファイルを作りたくないスクリプトには冒頭に「;#USE-FONT ####」などとあり得ないフォント名を指定して、処理を回避するテクニックもある。

●;#FONT (フォントプラグインに含める文字の羅列)
 例);#FONT 現在ver0.123456789
●;#FONT (4〜5桁16進数の文字コードで範囲指定)
 例);#FONT 3040-309f

 通常はシナリオテキストや[ch =text=""]などに含まれる文字を調べ、その文字をフォントプラグインに含めるように動作しますが、文字列操作や組み込み変数の値など、スクリプトに現われない文字にフォントを適用したい場合に、直にこの形で記述出来ます。

「特定の文字だけフォントが適用されない!」という場合、
●「フォントが適用される文字」は、【たまたま】シナリオテキストに含まれていて、ANBooksがそれを見て【この文字の字形は必要なんだな】と判断している
●「フォントが適用されない文字」は、「シナリオテキストに含まれていなかった」
という理由が考えられます。(変数の中で使用し、[ch]などで表示しているようなモノとか)
この際、上記の「;#FONT」にて文字を指定して下さい。シナリオ出現と「;#FONT」指定が重複してても問題ないですよ!

 漢字だけ含めたい、記号を含めたい場合など文字コードを調べたい場合は、この辺が参考になると思います。
  ユニコード一覧表:Unicode(文字入力可能)
 いくつか領域があるので、複数行使って複数指定して下さい。(CJK = Chinese-Japanese-Korean)

 日本語ノベルで使いそうな文字コードは、大体以下の範囲です。
基本ラテン文字 ;#FONT 0020-007F
一般句読点 ;#FONT 2000-206F
CJKの記号及び句読点 ;#FONT 3000-303F
平仮名 ;#FONT 3040-309F
片仮名 ;#FONT 30A0-30FF
  (上三つをまとめて ;#FONT 3000-30FF)
CJK統合漢字拡張A ;#FONT 3400-4DBF
CJK統合漢字 ;#FONT 4E00-9FFF
CJK互換漢字 ;#FONT F900-F9FF
半角・全角形 ;#FONT FF00-FFEF
CJK統合漢字拡張B ;#FONT 20000-2A6DF
CJK互換漢字補助 ;#FONT 2F800-2F8FF

セーブデータの保存パス  AIRNovel プロジェクトは、変数(sysスコープ、saveスコープ)やセーブデータを以下の場所に保存します。
 リリース前にクリアな状態からテスト(大いに推奨、むしろ絶対して下さい)をしたい場合、ここにあるファイルをゴミ箱へ捨てることで、インストールしたての状態のようにテストできます。

★疑似環境実行(「最初から読む」ボタンによる実行)
OSPath
Mac OS X /Users/[user]/Library/Application Support/com.fc2.blog38.famibee.ANBooks/Local Store/nobld/[id]/
Windows 7 C:\Users\[user]\AppData\Roaming\com.fc2.blog38.famibee.ANBooks\Local Store\nobld\[id]\
Windows Vista
Windows XP C:\Documents and Settings\[user]\Application Data\com.fc2.blog38.famibee.ANBooks\Local Store\nobld\[id]\
★ビルド実行、リリースパッケージ
OSPath
Mac OS X /Users/[user]/Library/Application Support/[id]/Local Store/
/Users/[user]/Library/Preferences/[id]/Local Store/(2012/11以前発表のノベルはこちら)
Windows 7 C:\Users\[user]\AppData\Roaming\[id]\Local Store\
Windows Vista
Windows XP C:\Documents and Settings\[user]\Application Data\[id]\Local Store\
Linux /home/[user]/.appdata/[id]/Local Store/
※[user]はインストールしたユーザー名、
 [id]は、config.anprj 内 save_ns name属性 の名前です。


 例えば疑似環境実行なら……

参考:アプリケーション記憶領域ディレクトリ

公開・頒布しよう

ANBooks同士で作品共有  ANBooks で製作したプロジェクトは、ANBooks ユーザーに渡すことが出来ます。
 拡張子 anbook 形式のファイルにします。(本質的に、必要最低限なファイルを zip 圧縮したものです)
 詳細画面で【anbook形式にパック】をクリックするだけで生成します。

 これで配布しやすい&ダウンロードしやすいと思います。
その際、素材やスクリプトファイルのファイル名に多少注意点があります。
サンプル配布と日本語ファイル名

それらに気をつければ、非常に便利な機能です。
動かしてみたほうが早いサンプルプロジェクトや公開プラグインも、この形式で配布しています。
 →AIRNovel 機能ギャラリー
 日本語ファイル名を避けた方が賢明です。
 AIRアプリ化(後述)すれば、そのような懸念はなくなります。
AIRアプリ化について  ここではAdobe AIR アプリ化する方法(Windows/MacなどデスクトップPC向け)を説明します。
(最終目的は「〜.air」というインストールファイルを作る事です)
1.(最初の一度のみ)アイコンを用意する。
2.インストーラー向けに説明などを設定する。
3.Adobe AIR パッケージを生成する。


●1.(最初の一度のみ)アイコンを用意する。
サイズの違う四つのアイコンを作る必要があります。
同じ絵柄でなくても良いですが、あまりにバラバラだとユーザーが混乱します。
  
OSや実行環境、ランチャーなどで使い分けられるためです。

 手軽に作るなら、ClockMakerさんの「Icon Generator」を使用しましょう。
 ですが作品の個性を発揮する小さなポイントでもあり、出来るだけオリジナルの素材を使用したアイコンを作るべきでしょう。

 ANBooksの書庫一覧画面用に 80x80ドットサイズの「icon.jpg」、
iconフォルダに 16x16、32x32、48x48、128x128サイズのアイコンファイル(ダミーファイルを上書き)を準備します。



●2.インストーラー向けに説明などを設定する。
 以下の項目について設定して下さい。
・【出版者】……著作権表示
・【内容】……インストーラーに表示する作品内容
・【バージョン】……「0」「0.0」「0.0.0」のいずれかの書式で、数値を入力。
   (バージョンアップ時は)変更する。




●3.Adobe AIR パッケージを生成する。
 制作やデバッグが終了し、リリースしたくなったら、*.airファイルを生成しましょう。
 サンプルゲームなども最終的には拡張子airの「UnderCherry.air」という
 一つのファイルを生成し、配布しているだけなのです。
 これがAIRNovelゲーム制作の完成品です。

【実行形式パッケージ】−「【ant air】Adobe AIR パッケージ(air)」をクリックします。


 ターミナルに色々表示されますが、しばし待ちます。
BUILD SUCCESSFUL」が表示されればOKです。



 開発環境により、以下のエラーが発生する場合があります(緑文字部分)
air:
[java] Could not generate timestamp: handshake alert: unrecognized_name

BUILD FAILED
C:\Users\***\AppData\Roaming\com.fc2.blog38.famibee.ANBooks\Local Store\unpack\(プロジェクト名)\build.xml:49: Java returned: 10
 これはネットに繋がっていない、或いはプロキシがない場合に起こるようです。
    Adobe AIR * ADT コード署名のオプション
    【ADT がタイムスタンプサーバーに接続できない場合、署名はキャンセルされ、パッケージは生成されません】

「build.xml」の143行目あたりに「<arg line="-tsa none"/>」の1行を追加すると、ビルドが通るようになります。
ただし、タイムスタンプなしでパッケージ化された AIR アプリケーションは、署名証明書の有効期限が切れるとインストールできなくなります

 しばらくすると、「(プロジェクト名).air」ファイルが生成されます。
 このファイルを配布するわけです。


 *.air ファイルをダブルクリックするとゲームのインストールが始まるか、
ゲームが正しく動作するか、正常に動作する事を確認してください。
(設定が四角部分に反映されているのが判ると思います)




 ちなみに *.air をもう一度開くと、以下のダイアログになります。

以上です。


以下は余談です。
 数年前にリリースした airパッケージをビルドする際、以下のようなエラーが発生してビルド失敗する場合があります(緑文字部分)
air:
[java] Your certificate expired on Mon Dec 15 11:37:59 JST 2014

BUILD FAILED
 これは自己署名ファイルを最初に生成してから、ビルドした今までの間で、自己署名ファイルの有効期限が切れてしまったためです。
 build.xmlのターゲットairの部分を以下の感じに変更します。
  (いったん ${app_name}0.air というファイル名でビルドし、
   -migrateオプションで 古い署名を追加した ${app_name}.air を生成)
	<target name="air" depends="cmp,anc,mk_signature">
		<echo message="== Win/Mac/Linux向けパッケージ(${app_name}.air)を生成します"/>
		<java jar="${ADT.JAR}" fork="true" failonerror="true">
			<arg line="-package"/>
			<arg line="-storetype pkcs12"/>
			<arg line="-keystore '${my_store_p12}'"/>
			<arg line="-storepass ${my_sign_key}"/>

			<arg line="${app_name}0.air"/>

			<arg line="prj-app.xml"/>
			<arg line="${app_name}.swf config.anprj icon album bgimage bgm config fgimage image menu rule scenario sound ssmenu system"/>
		</java>
		<java jar="${ADT.JAR}" fork="true" failonerror="true">
			<arg line="-migrate"/>

			<arg line="-storetype pkcs12"/>
			<arg line="-keystore (古い署名ファイル).p12"/>
			<arg line="-storepass (古い署名のパスワード文字列)"/>

			<arg line="${app_name}0.air"/>
			<arg line="${app_name}.air"/>
		</java>
	</target>
【参考】
(証明書の変更)Adobe AIR * AIR ファイルへの電子署名
Adobe AIR * ADT migrate コマンド
Adobe AIR * ADT コード署名のオプション
Androidアプリ化の方法 ここではAdobe AIR アプリ化する方法(Android 向け)を説明します。(最終目的は「〜.apk」というアプリファイルを作る事です)
「AIRアプリ化について」を読むなり実行するなり、理解した上で読み進めて下さい。手順がかなり近いためです。

手順は Desktop PC 向け(Windows/Mac)とほとんど同じですが、違うのは「Androidテンプレートで作る」「画像素材のサイズ(Android画面に合わせるなど)」です。
Android実機でのデバッグは以下のようにします。

●1.あるいはUSBで実機を繋ぐ。
 ※「「アプリケーション」 > 「提供元不明のアプリ」を「ON」」
 「開発」 > 「USBデバッグ」を「ON」に設定する。

●2.【実行形式パッケージ〜】−「【ant ir】ビルド&実機にインストール」をクリックします。
 実機用にビルドし、上書きインストールします。


●3.実機にインストールされます。実機テストなどを行ないます。
Web公開・Flash実行方法 ●1.【実行形式パッケージ〜】−「【ant local】ブラウザ向けビルド」をクリックします。
 Flash版のファイルが準備されます。


●2.Webブラウザで動作確認しましょう。
「index_l.htm」をブラウザにドラッグ&ドロップします。(このHTMLファイルはローカルPC実行版です)
 動作確認します。
設定画面はFlash版に差し替える必要があります。
「config」フォルダの内容を、
「(プロジェクトフォルダ)/Work/システム/plgConfig/差し替えconfig」に差し替えて下さい。

●3.必要なファイルをFTPなどでWebサーバーにアップします。

以下のファイルは不要です。アップしない方が良いでしょう。
・build.xml
・fontフォルダ、またその中身
・iconフォルダ、またその中身
・icon.jpg
・index_l.htm
・prj-app.xml
・SDKフォルダ、またその中身
・【プロジェクト名】_l.swf (【プロジェクト名】.swfは必要です)
・拡張子が「.swf.cache」のファイル
・Workフォルダ、またその中身

●4.Webブラウザで動作確認しましょう。
「index.htm」があるURLをブラウザで開きます。(このHTMLファイルはサーバーに置く本番版です)
 動作確認します。
(日本語ファイル名はトラブルの元です、出来れば避けた方が良いでしょう)
リリースにあたって リリースにあたってのチェックポイントを列挙します。ご参考までに。

★main.an関連
●スナップショット機能(pキー)を無効にするか否か
●スクリプトリロード機能(f5キー)を無効にするか否か
●処理負荷グラフ機能(f7キー)を無効にするか否か
●変数ダンプ機能(f8キー)を無効にするか否か
●起動するたびにタイトル画面などで[update_check]で更新をチェックするか
★_config.an関連
●バージョンアップデート機能は正しく動作するか。
(無効にする場合はボタンも表示しないようにすべき)
★その他
●インストール直後状態でも正しく動作するか。
セーブデータを削除orフォルダ名を一時変えて確認)
●開発環境とは違うOSでの動作はどうか。
(理想はaキーによる自動読み進めで全シナリオを確認)
確認する時間が無い場合、正直に「○○では動作未確認」と書くだけでずいぶん誠実です。
トラブル対策 ●インストール失敗
 主に Adobe AIR アプリとしてのトラブルになると思われます。

●PCを再起動するとセーブデータが消滅する
 ウイルス検知・削除ソフトウェアが悪さをしている場合があります。トラブルがあった場合、ゲームを監視対象外などと設定して下さい。
 特に「Windows Defender」というWindowsに最初から入っているものも悪さをしていた事例がありますので、以下に設定をザッと説明致します。
1.「Windows Defender」の【ツール】-【オブション】をクリック。
  (Windows 8 では【設定】)
2.【対象外のファイルとフォルダ】で、ゲームインストール先フォルダを指定する。普通ゲームのファイル(プロジェクト)名と同じ。
(参考:Vista/78

CD配布とAdobeAIRランタイム ベストはWeb配布の最新版をプレイヤーにダウンロードしてもらう方法です。
体験版配布と同時にインストールさせるような形でスマートに配布できます。

配布CDにランタイムを含めるには「Adobe AIR配布許諾契約」を申し込む必要があり、ちょっと面倒な予感です。
詳細は以下にあります。
 →アドビ - Adobe AIRランタイム配布
自動アップデートの設定方法 これは「AIRNovel Stand-alone」のソースファイルが良い例になります。参考のため、愛機にインストールしておいてください。

自動アップデートの仕組みですが、以下の流れになります。
1.AIRNovelスクリプトで[update_check]を呼ぶ。
2.Adobe AIRが[update_check]のurl属性で指定したネット上の場所から、「更新記述ファイル」をダウンロードする。
3.Adobe AIRが更新記述ファイルのversion要素と、実行中AIRNovel自身の「アプリケーション記述ファイル」のversion要素を比較する。
  同じか後者の方が新しいなら何もせず更新処理を終了。AIRNovelゲームはそのまま続行。
4.Adobe AIRが[update_check]のconfig_fn属性で指定した「ApplicationUpdater設定記述ファイル」の設定の動作を行なう。

  ※以下はAIRNovel Stand-aloneに設定された動作です。全てAdobe AIRが行ないます。
  4-1.更新があった場合、プレイヤーに更新するかダイアログで確認する。
  4-2.プレイヤーが更新する意志を選択した場合、必要なファイルをダウンロードする。
     (具体的には*.airファイルを更新記述ファイルのurl要素に示した場所からダウンロードする)
  4-3.ゲームを終了する。
  4-4.上書き更新処理を行なう。
  4-5.ゲームを再起動する。

更新記述ファイル」はXMLファイルで、インターネットからアクセスできる場所(HTTP・Webサーバーなど)に置いておきます。
「AIRNovel Stand-alone」の場合は「https://raw.githubusercontent.com/famibee/AIRNovel/master/open/ans_ver.xml」です。
特に有料アプリの場合、このURLは秘密にして下さい
以下のように記述します。(URLをブラウザで開くと同じモノが見えます)

ans_ver.xml(必ず文字コードUTF-8, 改行コードLFで保存、ファイル名そのものは自由で、変える際は[update_check]のurl属性に指定すればいい)
<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/2.5">
	<versionNumber>4.11</versionNumber>
	<url>https://raw.githubusercontent.com/famibee/AIRNovel/master/open/ans.air</url>
	<description><![CDATA[
4.11
	* upd:レイヤが無い部分があるまま[trans]を繰り返すと前の表示が残る仕様を緩和
]]></description>
</update>
XMLには主に以下の要素を記述します。(XML記述詳細はAdobeサイトにて)
version要素 …… 最新版のバージョン文字列
url要素 …… 最新版*.airファイルの公開URL。ans_ver.xmlなどと同じパス、サーバーである必要はありません。特に有料アプリの場合、このURLは秘密にして下さい
description要素 …… 更新ウインドウに表示するメッセージ(更新履歴など)を記述
ここでのans_ver.xmlや、ゲーム本体 ans.air をブラウザで開けるか、ダウンロードされるか確認しておきましょう。


アプリケーション記述ファイルはAIRアプリとしてのビルドに必要なファイルです。(詳細はAdobeサイトにて)

prj-app.xml(必ずUTF-8, LFで保存)(ANBooksで自動生成され、変更不要です)
<?xml version="1.0" encoding="utf-8" ?>
<application xmlns="http://ns.adobe.com/air/application/21.0">
	<id>com.fc2.web.famibee.(プロジェクト名)
	<versionNumber>4.11</versionNumber>

〜中略〜

</application>
更新記述ファイルと同様にversion要素があるのが判ります。AIRNovel内部ではこれらを比較するわけです。


最後にanスクリプトの更新確認したい部分で[update_check]を記述。
属性urlに更新記述ファイルのURLを書く。
[update_check url="https://raw.githubusercontent.com/famibee/AIRNovel/master/open/ans_ver.xml"]

新しいバージョンを公開する際は、以下の手順を行ないます。
1.新しいバージョンのゲームAIRアプリを制作し、
 「アプリケーション記述ファイル」のversion要素を更新してビルド。
  *.airファイルを生成する。
2.「更新記述ファイル」のversion要素やdescription要素を更新し、
  [update_check]のurl属性に示した場所に公開する。
3.*.airファイルを「更新記述ファイル」のurl要素に示した場所に公開する。
4.更新処理が正しく動作するか確認する。
inserted by FC2 system