弾幕風製作の基本その1 円滑に行うファイルの参照 さて、皆さんは各々スクリプトを作った事があると思います。 なので基本的な敵スクリプトの打ち方は知っている事と思います。 @Initialize(最初に一回だけ処理) @MainLoop(1秒間に60回処理(1フレームに1回処理)) @DrawLoop(@MainLoopの描画処理版) @Finalize(最後に一回だけ処理) 以上の4つの部分の理解が出来ていない場合は弾幕風Wikiのヘルプで参照して下さい。 特に@MainLoopが1秒間に60回処理されるということは重要なので必ず覚えて下さい。 (@BackGroundについては、覚えなくて構いません。エフェクトオブジェクトで代用できます) 尚、私はこれから弾幕風だけでなく、普通のC言語の内容も交えながら説明していきます。 その方がより理解が深まるでしょう。 今回のテーマでは、皆さんがスクリプトを製作するときにバグや労力を軽減する方法をお教えします。 何だ、弾幕製作とあんまり関係ないじゃないかとか言わずしっかり会得して下さい。 これを知っているかでプログラムを打つ時間が2倍近く短縮できます。 それでは早速今回のテーマ「円滑に行うファイルの参照」について話を進めていきましょう。 最初はファイル参照に使うletについて詳しく説明し、 後半で今回の本題となるインクルードの説明に入ります。 @変数の宣言位置 弾幕風ではletで変数を宣言できる事はご存じだと思います。 まず最初にこのletの宣言位置について深く理解しておきましょう。 letは普通@Initializeの前で宣言します。 @Initializeで宣言することも可能ですが、この方がバグが起きにくくなります。 また、後で確認する「task」中ではいつでもletを宣言する事が出来ます。 ただし宣言した変数はtask内限定の物になります。 詳しくは後でマイクロスレッドについて確認するときに説明します。 最重要事項↓ ・letは@Initializeの前で宣言する ・task、function、sub内ではいつでもletを宣言できる A変数の型と初期化 let a; let a=0; 皆さんはこの違いがお分かりでしょうか? この後に, a=4; とするとaの値は上下どちらの場合も4になります。 なので別に let a; としようが、let a=0; としようがいいではないかと思うでしょう。 しかしこの両者には大きな違いがあるのです。 それは、let a; の時点でのaの値は「文字列」で let a=0; のaの値は0という「数値」である事です。 if(a==0){a+=3;}といった分岐を作ったときに誤って let a; でaを宣言してしまうと、 「型の違う値を代入しようとしました」というエラーが出てしまいます。 これはaの値が文字であるのに数字で比較しようとしたからです。 コンピュータで扱う文字列や数値の事を「リテラル」といいます。 リテラルの中でも1,2,3,15等の数値の値を「数値リテラル」といい、a,abc,Hといった文字列の事を「文字列リテラル」といいます。 (C++等のコンピュータ言語ではa,b,Jなど、文字が一つの場合は「文字リテラル」と分類されますが、弾幕風言語では同等とみなします) そして文字と数字は異なるものだというのは皆さんすぐ分かると思います。 文字、数字等の変数の形式を「型」といいます。 (弾幕風では文字、文字列は文字の型として一纏めにされています) 型は文字、数字の区別だけでなく、数字を更に整数、浮動小数に区別する役割も担っています。 この型を理解し、利用することで色々な事が出来ますが、 それはかなり難しいと思いますので、今回は「型」という物があるという事だけ覚えておいて下さい。 let a=0;のように、変数宣言と同時に何かの値を代入する事を「変数の初期化」といいます。 前述のように型の違いによるエラーを防ぐために、 変数宣言は常に初期化を伴うようにすることが望ましいです。 最重要事項↓ ・弾幕風で「型の違う値を代入しようとしました」というエラーが出たら、変数が文字列リテラルになっていないかを確認する。 ・変数宣言の際は必ず初期化する。 Bファイルへのパス それでは今度は画像、bgm、効果音の読み込み等を説明します。 例えば画像はLoadGraphicで読み込まないとDrawGraphicをしても描画されないのはご存知かと思います。 そして画像はLoadGraphicやDrawGraphicの前に、画像へのパスをletで宣言し、変数にしておくといいというのも、 御存知かと思います。 そこで今回はそのパスについて詳しく見ていきましょう。 画像へのパスは皆さん設定した事があると思うので、説明は省略します。 あえて説明するなら、パスの頭に.\をつけて、ファイルが移動しても参照し続けられるようにしたパスを「相対パス」 といい、普通のパスを「絶対パス」という事位でしょうか。 ただし、パスを普通に書いておくよりももっと確実に画像を読み込める方法があります。 それが「GetCurrentScriptDirectory~"";」です。 let img = GetCurrentScriptDirectory~"画像へのパス"; のように使います。 これは弾幕風のスクリプトフォルダ内から画像を参照することを意味します。 要は普通にパスを書いておくよりも確実に画像を参照できるという事です。 この時、""内の画像へのパスは、変数宣言位置から見た絶対パス(大抵 img\img2.png のようにファイルがあるフォルダ名から始める) だという事に気をつけて下さい。 相対パスを使用することはできません。 最重要事項↓ ・画像、bgm、効果音へのパスはGetCurrentScriptDirectory~"";を利用すると確実。 Cインクルード さて、今回最後の内容であり、最も大切な部分です。 ステージを作ったり大作を作る際、幾つもの敵の攻撃のスクリプトを作る事になるでしょう。 そんな時、毎回画像や効果音のファイルをletで宣言するのは大変です。 そこで、今回は全てのファイルへのパスを一纏めにしておいて、簡単に参照できる方法、「インクルード」を紹介します。 T.まずはテキストファイルを一つ作成します。名前はお好きなように。 ここでは「変数集.txt」としておきます。 このインクルードに必要なファイルを、「ヘッダファイル」と言います。 U.次に新しく作ったヘッダファイルに、使用する変数の宣言をずらっと書いておきます。 下の例は画像のみですが、画像だけでなくBGM、効果音のパスも纏めて書いておきましょう。 例↓ //システム画像 let imgBIGCIRCLE = GetCurrentScriptDirectory~ "img\others\Circle_Hex.png"; let imgBLACK = GetCurrentScriptDirectory~"img\BG\black.png"; let Circle = GetCurrentScriptDirectory~"img\others\Circle.png"; let imgBlind = GetCurrentScriptDirectory ~ "img\others\blind.png"; let Effect = GetCurrentScriptDirectory~"img\others\Effect.png"; let Text = GetCurrentScriptDirectory~"img\others\Text.png"; let SpellName = GetCurrentScriptDirectory~"img\others\spell_name.png"; let LastwordName = GetCurrentScriptDirectory~"img\others\lastword_name.png"; let EnemyName = GetCurrentScriptDirectory~"img\others\enemy_name.png"; let EnemyLife = GetCurrentScriptDirectory~"img\others\enemy_life.png"; let SC1 = GetCurrentScriptDirectory~"img\others\STAGECLEAR.png"; let SC2 = GetCurrentScriptDirectory~"img\others\GETCLEARBONUS.png"; let Difficulty = GetCurrentScriptDirectory~"img\others\difficulty.png"; let imgShot = GetCurrentScriptDirectory~"System\shotimg\shot_all.png"; let ExtendFont = GetCurrentScriptDirectory~"img\others\extend.png"; let ItemLine = GetCurrentScriptDirectory~"img\others\Line.png"; let StageTitle1 = GetCurrentScriptDirectory~"img\others\title_stage.png"; let StageTitle2 = GetCurrentScriptDirectory~"img\others\title_stage2.png"; let failure = GetCurrentScriptDirectory~"img\others\failed.png"; let time = GetCurrentScriptDirectory~"img\others\time.png"; let numbers = GetCurrentScriptDirectory~"img\others\numbers.png"; let frame_word = GetCurrentScriptDirectory~"img\others\frame_word.png"; let frame_star = GetCurrentScriptDirectory~"img\others\frame_star.png"; let talkBackground = GetCurrentScriptDirectory~"img\others\talkBackground.png"; let sphere = GetCurrentScriptDirectory~"img\others\sphere.png"; let target = GetCurrentScriptDirectory~"img\others\target.png"; V.ヘッダファイルで宣言した変数を使用するスクリプトでscript_enemy_mainの一番最後(@Finalizeや各taskの後)に、 #include_function "ヘッダファイルへのパス" と書いておきます。 このとき注意しておきたいのは、ヘッダファイルへのパスは相対パスである事、 文末に;は付けないという事です。 例えば上の場合では、ヘッダファイル「変数集.txt」がSystemというフォルダの中にある場合、 #include_function ".\System\変数集.txt" とします。 このような#から始まる文は「コンパイラ」(私達が書いたプログラムを機械語に翻訳する装置)の、 「プリプロセッサ」という特別な部分によって勝手に翻訳されますので、 これ以上の作業をする必要はありません。 以上でインクルードの全ての作業は完了です。 これをやっておくと次のような利点があります。 例えば上の場合だと、let imgBLACK を宣言しておきましたね。 すると各スクリプトでletでimgBLACKの画像を宣言してからLoadGraphic(imgBLACK);としていたのが、 letを宣言せずにいきなりLoadGraphic(imgBLACK);を実行できるのです。 またインクルードでは変数だけではなく、関数を読み込むこともできるのです。 よく使う、way弾を撃つ関数をいちいち各スクリプトで定義しておくのは面倒です。 他にもよく使う関数は色々あるはずです。 関数集のヘッダファイルを一度作ってしまえば、後はそのファイルをインクルードさえすれば、 いちいち関数を定義せずに即座に使用できるのです。 是非このインクルードをマスターして、作業効率を上げて下さい。 最重要事項↓ ・インクルードをすると、各攻撃ごとにいちいち変数を宣言したり関数を定義する手間が省ける。 ・インクルードは、まずヘッダファイルを作り、そこに変数宣言や関数を書き込むことから始める。 ・作ったヘッダファイルは #include_function "ヘッダファイルへの相対パス" でインクルード(読み込み)する事が出来る。