黒の時代

弾幕風ph3初心者による弾幕風講座。まだ難しいことは出来ませんが、質問要望あればコメントにどうぞ。

no.3 弾を撃つ。@MainLoop

@MainLoopをいじくって、弾を撃ち始めます。

 

前回の

@MainLoop {
   ex = ObjMove_GetX(objEnemy);
   ey = ObjMove_GetY(objEnemy); 
   ObjEnemy_SetIntersectionCircleToShot(objEnemy, ex, ey, 32);
   ObjEnemy_SetIntersectionCircleToPlayer(objEnemy, ex, ey, 24);
   frame++;
   yield;
   if(ObjEnemy_GetInfo(objEnemy, INFO_LIFE) <= 0) { Obj_Delete(objEnemy); CloseScript(GetOwnScriptID()); return; }
 }

@MainLoop {
   ex = ObjMove_GetX(objEnemy);
   ey = ObjMove_GetY(objEnemy); 
   ObjEnemy_SetIntersectionCircleToShot(objEnemy, ex, ey, 32);
   ObjEnemy_SetIntersectionCircleToPlayer(objEnemy, ex, ey, 24);
   frame++;

      CreateShotA1(ex,ey,3,90,DS_BALL_L_RED,30);

   yield;
   if(ObjEnemy_GetInfo(objEnemy, INFO_LIFE) <= 0) {
      Obj_Delete(objEnemy);
      CloseScript(GetOwnScriptID()); return;
   }
 }

に変えて見ましょう。弾を発射する関数CreateShotA1を追加します。

 1) real:x座標→ex  2) real:y座標→ey 3) real:速度→3 4) real:角度→90*1 5) real:弾画像ID→赤大玉 6) real:遅延時間→30

っていうパラメータを関数に代入してますね。

さて弾幕風で実行してみると、毎フレーム@MainLoopが実行されてることが体感出来たかと思います。華麗に被弾でもグレイズでもしてあげてましょう。じゃりじゃり。

   if(frame==100) {
      CreateShotA1(ex,ey,3,90,DS_BALL_L_RED,30);
   }

に変えてみましょう。1発大玉が出てきたと思います。

これはリファレンスの分岐にあるifと比較式を使っています。frame==100という条件を満たしているときに、ローカルスコープ{}内を実行。

あっとframeの話をしてなかった。frameはスクリプトの最初の方で、let frame = 0;って最初の値を0として生み出された変数です。frame++;と言うのは、frameの値を1大きくするって意味です。C++と同じ。毎フレーム1大きな値になるようになってるってことは、今がスクリプト開始から何フレーム目か刻まれていることになります。

フレーム数を取得する関数とかあってもいいじゃない!って思うかもしれませんが、それを自分の手でやる=自由度が上がるってことなので、我慢してください。特にph3は自由度の高さ(と処理の早さ)がウリなので、必然的に手間がかかる部分も多かったりします。

あと、「;」は文の区切れ。実行ファイルが認識する改行のことです。htmlで言えば</br>。ちなみに弾幕風のスクリプトでは、単語の途中じゃなければ改行と半角スペースとタブインデントは好き放題出来ます。

変数の扱い方はスクリプトリファレンス参照で


CreateShotA1
(ex,
ey,3      ,     90,DS_BALL_L_RED,30)
;

×
CreateShot
A1(ex,ey,3,90,DS_BALL_L_RED,30);

 さて大玉を何個も続けて出したい時は…

A:if内を実行すると、frameが0になるようにする。イコールの扱いに注意。
   if(frame==100) {
      CreateShotA1(ex,ey,3,GetAngleToPlayer(objEnemy),DS_BALL_L_RED,30);
      frame=0;
   }

B:条件を、「frameを100で割った余りが0」に変更。
   if(frame%100==0) {
      CreateShotA1(ex,ey,3,GetAngleToPlayer(objEnemy),DS_BALL_L_RED,30);
   }

のどっちか書き換えましょう。角度を自機狙いにしてみました。*2

場合に寄るけど、後者の方が便利。何個かifを使う時とか、Bじゃないと無理。

   if(frame%40==0) {
      CreateShotA1(ex,ey,5,GetAngleToPlayer(objEnemy),DS_BALL_L_RED,30);
      CreateShotA1(ex,ey,4,GetAngleToPlayer(objEnemy),DS_BALL_M_RED,30);
      CreateShotA1(ex,ey,3,GetAngleToPlayer(objEnemy),DS_BALL_M_RED,30);
   }
   if(frame%3==0) {
      CreateShotA1(ex,ey,4,rand(0,360),DS_BALL_S_RED,10);
      CreateShotA1(ex,ey,4,rand(0,360),DS_BALL_S_ORANGE,10);
      CreateShotA1(ex,ey,4,rand(0,360),DS_BALL_S_YELLOW,10);
 }

こんな場合とか。でも前者も使う時はありますです。
あっと言い忘れてましたが、弾画像を変えたい場合は、リファレンスの【■弾画像(デフォルト)】の所を見てくださいね。

さて、そろそろ角度をもっと使いこなしたくなってきたのではないでしょうか。
ぐるぐるバラまく弾を作ります。

let imgExRumia = GetCurrentScriptDirectory~"ExRumia.png";
let objPlayer = GetPlayerObjectID();
let objEnemy;
let frame = 0;
let ex; let ey; let cx = GetStgFrameWidth() / 2;
let right = GetStgFrameWidth;
let bottom = GetStgFrameHeight; 
let angle = 0;

変数を一個追加。これ@MainLoopの内部に書いちゃダメです。ローカルスコープの件参照のこと。

そして@MainLoopに

   if(frame%4==0) {
      CreateShotA1(ex,ey,3,angle,DS_RICE_S_RED,0);
      CreateShotA1(ex,ey,3,angle-10,DS_RICE_S_RED,0);
      CreateShotA1(ex,ey,3,angle-20,DS_RICE_S_RED,0);
      CreateShotA1(ex,ey,3,angle-30,DS_RICE_S_RED,0);
      angle+=12;
   }

を追加。

敵が中心についてから弾を発射させたい場合は、
 if(frame%4==0&&frame>60) {
みたいに条件を付け加えましょう。

&&は「かつ」で、||が「または」です。

 

さてこれで

  • @MainLoopsの役割
  • 基本の弾の撃ち方
  • 変数について
  • ifについて

の話が終ったことにしましょう。

ああ、

   ObjEnemy_SetIntersectionCircleToShot(objEnemy, ex, ey, 32);
   ObjEnemy_SetIntersectionCircleToPlayer(objEnemy, ex, ey, 24);

は自分で調べてください。あたり判定の話です。

 

次は、ループの使い方とお手製関数functionの使い方でしょうか。

*1:角度は右を0度として、時計回りに1周360度。370度=10度=-350度でプラマイどんな値でもオッケーです。なんかx軸が0度が普通なんだとか。ようは慣れです。

*2:0.x系のユーザーならわかるけど、GetAngleToPlayerが引数をゲットしたのは便利な部分と不便な部分があるです

>>目次:no.0