なんちゃっテトリス
8x8のマトリクスLEDを使って、テトリスを作ってみた。
基本動作は、左移動、右移動のみ。だから、"なんちゃっテトリス"。
手元にある部品だけで作ったので、頭悪い設計。picは、余っていた16f1939。マトリクスの部分はシフトレジスタを使えば、もっとピン数の少ないpicでOK。
・スタートボタンでゲームスタート。
・操作は、左移動と右移動。
・ブロックを一列消すごとにブロックの落下スピードがup。LEDのレベルメータが点灯する。
回路図
プログラム
#include<stdio.h> #include <xc.h> #include <stdlib.h> #define _XTAL_FREQ 32000000 //32MHz // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. // CONFIG1 #pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset enabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is enabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable (All VCAP pin functionality is disabled) #pragma config PLLEN = OFF // PLL Enable (4x PLL enabled) #pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #define BLOCK1 0 #define BLOCK2 1 #define BLOCK3 2 #define BLOCK4 3 #define LSW RC0 #define RSW RC1 #define START_SW RC2 int matrix[8][10];//Block情報 int delete_sum;//消したBlockの総数 int active_block[3];//操作中のBlockの種類と始点 [0]:種類 [1]:x軸 [2]:y軸 unsigned int count;//Block落下用カウンタ int flg;//Block接触確認フラグ int mode;//GameMode /****************************************************************************** * COL → RB0?RB7 ROW → RA0?RA7 * *****************************************************************************/ void init(void); void matrix_plot(int x,int y,int color); void matrix_vline(int x,int color); void matrix_hline(int y,int color); void matrix_all(int color); void matrix_reset(void); void matrix_show(void); void matrix_set(int number); void create(void); void delete(int y); void move(int direction); void gamestart(void); void gameover(void); void difficulty(int number); void shift_register(int number); void interrupt timer(void); void main(void) { init(); int i,j; for(i=0;i<=10;i++){ shift_register(i); __delay_ms(300); } mode = 3; while(1){ if(mode == 0){//GameStartMode gamestart(); mode = 1; }else if(mode == 1){//GameMode matrix_show(); difficulty(delete_sum); }else if(mode == 2){//GameOverMode gameover(); mode = 3; }else if(mode == 3){//StayMode matrix_all(1); count = 0; delete_sum = 0; } } } /*レジスタ初期化関数*/ //入出力 //割り込み void init(void) { /*レジスタ設定*/ OSCCON = 0x70; TRISA = 0x00; TRISB = 0x00; TRISC = 0x0f; TRISD = 0x00; ANSELA = 0x00; ANSELB = 0x00; ANSELD = 0x00; PORTA = 0x00; PORTB = 0x00; PORTC = 0x00; PORTD = 0x00; /*割り込み関連のレジスタ設定*/ T2CON = 0x7f; PR2 = 0x7c; TMR2IE = 1; PEIE = 1; GIE = 1; } /*タイマー2割り込み関数*/ //Blockの落下スピード //移動用スイッチの監視 void interrupt timer(void) { if(TMR2IF == 1){ TMR2IF = 0;//フラグクリア if(mode == 1){//GameMode if(flg == 1){ create(); flg = 0; }else{ count++; } if(count == (25-delete_sum)){//Block落下スピード設定 move(2); count = 0; } if(LSW == 0){//左移動スイッチ while(LSW == 0); move(0); }else if(RSW == 0){//右移動スイッチ while(RSW == 0); move(1); } } if(START_SW == 0){//スタートスイッチ while(START_SW == 0); mode = 0; } } } /*マトリクスに点を打つ*/ //x軸、y軸、色を指定 //(0,0)は、左下 void matrix_plot(int x,int y,int color) { if(x == 0)PORTD = 0x01; if(x == 1)PORTD = 0x02; if(x == 2)PORTD = 0x04; if(x == 3)PORTD = 0x08; if(x == 4)PORTD = 0x10; if(x == 5)PORTD = 0x20; if(x == 6)PORTD = 0x40; if(x == 7)PORTD = 0x80; if(y == 0)PORTB = 0x7f; if(y == 1)PORTB = 0xbf; if(y == 2)PORTB = 0xdf; if(y == 3)PORTB = 0xef; if(y == 4)PORTB = 0xf7; if(y == 5)PORTB = 0xfb; if(y == 6)PORTB = 0xfd; if(y == 7)PORTB = 0xfe; } /*マトリクスに縦表示*/ //x軸、色を指定 void matrix_vline(int x,int color) { PORTD = 0xff; if(color == 0){ if(x == 7)RB0 = 1; if(x == 6)RB1 = 1; if(x == 5)RB2 = 1; if(x == 4)RB3 = 1; if(x == 3)RB4 = 1; if(x == 2)RB5 = 1; if(x == 1)RB6 = 1; if(x == 0)RB7 = 1; }else if(color == 1){ if(x == 7)PORTB = 0xfe; if(x == 6)PORTB = 0xfd; if(x == 5)PORTB = 0xfb; if(x == 4)PORTB = 0xf7; if(x == 3)PORTB = 0xef; if(x == 2)PORTB = 0xdf; if(x == 1)PORTB = 0xbf; if(x == 0)PORTB = 0x7f; } __delay_ms(1); } /*マトリクスに横表示*/ //y軸、色を指定 void matrix_hline(int y,int color) { PORTB = 0x00; if(color == 0){ if(y == 0)RD0 = 0; if(y == 1)RD1 = 0; if(y == 2)RD2 = 0; if(y == 3)RD3 = 0; if(y == 4)RD4 = 0; if(y == 5)RD5 = 0; if(y == 6)RD6 = 0; if(y == 7)RD7 = 0; }else if(color == 1){ if(y == 0)PORTD = 0x01; if(y == 1)PORTD = 0x02; if(y == 2)PORTD = 0x04; if(y == 3)PORTD = 0x08; if(y == 4)PORTD = 0x10; if(y == 5)PORTD = 0x20; if(y == 6)PORTD = 0x40; if(y == 7)PORTD = 0x80; } __delay_ms(1); } /*マトリクス全体に表示*/ //色を指定 void matrix_all(int color) { if(color == 0){ PORTD = 0x00; PORTB = 0x00; }else if(color == 1){ PORTD = 0xff; PORTB = 0x00; } } /*フィールドデータの初期化*/ void matrix_reset(void) { int i,j; for(i=0;i<8;i++){ for(j=0;j<10;j++){ matrix[i][j] = 0; } } } /*フィールドをマトリクスに表示*/ void matrix_show(void) { int i; for(i=0;i<8;i++){//マトリクス8行分の表示 RB0 = ~matrix[0][i]; RB1 = ~matrix[1][i]; RB2 = ~matrix[2][i]; RB3 = ~matrix[3][i]; RB4 = ~matrix[4][i]; RB5 = ~matrix[5][i]; RB6 = ~matrix[6][i]; RB7 = ~matrix[7][i]; if(i == 0){ RD0 = 1; __delay_ms(1); RD0 = 0; }else if(i == 1){ RD1 = 1; __delay_ms(1); RD1 = 0; }else if(i == 2){ RD2 = 1; __delay_ms(1); RD2 = 0; }else if(i == 3){ RD3 = 1; __delay_ms(1); RD3 = 0; }else if(i == 4){ RD4 = 1; __delay_ms(1); RD4 = 0; }else if(i == 5){ RD5 = 1; __delay_ms(1); RD5 = 0; }else if(i == 6){ RD6 = 1; __delay_ms(1); RD6 = 0; }else if(i == 7){ RD7 = 1; __delay_ms(1); RD7 = 0; } } } /*フィールドにBlockデータをセットする*/ //セットするBlockの番号を指定 void matrix_set(int number) { int x,y; x = 3; y = 7; active_block[0] = number; active_block[1] = x; active_block[2] = y; if(matrix[0][7] == 1 || matrix[1][7] == 1 || matrix[2][7] == 1 || matrix[3][7] == 1 || matrix[4][7] == 1 || matrix[5][7] == 1 || matrix[6][7] == 1 || matrix[7][7] == 1){ mode = 2; }else if(number == BLOCK1){ matrix[x][y] = 1; matrix[x+1][y] = 1; matrix[x][y-1] = 1; matrix[x+1][y-1] = 1; }else if(number == BLOCK2){ matrix[x][y] = 1; matrix[x][y-1] = 1; }else if(number == BLOCK3){ matrix[x][y] = 1; matrix[x][y-1] = 1; matrix[x+1][y-1] = 1; }else if(number == BLOCK4){ matrix[x][y] = 1; matrix[x+1][y] = 1; matrix[x+1][y-1] = 1; } } /*ランダムでBlockを発生させる*/ //単純にrand()を使っているため、初期起動時は重複あり void create(void) { int number; number = rand()%4; matrix_set(number); } /*フィールドを巡回し、対象を削除*/ //削除できそうなy軸を指定 void delete(int y) { int i,j,k; int cnt=0; for(i=y;i>=0;i--){ for(j=0;j<8;j++){ cnt += matrix[j][i]; } if(cnt == 8){ for(k=i;k<8;k++){ for(j=0;j<8;j++){ if(k == 7){ matrix[j][k] = 0; }else{ matrix[j][k] = matrix[j][k+1]; } } } delete_sum++; } cnt = 0; } } /*Blockの移動*/ //移動する方向を指定 //0:left 1:right 2:under //一回の呼び出しで1ドット移動 void move(int direction) { int x,y; x = active_block[1]; y = active_block[2]; if(direction == 0){//左移動 if(active_block[0] == BLOCK1 && x >= 1 && matrix[x-1][y] == 0 && matrix[x-1][y-1] == 0){ matrix[x][y] = 1; matrix[x][y-1] = 1; matrix[x-1][y] = 1; matrix[x-1][y-1] = 1; matrix[x+1][y] = 0; matrix[x+1][y-1] = 0; active_block[1] = x-1; }else if(active_block[0] == BLOCK2 && x >= 1 && matrix[x-1][y] == 0 && matrix[x-1][y-1] == 0){ matrix[x-1][y] = 1; matrix[x-1][y-1] = 1; matrix[x][y] = 0; matrix[x][y-1] = 0; active_block[1] = x-1; }else if(active_block[0] == BLOCK3 && x >= 1 && matrix[x-1][y] == 0 && matrix[x-1][y-1] == 0){ matrix[x][y-1] = 1; matrix[x-1][y] = 1; matrix[x-1][y-1] = 1; matrix[x][y] = 0; matrix[x+1][y-1] = 0; active_block[1] = x-1; }else if(active_block[0] == BLOCK4 && x >= 1 && matrix[x-1][y] == 0 && matrix[x][y-1] == 0){ matrix[x-1][y] = 1; matrix[x][y] = 1; matrix[x][y-1] = 1; matrix[x+1][y] = 0; matrix[x+1][y-1] = 0; active_block[1] = x-1; } }else if(direction == 1){//右移動 if(active_block[0] == BLOCK1 && x <= 5 && matrix[x+2][y] == 0 && matrix[x+2][y-1] == 0){ matrix[x+1][y] = 1; matrix[x+1][y-1] = 1; matrix[x+2][y] = 1; matrix[x+2][y-1] = 1; matrix[x][y] = 0; matrix[x][y-1] = 0; active_block[1] = x+1; }else if(active_block[0] == BLOCK2 && x <= 6 && matrix[x+1][y] == 0 && matrix[x+1][y-1] == 0){ matrix[x+1][y] = 1; matrix[x+1][y-1] = 1; matrix[x][y] = 0; matrix[x][y-1] = 0; active_block[1] = x+1; }else if(active_block[0] == BLOCK3 && x <= 5 && matrix[x+2][y-1] == 0 && matrix[x+1][y] == 0){ matrix[x+1][y] = 1; matrix[x+1][y-1] = 1; matrix[x+2][y-1] = 1; matrix[x][y] = 0; matrix[x][y-1] = 0; active_block[1] = x+1; }else if(active_block[0] == BLOCK4 && x <= 5 && matrix[x+2][y] == 0 && matrix[x+2][y-1] == 0){ matrix[x+2][y] = 1; matrix[x+2][y-1] = 1; matrix[x+1][y] = 1; matrix[x][y] = 0; matrix[x+1][y-1] = 0; active_block[1] = x+1; } }else{//下移動 if(active_block[0] == BLOCK1 && y >= 2 && matrix[x][y-2] == 0 && matrix[x+1][y-2] == 0){ matrix[x][y-2] = 1; matrix[x+1][y-2] = 1; matrix[x][y] = 0; matrix[x+1][y] = 0; active_block[2] = y-1; }else if(active_block[0] == BLOCK2 && y >= 2 && matrix[x][y-2] == 0 ){ matrix[x][y-2] = 1; matrix[x][y] = 0; active_block[2] = y-1; }else if(active_block[0] == BLOCK3 && y >= 2 && matrix[x][y-2] == 0 && matrix[x+1][y-2] == 0){ matrix[x][y-2] = 1; matrix[x+1][y-2] = 1; matrix[x][y] = 0; matrix[x+1][y-1] = 0; active_block[2] = y-1; }else if(active_block[0] == BLOCK4 && y >= 2 && matrix[x][y-1] == 0 && matrix[x+1][y-2] == 0){ matrix[x][y-1] = 1; matrix[x+1][y-1] = 1; matrix[x+1][y-2] = 1; matrix[x][y] = 0; matrix[x+1][y] = 0; active_block[2] = y-1; }else{ delete(y); flg = 1; } } } /*ゲーム開始時のアニメーション*/ void gamestart(void) { int i; matrix_all(1); __delay_ms(150); matrix_all(1); matrix_vline(3,0); matrix_vline(4,0); __delay_ms(150); matrix_all(1); matrix_vline(2,0); matrix_vline(3,0); matrix_vline(4,0); matrix_vline(5,0); __delay_ms(150); for(i=0;i<75;i++){ matrix_vline(0,1); matrix_vline(7,1); } matrix_all(0); __delay_ms(300); matrix_reset(); create(); } /*ゲーム終了時のアニメーション*/ void gameover(void) { int i; matrix_all(0); __delay_ms(150); for(i=0;i<75;i++){ matrix_vline(0,1); matrix_vline(7,1); } matrix_all(1); matrix_vline(2,0); matrix_vline(3,0); matrix_vline(4,0); matrix_vline(5,0); __delay_ms(150); matrix_all(1); matrix_vline(3,0); matrix_vline(4,0); __delay_ms(150); matrix_all(1); __delay_ms(300); matrix_reset(); } /*バーLEDの表示、レベルメータ*/ //表示する本数を指定 void difficulty(int number) { shift_register(number); } void shift_register(int number) { int i; RC7 = 0;//クリア RC7 = 1; for(i=0;i<number;i++){ RC4 = 0;//データセット RC4 = 1; RC6 = 0;//シフト RC6 = 1; } RC5 = 0;//ラッチ RC5 = 1; }