no.7 マイクロスレッドと弾オブジェクトの基礎(2)
前回の続き「諏訪大戦」です。藤蔦のほうを作っていきます。
6本、下から生えてきます。最初のX座標から上に行くに従ってうねうねしていきます。
うねうねと言えば三角関数。うねうね=半径*sin(角度変数)ってことにしましょう。半径を0からちょっとずつ大きく、角度変数を0から適当に回していけばいい感じですね。
ここらへんの細かい解説はしません。聞きたかったらコメントでよくわかんないって言ってください。
task fuji(X) {
let Y = bottom;
let r = 0; let a = 0;
while(Y>-15) {
CreateShotA(X+r*sin(a), Y, 0, 0, DS_RICE_S_GREEN, 15);
r+=1;
a+=11;
Y-=8;
wait(4);
}
}
なんか若干形が違う気がしますが、気にしない。
とりあえず、角度を調節します。
角度を、前の弾への角度を前のX,Yを逆算して手計算します。→atan2*1-(X-r*sin(a)))。
整理して、atan2(8,-(r-1)*sin(a-11)+r*sin(a))。aとYを微分してatan関数で角度を出すとかもできますが、黒の時代の処理能力が足りなかったので却下。
とにかく、弾幕風は万能関数セットを揃えてるわけじゃないので、この手の計算は自分で処理しちゃいましょう。
これで位置取りはばっちり。
task FUJI {
fuji(cx+70);
fuji(cx-70);
fuji(cx+130);
fuji(cx-130);
fuji(cx+190);
fuji(cx-190);
}
くらいにしておきます。
Objとして扱う!
さてこっからが本題。
オブジェクトです。0.x系ではSetShotDataなどなど色々弾を操作する関数があったんですが、ph3ではすべてオブジェクト用の関数で操作することになります。オブジェクト?モノですモノ。
オブジェクトに分類されるもの
- 敵
- 弾
- エフェクト
- アイテム
- レーザー
- 文字
- その他
はい。全てですね。CreateShotとかの関数は、
オブジェクト生成、画像指定、位置速度角度、登場エフェクトなどの動作をひとつにをまとめたfunctionだと思えばいいです。
↓こんなかんじ。
function CreateShotA1(x,y,speed,angle,color,time) {
let obj = ObjShot_Create();
Obj_SetPosition(obj,x,y);
〜
}
案ずるより産むがわかりやすし!
弾を撃ってた所を
CreateShotA(X+r*sin(a), Y, 0, 0, DS_RICE_S_GREEN, 15);
↓変更
fujishot(X+r*sin(a), Y,atans(10,(r-1)*sin(a-11)-r*sin(a)));
taskにしちゃいます。弾生成から時間を置いて変化させるので、taskで色々いじっていきます。
task fujishot(x,y,f_a) {
let obj = CreateShotA1(x, y, 0, f_a, DS_RICE_S_GREEN, 15);
wait(120);
ObjShot_SetGraphic(obj,DS_RICE_S_RED);
ObjMove_SetAcceleration(obj,0.02);
ObjMove_SetMaxSpeed(obj,2);
}
とりあえず、弾生成、120フレーム後に弾画像変更、加速度付加、(加速時)最大速度を設定しました。順に説明していきます。
◆ let obj = CreateShotA1(x, y, 0, f_a, DS_RICE_S_GREEN, 15);
CreateShot関数が変数に? ・・・オブジェクトとして扱う際には、つねにどのオブジェクトに指示を与えているのか書く必要があります。そのため、CreateShot系の関数や、オブジェクト生成関数(Obj_Create,ObjShot_Create等)は常に返り値を持った関数として定義されています。その返り値(realなので数字)がオブジェクトのID名であり、その数字を適当な変数(obj, objEnemy, objPlayerなどなど)に代入して、オブジェクトの名前として使っていきます。
あ、返り値のことno.5でまともに説明してないんでしたっけ。ロベールさんの解説をお読みくだされ。(←やっぱり投げる)
要するに:オブジェクトは全部、let obj = とか適当に名前をつけて弄っていきます。それだけわかればよかです。
◆ ObjShot_SetGraphic〜MaxSpeed(obj,2);
wait(120);した後に、objの運命を書き換えます。弾オブジェクトはObjShot_系のオブジェクトなので、リファレンスに示されている通りObj_、ObjMove_、ObjShot_、ObjRender_系の関数が使えます。
え、何言ってるわかんない?
オブジェクト関数は、先ほども言ったとおり様々なモノをいじくれる関数群です。そのため、例えば弾オブジェクトに画像変形用の関数を適用したり、レーザーにライフを設定したりしないように、関数がジャンル分けして作られているわけです。
で、上のリンクを見て下さい。これ以上詳しい説明とかいらないよね。
弾オブジェクトについては、場所速度角度をObjMove_で弄って、その他のことをObjShot_で弄ります。
ちょい変更と仕上げ
まだ本家のうねうねとは少し違いますね。
1. 色変化時にエフェクトがある
2. 途中で消える
これを解決していきましょう。
1. エフェクト
弾幕風には特にプリセットエフェクトは無いので、作るのも面倒だし、
緑弾のある所から、赤弾を生成して、遅延時間エフェクトを使います。そして役目を終えた緑はその場で消えてもらいます。
task fujishot(x,y,f_a) {
let obj = CreateShotA1(x, y, 0, f_a, DS_RICE_S_GREEN, 15);
wait(120);
CreateShotA2(x,y,0,f_a,0.02,2,DS_RICE_S_RED,8);
Obj_Delete(obj);
}
加速度とかがあるのでCreateShotA2を使いました。むしろ短くなりましたね。
ObjShot_FadeDelete(obj)を使うと少し違った感じになります。お好みでどうぞ。
さて、2. 途中で消える。
後から出てきた弾の方が先に消えてますね…めんどい
task fujishot(x,y,f_a,time) {
let obj = CreateShotA1(x, y, 0, f_a, DS_RICE_S_GREEN, 15);
wait(120);
let obj2 = CreateShotA2(x,y,0,f_a,0.02,2,DS_RICE_S_RED,8);
Obj_Delete(obj);
wait(time);
ObjShot_FadeDelete(obj2);
}
消えるエフェクトは、FadeDeleteで代用します。ちかたない。
オブジェクトの名前を別にするのは忘れないでください。
task fuji(X,a_rand) {
let Y = bottom; let r = 0; let a = rand(a_rand,-a_rand);
let time = 560;
while(Y>-15) {
fujishot(X-r*sin(a),Y,atan2(8,-(r-1)*sin(a-11)+r*sin(a)),time);
r+=1; a+=11; Y-=8; wait(4);
time-=7;
}
}
調節は適当です。
ヘニョリ具合もばらけさせました。
ちょっとめんどくさかったので
task MAIN {
let count = 0;
wait(120);
let a_rand = 40;
loop {
fuji(cx+70, a_rand);
fuji(cx-70, a_rand);
fuji(cx+130, a_rand);
fuji(cx-130, a_rand);
fuji(cx+190, a_rand);
fuji(cx-190, a_rand);
wait(400);
IRON(count%2);
wait(400);
count++;
a_rand+=40;
}
}
ここで打ち切りますが、
なんかさらっと終っちゃうスペルになりましたね…
耐久スペルにするには、ObjEnemyBossScene_SetSpellTimer(objEnemy, 時間)を@Initializeに書き込みます。
敵の体力を変えるには、@Eventの所と@Initializeの所2カ所を変えておいてください。
↓いちおう完成形をきちんと貼っておきます。
追記:今回の内容、マイクロスレッドを使わなくてもObjShot_AddShotA1とObjMove_AddPatternA3で出来るっぽいですね。すいません。まぢ情弱初心者。マイクロスレッドの説明になったってことにして許してください。
*1:Y+8)-Y,(X-(r-1)*sin(a-11