前回のプログラムに星を降らせる部分と星を拾う部分を追加して、ゲームは完成です。
星は、画面内に妖精を飛ばせて、その妖精から落とさせます。
プレイヤーが星を拾ったら、次の星を降らせるようにします。
弾む円は最初は数を少なくして、プレイヤーが星を取るたびに円を1つずつ増やしていきます。
また、ゲームの終了処理も少し追加します。
迷路探検ゲームのときはゴールすればそのまま終了にしていましたが、今回はプレイヤーがやられた後、円の弾む動きを続行し、画面外へすべての円が出て行くのを待ってゲーム終了にしてみました。
星の動きのアニメーションは、15日目で作成した「落ちた後2回弾んで止まる」という動きを使います。
また、星を落とす妖精はスプライトで表示します。
星の動きのアニメーションは、開始地点のY座標が50のときに画面下端まで落ちるように設計しています。
従って、妖精の動きは下図のように、画面上端から50ピクセルの位置で、左右に往復するようにします。
また、落とした星が画面外に出ないように、星のアニメーション開始のX座標は画面中央100ピクセルの範囲とします。
妖精の移動範囲はこれよりも広い幅300ピクセルの範囲としました。
これで、プレイヤーが星を取ってから、次の星が降ってくるまでのタイミングに変化が生じます。
妖精が左右に行ったり来たりする動きは、振り子の動きのように、端へ近づくほどスピードを落とすと雰囲気が出ます。
そのような動きをさせるために、今回は三角関数の一つであるサイン関数を使います。
サイン関数は角度をパラメータとする関数で、その値は下のグラフのように-1~1の範囲を往復します。
これを妖精の動きのX座標に使えば、振り子が往復するような動きをさせることができます。
なお、横軸の単位は円周率πです。グラフの右端はθ=2ですが、これはθ=2πと読み替えてください。
θが0、π、2πのときsin(θ)=0、θがπ/2のときsin(θ)=1、θが3π/2のときsin(θ)=-1となります。
以上の処理を行うプログラムは以下のようになります。(今回はプログラム全体は大きいので、一部分だけ掲載します。)
赤字の箇所が妖精の処理、青字が星の処理です。
ACLS _MAN=0:_FRY=1:_STAR=2 GPRIO 1 'PLAYER MANX=200 SPSET _MAN,1128 SPCOL _MAN,12,16 SPANIM _MAN,"I",9,1128,9,1129,9,1130,9,1131,0 'FAIRY FRYT=0 SPSET _FRY,900 SPHOME _FRY,8,8 SPSCALE _FRY,1.5,1.5 SPANIM _FRY,"I",15,900,15,901,0 'STAR SPSET _STAR,226 SPCOL _STAR,16,16 SPANIM _STAR,"C",4,&HFFFFFFFF,4,&HFF808080,0 NOSTAR=TRUE SCORE=0 BGMPLAY 39 N=1 'NUMBER OF BALLS-1 HITX=6:HITY=7 'PLAYER HIT TEST AREA HITW=16-HITX*2:HITH=16-HITY DIM PXL[HITW*HITH] @LOOP GSAVE MANX+HITX,224+HITY,HITW,HITH,PXL,1 HIT=0 FOR I=O TO HITW*HITH-1 HIT=HIT OR PXL[I] NEXT IF HIT!=0 THEN GOTO @EXIT STICK OUT SX,SY MANX=MANX+SX*4 MANX=MIN(384,MAX(0,MANX)) SPOFS _MAN,MANX,224,0 FRYT=FRYT+.02 FRYX=200+SIN(FRYT)*150 IF FRYT > 2*PI() THEN FRYT=0 SPOFS _FRY,FRYX,50,-1 IF NOSTAR && 150 < FRYX && FRYX < 250 THEN NOSTAR=FALSE SPOFS _STAR,FRYX,50,0 IF PI()/2 < FRYT && FRYT < 3*PI()/2 THEN SPANIM _STAR,"XY+",LFALL,1 ELSE SPANIM _STAR,"XY+",RFALL,1 ENDIF ENDIF IF SPHITSP(_MAN,_STAR) THEN N=MIN(NMAX-1,N+1) 'INCREASE BALLS SPOFS _STAR,-100,-100 'HIDE THE STAR NOSTAR=TRUE BEEP 12 SCORE=SCORE+1 LOCATE 0,0 COLOR 7 PRINT "★"*SCORE COLOR 15 ENDIF
最初に、プレイヤー・妖精・星のスプライト番号を変数に代入しています。
これはプログラムを読みやすくするためで、BASICには名前つき定数が無いので変数を使っています。
_MAN=0:_FRY=1:_STAR=2
妖精の位置を表す変数はFRYTです。
これは座標ではなく、サイン関数に渡すための角度です。
SPHOMEでスプライトの原点をスプライトの中心とし(通常は原点は左上)、スプライトのサイズを1.5倍にしています。
ループの中で変数FRYTを0.02ずつ大きくし、2πを超えたら0にリセットしています。
FRYT=FRYT+.02
FRYX=200+SIN(FRYT)*150
IF FRYT > 2*PI() THEN FRYT=0
X座標FRYXは、三角関数でX=200からプラスマイナス150ピクセルの範囲で変化させています。
星のスプライトは、SPCOLで当たり判定を有効にしています。プレイヤーのスプライトもSPCOLを追加しています。
そして、星が画面内に表示されている状態かどうかを表す変数NOSTARを用意します。
星の出現処理は、NOSTARがTRUEのときのみ行います。
星を出現させたらNOSTARをFALSE、プレイヤーが星を取ったらNOSTARをTRUEにします。
星の出現処理は、ループの中の
IF NOSTAR && 150 < FRYX && FRYX < 250 THEN
という条件が満たされたとき実行します。
出現地点は妖精の現在位置です。
また、アニメーションは「右に落ちる動作(RFALL)」「左に落ちる動作(LFALL)」の2種類を用意し、妖精の移動方向に合わせて選択しています。
プレイヤーが星を取ったかどうかは
SPHITSP(_MAN,_STAR)
で判定します。
衝突していれば円を増やし、次の星を出現可能にし、スコア表示を更新します。
円とプレイヤーが衝突するとラベル@EXITへジャンプします。
それ以降がゲーム終了処理です。
円が左右ではね返る処理を無くし、すべての円が画面から出てくるまで待ってからプログラムを終了します。
プログラムはこちらです。
@EXIT SPCHR _MAN,1141 BEEP 13 REPEAT DONE=TRUE GCLS FOR I=0 TO N GCIRCLE X[I],Y[I],R[I],C[I] GPAINT PAINTX(X[I],R[I]),Y[I],C[I],C[I] V[I]=V[I]+G IF Y[I]+V[I] > SCH-R[I] THEN V[I]=V0[I] Y[I]=SCH-R[I] ENDIF INC Y[I],V[I] INC X[I],DX[I] IF -R[I] < X[I] && X[I] < SCW+R[I] THEN DONE=FALSE ENDIF NEXT VSYNC 1 UNTIL DONE DEF PAINTX(X,R) IF X < 0 && (X+R) > 0 THEN RETURN 0 IF X > SCW && (X-R) < SCW THEN RETURN SCW RETURN X END BGMSTOP ACLS
REPEAT文の内側の処理は、メインのループの中での処理とほとんど同じですが、一部だけ違っています。
まず、円が画面から半分以上出た時のPAINTの処理です。
メインループでは、PAINTの開始点を円の中心にしています。
下図左のような状態のときはメインループと同様の処理で問題ありませんが、下図右のようになった場合、円の中心が画面の外にあるため、PAINTが実行されません。
このような場合のPAINT開始点を求める関数PAINTXを定義して使っています。
Y座標は円の中心のY座標ですので、必要なのはX座標だけです。
また、X座標は円が画面左から画面外へ出て行く場合はスクリーン左端(0)、画面右から画面外へ出て行く場合はスクリーン右端(399)となります。
次に、全ての円が画面外へ出たかどうかの判定です。
これはFOR~NEXTループ内で
IF -R[I] < X[I] && X[I] < SCW+R[I] THEN
のところで判断しています。
この条件を満たす円は、スクリーンに残っていると判断されます。
FOR~NEXTループに入る前に変数DONEにTRUEを代入し、上記の条件を満たす円があったときはDONEにFALSEを代入します。
すべての円の処理が終わったとき、DONEがTRUEであれば、全ての円が画面外に出たことになります。
今回のプログラムはMiiverseで公開しています。
公開キーは【KKQEA1】です。
単純なゲームですが、BGMや効果音もつけて、それなりに遊べるゲームになったと思います。
コメント