はじめに、東方弾幕風のスクリプト言語にはバージョンがあり、過去のph3において過去の文法で記述するとエラーがおこる。よって古い情報のコードをコピペしても動かないことがあることをまず理解しておく。この記事では東方弾幕風ph3について書いていく。ph3は言語バージョンがおそらく3である。情報がなさすぎて、確証がもてないがこのまますすめる。
天狗のネタ帖をダウンロード
天狗のネタ帖とは弾幕風用のスクリプトを書くためのエディターである。たぶんテキストエディターといってよいだろう。これを使う理由としては、弾幕風スクリプト言語のシンタックスハイライトとインテリセンスがあるのでおそらくこれを使うのが最善なのだろう。
◎天狗のネタ帖のリンク(ダウンロードリンクではありません)
ツール・ライブラリ – 東方弾幕風wiki(仮・三代目)
- 弾幕風のフォルダにとりあえずいれる
- tengNote.exeを起動しやすいように環境変数(Path)に登録する→必須ではない
- tengNote.exeを起動してツール→設定にいく。
- オートインデントにチェック。初期表示フォルダを弾幕風のscirptフォルダに。使用する関数群をv3に。インテリセンスの自動で呼び出すにチェック。
弾幕風ph3スクリプト言語の基本文法
基礎文法については、 弾幕風公式ヘルプ をみたほうがいい。ここでは筆者が気になった部分だけを抜粋する。
- コメントアウト → /, /**/
- 変数宣言 → let
- データ型 → real, char, boolean (realは数値)
- 配列 → [,,]
- 演算子 → ++, +=, &&, ||
- 条件分岐 → if(){}, alternative(a)case(0){}
- 繰り返し → loop, times, while, ascent, descent
- 脱出 → break(繰り返し) return(関数)
- サブルーチン → つかわない
- 関数 → function 関数名(,,){}
- マイクロスレッド → わからん。 書き方: task マイクロッドスレッド名{}
- 外部ファイル読み込み → #include “ファイル名” → 相対パスで記述。セミコロンがいらない点に注意
条件分岐のalternativeはswitchと同じ。繰り返しのascentとdescentはとりあえず今はいい・・。
東方弾幕風ph3 スクリプトヘッダと組み込みルーチン
このあたりも公式ヘルプ見るのがいいけど、とりあえず自分が気になる部分だけ抜粋
- スクリプトヘッダ → スクリプトを認識させるためにスクリプトの先頭に書くテキスト
- 組込ルーチン → @ではじまる。特定のタイミングで呼び出されるプログラム
- #東方弾幕風[]または#TouhouDanmakufu[] → メニュー登録用。パラメーターは、とりあえず公式参照
- #ScriptVersion[3] → 必須。スクリプトバージョン3
- #Title[“”] → ph3ではダブルクォーテーションが必要。メニュータイトルに使用される
- #Text[“”] → メニューの説明に使用される文字列
- @Initialize{} → スクリプト初期化時に1回だけ呼び出される
- @Finalize{} → スクリプト終了時に一度だけ呼び出される
- @MainLoop{} → 毎フレーム呼び出される
- @Loading{} → よくわからん
- @Event{} → 特定のイベントが発生したときに呼び出される
はじめてのスクリプト
人がつくったスクリプトを天狗のネタ帖にコピペ。ファイルの拡張子は.txt。基本は弾幕風のscriptフォルダにつくっていく。
#TouhouDanmakufu[Single] #ScriptVersion[3] #Title["Tutorial 01"] #Text["Simple enemy + bullet tutorial"] let bossObj; let bossX = 0; let bossY = 0; let imgBoss = GetCurrentScriptDirectory ~ "minizira.png"; #include "script/default_system/Default_ShotConst.txt" @Initialize { // define a boss in bossObj and register it bossObj = ObjEnemy_Create(OBJ_ENEMY_BOSS); ObjEnemy_Regist(bossObj); // texture the boss, set centre as true centre. ObjPrim_SetTexture(bossObj,imgBoss); ObjSprite2D_SetSourceRect(bossObj,0,0,100,100); ObjSprite2D_SetDestCenter(bossObj); // move boss to desired x y location at desired speed ObjMove_SetDestAtSpeed(bossObj,192,120,5); mainTask; // run mainTask } @Event { // setting the boss timer and life alternative(GetEventType()) case(EV_REQUEST_LIFE) { SetScriptResult(1000); } case(EV_REQUEST_TIMER) { SetScriptResult(45); } } @MainLoop { bossX = ObjMove_GetX(bossObj); bossY = ObjMove_GetY(bossObj); yield; } @Finalize { } // your best friend, forever. function wait(w) { loop(w) { yield; } } task mainTask { fire; } task fire { loop { CreateShotA1(bossX,bossY,3,90,14,0); wait(60); } }
よくわからないので調べてみる。
- GetCurrentScriptDirectory → スクリプトディレクトリを返す
- ObjEnemy_Create() → パラメーターは以下OBJ_ENEMY: 敵オブジェトOBJ_ENEMY_BOSS: 敵ボスオブジェクト
- ObjEnemy_Regist(objid) → 指定した敵をアクティブに。
- ObjPrim_SetTexture(objid, imgpath) → テクスチャ設定
- ObjSprite2D_SetSourceRect(objid, left, top, right, bottom) → 描画範囲
- ObjSprite2D_SetDestCenter(objid) → 描画を中心にする。
- ObjMove_SetDestAtSpeed(objid, x, y, speed) → 指定した座標にむかって指定した速度で移動。到達したら停止
- GetEventType() → イベントの種別を取得
- EV_REQUEST_LIFE → ライフ。ボスだけ呼び出せる
- EV_REQUEST_TIMER → タイマー。ボスだけ呼び出せる
- SetScriptResult(real) → 不明。設定
- ObjMove_GetX(objid) → 指定したオブジェクトのx座標を取得
- ObjMove_GetY(objid) → 指定したオブジェクトのy座標を取得
- CreateShotA1(x, y, speed, ang, bulletid, delay) → 指定した位置に敵弾を出現
1秒間に一回、弾をうってくるコードなのだろうおそらく。yieldとかよくわからん
functionに似ていますが、途中で戻ってくることができます。複数のマイクロスレッドを並列して存在させ、順次yieldによって切り替える事で、
あたかも同時に複数のスクリプトが走っているような記述ができます。引用元: 弾幕風ヘルプ – マイクロスレッド
弾画像はどこにあるのか
CreateShotA1のパラメーターで、bulletidを指定しているがその弾画像はどこにあるのか。
弾画像の本体は → script\default_system\img
弾画像の定数が記述してあるファイルは #include で読み込んでいる。ファイルの中身をみると、定数名に数値が代入されているのが確認できる。
とはいえ、どの定数がどんな画像に対応しているかはわからないのでそこは公式ヘルプで確認する必要がある。今回のスクリプトで使っている弾画像は青の小弾だった。天狗のネタ帖から公式ヘルプにとべるっぽいけど、「ファイルが見つかりませんでした」といわれる。このあたりはとりあえずまあいいか。
まとめ
今回のスクリプトは1秒間に1回、真下に弾をうってくるだけのスクリプトだった。敵のライフ、タイマー等設定しているものの、時間切れになったときの処理、当たり判定が実装されていない模様。
コメント