#東方弾幕風 #Title[レーザーと反射弾] #Text[レーザーと反射弾] #Image[] #BackGround[] #BGM[] #PlayLevel[Sexy] #Player[REIMU,MARISA] #ScriptVersion[2] script_enemy_main { @Initialize { //敵出現時に一度だけ実行される部分 SetX(GetCenterX); SetY(GetClipMinY+120); SetLife(2000); LoadGraphic("script\img\ExRumia.png"); SetTexture("script\img\ExRumia.png"); SetGraphicRect(0, 0, 63, 63); Main; Main2; } @MainLoop { //敵のライフが0になるまで、この部分が1フレームに1回実行 SetCollisionA(GetX, GetY, 24); SetCollisionB(GetX, GetY, 24); yield; } @DrawLoop { //描画ループ。1フレームに1回実行 DrawGraphic(GetX, GetY); } @Finalize { //敵が消滅した瞬間に一度だけ実行される部分 DeleteGraphic("script\img\ExRumia.png"); } @BackGround { //スペルカード時の背景部分 //無くてもよい } task Main{ loop(100){yield;} loop{ loop(10){ let angle=-120; while(angle<=-60){ obj_shot(GetX,GetY,3,angle); angle+=15; } loop(10){yield;} } loop(100){yield;} } }//いらないものを削った task Main2{ loop(100){yield;} let angle2=0; while(angle2<360){ LaserObject(GetX,GetY,300,10,angle2,RED04); angle2+=90; } } let arrayLaser=[]; //以前言われていたようにタスク内で宣言されている変数はそのタスク内でのみ有効 //そのためオブジェクト同士の接触判定=タスク同士の干渉はそのままでは行えない //変数arrayLaserはこれを解決するための変数 //これ自体はscript_enemy_mainというタスク全体で有効な変数(グローバル変数) //これに干渉させたいオブジェクトのIDを放り込むことで別タスクにちょっかいをかけられるようになる task LaserObject(let x,let y,let laser_length,let laser_width,let angle3,let color){ let obj=Obj_Create(OBJ_LASER); //ここで変数objを宣言しているがこれはCreateShotAでいうID //変数自体はこのタスク内でのみ使えるが…… arrayLaser = arrayLaser~[obj]; //グローバル変数にこの変数を格納することで //このタスクの外にこのレーザーオブジェクトの情報を持って行けるようになる //このタスクのレーザーが消滅するときはここに放り込んだ要素も削除しないと //動作がだんだん重くなったり、変な動作の原因になったりする //今回はレーザーは消滅しないので配列要素の削除は無くてもいい //ヘルプのサンプルに削除が必要なケースがあるからそちらを参考に Obj_SetPosition(obj,x,y); ObjShot_SetGraphic(obj,color); Obj_SetSpeed(obj,0); Obj_SetAngle(obj,angle3); ObjLaser_SetLength(obj,laser_length); ObjLaser_SetWidth(obj,laser_width); let count2=0; loop{ count2++; if(count2<200){ Obj_SetPosition(obj,x,y); Obj_SetAngle(obj,angle3); ObjLaser_SetWidth(obj,2); Obj_SetCollisionToPlayer(obj,false); Obj_SetCollisionToObject(obj,false); //プレイヤーへの当たり判定だけでなく //オブジェクト同士の当たり判定も消すのを忘れずに ObjLaser_SetSource(obj,false); } if(count2>=200){ Obj_SetPosition(obj,x,y); Obj_SetAngle(obj,angle3); ObjLaser_SetWidth(obj,laser_width); Obj_SetCollisionToPlayer(obj,true); Obj_SetCollisionToObject(obj,true); //プレイヤーへの当たり判定だけでなく //オブジェクト同士の当たり判定を復帰させるのを忘れずに ObjLaser_SetSource(obj,false); } if(count2==400){count2=0;} angle3++;if(angle3>360){angle3=0} yield; } } task obj_shot(let set_x,let set_y,let speed,let angle){ let obj=Obj_Create(OBJ_SHOT);//この変数はこのタスク内のみで有効。よって[i]は不要。 ObjShot_SetGraphic(obj,BLUE21); Obj_SetPosition(obj,set_x,set_y); Obj_SetSpeed(obj,speed); Obj_SetAngle(obj,angle); let count=0; while(!Obj_BeDeleted(obj)){ //whileループは条件がfalseになるまで繰り返される処理 //この場合は弾オブジェクトが消滅するまでループ //そのため改変前の形だと1回目のループを抜け出す=弾が消滅している //なので2回目のループの条件が既にfalseになっており //接触判定が行われることが無い //この問題の解消法のひとつが反射と接触判定を同時に行うこと //ただし今回のスクリプトはレーザー発生位置と弾発生位置が同じなので //弾発生即軌道変化ということになってしまう if(count < 1){ if(Obj_GetX(obj)<=GetClipMinX || Obj_GetX(obj)>=GetClipMaxX) { Obj_SetAngle(obj,180-Obj_GetAngle(obj)); count++; }//せっかくだからまとめておいた。 if(Obj_GetY(obj)<=GetClipMinY) { Obj_SetAngle(obj,-Obj_GetAngle(obj)); count++; } } ascent(i in 0..length(arrayLaser)){ if(Collision_Obj_Obj(arrayLaser[i],obj)){ set_x=Obj_GetX(obj); set_y=Obj_GetY(obj); CreateShot01(set_x,set_y,1,Obj_GetAngle(arrayLaser[i])-90,GREEN21,0); Obj_Delete(obj); //レーザーと接触していたらレーザーと垂直方向に弾を出して //この弾自体は消滅する break; //このbreakの意味は後述 } } //変数iを増やしつつ特定回数をループさせる、などの操作にはascent関数が便利 //処理の内容は改変前と同じで、ループ内のみ有効な変数iが0(最初の数字)から //length(arrayLaser)(最後の数字、ただしこの数字は含まない)まで //1ずつ増加しながら増えていく、という処理 yield; } } //おまけ 反射してからレーザーと接触して軌道を変えるようにする場合 task obj_shot2(let set_x,let set_y,let speed,let angle){ let obj=Obj_Create(OBJ_SHOT); ObjShot_SetGraphic(obj,BLUE21); Obj_SetPosition(obj,set_x,set_y); Obj_SetSpeed(obj,speed); Obj_SetAngle(obj,angle); let count=0; while(!Obj_BeDeleted(obj)){ if(Obj_GetX(obj)<=GetClipMinX || Obj_GetX(obj)>=GetClipMaxX){ Obj_SetAngle(obj,180-Obj_GetAngle(obj)); count++; if(count >= 1){break;} //既定の回数反射するとこのwhileループから脱出 } if(Obj_GetY(obj)<=GetClipMinY) { Obj_SetAngle(obj,-Obj_GetAngle(obj)); count++; if(count >= 1){break;} //既定の回数反射するとこのwhileループから脱出 } yield; } while(!Obj_BeDeleted(obj)){ ascent(i in 0..length(arrayLaser)){ if(Collision_Obj_Obj(arrayLaser[i],obj)){ set_x=Obj_GetX(obj); set_y=Obj_GetY(obj); CreateShot01(set_x,set_y,1,Obj_GetAngle(arrayLaser[i])-90,GREEN21,0); Obj_Delete(obj); //レーザーと接触していたらレーザーと垂直方向に弾を出して //この弾自体は消滅する break; //同時に複数のレーザーに接触した場合に備え、最初に接触が //確認された段階でascentループから抜け出す //breakは一番内側のループから抜け出す関数 //この場合はascent //このbreakがないと既に消えた弾とレーザーとの判定比較という //無駄な処理が発生してしまう } } yield; } } //task Mainにおいてobj_shotの代わりにこのobj_shot2を使うとこちらになる }