プチコン3号入門講座

グラフィック表示をしよう


RGB指定して線を描いてみよう



 さて、今まではプチコン3号でコンソール画面による文字表示のみを行ってきましたが、やはり文字表示だけでは寂しいですね。「いや文字だけでも立派にゲームは作れる」という声も聞こえそうですが、せっかくプチコン3号に備わっている機能を使わないのはもったないないのでそういう声はスルーして先に進もうと思います。

 まずは基本となるのがGLINE命令です。これは画面上の2つの点を指定してそれを結んで直線を描く命令です。
 ここでの座標ですがコンソール画面ではX座標が049、Y座標が029の範囲となっていたのに対してグラフィック画面ではX座標が0399、Y座標が0239の範囲となっています。画面外の座標は指定できますが、範囲外だと画面には表示されません。



GLINEは次のような書式になっています。

 GLINE 始点X座標 , 始点Y座標 , 終点X座標 , 終点Y座標 , 色コード (※[, 色コード]は省略可能)

 単純に始点と終点の座標を線で繋ぐだけなので始点と終点の座標はどちらが大きくなっても構いません。さて、問題は色コードです。これは直接指定するのが難しいので簡単に指定できるRGB()関数が用意されています。
 RGB()関数はR(赤)成分を0〜255の範囲、G(緑)成分を0〜255の範囲、B(青)成分を0〜255の範囲で指定できます。パソコン等でお絵かきソフトを使ったことがあれば簡単に分かると思いますが、R、G、Bの各成分を調整するだけであらゆる色を表現できます。(赤、緑、青は光の三原色)

《 RGBによる色指定の例 》
255
0
0
明るい緑
0
255
0
0
0
255
0
128
0
黄色
255
255
0
ピンク
255
0
255
水色
0
255
255
255
255
255
0
0
0
128
0
255
肌色
255
200
160
 ※これはあくまで一例なので自由な色の設定ができます。(RGB各256段階で色指定が可能になるといっても下記のように実際には8の倍数で丸められるため注意が必要)

 では、座標(70,50)と座標(250,180)を結んだ水色の線を描いてみましょう。簡単ですね。

 GLINE 70,50,250,180,RGB(0,255,255)

 RGB設定ではなくあらかじめ決められた色を手軽に使いたいという人のためにプチコン3号 ver.3.2.0からは定数リテラルが導入されました。例えば色コードで赤を選択する場合にはRGB(255,0,0)としなくても#REDと指定することも可能になっています。

 GLINE 70,50,250,180,#RED

 この定数リテラルで設定されている色は#を入力して[?](ヘルプボタン)で見ることができますが、コンソールの定数リテラルから"T"を省いたものがグラフィックにおける定数リテラルの設定名となっています。(例:コンソールで白:#TWHITE → グラフィックで白 #WHITE

 ちなみに透明色を指定するときはRGB(0,0,0,0)としてください。透明度を指定する時は3つだったカッコの中の引数が4つへと増えます。先頭に追加した0が透明度を示しますが、透明度は「255の時は不透明」で「255以外の時は透明」になります。
 ただし、半透明にすることはできないので赤の半透明をしようとRGB(100,255,0,0)とするのは無意味でRGB(0,0,0,0)と同じ透明色になります。下記GSPOIT()で読み出す時に透明色の色コードがバラバラだとあまり良くないので透明色を指定するときはRGB(0,0,0,0)に統一するのがベターだけど同じ透明なのにGSPOITで異なる色コードになるのを逆に利用して32768種類のキャラを簡単に判別できるお手軽当たり判定を作ることも可能)

 もっとも、RGB(0,0,0,0)の値は0になるため透明色を設定したい場合はRGB()関数を使わず色コード0を直接指定しても良いです。

 標準設定だと背景色が黒なので黒と透明は区別が付きませんがグラフィックの奥にコンソール画面を表示してやればその違いは一目瞭然です。

《 黒と透明色の違いを見つけるプログラム 》
COLOR 14
FOR X=0 TO 49
 FOR Y=0 TO 29
  LOCATE X,Y,1024:PRINT "■"
 NEXT
NEXT
GLINE 0,50,399,50,RGB(0,0,0)  ※黒色の線
GLINE 0,200,399,200,RGB(0,0,0,0)  ※透明の線

 このプログラムを実行すると本来ならば2本の線が表示されるはずですが、上の黒色の線しか表示されておらず下の透明色の線は奥にあるコンソール画面が透けて見えている(見た目では線が見えない)のが分かります。


いろいろなグラフィック命令を使って描いてみよう



 プチコン3号では上記GLINEの他にも多くのグラフィック命令が使用できます。

 まず紹介するのが描画色を指定する命令であるGCOLORです。GCOLOR 色コードという形で指定できます。(色コード指定はRGB()関数を使うと簡単)
 線や四角形などを描画する際には毎回描画色を指定する必要がなくGLINEと同じく描画色は省略が可能なのですが、その描画色を省略した場合にはこのGCOLORで指定した色で描画されます。よく使う色があればあらかじめここで指定しておくと良いでしょう。

 では、GLINE以外のさまざまな図形が描ける命令を見てみます。

GPSET (指定した座標に点を描く命令)
GPSET X座標 , Y座標 , 色コード
GBOX (指定した2つの座標を対角頂点とする四角形を描く命令)
GBOX 始点X座標 , 始点Y座標 , 終点X座標 , 終点Y座標 , 色コード
GFILL (指定した2つの座標を対角頂点とする塗りつぶされた四角形を描く命令)
GFILL 始点X座標 , 始点Y座標 , 終点X座標 , 終点Y座標 , 色コード
GTRI (指定した3つの座標を頂点とする塗りつぶされた三角形を描く命令)
GTRI X座標1 , Y座標1 , X座標2 , Y座標2 , X座標2 , Y座標2 ,色コード
GCIRCLE (指定された座標を中心とした円を描く命令)
GCIRCLE 中心X座標 , 中心Y座標 , 半径 , 色コード
GPAINT (指定された座標を基準にして塗りつぶす命令)
GPAINT 基準X座標 , 基準Y座標 , 色コード , 境界色コード
GTRI命令はver.3.1.0で新しく加わった命令です

 どれも実際に自由な座標で描いてみればすぐに分かります。

 この中で少し分かりにくいのがGPAINTです。GPAINTは囲まれた領域を塗りつぶす命令であるため囲まれた内部の座標を指定する必要があります。正しく囲まれておらず色がはみ出る場合は正常には塗りつぶすことができません。
 囲まれている部分というのは基準座標と異なる色であれば何でもいいので基準座標の点がが黒色だとすると上側を囲っているのが白、下側を囲っているのが赤、右側を囲っているのが緑、左側を囲っているのが青というようにバラバラの色で囲まれていてもその範囲を塗りつぶします。
 そこで、どの色で囲まれている部分を塗りつぶすかというのを指定するのが4つ目の引数である境界色です。これを指定することで指定色で囲まれた部分のみを塗りつぶすことが可能です。(境界色は省略可能)

 画面上の特定のドットの色を調べるにはGSPOIT()関数を使います。A=GSPOIT(X,Y)とすることで座標(X,Y)のドットの色コードが変数Aに入ります。ただし入るのは色コードであるためこのままでは分かりづらいです。
 そこでRGB()関数の逆として色コードをRGBに変換するRGBREAD命令が用意されています。変数Aに色コードが入っている場合はRGBREAD A OUT R,G,Bとすることで変数Rに赤成分、変数Gに緑成分、変数Bに青成分が0〜255の範囲の値で入ります。

 さて、いろいろ描いていたらごちゃごちゃしてくると思います。そこでグラフィック画面を消すGCLS命令が用意されています。画面全体ではなく一部を消したい場合は消したい部分の上にGPSETGFILLなどを使って透明色で描画していくと良いでしょう。

 コンソール画面がCLS、グラフィック画面がGCLSと画面消去命令を2回も使うのが面倒ならばACLSでコンソール画面もグラフィック画面も両方消去できます。ただし、ACLSではグラフィック画面のページ0とページ1のみを消去するだけなので下記のようにグラフックページの設定を変えている場合はACLSでは削除できず、消去したいグラフィック面のページを指定してそこでGCLSを行う必要があります。

 また、GCLSはグラフィック画面を消すだけではなくGCLS , 色コードとすることで画面全体を特定の色で塗りつぶすことができます。簡易的に背景色の設定ができるので活用すると良いでしょう。

 GSPOIT()による当たり判定を行うサンプルゲームを用意しました。

《 サンプルゲーム「ドットよけ」 》
Y=120:S=0:L=1
@START
 ACLS
 X=0
 FOR I=1 TO L*300
  GPSET RND(380)+20,RND(240),#RED
 NEXT
@LOOP
 S=S+1
 B=BUTTON()
 IF B==16 THEN Y=Y-1 ELSE Y=Y+1
 G=GSPOIT(X,Y)
 GPSET X,Y,#GREEN
 IF G=#RED OR Y<0 OR Y>239 THEN @END
 X=X+1
 IF X>399 THEN @CLEAR
 VSYNC 2
 GOTO @LOOP

@CLEAR
 BEEP 71
 S=S+99
 L=L+1
 GOTO @START

@END
 BEEP 11
 LOCATE 0,1:?"SCORE=";S
BUTTON()に関しては後述の「ボタンやスライドパッドでキャラを動かしてみよう」を参照

 これは画面左端から伸びている緑の線がプレイヤーでAボタンを押している間は上に行き押してない間は下に行くので障害物である赤のドットを避けて画面上下にはみ出すことなく画面右端に到達すればステージクリアというゲームです。
 最初にFORNEXTを使用して画面上にランダムに赤いドットを表示しています。ここではステージである変数Lの値が大きくなるほど難易度が高くなるようにたくさんのドットを表示していますが、ランダムに表示するにはRND()関数を使います。詳しくは後述の「乱数は分からん数」で書きますが、RND(380)+20とすることで20399の範囲の乱数を発生させることで画面左端の20ドット分には障害物が表示されないようにして始まった瞬間にゲームオーバーになるのを防止しています。
 肝心の当たり判定ですが。これは変数Gの値で判断しています。Gの値が#REDならば衝突したと見なしてゲームオーバーになるのですが、コンソールのCHKCHR()での判定と同じく自キャラで上書きされるのを避けるためにプレイヤーの移動座標を決定 → GSPOIT()で読み取る → 障害物が無ければそこに移動(障害物があれば衝突処理を行う)という流れで判定を行う必要があります。
 判定の際に注意すべき点は定数リテラルを使わずRGB()関数を使用する場合は下記の「RGBによる色指定の罠」で書いているようにRGBの各成分は8の倍数で指定しないと誤動作してしまいます。例えば上記サンプルゲーム「ドットよけ」に2箇所ある定数リテラルの#REDRGB(255,0,0)に変えてみてください。すると正常に当たり判定が行われなくなります。RGB()を使って赤を表示して当たり判定を正しく行うには8の倍数であるRGB(248,0,0)とする必要があるわけです。RGB(248,0,0)RGB(255,0,0)は異なる値を返すのですが、表示したものをGSPOIT()で読み出した場合には両者は同じ値になることが誤動作の原因)


グラフィック画面のページについて



 プチコン3号ではグラフィック画面は0〜5の6ページ分が使用できます(以下、GRP0〜5とする)。標準設定ではGRP0が上画面グラフィック用、GRP1が下画面グラフィック用、GRP4がスプライトキャラ用、GRP5がBGキャラ用に割り当てられています。



 グラフィック画面に割り当てるGRPページの設定はGPAGE命令で可能です。

 GPAGE 表示ページ , 操作ページ

 では、GPAGE 4,0としてみてください。
 そうするとスプライトで使えるキャラが画面上にたくさん出ましたね。これは現在スプライトキャラが置いてあるGRP4を表示しているためです。これは、GCLS 4,0では表示ページがGRP4、操作ページがGRP0になっているためです。

 この状態でGFILL 50,100,300,200,RGB(255,0,0)として赤色で塗りつぶされた四角形を画面に描いてみましょう。
 すると何も描かれません。それはGRP0に描画しているためです。(表示しているのはGRP4
 ここで、GPAGE 0,0として元に戻してみましょう。ちゃんと赤色の四角形は描画されていることが分かります。

 では、今度はGPAGE 4,4としてみてください。先ほどと同じくスプライトキャラが表示されましたね。ここで同じくでGFILL 50,100,300,200,RGB(255,0,0)として赤色の四角形を描画すると今度はちゃんと描画されました。
 これは操作ページがGRP4になっているため表示ページと一致しているためです。
 この状態でGCLSとするとスプライトキャラがすべて消えてしまいます。でも、安心してください。ACLSを実行すればスプライトキャラはちゃんと元の状態に戻ります。つまり、グラフィックページが6ページあるといってもグラフィック用として自由に使えるのは0〜3の4ページのみということです。(スプライトやBGを使わず、ACLSも使わないならば6ページフルに使える)

 では、グラフィックページが4ページもあって何に使うのか分からないという人もいるでしょう。
 使用の一例としては表示ページと操作ページを別々に指定できるため表示していないページを裏画面として描画し、描画が終わったら操作ページと描画ページを切り替えることでちらつきのない画面にすることが可能ということです。(ちらつかないためにはVSYNCのタイミングに合わせて1フレーム以内に描画する必要があるけど複雑な図形を描く場合はそれは難しい)
 またキャラクタデータなどを置いて下記GCOPY命令を使って描画するという使い方もできます。
(スプライト用は1ページ分しかないので大きなキャラを表示したい場合には有効活用できる)

 そろそろ「グラフィック画面では奥行き表示はできないの?」と感じ始めている人もいることでしょう。

 ここまで書いて「コンソール画面で文字表示をしよう」では最初に書いた立体視を行うためのZ座標(奥行き)指定がグラフィック命令ではありませんからね。というのもグラフィック描画命令では奥行き設定はできないためです。

 グラフィック描画命令では奥行き指定はできませんがグラフィック画面そのものの奥行き設定はできます。それを行えるのがGPRIO命令です。GPRIO Z座標とすることでグラフィック画面のZ座標を変えることができます。このZ座標を変えることで表示の優先順位が変わります。したがって、例えばコンソール文字の手前にグラフィック表示したいという場合はその文字のZ座標よりも小さい値をGPRIOで指定する必要があります。
 標準ではGPRIO 512に設定されています。上記の透明色の描画確認としてLOCATEでZ座標1024を設定しているのは512よりも大きな値にしないと標準設定のグラフィック画面よりも奥に文字表示ができないためです。


グラフィック画面をスクロールさせよう



 上記の描画命令とは違い一旦描画したグラフィックを別の場所にコピーできるGCOPY命令があります。

 GCOPY コピー元ページ , 始点X座標 , Y座標 , 終点X座標 , Y座標 , コピー先X座標 , Y座標 , コピーモード
   ※コピーモードは0の時は透明色はコピーせず、1の時はコピーする

 これですでに描画されているグラフィックをコピーして現在操作しているページの好きな場所に貼り付けることができます。例えばGCOPY 5,384,288,351,399,0,0,0とすると上画面の左上に木が表示されます。GRP5はBGキャラに使われていますが、そのページの座標(384,288)〜(351,399)にあらかじめ用意されている木のグラフィックをコピーして貼り付けたというわけです。

 このGCOPYは様々な応用ができますが、その1つにグラフィック面では本来できないスクロールを行うということができます。

《 GCOPYによるスクロール サンプルプログラム 》
ACLS
GPAGE 0,1
GCLS RGB(40,160,200)
GFILL 0,160,511,239,RGB(48,48,0)
FOR I=0 TO 450 STEP 90
 GCOPY 5,384,288,351,399,I,49,0
NEXT
GPAGE 0,0
FOR I=0 TO 511
 GCOPY 1,0,I+399,239,0,0,0
 VSYNC 1
NEXT

 これを実行すればGRP画面がスクロール可能だと分かります。これはGCOPYによってコピー元のページのグラフィックを1ドットずつずらしたものを貼り付けているという簡単な原理です。
 上記においてグラフィック描画命令では画面外の座標を指定すると表示はできないと書きましたが、グラフィックページそのものは512×512ドットのサイズ(X座標0〜511、Y座標0〜511)であるためその範囲内ならばちゃんと描画は行われていますGCOPYを行うことでその画面の外にある見えない部分を有効活用できるわけです。(4行目のGFILLで画面外の座標を指定しているのもそのため)
 ただし、GCOPYでスクロールをする場合には512ドット以上のスクロールを行う場合にはその都度新規描画をしていかないとグラフィックが途切れてしまうことに注意しましょう。
 その都度新規描画を行うというのがどのようなものかを記すために横スクロールゲーム「CAVE」を用意しました。

《 「CAVE」プログラムリスト 》
ACLS:BGMPLAY 41
Y=30:V=RND(160)
REPEAT
 P=P+1
 W=80-P/40
 GCOPY 1,0,399,239,0,0,1
 GLINE 399,0,399,239,RGB(80,50,0)
 GLINE 399,V,399,V+W,0
 G=GSPOIT(34,Y)
 GFILL 32,Y-1,34,Y+1,#RED
 Z=Z-(BUTTON()AND 16)/16+0.5
 Y=Y+Z/2
 S=S+FLOOR(ABS(Z))+1
 U=RND(9)-4
 V=V+U*(U+V>0*(U+V+W<239)
 LOCATE 0,0:?"SCORE ";S
 VSYNC 1
UNTIL G||Y<0||Y>239
BGMSTOP:BEEP 115
GPUTCHR 90,90,"GAME OVER",3,5,#YELLOW

 これはAボタンを押せば上昇、離せば下降するので洞窟にぶつかったり画面外に出たりしないように進んでいくゲームです。移動には加速が付くのでテクニカルなボタン操作が必要になります。
 7〜8行のGLINE 399,0,399,239,RGB(80,50,0)GLINE 399,V,399,V+W,0の部分が新規描画の部分に相当しGCOPYによって画面に表示されたグラフィックの全体を1ドット左にずらし空いた右端のラインにおいて画面の上下一杯の茶色の線を引いてそこに空白の部分を付けることで新しい洞窟がどんどん描画されていくわけです。

 ボタン操作や移動部分については「ボタンやスライドパッドでキャラを動かしてみよう」「論理式で深まる条件判断」REPEATUNTILについては「ループ命令で条件判断」、GPUTCHR命令は下記を参照してください。


RGBによる色指定の罠



 プチコン3号では上記のようにグラフィックページではRGB()関数を使うことで赤成分が0255、緑成分が0255、青成分が0255で指定できます。一見すると256段階(各成分8bit)で指定できている感じですが実はそうではありません。それはプチコン3号は仕様上32768色+透明色しか表示できないためです。(この色は「物理16bit色コード」と呼ばれていて詳しくは下記参照)
 つまり、RGBの各成分は256段階(8bit)で指定しても32段階(5bit)に丸められてしまうということです。

 これは実際にグラデーション表示を行えば一目瞭然です。
 例えば赤、緑、青成分が同じ場合にはグレーになるわけですが、それを使って黒から白へのグラデーション表示を行ってみましょう。

ACLS
FOR I=0 TO 255
 GLINE I,0,I,239,RGB(I,I,I)
NEXT

 これを実行すると黒から白へは32段階しかないことが分かります。
 プチコン3号では32768色表示のためRGBの各成分は32段階(5bit)に丸められてしまうのですが、これがどのように丸められるかというと8の倍数になるように丸められます。
 つまり、黒はRGB(0,0,0)ですがそれより一段階明るいグレーはRGB(1,1,1)ではなくRGB(8,8,8)になるということです。次がRGB(16,16,16)RGB(24,24,24)、(中略)、RGB(248,248,248)といった感じです。例えばRGB(255,248,253)という色で指定してもRGB(248,248,248)に変えられてしまうというわけです。
 これを覚えておかないと上記のようにGSPOIT()で描画色を読み取った時に指定した色と食い違いが生じる場合があり正しい判定ができなくなってしまう恐れがあります。
 プチコン3号でver.3.2.0から新たに加わった定数リテラルにおいて赤の論理色コードを示す#REDRGB(255,0,0)を示す-65536でしたが、これはver.3.2.1では、RGB(248,0,0)を示す-524288に変更されています。その理由は上記のように表示の際に8の倍数で丸められるため「表示に使った色コードとGSPOITで取得された色コードが一致しない」という問題を回避するためのものでしょう。つまり、ver.3.2.1以降は定数リテラルを使用する限りは「8の倍数で丸められる」というのを意識せず使用可能になるということです。

 このRGBが各成分32段階の表示しかできないというのは仕様上の問題なのでどうしようもできないですが、擬似的ならば256段階にできます。それが「まず最初に何から始めたらいいの?」で公開キーを使ったファイルのダウンロードの練習用として私が用意した「擬似256階調関数 GRAY()(ファイル名:OCHA_GRAYというプログラムなのです。
 このプログラムを実行すれば分かりますが、擬似的とはいえなめらかなグラデーションになっていますね。

《 OCHA_GRAY の実行結果のスクリーンショット 》

※上半分がRGB()関数で普通に表示したもので、下半分がGRAY()関数を使って表示したもの

 実は赤、緑、青は輝度が大きいものから順に緑、赤、青となっています。そこで見た目の輝度をなめらかに変化させるため赤成分、緑成分、青成分が均等にならないようにうまく組み合わせることで実現しています。このためじっくり見たら赤みがかったグレー、緑がかったグレーが見えてしまいますがぱっと見た感じだと分かりにくいレベルだと思います。
 なお、この擬似的に256階調のグレー表示が可能になる関数GRAY()は皆さんの自作プログラムの中で自由に使って良いです。

《 GRAY()関数 プログラムリスト 》
DEF GRAY(GR)
 RETURN RGB(GR+(GR MOD 4>1)*8,GR+(GR MOD 8>3)*8,GR+(GR MOD 2)*8)
END
DEFによる自作関数の作り方は後述参照。

 プチコン3号が透明色を含めた16bitカラーになっているのはファイルサイズを小さくするためだと思います。それでもGRPが1枚512KBなので32bitカラーだと1枚が1MBになってしまいます。大して変わらないと思うかもしれませんが、通信速度の問題やスマイルブームのサーバーの問題があるため難しいところですね。
 それに、もしも32bitカラーだとプチコン3号で使用できるグラフィック面が減るとか処理速度が遅くなるという可能性を考えると現状の16bitカラーがベターかもしれません。


タッチでグラフィック画面に絵を描いてみよう



 3DSの下画面はタッチ対応であり、プチコン3号でもそれは使用できるためタッチペンでお絵かきをすることも可能です。
 プチコン3号ではユーザーが作った様々なお絵かきソフトが公開されていますがここではプチコン3号に標準で含まれているSMILEツールを使って描いてみることにします。(個人的にはなおさんの「PETIT BRUSH」、ロッドさんの「EASY PAINT」、クッキーさんの「k2kPaint」などがオススメなので詳しく知りたい人は各自で検索してね)
 SMILEツールは標準では[SMILE]ボタン(キーボード最下段中央の緑のキー)を押すと起動できます。これは制作中のプログラムとは独立した動作になる(隠しプログラムスロットの4番で動作している)ためこれを起動しても制作中のプログラムが消えることはありません。(SMILEツールはあまり使わないという人は自分が良く使うツールをSMILEボタンに登録しておくと便利)

 SMILEツールの使い方は電子説明書の23ページに書かれていますがあまり詳しくは書かれてないため「絵を描く」という部分のみ詳しく説明をしていきます。
 絵を描くには右端の[おえかき]を選択します。
 すると標準ではスプライト[SP]のグラフィックページの編集になっています。グラフィック画面に描くならば下段中央の[G0][G1][SP][BG]の中から[G0]もしくは[G1]を選択してください。ここでは[G0]を選択してみます。[G0]はグラフィックページ0、[G1]はグラフィックページ1を示す)
 画面右のパレットで色を選んで[PSET]で点を打つ(というか、自由な線を描く)[LINE]で直線を描く、[PAINT]で塗りつぶすの選択ができます。[UNDO]ボタンでアンドゥ(やりなおし)ができるため間違えたら焦らずに押しましょう。
 描き終わったら忘れずにセーブをしましょう。ACLSを実行したり、他のグラフィックをロードしたりすると消えてしまいます。
 Yボタンを押すとファイルメニューです。ver.3.1.0より古いバージョンでは英語のメッセージのみで慣れないと分かりにくかったですが、ver.3.1.0からはダイアログのメッセージに従って操作が可能になりました。ファイルメニューではAボタンでロード、Xボタンでセーブ、Bボタンでファイルメニューから抜けることができます。なお、ファイル名のチェック機能がないため使えないファイル名を選んでしまうとエラーでSMILEツールの動作が終了してしまいますが、描いている絵が消えることはないのであせらずすぐにSMILEツールを起動すれば問題ないです。GCLSACLSを実行したら描いていた絵が消えてしまうので注意)
 [おえかき]の画面でXボタンを押すと「ツールを終了しますか?」と聞いてくるので「はい」か「いいえ」を選択してください。なお、ツールを終了した場合にはSMILEツールの初期画面に戻りますが、この初期画面でXボタンを押すとSMILEツールは終了できます。
 なお、SMILEツールを終了時には余分なものが画面に残っているのでそれを消すにはACLSとしてください。
 セーブしたグラフィックをプログラムで使いたい場合にはLOAD "GRP0:(ファイル名)"とします。毎回ロードのダイアログが出るのが嫌ならばLOAD "GRP0:(ファイル名)",0と最後に",0"を付けてください。ロードの音を消したい場合はSYSBEEP=0(元に戻すにはSYSBEEP=1としてください。

 SMILEツールはクセがあるソフトで決して万人向けとは言えないし、自分が使いたい機能が備わってないと感じている人もいることでしょう。そのため「自分が使いたい機能を搭載したお絵かきソフトを作ってみよう」という人もいると思うかもしれませんが何をどうしたらいいのか分からないという人もいることでしょう。
 そこで私が「超簡易お絵かきプログラム」を用意しました。

《 超簡易お絵かきプログラム 》
XSCREEN 2
DISPLAY 1
GPAGE 1,1
WHILE 1
 BX=X:BY=Y
 TOUCH OUT T,X,Y
 IF T>1 THEN GLINE BX,BY,X,Y
 VSYNC
WEND

 下画面をタッチすると自由な線を描けます。というか、それだけのプログラムです。線の色を変えたい時はDIRECTモードでGCOLOR命令を使って色指定してください。消しゴムはGCOLOR 0とすることで使えますが、細いため使いやすいとは言えないかもしれません。(下画面の端の上下左右5ドット分に何も描けないのはTOUCH命令の仕様なので端まで描きたい場合はMiiverseの添付用お絵かきツールのように「キャンバスを動かす」などの工夫が必要)
 セーブやロードもDIRECTモードで行います。セーブはSAVE "GRP1:(ファイル名)"、ロードは上画面で使用する場合はLOAD "GRP0:(ファイル名)"、一旦描いた絵を続きを描くなどで下画面で使用する場合はLOAD "GRP1:(ファイル名)"としてください。画面を消すにはDIRECTモードでACLSとしてください。

 プログラムの解説については後述の「下画面を使ってみよう」で行いますが、簡単に説明すると前フレームのタッチ座標(変数BY、変数BYを記録しておき現在のタッチ座標(変数X、変数Yと線で繋いでいるだけです。ただし、TOUCH命令の仕様上、タッチしてない時は最後にタッチした座標を保持しています。そのため前回の座標と現在の座標を繋ぐだけだと一旦離した場合に離した座標(最後にタッチしていた座標)と新しくタッチし始めの座標が線で結ばれるためタッチしているのが「1フレーム超」である場合(タッチしているフレーム数が小数値になることはないため「1フレーム超」は「2フレーム以上」と同じ意味になる)のみ線で結んでいます。(「2フレーム以上」なのは「タッチされた」と判断可能な段階でTの値は1になっているので前フレームと現フレームでタッチしている必要があるためにはTの値は2以上であることが必要になる)
 ちなみに1フレームしかタッチしてない場合は何も描画されないのですが、普通にタッチする限りは「1フレームのみタッチ」という状況にならないため問題ありません。もしも気になるならばTOUCH OUT T,X,Yの後にIF T==1 THEN GPSET X,Yを記述すれば解決できます。

 非常にシンプルな内容ですが、初心者の方はこれを元にいろいろと機能を付け足していって自分だけのお絵かきソフトを作ってみるのがいいかもしれません。自分で作れば自分が欲しい機能を搭載できるし操作方法なども自分好みにすることが可能です。これを改造したものは自由に発表してもらって構わない(私の名前を出す必要は全く無い)のでどんどん改造してみてください。
 「1フレームのみタッチという状況にならない」と書いたものの点描をするため名人級の連射をすれば1フレームのみタッチという状況になりますが、そんなに激しくタッチしなければならない状況があるならば「点描モードを付ける」というのも良いでしょう。こんな感じで自分でツールを作れば自分が欲しい機能を付けられます。(QSPという文字数制限の中で私が欲しい機能を追加した「PETIT PAINT QSP」「SIMPLE PAINT QSP」も参考にしてみてください)


GRP(グラフィック)画面に文字表示をしてみよう



 グラフィック画面と文字表示に用いられているコンソール画面はお互い独立しているため文字をグラフィック画面に表示をすることはできません。したがって、文字をテキストではなくグラフィックにすることでGRP面に描画が可能になるGPUTCHR命令があります。
 この命令はver.3.1.0で新しく加わった命令ですが、GPUTCHR X座標 , Y座標 , "文字列" , 横拡大率 , 縦拡大率 , 色で表示できます。(拡大率はスプライトと異なり整数倍のみ有効)

 GPUTCHR 100,50,"プチコン3ごう",3,5,RGB(255,0,0)

 とすることで座標(100,50)(この座標が表示する文字の左上の座標)"プチコン3ごう" という赤色の文字が横3倍、縦5倍に拡大されて表示されます。(元はコンソール文字なので縦横8ドットのサイズなので横24ドット、縦40ドットになる)
 もちろん、上記のようにこの文字はコンソール文字ではなくグラフィックなのでCLSでは消去できずGCLSACLSが必要です。
 ちなみに文字列の所は数値を入れるとその文字コードの文字を1文字分表示可能です。

 GPUTCHR 100,50,65,8,8,RGB(0,0,255)

 とすることで、キャラコード65の文字 "A" が縦横8倍の青色で表示されます。

   さて、プチコンmkIIを使っていた人ならばコンソール文字だけではなくスプライトキャラやBGキャラもGPUTCHRで表示できるのではと感じるかもしれないですが、実はプチコン3号のGPUTCHRはコンソール文字のみとなっています。
 これはmkIIでは指定文字コードの文字だけだったのが文字列に対応したという大きな進化や縦横自由拡大率が実現されたというメリットがある反面で残念に感じている人もいるかもしれません。

 しかし、プチコン3号では新しく加わったユーザー定義命令が作れるDEF命令を使うことで対応が可能になります。(DEF命令においては後述参照)
 というわけで、GPUTCHRのスプライト版であるGPUTSPを作りました。

《 GPUTSP 命令 プログラム 》
DEF GPUTSP X,Y,N,J,K,C
 VAR D,G%[0],H,I,P,Q,U,V,W,R1,R2,G1,G2,B1,B2
 C=-ABS(C)
 SPDEF N OUT U,V,W,H
 GSAVE 4,U,V,W,H
 IF J==1 && K==1 && C==-1 THEN
  GLOAD X,Y,W,H,G%,0,0
 ELSE
  H=W*H
  WHILE I<H
   D=G%[I]
   P=I DIV W
   Q=I DIV W
   IF D< THEN
    IF C!=-1THEN
     RGBREAD C OUT R1,G1,B1
     RGBREAD D OUT R2,G2,B2
     D=RGB(R1/255*R2,G1/255*G2,B1/255*B2)
    ENDIF
    GFILL X+Q*J,Y+P*K,X+Q*J+J-1,Y+P*K+K-1,D
   ENDIF
   INC I
  WEND
 ENDIF
END

《 画面表示例 》


 これを使えばGPUTCHRとほぼ同じ書式となる GPUTSP X座標 , Y座標 , スプライト定義番号 , 横拡大率 , 縦拡大率 , 色 でスプライトキャラをグラフィック画面に表示できます。文字コードがスプライト定義番号に変わっただけですね。(色は「1」を設定すればデフォルトの色を表示する)

 GPUTSP 100,50,1433,5,2,RGB(200,100,50)

 こうすることでスプライト定義番号1433のハカセを座標100,50に横5倍、縦3倍のサイズで表示して赤味を帯びた感じで表示されます。
 ちなみにこのGPUTSPは縦横拡大率、色がすべて「1」の時は1秒間に1850回くらいの高速表示が可能ですが、拡大や縮小をしたときや色を変えたときには桁違いに遅くなってしまうため注意が必要です。あとアトリビュート設定を変えて定義されているキャラ(上や横に回転させた状態で定義されているキャラ)も速度の関係でデフォルト方向で表示されます。

 後述のようにスプライトは拡大縮小以外にも回転や半透明表示が可能ですが、このGPUTSPは速度面の問題とリストが長くなるという問題があるため回転や半透明にも対応していません。これはGPUTCHRも対応してないため問題はないでしょう。


GRP(グラフィック)のさらに高度な使い方



 ここではやや発展的な内容を扱います。

 上記GPUTSPのプログラムではGSAVEGLOADという命令が使われています。GSAVEでグラフィックの指定範囲を配列にコピーしてGLOADで配列のデータをグラフィック面にコピー(要するにグラフィック表示)ができます。つまり、GLOADGSAVEを使えばGCOPYみたいなこともできるわけです。
 GCOPYとは異なる点といえばあくまで配列変数によるデータであるためSAVE命令やLOAD命令を使って自由にファイルとしてセーブやロードができるという点です。(プログラムやGRP以外でファイルとしてセーブが可能なのは文字列と数値配列に限られる)
 あと注意する点としては1次元配列であれば要素数に不足が生じても自動的にサイズを合わせてくれますが、2次元配列ではサイズを揃えなくてはなりません。つまり、指定する大きさに応じて宣言するサイズが変わってくる(16x16ドットの範囲をGSAVEするには16x16の大きさの2次元配列が必要になるけどさらに詳しく言うならば32x16のように1次元目のみ大きい場合は問題なく動作が可能で16x32のように2次元目が大きい場合は問題が生じるけどその理由については後述参照)ということです。プチコン3号では2次元配列を一旦宣言したらそのサイズを変更できないためGSAVEGLOADは1次元配列でも2次元配列でもどちらでも良いけど1次元配列の方が扱いやすいと言えます。(より正しく言うならば1次元配列、2次元配列だけではなく3次元配列でも4次元配列でも問題はないけど2次元を超えると格納のされ方が複雑になるので使う意味はない)
 それと動作用のメモリを大量に消費するためあまり多く使っていたらOut of memoryエラーが出やすくなります。(あらかじめ宣言しておいた1つの配列変数を使い回すのがベター)

 このGSAVE命令を使えば本来は512x512ドットのサイズで固定だったGRPを自由なサイズで保存が可能になります。例えばスプライトキャラが置いてあるGRP4において左上のイチゴのスプライトキャラのみのGPR(つまり、16x16ドットのサイズのGRP)として保存)したい場合には下記のようにすれば良いです。(なぜ、扱いやすい1次元配列ではなく2次元配列にしているかは後述参照)

VAR G%[16,16]
GSAVE 4,0,0,16,16,G%,1
SAVE "DAT:ICHIGO",G%

 これは配列変数の値が保存されたDATファイルですが、LOAD "GRP0:ICHIGO" とすれば問題なくロードが可能であり、GRPとして保存されていることが分かります。作ったプログラムを公開する場合には有償のゴールド会員権を取得しない限りは1つのファイル(1つのプロジェクトフォルダ)の制限は4MBでそれを最大10個までしか公開できないため自作GRPが含まれたプログラムだとすぐに上限に達してしまいますが、小さいGRPならばファイルサイズを削減できるためたくさんのプログラムを公開できるようになるというわけです。
 ファイルに保存されたGRPはただの2次元配列変数によるデータファイルであるためGSAVEを使わなくても配列変数に適当な値を入れていけばそれでGRPとして保存が可能です。1次元配列だと単なるデータ配列として扱われてしまいGRPとしては読み込むことができないため注意!)

VAR G%[16,16]
FOR I=0 TO 15
 FOR J=0 TO 15
  G%[J,I]=65535
 NEXT
NEXT
SAVE "DAT:WHITEBOX",G%

 これも LOAD "GRP0:WHITEBOX" とすれば白の四角形が画面に表示されちゃんとGRPとして保存されていることが分かります。

 ここで注意するのがプチコン3号で扱う色には32bit論理色コード16bit物理色コードがあるということです。
 32bit論理色コードでは、RGBの各256段階(8bit)での色設定が可能でさらにそれに加えてA(アルファチャンネル)も256段階で設定可能であり、全部で32bitカラーが指定できます。(2進数については後述のビット演算のところで詳しく解説しています)

《 32bit論理色コード 》
A
R
G
B
11111111
11111111
11111111
11111111
8bit
8bit
8bit
8bit
※この32bit色コードは補数で表記されているため上位1bitは符号になっている

 16bit物理色コードでは、RGBの各32段階(5bit)での色設定が可能でさらにそれに加えてA(アルファチャンネル)も2段階(1bit)で設定可能であり、全部で16bitカラーが指定できます。

《 16bit物理色コード 》
R
G
B
A
11111
11111
11111
1
5bit
5bit
5bit
1bit

 32bit論理色コードで赤は 11111111 11111111 0000000 00000000 で10進数に変換すると-65536になり、16bit物理色コードで赤は 11111 00000 00000 163489になります。GRPは半透明にはできないため32bit論理色コードにおけるアルファチャンネルは自動的に255(=11111111になります。(32bit論理色コードにおける赤が11111111 11111111 0000000 00000000、10進数で-65536になるというのは理論上の話であり、画面表示を行う場合は上記のようにRGB(255,0,0)は実質RGB(248,0,0)と同じであるためこれは2進数で表記すると11111111 11111000 00000000 00000000、10進数で表記すると-524288となる)

 16bit物理色コードはRGB()関数などによって簡単に表示が行える32bit論理色コードと違って扱いにくいため16bit物理色コードを32bit論理色コードに変換するPTOL()関数を作ってみました。PTOLPhysics color to Logic color)

《 PTOL関数 プログラム 》
DEF PTOL(C)
 VAR A,R,G,B
 R=(C>>11)*8
 G=(C>>6)*8 AND 255
 B=(C>>1)*8 AND 255
 A=(C AND 1)*255
RETURN RGB(A,R,G,B)
END

《 PTOL関数を使ってイチゴを8倍に拡大するサンプル 》
VAR G%[16,16]
GSAVE 4,0,0,16,16,G%,1
FOR I=0 TO 15
 FOR J=0 TO 15
  GFILL J*8,I*8,J*8+7,I*8+7,PTOL(G%[I,J])
 NEXT
NEXT

DEF PTOL(C)
 VAR A,R,G,B
 R=(C>>11)*8
 G=(C>>6)*8 AND 255
 B=(C>>1)*8 AND 255
 A=(C AND 1)*255
RETURN RGB(A,R,G,B)
END

 このサンプルではGSAVEによって配列には16bit色コードを入れてそれをPTOL()関数によって32bit論理色コードに変換しているのですが、32bit論理色コードで扱うのが前提であれば、GSAVEの最後の引数である色変換フラグは0にして配列には32bit論理色コードを入れておいた方が良いでしょう。このサンプルを見てのように2次元配列を使用した場合には配列の1次元目はY座標、2次元目はX座標となっています。2次元配列を使用した場合には1次元目が大きい場合が問題なく2次元目が大きい場合に問題が生じるのはこのためです。(仮にG%[16,17]という配列を宣言しておいた場合には1ラインごとに1ドットずつずれて格納されていく)
 GSAVEで配列に入れたデータをGLOADで表示する場合には配列に入っているのが16bit論理色コードならばGLOADでもそれを変換せずに16bit論理色コードのままにしなくては表示が行えません。逆にGSAVEで32bit論理色コードに変換したものを配列に入れているならばGLOADでも32bit論理色コードに変換の必要性があります。なお、GSAVEした配列をGLOADでのみ使用するならば両方とも16bit論理色コードで統一した方が変換処理が要らない分だけ高速です。

 また、プチコン3号は&B1111111111111111000000000000000のように2進数で表した数字の先頭に「&B」を付けると2進数を10進数に変換できますが、その逆はできません。そこで、10進数を2進数に変換するBIN$関数を作ってみました。

《 BIN$関数 プログラム 》
DEF BIN$(A,N)
 VAR B$,C=FLOOR(A),Z
 IF C#<0 THEN INC C#,POW(2,53)
 IF CLASSFY(C#)||N>=54||N<1 THEN B$=BIN$()
 REPEAT
  Z=FLOOR(C#/2)
  B$=STR$(C#-Z*2)+B$
  C#=Z
 UNTIL C#<1
RETURN RIGHT$("0"*N+B$,N)
END

 このBIN$関数の簡単な使い方を説明すると変数Aに10進数の値が入っていて、それを32桁の2進数に変換したい場合はBIN$(A,32)とするだけです。Aの値が-65536ならば文字列"1111111111111111000000000000000"を返します。(このプログラムでは最大53桁までの2進数に変換でき範囲外の値を入れた場合にはIllegal function callエラーを出すように作っている)

 GRPでは32bit論理色コードで設定して内部では16bit物理色コードで動作しています。それが、いくら細かく設定しても実際に描画されるものはRGBが各32段階になる理由です。GRPを使ったスプライトなどでもそれと同じことが言えていくらスプライトで半透明処理ができるといっても表示できる色数が32768色しかないというのは変わりません。
 GRPと根本的に仕組みが異なるコンソールではFONTDEFによるキャラ定義をする際には32bit論理色コードではなく16bit物理色コードで設定します。

 GRPに話題を戻すとファイルとして保存されているGRPの画像データも実は単なる配列変数のデータファイルでしかないというのはすでに書いている通りでそれは "WHITEBOX" のように普通に16bit物理色コードが入った2次元数値配列を保存すればGRPとして扱われるわけですが、最初からGRPとして保存されたものとの最大の違いはファイルサイズです。
 GRPとして保存されたものは16bit整数の2次元配列であり、プチコン3号の整数型は32bitであるため同じドット数のGRPでもDATで保存すると2倍のサイズに膨れあがってしまいます。そのためDATで任意のサイズが保存できるといっても512x512の半分となる512x256以上のサイズのGRPをDATで保存すると普通に保存するよりもサイズが大きくなるため小さいGRPを保存することでファイルサイズを削減するというメリットは失われてしまいます。
 
 なお、GRP面の半透明化はできないのですが、ピクセル単位でRGBの演算を行うことによって遅くても良いならばGRPの半透明処理そのものは可能になります。
 それを誰でも簡単に可能にするGBLEND命令やGCOPYBLEND命令を作りました。アルファチャンネルの値を変更することで自由な透明度で乗算、加算、オーバーレイなどさまざまな重ね合わせ処理が可能になるため自作のお絵かきソフトでPCの「フォトショップ」のような高度な加工が可能になります。
 詳しくはこちらの方を見てください。(まだサイト内に専用ページができてないためMiiverseへのリンク)


RETURN (プチコン3号講座のページにもどる) RETURN *MAIN (トップページにもどる)

inserted by FC2 system