続、コンソールでリズムゲーム

先日書いたプログラムについて、あるお方から「termiosを使えば出来そうですね」と助言がありました。へぇ、ターミナルの調整とかこんな機能があったんですか。簡単そうだし早速コレ(termios)を使って実装してみましょう。


以下、改良版ソースコード

// コンソールだけでリズムゲーみたいなの作れるか
// ncursesで組む前に検証
#include 
#include 
#include 
#include 

// 1コマ辺りのミリ秒
#define TIME_BAR_ONE 50
// バー全体のマス数
#define TIME_BAR 20
// 当たり判定を許すミリ秒
#define TIME_DIV1 40
//#define TIME_DIV2 30
//#define TIME_DIV3 20
//#define TIME_DIV4 10

// コードデータ構造体
typedef struct{
	unsigned long time;
	int key;
}code_t;

// コードデータ実体とその長さ
code_t code_line = {{5000, 0},{7000, 0},{8000, 0},{9000, 0},{10000, 0},{11000, 0}};
int code_line_len;
// 現在のコード位置
int now_code;

// プログラム開始時間と現在時間
unsigned long start_time, now_time;

int score;// 現在の得点

unsigned int hit_f;// ヒット状態(0で何もない、1で失敗、2で)

// ターミナルの状態
struct termios save_term;
struct termios temp_term;

unsigned long getmilisec(void)
{
	struct timeb sec;
	ftime(&sec);
	return ((unsigned long)sec.time*1000) + sec.millitm;// バグ過ぎる
}

int init(void)
{
	// ターミナルのセーブ
	tcgetattr(fileno(stdin), &save_term);
	// 端末設定、非カノニカルモード、readでブロックしないように、エコーも無し
	temp_term = save_term;
	temp_term.c_lflag &= ~ICANON;
	temp_term.c_lflag &= ~ISIG;
	temp_term.c_lflag &= ~ECHO;
	temp_term.c_cc[VMIN] = 0;
	temp_term.c_cc[VTIME] = 0;
 	tcsetattr(fileno(stdin), TCSANOW, &temp_term);
	
	// コードデータ読み込み
	code_line_len=6;
	now_code = 0;
	
	start_time = now_time = getmilisec();// 開始時刻の読み込み
	
	score = 1000;// スコアを初期化する
	
	return 0;
}

int display(void)
{
	int disp_code;
	int i;
	
	putc('\r', stdout);
	printf("[score:%8d] ", score);
	if (hit_f & 0x00000001){
		putc('-', stdout);
	} else {
		putc(' ', stdout);
	}
	if (hit_f & 0x00000002){
		putc('x', stdout);
	} else {
		putc('#', stdout);
	}
	// 50ミリ秒単位で' 'を入れてみよう
	disp_code = now_code;
	for(i=0; i= code_line_len){
			putc(' ', stdout);
		}else{
			if ((((now_time-start_time)+i*TIME_BAR_ONE)-code_line[disp_code].time) < TIME_BAR_ONE){
				putc('o', stdout);
				disp_code++;
			}else{
				putc(' ', stdout);
			}
		}
	}
	putc('|', stdout);
	
	return 0;
}

int destroy(void)
{
	// なにもすることがねえ、得点記録とか?
	putc('\n', stdout);

	// ターミナルの復元
	tcsetattr(fileno(stdin), TCSANOW, &save_term);
	return 0;
}

int main(int argc, char *argv)
{
	char ch;

	init();
	while(1){
		hit_f = 0;
		
		// 時間を取得
		now_time = getmilisec();
		
		// 制限時間を越えてしまったコードは読み飛ばす
		for(; now_code=code_line_len) break; // 全コード読んだ
		
		// コンソールだとsleepしてられない
//		usleep(100); // 少しスリープする
	}
	destroy();

	return 0;
}

おお出来ました。確かにread(fgetc)のブロッキングがしない。コレは面白い関数を教えてもらいました^−^

〜〜〜
感動して数回実行してみる
〜〜〜

・・・どうでもいいけどEnter押しっぱなしが高得点出せるってどんなチートなのよ(こんなコードじゃ仕方ないけど)