サンプルで遊ぶ
サンプルプログラムを色々書き換えて動かしたいところなのですが、サンプルはあとから見直すことが少なくないため、そのまま残しておきましょう。
モジモジする文字
サンプル中にあるiprintfで遊んでみましょう。
このiprintfは文字を画面に表示する関数(命令)です。
以下のように、"表示したい文字"をiprintの中に入れて下さい。
ただし、半角英数字に限ります。
"\n"を表示すると、その場所で改行されるので、この改行コードを使用すると、数行の文字が1行で記述できたりします。これも以下に示します。
iprintf("mojimojimojimojimojimojimoji");
iprintf("mojimojimojimojimojimojimoji");
iprintf("mojimojimojimojimojimojimoji");
iprintf("mojimojimojimojimojimojimoji");
iprintf("\n");
iprintf("\n");
iprintf("Welcome to Biginners' Rack\n");
iprintf("DS Programming\n");
iprintf("\n");
iprintf("Welcome to Biginners' Rack\nDS Programming");
iprintf("mojimojimojimojimojimojimoji");
iprintf("mojimojimojimojimojimojimoji");
iprintf("mojimojimojimojimojimojimoji");
iprintf("\n");
iprintf("\n");
iprintf("Welcome to Biginners' Rack\n");
iprintf("DS Programming\n");
iprintf("\n");
iprintf("Welcome to Biginners' Rack\nDS Programming");
日本語表示ができないので"moji"という文字を表示しました。
"moji"7コが連続して並びます。
その後、2行の改行があり、2行のメッセージがあります。
最後の1行は2行のメッセージをまとめたものです。
1行のメッセージでも、メッセージの途中で改行コード(\n)をいれることで2行の表示に出来ることを示しています。
本来のサンプルが残っているので、そのあとに表示されます。
数々の数
サンプルでは "while" という繰り返しの命令がありました。サンプルでは繰り返す条件が「常に真」の状態であり、無限ループの使い方をしていたので、ここではこの条件の部分で遊んでみましょう。
サンプルの while(1) のある行の上に以下の5行を入力して下さい。
int n=0;
while (n<1000) {
iprintf("%d",n);
n++;
}
while文の条件で数式を入れています。
変数nの内容が1,000未満であれば{}内が繰り返されるという条件式になります。
while分の前に、変数nは整数であるという宣言があり、そこでその値を0としています。
もし変数nがそのままならこのwhile文の条件式は常に成り立つため、サンプルと同じ無限ループになるのですが、while文の{}内のn++;という文で変数nの値を1つ増やすことでこの繰り返しが有限となります。
つまりこのループは、数字を0から999まで表示するという処理をする訳です。
1,000回のループだと一瞬で終わってしまい、そのあとにある本来のサンプルの無限ループに入ります。10,000回だと少し表示途中の状態を確認できます。
せっかくの「数々の数」ですので、100,000回ループさせてみましょう。
6〜7秒くらいは「数々の数」をお楽しみになれると思います。
while (n<1000) {
iprintf("%d",n);
n++;
}
ところどころに「所」
サンプルや「数々の数」では "while" という繰り返しの命令がありましたが、ここでは別の繰り返し命令を使って文字を表示してみましょう。
別の繰り返し命令とは for です。
前述の「数々の数」で追加した5行を、このforという繰り返し命令を使うと以下のようになります。
for ( n=0 ; n<1000 ; n++) {
iprintf("%d",n);
}
変数nの初期設定と条件設定と増分設定が1行で記述されています。
繰り返し命令はこれだけではないので、プログラミングの都合や好みで使い分けて下さい。
今回は乱数を使って所々に「所」の文字を表示しようと思ったのですが、漢字の表示ができないので、アルファベットで「TOKORO」を1文字づつ表示しようと思います。
せっかくなので、配列変数も使ってみましょう。
a(1)というのが配列変数で、同じaでもa(1)とa(2)で違う値を入れることができます。
これを拡張して、a(3,4)という使い方もできます。
例えば、学校の名簿で氏名をnameという配列変数で管理する時、3年4組15番の子の名前ならname(3,4,15)という配列変数に入れる感じになります。
この配列変数を使うと、()の数字の部分に変数を使うことによって、ループを回すことができ、プログラムをスマートにすることができます。
文字の配置はランダムに画面に表示させてみましょう。
プログラム中で乱数を得るにはrand()を使います。
ただ、rand()を使うにはstdlib.hが必要です。nds.hやstdio.hと同様に宣言して下さい。
それでは、以下のプログラムをwhile(1)の前に追加して下さい。
int n ;
char moji[]="TOKORO" ;
int tokoro_x ;
int tokoro_y ;
for( n=0 ; n<6 ; n++ ){
tokoro_x = rand() % 32 ;
tokoro_y = rand() % 24 ;
iprintf("\x1b[%d;%dH%c",tokoro_x,tokoro_y,moji[n]);
}
変数nはforループに使用し、文字数をカウントします。
moji[]は文字型の配列変数として宣言しています。ここで、"TOKORO"を入れることでmoji[0]から順に"T","O",・・・と格納されます。ちなみに、配列は0から始まります。
tokoro_xとtokoro_yは配置する位置を入れるために用意しました。
次のfor文は6回処理をするループで、その処理の内容が次の3行です。
rand()で乱数を発生し、32で割った余りをtokoro_xに格納します。tokoro_yも同様です。
最後のiprintfで文字を表示するのですが、このように書くことで、文字位置を指定することが出来ます。
変数nが0から5まで変化するので、moji[n]により1文字づつ表示されます。
ちなみに、forループをwhile(1)の中に入れるとずっと文字を表示し続けます。
グルグル処理になるので当然画面いっぱいに文字が表示されるはずなのですが、横方向に24文字しか表示されません。せっかく32もじ表示できるようにプログラムを書いたのにどうしてでしょう・・・
プログラムミスなのか、コンパイラの問題なのか、そもそも仕様上の問題なのか、分かり次第更新したいと思います。
iprintf("%d",n);
}
char moji[]="TOKORO" ;
int tokoro_x ;
int tokoro_y ;
for( n=0 ; n<6 ; n++ ){
tokoro_x = rand() % 32 ;
tokoro_y = rand() % 24 ;
iprintf("\x1b[%d;%dH%c",tokoro_x,tokoro_y,moji[n]);
}
いろいろな色
今回は画面をタッチしている間、画面上の文字をいろいろな色に変えてみましょう。
いろいろな色と言ってもランダムな色ではなく、規則的に変化する色です。
サンプルの中に以下の行があります。
BG_PALETTE_SUB[255] = RGB15(31,31,31);
これは、画面上の文字の色を指定しています。
どの色にするかが右側のRGB15(31,31,31)です。
()内の数字はそれぞれRGB、つまり赤・緑・青に対応し、0〜31が入ります。
15は15bitを表しますが、詳しいことは省きます。
サンプルのように、RGBそれぞれ指定できる最大値31の時は白を指定しています。
ちなみにRGB15(0,0,0)なら黒、RGB15(0,31,0)なら緑、RGB15(31,0,31)なら紫といった感じです。
このRGB15を使って画面上の文字の色を変化させましょう。
変化のさせ方は、RGBそれぞれに違う数字を入れられるようにr,g,bという変数を用意し、画面をタッチしているかどうかを検出し、タッチしている間だけ変数を増加させ、RGB15の設定で色を変化させます。
変数の増加は単純に+1していくのですが、上限が31なので31を越えたら0に戻さなければなりません。
そこで if の登場です。
英語に触れたことがあればよっぽどお分かりになるかと思いますが、「もし」という意味です。
プログラムで使うと、「もし〜なら〜をしなさい」という処理ができます。
while(1)の前後に以下のプログラムを追加して下さい。
int r = 0;
int g = 0;
int b = 0;
while(1) {
scanKeys();
if (keysHeld() & KEY_TOUCH) {
r = r + 1;
if ( 31 < r ) {
r = 0 ;
g = g + 1 ;
if ( 31 < g ) {
g = 0 ;
b = b + 1 ;
if ( 31 < b ) {
b = 0 ;
}
}
}
BG_PALETTE_SUB[255] = RGB15(r,g,b);
iprintf("\x1b[13;0HR:G:B=%02d:%02d:%02d", r,g,b);
}
while(1)の前には、変数(整数)の宣言です。何度も宣言しなくて良いのでグルグル命令であるwhile(1)の中には入れず、while(1)前に宣言します。
タッチ検出と色の変化は常に監視しなければならないのでwhile(1)の後に配置します。
早速while(1)の後に if が出てきましたね。
keysHeld() & KEY_TOUCHでタッチ検出ができるので、この文は「もじタッチスクリーンがタッチされていたら・・・」という意味になります。
タッチされていたらどうするかが次の行で、変数rの値を1増やします。数学的には成り立たない書き方ですが、プログラム的にはこのように書き、1増やしたrを改めてrにセットするという感じで覚えて下さい。
次にまた if 文が出ました。
変数rを増加させるのですが、上限が31なので、「rが31を越えたら・・・」という意味になります。
rが31を越えたらrを0にし、gの値をrと同じように増加させます。
gに関してもrと同じく上限があるため、gにもif文が必要になります。
bも同様です。
このようにr,g,bそれぞれ処理を施し、RGB15で色を設定します。
最後のiprintfは現在のr,g,bの値を表示します。
保存してビルド(make)してみましょう。
タッチしている間だけ刻々と色が変化していますでしょうか?
遅いですね・・・
swiWaitForVBlank();があるため思ったより遅く感じます。
すこし速くするためにこの処理を無効化しましょう。
以下のように//を行の先頭に記述すれば以下の処理は無効化されます。
//swiWaitForVBlank();
この処理の無効化はオススメできませんが、安易なスピードアップには最適です。
くれぐれも一時的なものにしておいて下さい。
さらに速くするにはプログラム上で「処理のムダ」を省く必要があります。
ここでは if文がムダの大半を占めているので、if文を使わずに同じ処理をしましょう。
詳しく説明しませんが、「ビット操作」という手を使ってみましょう。
int r = 0;
int g = 0;
int b = 0;
int color = 0;
while(1) {
scanKeys();
if (keysHeld() & KEY_TOUCH) {
color++ ;
r = color & 31 ;
g = (color >> 5) & 31 ;
b = (color >> 10) & 31 ;
BG_PALETTE_SUB[255] = RGB15(r,g,b);
iprintf("\x1b[13;0HR:G:B=%02d:%02d:%02d", r,g,b);
}
if文を使わずにr,g,bの値を設定していることがお分かりになりますでしょうか?
これでかなり速くなるはずです。
試してみて下さい。
int g = 0;
int b = 0;
while(1) {
scanKeys();
if (keysHeld() & KEY_TOUCH) {
r = r + 1;
if ( 31 < r ) {
r = 0 ;
g = g + 1 ;
if ( 31 < g ) {
g = 0 ;
b = b + 1 ;
if ( 31 < b ) {
b = 0 ;
}
}
}
BG_PALETTE_SUB[255] = RGB15(r,g,b);
iprintf("\x1b[13;0HR:G:B=%02d:%02d:%02d", r,g,b);
}
int g = 0;
int b = 0;
int color = 0;
while(1) {
scanKeys();
if (keysHeld() & KEY_TOUCH) {
color++ ;
r = color & 31 ;
g = (color >> 5) & 31 ;
b = (color >> 10) & 31 ;
BG_PALETTE_SUB[255] = RGB15(r,g,b);
iprintf("\x1b[13;0HR:G:B=%02d:%02d:%02d", r,g,b);
}