2017-11-09 16:14 | カテゴリ:PIC応用回路


アナログ時計のプログラムを検討するに際して、色々なライブラリー関数を検討しています。
今回は、ちょっと横道にそれるかも知れませんが、昔のTVゲームのテニスボールの反射動作の様な動きをさせる関数を考えてみました。

任意の点を始点として表示し、それを連続的に直線的(縦横斜め)に移動させ、境界(マトリックスLEDの端)に達したら、反射します。
しかし、通常のボールの反射とは異なり、任意(ランダム)な角度で跳ね返るようにします。

ボールの数が1個の場合の例です。

(MTX70)



途中の待ち時間を短くすると結構速いです。

(MTX71)



続きは、、、



初めにこの関数の主要部分のプログラムをご覧ください。

制御するボールの数を一つではなく、19個に増やした例です。
大きく二つの主要部分(最内側の二つのFor文)によって構成されています。
その外側には、同時に移動させるボールの数を増やしたり、その数を設定する別のFor文があります。


restart:

for (count = 0; count <= 19; count++) {//同時表示のボールの数を最大20個に設定
for (count1 = 1; count1 <= 150; count1++) {//ボールの数を増やす間隔を指定
for (DotNo = 0; DotNo <= count; DotNo++) {//表示するボールの数を徐々に増やす

Dot_On(x0[DotNo], y0[DotNo]); // 指定されたドットをONにする
Oldx[DotNo] = x0[DotNo];
Oldy[DotNo] = y0[DotNo];

if (((x0[DotNo] == 0) | (x0[DotNo] == 31)) & ((y0[DotNo] == 0) | (y0[DotNo] == 31))) { //コーナーの場合
xd[DotNo] = xd[DotNo] * -1;
yd[DotNo] = yd[DotNo] * -1;
goto Proc_z;
}
if ((x0[DotNo] == 0) | (x0[DotNo] == 31)) {// y軸の境界
Moni_LED ^= 1;
xd[DotNo] = xd[DotNo] * -1;
RandB[DotNo] = rand();
if (RandB[DotNo] % 2 == 0) yd[DotNo] = yd[DotNo] * -1;
goto Proc_z;
};
if ((y0[DotNo] == 0) | (y0[DotNo] == 31)) {// X軸の境界
Moni_LED ^= 1;
yd[DotNo] = yd[DotNo] * -1;
RandB[DotNo] = rand();
if (RandB[DotNo] % 2 == 0) xd[DotNo] = xd[DotNo] * -1;
goto Proc_z;
}

xc[DotNo] = xc[DotNo] - 1;
if (xc[DotNo] == 0) {
xc[DotNo] = xset[DotNo];
x0[DotNo] = x0[DotNo] + xd[DotNo];
}
yc[DotNo] = yc[DotNo] - 1;
if (yc[DotNo] == 0) {
yc[DotNo] = yset[DotNo];
y0[DotNo] = y0[DotNo] + yd[DotNo];
}
goto Begin;

Proc_z:
RandC[DotNo] = rand();
RandA[DotNo] = rand();
if (RandC[DotNo] % 2 == 0) {
xset[DotNo] = RandA[DotNo] >> 13;
yset[DotNo] = 1;
} else {
yset[DotNo] = RandA[DotNo] >> 13;
xset[DotNo] = 1;
}
xc[DotNo] = xset[DotNo];
yc[DotNo] = yset[DotNo];
x0[DotNo] = x0[DotNo] + xd[DotNo];
y0[DotNo] = y0[DotNo] + yd[DotNo];
goto Begin;
Begin:
;
}
Data_Buff_Out();

__delay_ms(3);
for (DotNo = 0; DotNo <= 19; DotNo++) {
Dot_Off(Oldx[DotNo], Oldy[DotNo]); // 古いドットをOFF;
}
Data_Buff_Out();
}
}
goto restart;



まず、二つの主要部分ですが、初めの部分は、条件によって次にボールを移動させ表示する場所(X,Y)を計算する部分と、ここで表示されたボールを消去する部分です。

初期位置にドットをセットした後、消去の為にその位置を記憶します。
その後、現在の位置が、LED表示の境界上か否かを判定し、それによって、ボールの進行方向を反転させます。
境界上の場合は、ボールが表示エリア外に行かないように、向きを反転します。
反射する角度もこの時に乱数で決めます。


後半部分は、先ほど記憶した消去位置のボールを消します。
今回のプログラムは、表示するボールの数を最大20個に設定していますので、配列の記述で複雑に見えますが、基本、ボールの数が減っても増えても同じです。





なお、実際には、以下の初期設定が必要です。

void Ball_Moving(void) {
int count, count1;
int DotNo = 0;
int Oldx[20] = {0}, Oldy[20] = {0}, x0[20] = {0}, y0[20] = {0};
int xd[20] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
int yd[20] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
int xc[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int yc[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int xset[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int yset[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int RandA[20], RandB[20], RandC[20];



x0[0] = 1;
y0[0] = 1;
x0[1] = 2;
y0[1] = 2;
x0[2] = 3;
y0[2] = 3;
x0[3] = 4;
y0[3] = 4;
x0[4] = 5;
y0[4] = 5;
x0[5] = 6;
y0[5] = 6;
x0[6] = 7;
y0[6] = 7;
x0[7] = 8;
y0[7] = 8;
x0[8] = 9;
y0[8] = 9;
x0[9] = 10;
y0[9] = 10;
x0[10] = 11;
y0[10] = 11;
x0[11] = 12;
y0[11] = 12;
x0[12] = 13;
y0[12] = 13;
x0[13] = 14;
y0[13] = 14;
x0[14] = 15;
y0[14] = 15;
x0[15] = 16;
y0[15] = 16;
x0[16] = 17;
y0[16] = 17;
x0[17] = 18;
y0[17] = 18;
x0[18] = 19;
y0[18] = 19;
x0[19] = 20;
y0[19] = 20;



これらを組み込んでデモ動画を撮影しました。
ご笑覧ください。
デモ画像は、ドットの数を30個まで増やしています。

(MTX72)



これと時計文字盤表示関数を組み合わせて、こんなこともやってみました。(笑)
こんな遊びもアナログ時計のアイデアに組み入れても面白いと思います。
このケースでは、ボールの数を一つから徐々に増やしていっています。

(MTX73)



続きはまた。

関連記事

管理者のみに表示する