東方弾幕風ph3で当たり判定があるスクリプトの実装。とりあえずヘルプ見ないと無理なのでリンクをはる。
敵の当たり判定がある弾幕風のソースコード
人が作ったスクリプトをコピペする。
#TouhouDanmakufu[Single] #ScriptVersion[3] #Title["Tutorial 02"] #Text["Boss collision, movement and firing"] let bossObj; let bossX = 0; let bossY = 0; let imgBoss = GetCurrentScriptDirectory ~ "chilno.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); // Warp the boss to this location when loaded ObjMove_SetPosition(bossObj,192,-100); // 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); // collision for the shots and player ObjEnemy_SetIntersectionCircleToShot(bossObj,bossX,bossY,24); ObjEnemy_SetIntersectionCircleToPlayer(bossObj,bossX,bossY,32); yield; } @Finalize { } // your best friend, forever. function wait(w) { loop(w) { yield; } } task mainTask { renderBoss; movement; } task renderBoss { let dir; let speed; // texture the boss, set centre as true centre. ObjPrim_SetTexture(bossObj,imgBoss); ObjSprite2D_SetSourceRect(bossObj,0,0,110,110); ObjSprite2D_SetDestCenter(bossObj); ObjRender_SetScaleXYZ(bossObj,0.7,0.7,0); while(!Obj_IsDeleted(bossObj)) { // update boss speed and direction locally dir = ObjMove_GetAngle(bossObj); speed = ObjMove_GetSpeed(bossObj); // if the boss is idle, show this image/rect if(speed == 0) { ObjSprite2D_SetSourceRect(bossObj,0,0,100,100); ObjRender_SetAngleXYZ(bossObj,0,0,0); } // boss holding location else if(cos(dir) 0) { ObjSprite2D_SetSourceRect(bossObj,0,0,100,100); ObjRender_SetAngleXYZ(bossObj,0,180,0); } // boss moving to the right yield; } } task movement { wait(60); fire; wait(30); loop { ObjMove_SetDestAtSpeed(bossObj,100,120,5); // move to the left wait(45); fire; wait(30); ObjMove_SetDestAtSpeed(bossObj,280,120,5); // move to the right wait(45); fire; wait(30); } } function angleToPlayer { let dir = atan2(GetPlayerY-bossY,GetPlayerX-bossX); return dir; } task fire { let dir = angleToPlayer; // call function angleToPlayer, calculate the angle and store it inside dir. loop(10) { CreateShotA1(bossX,bossY,3,dir-20,14,0); CreateShotA1(bossX,bossY,3,dir,14,0); CreateShotA1(bossX,bossY,3,dir+20,14,0); wait(3); } }
わからないところを解体する。
- ObjMove_SetPosition(objid, x, y) → 指定したオブジェクトのx, y座標を指定
- ObjMove_SetDestAtSpeed(objid, x, y, speed) → 指定した座標にむかって指定した速度で移動。到達したら停止
- ObjEnemy_SetIntersectionCircleToShot(objid, x, y, radius) → この円に自弾が接触するとダメージ
- ObjEnemy_SetIntersectionCircleToPlayer(objid, x, y, radius) → この円に自機が接触すると撃墜される
- ObjRender_SetScaleXYZ(objid, x, y, z) → xyzは拡大率。詳細不明
- while(!Obj_IsDeleted(bossObj)) → ボスがまだ生きていたら
- ObjRender_SetAngleXYZ(objid, x, y, z) → 指定したオブジェクトのxyz角度を設定
どういうプログラム(コード)なのか
敵が移動しつつ3wayの自機狙いを撃ってくるコードになる。
- @Initializeでとりあえずボス登場後→mainTask開始
- mainTaskはrenderBossとmovement
- @Eventでボスのライフとタイマーを設定
- @MainLoopでボスの当たり判定(攻撃 and 防御)を毎フレーム変える
- task renderBoss → 右に移動しているときだけオブジェクトを反転
- task movement → 移動と攻撃
- function angleToPlayer → 自機狙い
- task fire → 3way弾
task renderBossでcos()などがでてきているけどよくわからない かつ 自機狙いのところの atan2が全く意味がわからない。とりあえず考えたら負けと考えることにする。ずっとコードを見ていればなにをしているかなんとなくわかるけど、もしかしたら挫折以前の問題かもしれない。
このコードは、ボス(敵)の当たり判定が実装されているので、ショットをあてるとボスのライフが減っていく。自機関係の実装はまったくなにもやってないけど、自機弾を敵にあてると敵のライフが減ったり、敵の弾に被弾して死ぬのは、弾幕風フォルダのどこかに自機のプログラムがあるのだろう。ひとまずボスの当たり判定を実装しているので、ボスのライフは減っていくけど、0になっても敵が破壊されないのでそのあたりは未実装になっている。
こんなコードをいちから書ける人はすごいなーと思っている時点でもうダメ。とりあえず気長に。
上記コードで改造できそうな部分
弾数を増やす
task fireのloop(10)は弾数になっているのでこれを10から30にかえれば単純に30発弾を撃ってくる。しかし、ボスは移動もしているので、task movementの待ち時間等を調整しないとひどい弾幕になる。
3wayを5wayにする
単純にCreateShotA1()を増やす。
task fire { let dir = angleToPlayer; // call function angleToPlayer, calculate the angle and store it inside dir. loop(10) { CreateShotA1(bossX,bossY,3,dir-40,14,0); CreateShotA1(bossX,bossY,3,dir-20,14,0); CreateShotA1(bossX,bossY,3,dir,14,0); CreateShotA1(bossX,bossY,3,dir+20,14,0); CreateShotA1(bossX,bossY,3,dir+40,14,0); wait(3); } }
偶数弾にしたいときは、いらない部分を消す。
コメント