tanagorou20181014
@tanagorou20181014

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

system("cls")の画面のちらつきについて

Q&A

解決したいこと

テトリスを小一時間で作ってみたⅡ【C言語ゲームプログラミング実況】Programming Tetrisの動画を見ながらテトリスを作成していたのですが、コンソール画面上ですさまじい画面の更新が行われちらつきがすごいです。投稿者の画面はそのようなことはありませんでした。

書いたプログラム

#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define FIELD_WIDTH  10
#define FIELD_HIGHT  20

#define SHAPE_WIDTH_MAX 4
#define SHAPE_HIGHT_MAX 4

enum {
	SHAPE_I,
	SHAPE_0,
	SHAPE_S,
	SHAPE_Z,
	SHAPE_MAX,
};

typedef struct {
	int width, hight;
	int patterm[SHAPE_HIGHT_MAX][SHAPE_WIDTH_MAX];
}SHAPE;

typedef struct {
	int x, y;
	SHAPE shape;
}MINO;

SHAPE shape[SHAPE_MAX] = {

	{
		4,4,
		{
			{0,0,0,0},
			{1,1,1,1},
			{0,0,0,0},
			{0,0,0,0}
		}
	},

	{
		4,4,
		{
			{0,1,0,0},
			{1,1,1,0},
			{0,0,0,0},
			{0,0,0,0}
		}
	},
	{
		2,2,
		{
			{1,1},
			{1,1},

		}
	},

	{
		4,4,
		{
			{0,1,1},
			{1,1,0},
			{0,0,0}
		}
	},
};

int field[FIELD_HIGHT][FIELD_WIDTH];
int screen[FIELD_HIGHT][FIELD_WIDTH];
MINO mino;

void DrowScreen() {
	memcpy(screen, field, sizeof field);

	for (int y = 0; y < mino.shape.hight; y++) {
		for (int x = 0; x < mino.shape.width; x++)
			if (mino.shape.patterm[y][x])
				screen[mino.y + y][mino.x + x] |= 1;
	}

	system("cls");

	for (int y = 0; y < FIELD_HIGHT; y++) {
		printf("□");
		for (int x = 0; x < FIELD_WIDTH; x++)
			printf("%s",screen[y][x]?"■":" ");
		printf("□");
		printf("\n");
	}
	for (int x = 0; x < FIELD_WIDTH+2; x++)
		printf("□");
}

void InitMIno() {
	mino.shape = shape[rand() % SHAPE_MAX];
	mino.x = (FIELD_WIDTH - mino.shape.width) / 2;
	mino.y = 0;
}

void Init() {
	memset(field, 0, sizeof field);
	InitMIno();

	DrowScreen();
}

int main() {
	srand((unsigned int)time(NULL));
	Init();
	while (1) {
		if (_kbhit()) {
			switch (_getch()) {
			case 's':
				mino.y++;
				break;
			case 'a':
				mino.x--;
				break;
			case 'd':
				mino.x++;
				break;
;			}
		}DrowScreen();
	}
}

自分で試したこと

画面のちらつきを抑えるためにダブルバッファリングという手法があるのを知りました。system("cls")が画面のちらつきの原因になっていると思いますが、どのようにこのプログラムを改善していけばよろしいですか。

0

2Answer

はい。 まさにダブルバッファリングがごく一般的な解決方法です。 C の言語仕様としては画面の詳細な制御などを定めていませんのでホスト環境 (OS など) のドキュメントを読んでそれに沿ってプログラムを構成してください。

system("cls") を使っているということは Windows でしょうか? コンソール画面はスクリーンバッファと呼ばれる抽象的な画面内容を元に表示することになっており、事前に用意した別のスクリーンバッファに更新内容を書き込んだ後で実画面 (コンソール) とスクリーンバッファの割り当てを切り替えると一瞬にして表示の切り替えが完了するのでちらつきを抑えることが出来るという理屈です。 ふたつのバッファを使うのでダブルバッファリングと呼ばれます。

詳細はマイクロソフトが提供するドキュメントをご覧ください。

0Like

Comments

  1. 回答ありがとうございます。ダブルバッファリングの説明すごくわかりやすかったです。質問なのでが、別のスクリーンバッファに更新に内容を書き込んだ後、というのは元の内容に新しい内容を上書きしているという解釈でよろしいでしょうか?元の内容を捨てないとデータが積み重なり重くなる気がしました。一方systm("cls")は内容を一度クリアしているので、データが積み重ならず重くならないのかなぁと。お門違いなことを言っていたらすみません。

  2. バッファは上限を超えた分は消えていくので際限なく蓄積されるということはないです。
    一般論としては上書きで済むならそうするのが望ましいでしょう。
    前回から変わった部分だけを書き換えるほうが消去してから全体をやり直すより低コストだからです。
    とはいえ、それはアプリケーションの性質によります。
    画面全体の変化が大きいなら変化がある部分と無い部分を区別する処理のほうが面倒になるのでどちらが良いかは状況を見極めて判断してください。

    基本的な仕組みを理解してからでないと想像で心配してもしょうがないのでまずはドキュメントをよく読むことから始めてください。

Cursesというライブラリのclear()関数を使うのが一番手っ取り早いと思います。

コード #include <curses.h>
リンカ -lcurses

画面周りやカーソルを操作するapiライブラリ

0Like

Comments

  1. 追伸;

    Windowsだと、'ncurses' かも?

Your answer might help someone💌