トップページ > 電子工作インデックス > テトリス > 4. ランダムブロック生成関数

4. ランダムブロック生成関数

テトリスは上からどんどん落ちてくるブロックをうまく並べるゲームですが、 毎回落ちてくるブロックはランダムに選ばなければなりません。 今回はH8の内蔵タイマーモジュールを利用して、タイマーカウンタの値をもとに ブロックを選ぶことにします。これで乱数が生成できるのかは微妙なところなのですが、 とりあえず遊んでみると違和感ないので、これでよしとします(笑)

H8のタイマーについて

テトリスの制御につかっているマイコンはH8-3052ですが、3052には5チャンネルのタイマーが 用意されています。今回はタイマー0を利用します。 H8のタイマーモジュールはITU(Integrated Timer Unit)と呼ばれ、設定するレジスタは いくつかありますが今回は、タイマーの実際のカウント値を保存するTCNT (タイマーカウンター)レジスタ・タイマーの動作に関する設定をするTCR (タイマーコントロールレジスタ) レジスタ・タイマー割り込みについて設定をするTIER (タイマーインタラプトイネーブルレジスタ) レジスタ・タイマーのスタート/ストップを制御する TSTR(タイマースタート)レジスタ …の4つだけを見ていくことにします。


※以下、設定値は全て16進数です。


TCRレジスタ
bit7bit6bit5bit4bit3bit2 bit1bit0
ナシCCLR1CCLR0CKEG1CKEG0 TPSC2TPSC1TPSC0


TPSC0〜TPSC2:タイマープリスケーラ(分周機)

0→内部クロックでカウント(今回はコレです)
1→内部クロックの1/2
2→内部クロックの1/4
3→内部クロックの1/8
4→外部クロックTCLKA端子入力
5→外部クロックTCLKB端子入力
6→外部クロックTCLKC端子入力
7→外部クロックTCLKD端子入力


CKEG0・CKEG1:クロックエッジ選択

0→立ち上がりエッジでカウント(今回はコレです)
1→立下りエッジでカウント
2→立ち上がり&立下りでカウント
3→同上


CCLR0・CCLR1:カウンタクリア設定

0→クリア禁止(今回はコレです)
1→GRAの値をもとにクリア
2→GRBの値をもとにクリア
3→他の同期カウンタと同時にクリア


…とうことで、TCRレジスタは0x00に設定します。



TIERレジスタ
bit7bit6bit5bit4bit3bit2 bit1bit0
ナシナシナシナシナシ OVIEIMIEBIMIEA


IMIEA:インタラプトイネーブルA

0→IMFAフラグによる割り込み禁止(今回はコレです)
1→IMFAフラグによる割り込み許可


IMIEB:インタラプトイネーブルB

0→IMFBフラグによる割り込み禁止(今回はコレです)
1→IMFBフラグによる割り込み許可


OVIE:オーバーフロー(桁あふれ)インタラプトイネーブル

0→OVAフラグによる割り込み禁止(今回はコレです)
1→OVAフラグによる割り込み許可


…とうことで、TIERレジスタは0x00に設定します。



TSTRレジスタ
bit7bit6bit5bit4bit3bit2 bit1bit0
ナシナシナシ STR4STR3STR2STR1STR0

"1"にしたビットに対応する番号のタイマーを動作させます。
TCNTレジスタ

各チャンネルごとにカウント値を保存しています。
//********************************************************************
//タイマーの設定


  ITU0.TCR.BYTE=0;
  ITU0.TIER.BYTE=0;
  ITU.TSTR.BIT.STR0=1; //タイマースタート
    
//********************************************************************

…こんな感じで。

ブロックを作る関数

まず、前述の通りブロックの形を決めるための const型の配列、blocksを用意しておきます。処理内容は非常に単純で、 ただグローバル変数の2次元配列blockに、雛型をコピーするだけです。 あとはblockを他の関数で使いまわせばいい…と。もう一つ、ブロック生成の 時点でゲームオーバーになっているかもしれないので、それだけチェックして おくことにします。 グローバル変数はお行儀悪い(?)らしいのですが、 このテトリスはC言語の習作として作ったものなので、ご容赦ください。


//*********************************************************************
//グローバル変数

//操作中のブロック用配列
char block[8][8];

//操作中のブロックの位置を表す変数
char x;
char yl

//*********************************************************************
//ブロック生成
void make_block(void)
{
 int i,j; //forループ用
 int block_type;  //ブロックの種類

 //乱数を発生させ、ブロックの種類を決定
 block_type = ITU0.TCNT % 7;

 //新しいブロックを作ったので、座標は初期位置(中央の一番上)にセット。
 x=8;
 y=0;

 //グローバル変数のblockに、選ばれたブロックの形をコピーする(他の関数でも扱えるように)。
 for(i=0;i<8;i++)
 {
  for(j=0;j<8;j++)
  { 
   block[i][j]=0;
   block[i][j]=blocks[block_type][i][j];
  }
 }


 //ブロック生成の段階で、一番上までつみ上がっていればgameoverのフラグを立てる。
 for(i=0;i<8;i++)  
 {
  for(j=0;j<8;j++)
  {
   if(field[i][j+8]==1) gameover=1;

   field[i][j+8]=stage[i][j+8]+block[i][j];
  }
 }
}

//*********************************************************************


前へ   次へ