【プチコン/mkII 両対応】
第1回ではプチコンにおいてコンソールとグラフィックの使い方を私の自作ゲームを例に出して書いていきました。コンソールとグラフィックだけでもさまざまなジャンルのゲームを作ることができるのですが、スプライトやBG画面を使いこなせるようになればさらにさまざまなゲームを作ることができるようになります。
CLS GCLS CLEAR SPSET 0,64,0,0,0,0 @LOOP SPOFS 0,X,80 B=BUTTON() IF B==4 THEN X=X-1 IF B==8 THEN X=X+1 VSYNC 1 GOTO @LOOP |
改善すべきポイント (1) 左に移動中はキャラを左向きにして右に移動中はキャラを右向きにする (2) 足を動かしているように見せる |
CLS GCLS CLEAR SPSET 0,64,0,0,0,0 SPANIM 0,4,10 @LOOP SPOFS 0,X,80 B=BUTTON() IF B==4 THEN X=X-1:SPCHR 0,72,0,0,0,0 IF B==8 THEN X=X+1:SPCHR 0,64,0,0,0,0 VSYNC 1 GOTO @LOOP |
10進数 | |||||||||||
2進数 |
CLS GCLS CLEAR X=128 Y=96 SPSET 0,64,0,0,0,0 SPANIM 0,4,10 @LOOP SPOFS 0,X,Y B=BUTTON() IF (B AND 4)==4 THEN X=X-1:SPCHR 0,72 IF (B AND 8)==8 THEN X=X+1:SPCHR 0,64 IF (B AND 1)==1 THEN Y=Y-1:SPCHR 0,76 IF (B AND 2)==2 THEN Y=Y+1:SPCHR 0,68 VSYNC 1 GOTO @LOOP |
CLS GCLS CLEAR X=128 Y=96 SPSET 0,64,0,0,0,0 SPANIM 0,4,10 @LOOP SPOFS 0,X,Y B=BUTTON() IF B AND 4 THEN X=X-1:SPCHR 0,72 IF B AND 8 THEN X=X+1:SPCHR 0,64 IF B AND 1 THEN Y=Y-1:SPCHR 0,76 IF B AND 2 THEN Y=Y+1:SPCHR 0,68 VSYNC 1 GOTO @LOOP |
CLS GCLS CLEAR X=128 Y=96 SPSET 0,64,0,0,0,0 SPANIM 0,4,10 @LOOP SPOFS 0,X,Y B=BUTTON() C=B AND 15 IF C==4 THEN X=X-1:SPCHR 0,72 IF C==8 THEN X=X+1:SPCHR 0,64 IF C==1 THEN Y=Y-1:SPCHR 0,76 IF C==2 THEN Y=Y+1:SPCHR 0,68 VSYNC 1 GOTO @LOOP |
V=COS (PI()*A/180)*8-SIN (PI()*A/180)*8 W=SIN (PI()*A/180)*8+COS (PI()*A/180)*8 |
V=COS (PI()*(A+45)/180)*8*SQR(2) W=SIN (PI()*(A+45)/180)*8*SQR(2) |
CLS GCLS X=128 Y=96 GLINE X,0,X,191,2 GLINE 0,Y,255,Y,2 SPSET 0,96,0,0,0,0 SPSCALE 0,200 @LOOP FOR I=0 TO 359 V=COS (PI()*(I+45)/180)*16*SQR (2) W=SIN (PI()*(I+45)/180)*16*SQR (2) SPANGLE 0,I SPOFS 0,X-V,Y-V VSYNC 1 NEXT GOTO @LOOP |
CLS GCLS X=128 Y=96 GLINE X,0,X,191,2 GLINE 0,Y,255,Y,2 SPSET 0,96,0,0,0,0 SPSCALE 0,200 SPHOME 0,8,8 @LOOP FOR I=0 TO 359 SPANGLE 0,I SPOFS 0,X,Y VSYNC 1 NEXT GOTO @LOOP |
CLS GCLS CLEAR FOR I=0 TO 31 FOR J=0 TO 31 BGPUT 0,I,J,I*32+J NEXT NEXT BGCLIP 8,4,24,20 @LOOP BGOFS 0,X,Y LOCATE 0,0 PRINT X,Y, B=BUTTON() IF B AND 4 THEN X=X-1 IF B AND 8 THEN X=X+1 IF B AND 1 THEN Y=Y-1 IF B AND 2 THEN Y=Y+1 VSYNC 1 GOTO @LOOP |
0・・・・・31 ・ ・ 使用 ・ 31 | 32・・・・・63 未使用 |
32 ・ ・未使用 ・ 63 | 未使用 |
CLS GCLS CLEAR FOR I=0 TO 31 FOR J=0 TO 31 BGPUT 0,I,J,I*32+J NEXT NEXT @LOOP BGCLIP 8,4,24,20 BGOFS 0,X,Y VSYNC 5 BGCLIP 0,0,31,23 BGOFS 0,X,Y VSYNC 5 LOCATE 0,0 PRINT X,Y, B=BUTTON() IF B AND 4 THEN X=X-1 IF B AND 8 THEN X=X+1 IF B AND 1 THEN Y=Y-1 IF B AND 2 THEN Y=Y+1 GOTO @LOOP |
コラム 「VSYNC 2=30fps」なのか?VSYNCは初代プチコンのマニュアルによると「画面更新周期との同期(描画更新待ち)」となっており、引数は「直前のVSYNC呼び出しからの経過フレーム数」となっています。VSYNCを使えば画面のちらつきが無くなるのと同時にゲームのフレームレートを安定させることが可能になるのですが、期待しているようなフレームレートにはならない場合もあります。その期待しているフレームレートというのはVSYNC 1ならば60fps、VSYNC 2ならば30fps、VSYNC 3ならば20fpsになるというものです。メインルーチン1回分の処理が1フレーム(1/60秒)で完了するような高速なゲームの場合はその計算は通用しているのですが、1フレームで完了しない場合はこの計算が通用しません。 VSYNC無しで45fpsのゲームの場合はVSYNC 1を入れた場合に前回からの経過時間が1/60秒以上すぎているため無視されるのかと思いきやそうはならず、30fps程度まで低下しているからです。そして、VSYNC2ならば前回から2フレーム(1/30秒)以上すぎているから30fpsが維持されるかと思えば今度は20fps程度まで低下しています。そして、VSYNC 3ならば15fps程度まで低下しています。 VSYNC無しで30fpsのゲームの場合はVSYNC 1を入れたら30fpsのままで、VSYNC 2、VSYNC 3でもVSYNC無しで45fpsのゲームと動作速度は変わりませんでした。 したがって、VSYNCでその指定した値通りのきっちりとした速度を得たいならば1フレーム(1/60秒)以内にで処理を完了させるようにするしかないと言えます。どうしても30fpsを維持したいというのであればMAINCNTLを使うしかありません。 以上は初代プチコンにおけるVSYNCです。 mkIIではVSYNCの仕様が変わりました。初代プチコンだと1回の処理に1.5フレームの時間がかかる場合にVSYNC 2としてしまえば、1〜2フレーム分のウエイトが加算されてしまうため上記のようなことが起きてしまいました。しかし、mkIIでは前回のVSYNCの終了時を起点にしているためVSYNC 2ならば0.5フレーム分のウエイトとなります。このためmkIIではVSYNC 2で30fpsが維持されます(処理落ちしている場合を除く)。VSYNC1指定して処理に1フレームを超える時間がかかっている処理落ち状態の時は初代はウエイトが加算されていましたが、mkIIのVSYNCはウエイトがかからずすぐ抜けるようになっています。 このような動作の違いがあるためmkIIでは初代プチコンのVSYNCと全く同じ処理を行うWAIT命令が追加されました。初代プチコンにセーブしているプログラムをmkIIにコピーを行う際にはVSYNCは自動的にWAIT命令に置き換わるためユーザーは従来プログラムの互換性の心配をする必要はありません。(もっとも常時60fpsで動作しているならばmkIIにおいてもVSYNCとWAITに差異はないけど) メインルーチンを一定の速度で動作させたいときにはmkIIのVSYNCはかなり有用なのですが、単にウエイトが欲しいときにはWAIT命令の方が便利なのでmkIIユーザーは処理によって使い分けるのがベストだと思います。 mkIIの新しいVSYNC命令によって30fpsや20fpsで固定のゲームも簡単に作れるようになったのですが、60fpsで動作していないプログラムにおいて注意すべき点は一部正常に動作しない入力命令があるということです。ボタン入力においてはBUTTON()関数はmkIIでは連射の設定も可能になっていますが、BUTTON(1)、BUTTON(2)、BUTTON(3)、BTRIG()においては60fps時以外は入力の取りこぼしが出てしまいます。タッチパネルにおいてもシステムアイコン用のICONCHK()も同様に60fpsでないと取りこぼしが出てしまいます。(BUTTON関数やICONCHK関数やタッチパネル関係のシステム変数はVSYNC更新から次のVSYNC更新までの1フレームの間は同じ値を取ることに気を付ける必要がある) これらの命令を使う場合には何とかして60fpsでの動作(1フレームに1回読み出しを行う)を試みるか別の命令で代用するしかありません。
例えばレトロタイプなアクションゲームにおいて処理速度は十分に間に合っているけど時間稼ぎのために単純にVSYNC 8(7.5fps)と記述してしまうとBUTTON関数を使っていても入力の判定が8フレームに1回しかない(その判定がある1/60秒間以外に押したり離したりしたら正しい判定が行えない)ためボタン操作に対してキャラの動きが追従してくれない場合があります。その時は上記のように1フレームごとに入力を行いそれを元に入力判定を行えばスムーズな操作感覚が味わえるようになります。 また、常時60fpsで動作しているプログラムでないならばVSYNCやWAITの置き方によっては表示のちらつきが発生してしまう場合があります。これはプチコンでは画面の表示更新を1/60秒ごとに行っていてVSYNCやWAITを使うことでそのタイミングに自動的に合わせてくれているため普段が気が付きませんが、30fpsなどの60fps以外で動作しているプログラムならばその処理の途中で画面表示更新のタイミングが訪れます。CLSやGCLSを使っているプログラムの場合は1/60秒ごとの表示更新のタイミングで画面に表示されていなければちらついているように見えるわけです。 表示をちらつかさないためにはCLSやGCLSを行ってから次の表示更新までの間に表示を完了させる必要があります。そのため表示の処理が重いプログラムの場合はCLSやGCLSはなるべくVSYNCやWAITを実行してからすぐに実行して1/60秒をフル活用できるようにした方がベターです。(逆に言えばCLSやGCLSの直前にVSYNCやWAITを置けばよい) 1/60秒では消去と表示をすべて完了させるのは無理という場合には全体消去は行わず、部分消去、部分表示を行うことで1/60秒に収めるという方法もあります。この場合であっても次の部分消去を行った段階で表示更新が行われたらちらついてしまうので途中にVSYNC 1を挟むことでちらつきが改善ができます。(私が作った「2D→3D レース」ではその方法が用いられている) グラフィック面に限定するならば表示をしていない裏画面に描画をして表示が終わったらGPAGEで表画面に切り替えるという方法もあります。(Tipsコーナーの「ダブルバッファリング」を参照) なお、ACLSは便利な命令ですが1回の実行につき0.966フレームかかる非常に動作が重い命令なので1フレームで表示を完了させるのがほぼ無理になってしまうためプログラムの最初以外では使わない方が良いでしょう。CLSならば0.116フレームなので表示のちらつきを無くすのは容易です。 ※mkII(ver.2.0)においては初回実行時にVSYNCが無視されるというバグがありました。 このバグはver.2.1の更新で解消されました。 |