滑らかな画面スクロール(ゲームプログラミング)

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
table_in_trace
記事: 12
登録日時: 5年前
住所: 大阪

滑らかな画面スクロール(ゲームプログラミング)

#1

投稿記事 by table_in_trace » 5年前

Win32 APIを使ってファミコンレベルのRPGを作成しようと思っています。
まずはワールドマップ上を主人公が歩くプログラムを組んでみたのですが、
ワールドマップをスクロールする時に若干引っかかるような違和感を感じます。

ゲームプログラミングのサイトなどでは「ちらつき対策」としてダブルバッファリングが紹介されていましたが
私の感じている「引っ掛かり」のような感覚について記載のあるサイトは見つけられませんでした。

ワールドマップ用の非表示画面(デバイスコンテキスト?)が大きすぎるのか、bmpファイルが良くないのか
または単にPCスペックの問題なのか皆目見当がつきません。

今のプログラムを活かしつつ、より滑らかに画面スクロールが出来るようにするにはどうすれば良いでしょうか?

コード:

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
DWORD WINAPI Main(LPVOID param);

class commonstate{
public:
	BOOL MainThreadActive;
	int ActiveScene;

	HWND hMainWindow;	//  画面表示ウィンドウ
	HDC hMainDC;
	int MainClientSize[2];	//  クライアントサイズ

	HDC hOriginalDC;	//  hMainWindow に表示させるための元画面(非表示)
	HBITMAP hOriginalBitmap;
	int OriginalSize[2];	//  元画面のサイズ

	HDC hMapDC;	//  ワールドマップ全体
	HBITMAP hMapBitmap;
	int MapDrawpoint[2];	//  hOriginalDC にStretchBltでコピーする左上の座標

	HDC hCharacterDC;	//  キャラクターの上下左右×2パターン
	HDC hCharacterMaskDC;	//  キャラクターのマスク
	HBITMAP hCharacterBitmap;
	HBITMAP hCharacterMaskBitmap;
	int Character[5][2];	//  表示すべきキャラクターの座標(5キャラまで対応可能)
	int CharacterDrawpoint[5][2];	//  キャラクターを表示する hOriginalDC の座標

	HANDLE hMainThread;
	DWORD MainThreadID;
};


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow){
	commonstate common;	//  プログラム内の共有情報
	WNDCLASS wndclass;
	MSG msg;
	RECT rect;

	common.MainThreadActive = TRUE;
	common.ActiveScene = 0;	//  シーン0: 準備中、ロード中
	common.OriginalSize[0] = 300;	//  元画像サイズを 300×225に設定
	common.OriginalSize[1] = 225;	//  元画像サイズを 300×225に設定
	common.MainClientSize[0] = common.OriginalSize[0] * 2;	//  Main クライアントサイズを Original の2倍に設定
	common.MainClientSize[1] = common.OriginalSize[1] * 2;	//  Main クライアントサイズを Original の2倍に設定

	wndclass.style			= CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= wndclass.cbWndExtra = 0;
	wndclass.hInstance		= hInstance;
	wndclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName	= NULL;
	wndclass.lpszClassName	= TEXT("ClassName01");
	if(!RegisterClass(&wndclass))	return 0;	//  ウィンドウクラスを登録
	common.hMainWindow = CreateWindow(	//  ウィンドウ生成
		TEXT("ClassName01"),
		TEXT("Window Title"),
		WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX ,
		CW_USEDEFAULT, CW_USEDEFAULT,	//  表示位置は Windows に委ねる(オート)
		common.MainClientSize[0] + 8,	//  非クライアント領域のピクセル数が分からないので、暫定で「+8」
		common.MainClientSize[1] + 27,	//  非クライアント領域のピクセル数が分からないので、暫定で「+27」
		NULL, NULL, hInstance, NULL
	);
	if(common.hMainWindow == NULL)	return 0;
	SendMessage(common.hMainWindow, WM_NULL, (WPARAM)101, (LPARAM)(&common));	//  コールバック関数に common のアドレスを渡す

	int OutofclientareaSize[2];	//  非クライアント領域のサイズ
	GetClientRect(common.hMainWindow, &rect);	//  クライアントサイズ取得
	OutofclientareaSize[0] = common.MainClientSize[0] + 8 - rect.right;	//  非クライアント領域計算
	OutofclientareaSize[1] = common.MainClientSize[1] + 27 - rect.bottom;	//  非クライアント領域計算
	GetWindowRect(common.hMainWindow, &rect);	//  ウィンドウ表示位置取得
	MoveWindow(common.hMainWindow,
		rect.left, rect.top,	//  表示位置は変更せず
		common.MainClientSize[0] + OutofclientareaSize[0], common.MainClientSize[1] + OutofclientareaSize[1],	//  Windowサイズを再計算
		TRUE);
	common.hMainDC = GetDC(common.hMainWindow);

	//  OriginalWindow 作成(Invisible)
	common.hOriginalDC = CreateCompatibleDC(common.hMainDC);	//  メモリデバイスコンテキストのハンドル取得(幅1、高さ1)
	common.hOriginalBitmap = CreateCompatibleBitmap(common.hMainDC, common.OriginalSize[0], common.OriginalSize[1]);	//  hBitmap の幅、高さを設定
	SelectObject(common.hOriginalDC, common.hOriginalBitmap);	//  メモリデバイスコンテキストに hBitmap の幅、高さを取得(拡張)

	//  OriginalWindow に、白地&「なうろ~でぃんぐ」描画
	Rectangle(common.hOriginalDC, -1, -1, common.OriginalSize[0]+1, common.OriginalSize[1]+1);	//  OriginalWindow の描画領域より1ピクセル外側に黒線の枠
	TextOut(common.hOriginalDC, common.OriginalSize[0]/10, common.OriginalSize[1]/3, TEXT("なうろ~でぃんぐ"), lstrlen(TEXT("なうろ~でぃんぐ")));

	//  MainWindow 表示
	ShowWindow(common.hMainWindow , SW_SHOW);
	InvalidateRect(common.hMainWindow, NULL, FALSE);
	UpdateWindow(common.hMainWindow);

	//  Main スレッド起動
	common.hMainThread = CreateThread(NULL, 0, Main, (LPVOID)(&common), 0, &common.MainThreadID);
	if(!common.hMainThread){
		MessageBox(common.hMainWindow, TEXT("MainThread 起動失敗"), TEXT("エラー"), MB_OK);
		return -1;
	}

	while(GetMessage(&msg, NULL, 0, 0)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){
	static commonstate *common;

	//  Mainスレッドの動作制御用(後で書き換える)マップ移動とかに応用する予定
	if(msg == WM_KEYDOWN){
		if(wp == VK_SPACE){
			int suspend = ResumeThread(common->hMainThread) - 1;
			while(suspend < 0)	suspend = SuspendThread(common->hMainThread) + 1;
			while(suspend > 0)	suspend = ResumeThread(common->hMainThread) - 1;
		}
	}


	switch(msg){

	case WM_NULL:
		if(wp == (WPARAM)101){
			common = (commonstate *)lp;	//  commonstate変数のアドレスをコールバック関数に渡す
		}
		return 0;

	case WM_PAINT:
		HDC hPaintDC;
		PAINTSTRUCT ps;
		hPaintDC = BeginPaint(hwnd, &ps);

		StretchBlt(
			hPaintDC, 0 , 0 , common->MainClientSize[0], common->MainClientSize[1],
			common->hOriginalDC, 0 , 0 , common->OriginalSize[0], common->OriginalSize[1], SRCCOPY
		);

		EndPaint(hwnd, &ps);
		return 0;

	case WM_SIZE:
		RECT rect;
		GetClientRect(common->hMainWindow, &rect);
		common->MainClientSize[0] = rect.right;
		common->MainClientSize[1] = rect.bottom;
		return 0;

	case WM_DESTROY:
		common->MainThreadActive = FALSE;
		SendMessage(common->hMainWindow, (UINT)WM_KEYDOWN, (WPARAM)VK_SPACE, NULL);	//  Main スレッドの動作を再開し、終了させる。
		Sleep(100);
		PostQuitMessage(0);
		return 0;
	}


	//  シーンごとに制御を変える必要あり
	//  とりあえずはマップ画面である事を前提に記述
	switch(msg){

	case WM_KEYDOWN:
		switch(wp){
		case VK_UP:
		case VK_DOWN:
		case VK_LEFT:
		case VK_RIGHT:
			if(wp == VK_UP)		common->Character[0][0] = 16*2;	//  上向き
			if(wp == VK_DOWN)	common->Character[0][0] = 16*0;	//  下向き
			if(wp == VK_LEFT)	common->Character[0][0] = 16*4;	//  左向き
			if(wp == VK_RIGHT)	common->Character[0][0] = 16*6;	//  右向き

			int i1;
			int DefTime;	//  基準からの経過時間
			SYSTEMTIME BaseTime, NowTime;

			GetLocalTime(&BaseTime);
			for(i1=0; i1<16; i1++){	//  1マス分が16x16ピクセル(キャラクター画像も16x16)
				if(i1==8)	common->Character[0][0] += 16;	//  半分移動した時点で、2パターン目に変更
				while(1){
					GetLocalTime(&NowTime);
					DefTime = (1000*60*60)*(NowTime.wHour - BaseTime.wHour) + (1000*60)*(NowTime.wMinute - BaseTime.wMinute) + (1000)*(NowTime.wSecond - BaseTime.wSecond) + (NowTime.wMilliseconds - BaseTime.wMilliseconds);
					if( (NowTime.wHour - BaseTime.wHour) >= 48 ){
						MessageBox(NULL, TEXT("48時間以上経過(エラー)"), TEXT("でばっく用"), MB_OK);
						DefTime = (1000*60*60) * 48;
					}
					if(DefTime >= (i1+1)*500/16)	break;
					Sleep((i1+1)*500/16 - DefTime);
				}
				switch(wp){	//  画面スクロール
				case VK_UP:		common->MapDrawpoint[1]--;	break;
				case VK_DOWN:	common->MapDrawpoint[1]++;	break;
				case VK_LEFT:	common->MapDrawpoint[0]--;	break;
				case VK_RIGHT:	common->MapDrawpoint[0]++;	break;
				}
				BitBlt(common->hOriginalDC, 0, 0, common->OriginalSize[0], common->OriginalSize[1], common->hMapDC, common->MapDrawpoint[0], common->MapDrawpoint[1], SRCCOPY);
				BitBlt(common->hOriginalDC, common->CharacterDrawpoint[0][0], common->CharacterDrawpoint[0][1], 16, 16, common->hCharacterMaskDC, common->Character[0][0], common->Character[0][1], SRCERASE);
				BitBlt(common->hOriginalDC, common->CharacterDrawpoint[0][0], common->CharacterDrawpoint[0][1], 16, 16, common->hCharacterDC, common->Character[0][0], common->Character[0][1], SRCERASE);
				InvalidateRect(common->hMainWindow, NULL, FALSE);
				UpdateWindow(common->hMainWindow);
			}
		}
	}


	return DefWindowProc(hwnd, msg, wp, lp);
}


DWORD WINAPI Main(LPVOID param){
	commonstate *common = (commonstate *)param;

	//  ファイルの読込み(ワールドマップ)
	common->hMapBitmap = (HBITMAP)LoadImage(NULL, TEXT("ワールドマップ(256色).bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
	if(common->hMapBitmap==NULL){
		MessageBox(NULL, TEXT("読込みエラー"), TEXT("でばっく用"), MB_OK);
		return -1;
	}
	common->hMapDC = CreateCompatibleDC(common->hMainDC);
	SelectObject(common->hMapDC, common->hMapBitmap);
	//  表示位置設定 & 描画
	common->MapDrawpoint[0] = 16*160-6;	//  hOriginalDC にStretchBltでコピーする左上の座標
	common->MapDrawpoint[1] = 16*206;	//  hOriginalDC にStretchBltでコピーする左上の座標
	BitBlt(common->hOriginalDC, 0, 0, common->OriginalSize[0], common->OriginalSize[1], common->hMapDC, common->MapDrawpoint[0], common->MapDrawpoint[1], SRCCOPY);
	InvalidateRect(common->hMainWindow, NULL, FALSE);
	UpdateWindow(common->hMainWindow);

	//  bmpファイルの読込み(Character)
	common->hCharacterBitmap = (HBITMAP)LoadImage(NULL, TEXT("キャラ画像whiteback(24bit).bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
	if(common->hCharacterBitmap==NULL){
		MessageBox(NULL, TEXT("読込みエラー"), TEXT("でばっく用"), MB_OK);
		return -1;
	}
	common->hCharacterDC = CreateCompatibleDC(common->hMainDC);
	SelectObject(common->hCharacterDC, common->hCharacterBitmap);
	//  bmpファイルの読込み(Characterマスク)
	common->hCharacterMaskBitmap = (HBITMAP)LoadImage(NULL, TEXT("キャラ画像マスク(モノクロbmp).bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
	if(common->hCharacterMaskBitmap==NULL){
		MessageBox(NULL, TEXT("読込みエラー"), TEXT("でばっく用"), MB_OK);
		return -1;
	}
	common->hCharacterMaskDC = CreateCompatibleDC(common->hMainDC);
	SelectObject(common->hCharacterMaskDC, common->hCharacterMaskBitmap);
	//  表示位置設定 & 描画
	common->Character[0][0] = 0;	//  前向き
	common->Character[0][1] = 0;	//  前向き
	common->CharacterDrawpoint[0][0] = 6 + 16*9;	//  hOriginalDC の中央付近
	common->CharacterDrawpoint[0][1] = 16*7;	//  hOriginalDC の中央付近
	BitBlt(common->hOriginalDC, common->CharacterDrawpoint[0][0], common->CharacterDrawpoint[0][1], 16, 16, common->hCharacterMaskDC, common->Character[0][0], common->Character[0][1], SRCERASE);
	BitBlt(common->hOriginalDC, common->CharacterDrawpoint[0][0], common->CharacterDrawpoint[0][1], 16, 16, common->hCharacterDC, common->Character[0][0], common->Character[0][1], SRCERASE);
	InvalidateRect(common->hMainWindow, NULL, FALSE);
	UpdateWindow(common->hMainWindow);

	//  コールバック関数の動作をマップ画面用に設定
	common->ActiveScene = 1;	//  マップシーン


	while(common->MainThreadActive){

		SuspendThread(common->hMainThread);
	}

	DeleteDC(common->hMapDC);
	DeleteDC(common->hCharacterDC);
	DeleteDC(common->hCharacterMaskDC);
	DeleteObject(common->hMapBitmap);
	DeleteObject(common->hCharacterBitmap);
	DeleteObject(common->hCharacterMaskBitmap);

	return 0;
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: 滑らかな画面スクロール(ゲームプログラミング)

#2

投稿記事 by h2so5 » 5年前

ここで使われているGDIというAPIは、滑らかなアニメーションが苦手なのでゲームプログラミングにはあまり使われません。
ほとんどのWindows用ゲームは、DirectXというAPIを使っています。

ただし、DirectXはGDIと書き方が異なるのでこのプログラムをそのまま活かすのは難しいかもしれません。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 滑らかな画面スクロール(ゲームプログラミング)

#3

投稿記事 by softya(ソフト屋) » 5年前

DXライブラリなどを利用して頂くとWin32APIよりも楽に少ないコードで滑らかスクロールが実現可能かと思います。

「補足」
滑らかスクロールのサンプルです(1マスづつスクロール・サンプルの下にあります)。
http://homepage2.nifty.com/natupaji/DxL ... am.html#N4
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1596
登録日時: 7年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#4

投稿記事 by usao » 5年前

>Win32 APIを使ってファミコンレベルのRPGを作成しようと思っています。

という前提から否定されてしまっている(?)ようですが…


とりあえず VS2012にて,ウィザードが吐いたWin32アプリケーションの雛形にちょっと手を入れて
簡素なスクロールをやってみました.
一定タイミングの処理を行うのに有利ではないと思われるInvalidateRect()とSleep()を使っていますが,
それでも「引っかかり」といったものを感じない程度のスクロールはできるのではないかと感じます.
(どの程度滑らかであればOKなのか によるのでしょうけど)


サイズ640x480なクライアント領域に,32x32のビットマップを敷き詰めた絵を横方向にスクロールしてます.
(コード長いのでスポイラーにしておきます)
► スポイラーを表示

アバター
usao
記事: 1596
登録日時: 7年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#5

投稿記事 by usao » 5年前

オフトピック
あ,
HWND CreateMainWnd(HINSTANCE hInstance ) の中で return false; とか書いてる…
はずかしい.

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#6

投稿記事 by ISLe() » 5年前

usaoさんがサンプルコードを投稿されてますが、肝はメッセージループで処理する部分ですね。
ウィンドウプロシージャにごちゃごちゃとゲーム本編に関するコードを書くべきではないです。

質問者さんはメイン処理をマルチスレッド化してますが、ごちゃごちゃする根本的な要因はここにあると思います。
どうしてもマルチスレッドにしなければいけないのでしょうか。

GDI関連は同一のスレッドコンテキストで処理する必要があるので、どうしてもマルチスレッドを使いたいなら、画像リソース関連から描画まで含めたモジュール化を再優先で行うべきです。
それができればウィンドウプロシージャのごちゃごちゃは解消します。

その辺根本から変えていかないと、DirectX使っても同じだと思いますけど。

DirectXが登場するよりずっと前から滑らかにスクロールするゲームはありました。
Windows3.1でWin32s使ったゲームとか。
GDIがゲームに向いてないから使われないというのはダウトです。

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: 滑らかな画面スクロール(ゲームプログラミング)

#7

投稿記事 by h2so5 » 5年前

ISLe() さんが書きました: DirectXが登場するよりずっと前から滑らかにスクロールするゲームはありました。
Windows3.1でWin32s使ったゲームとか。
GDIがゲームに向いてないから使われないというのはダウトです。
GDIがゲームに向いてないというのは当然ながらDirectXと比較しての話です。
現在の環境でGDIがゲームに向いてないから使われないのは事実です。

GDIでゲームが作れないなどとは言っていませんし、比較での話なのでDirectX以前の話を引き合いに出しても意味がないと思います。

table_in_trace
記事: 12
登録日時: 5年前
住所: 大阪

Re: 滑らかな画面スクロール(ゲームプログラミング)

#8

投稿記事 by table_in_trace » 5年前

> h2so5 様

非常に個人的な問題ですが、私は「標準 Windows API」というサイトでWindowsプログラムを勉強し始めたので
その延長上で記述したいと思っていて、
DirectXの勉強は、Win32 APIでどうしても実現できない場合に、次のステップとして勉強しようかと思っています。

includeするものが多くなってきたりすると私自身すぐ混乱してしまう事があるので
なるべく自分にとってブラックボックスというか呪文に近い部分を作らずに作成していきたいので。。。

なので、どうしてもWin32 APIでは私には目的のプログラムが作れないと思った時は
皆さんの仰るDirectXを使った書き方を取り入れようと思います。
コメントありがとうございます。


> softya(ソフト屋) 様

上記のとおり、DirectXを使ったプログラムの勉強は次のステップにしたいと考えているため
まずはWin32 APIにこだわって作成したいと思っています。
ただ、DirectXを使った書き方の中にヒントがあるかもしれないので
リンク先については拝見させて頂きます。


> usao 様

最終的に単純なWin32 APIの形に持っていけたら嬉しいので
記載して頂いたコードは非常に参考になります。
ただ一読しただけでは意味合いを理解できないので
内容については中身を熟読した上でコメントさせて頂きます。

特にメッセージループをPeekMessageでまわして
入力が無い場合にスクロールして再描画している点と
「case WM_CREATE:」内の処理がポイントになっていると思いますので
その辺りを重点的に読み込んで(出来ればこのコードに沿ったプログラムを動かして)
自分のプログラムに活かさせて頂きたいと思っています。

具体的なプログラムコードを示して頂いてありがとうございます。


> ISLe() 様

> usaoさんがサンプルコードを投稿されてますが、肝はメッセージループで処理する部分ですね。
> ウィンドウプロシージャにごちゃごちゃとゲーム本編に関するコードを書くべきではないです。
> 質問者さんはメイン処理をマルチスレッド化してますが、ごちゃごちゃする根本的な要因はここにあると思います。
> どうしてもマルチスレッドにしなければいけないのでしょうか。

すいません、基本が分からないもので教えてください。
ウィンドウプロシージャ内にはゲーム本編のコードを書くべきではないのですか?
入力に対する挙動をプロシージャ内に記述するのは当然のように感じるのですが・・・
特にシーンによって(今ワールドマップを歩いている状況なのか、メニュー画面を開いているのか)
処理は変わってきますので、その辺りの記述はプロシージャ内で処理するものと思っているのですが
それは間違っているのでしょうか?

また、もしusao様が記載してくださったコードに関する事でしたら
取り急ぎ返答してくれたコードですのでそのような細かな点の指摘よりも
私のプログラムに転用できる部分が少しでもあれば質問者の私にとってはありがたい情報ですし
そんな事は後でどうとでも修正できる内容かと思います。

メイン処理をスレッド内で行っている事に関してはごちゃごちゃしているとは感じておりませんのでご安心ください。
また「引っ掛かり」が発生する要因になっているとも考えておりません。

アバター
usao
記事: 1596
登録日時: 7年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#9

投稿記事 by usao » 5年前

>「case WM_CREATE:」内の処理がポイントになっていると思いますので

そうでもないです.

私のサンプルは,
「単に同じマップチップが敷き詰められた絵を表示するだけの内容」
なので,あらかじめ最初に
「表示すべき絵=単一のマップチップ画像を敷き詰めた絵」を WM_CREATE のタイミングで作ってしまっているだけです.
(クライアント領域サイズよりも横方向に32だけ大きい絵を作っておいて,
 WM_PAINT時には,ここからクライアント領域サイズ分の領域を切り出して表示しています.
 スクロール量に合わせて切り出し位置を変えることでスクロールしているように見せています)


本来であれば,表示すべき内容というのは
・現在のスクロール量
・マップのデータ
等から定まるはずですから,
各時刻で表示すべき絵というのは,その時々で必要に応じて描画し直す必要があるハズです.

アバター
みけCAT
記事: 6294
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 滑らかな画面スクロール(ゲームプログラミング)

#10

投稿記事 by みけCAT » 5年前

僕の玩具はC言語 さんが書きました:ウィンドウプロシージャ内にはゲーム本編のコードを書くべきではないのですか?
入力に対する挙動をプロシージャ内に記述するのは当然のように感じるのですが・・・
設計思想によるかもしれません。
DXライブラリを使った時のようにメインループでキー入力をポーリングするプログラムを書きたいなら、プロシージャ(のキー入力に関するメッセージの処理を行う部分)には入力状態データの更新を行う処理のみを書くべきでしょう。
一方、イベントドリブンな処理を行いたいなら、プロシージャ、もしくはそこから呼び出される関数にキー入力の結果行われる動作を直接書くのは自然だと思います。

ただし、今回のようにプロシージャ内にウェイトを含むループを書くのはおかしいと思います。
代わりにするべき動作は、例えば「common->Character[0][0]と動く方向を設定した後、移動を行わせるタイマーをセットする」でしょう。
オフトピック
一般論として、思い込みは危険です。
僕の玩具はC言語 さんが書きました:メイン処理をスレッド内で行っている事に関してはごちゃごちゃしているとは感じておりませんのでご安心ください。
「納得してください」ならまだわかりますが、「ご安心ください」というのはなんか違う気がしましたが…気のせいだろうか?
僕の玩具はC言語 さんが書きました:また「引っ掛かり」が発生する要因になっているとも考えておりません。
「考えておりません」というのは、ただの勘、もしくは思考停止ですか?
それともきちんと根拠を持って否定しているのですか?
(確かに今回の場合はMain関数にはほぼ初期化と片付けのコードしかないので、あまり関係なさそうだとは思いますが…)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
usao
記事: 1596
登録日時: 7年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#11

投稿記事 by usao » 5年前

ところで「引っかかり」というのは

・マス1から隣のマス2まで移動するアニメーションの間になにかしら引っかかる
・そうではなくて,マス1→マス2→マス3 という連続移動の際に,
 マス2に到達した後でマス3へ移動開始するまでに時間がかかる場合がある

のどちら(あるいは両方?)なのでしょうか.


もし後者であれば
「WM_KEYDOWN ってどんなタイミングで来るのか?」
的な話に起因してたりしないのでしょうか?

例えば,メモ帳とかで aキーを押しっぱなしにすると
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
という結果になりますけど,このときの隣接a間の時間間隔は

・1個目→2個目 は比較的時間が長い
・以降は 何らかの一定の間隔

とかいうことになりますよね.
(これらはキーボードの設定で決まるものと思われる)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 滑らかな画面スクロール(ゲームプログラミング)

#12

投稿記事 by softya(ソフト屋) » 5年前

そうですね。Win32APIで作れないわけではないです。
ただ面倒で作るのが難しいのが問題なのです。
なので簡単な方法を提示したまでです。

>includeするものが多くなってきたりすると私自身すぐ混乱してしまう事があるので
>なるべく自分にとってブラックボックスというか呪文に近い部分を作らずに作成していきたいので。。。

ブラックボックスを減らすと手間が増え、ややこしいものとなりがちです。
DXライブラリは、Win32APIやDirectXのややこしい所をブラックボックス化することでシンプルに扱えるようにしています。
つまり、ゲームを作ることに集中できるわけです。
Win32APIの勉強をしたいのか、ゲームを作りたいのかで変わりますが、目的と手段は混同しない様にしてください。
どちらが目的で、どちらが手段ですか?

「補足」
Win32API自体が既に20年の歴史を超えるレガシーなインターフェイスです。
マイクロソフトは.NETなど何度もWin32APIを無くそうとしてきましたし、今後もチャンスが有れば表面から徹底的に隠すことは厭わないでしょう。
※ もし、Windows8がうまく軌道に乗っていたらWin32→WinRTとメインAPIが切り替わる予定でした。
なので、私はWin32APIに固執される理由は余り無い、どちらかと言うとしないほうが良いと思っています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1596
登録日時: 7年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#13

投稿記事 by usao » 5年前

オフトピック
>そうですね。Win32APIで作れないわけではないです。
>ただ面倒で作るのが難しいのが問題なのです。

という話が真なのだとしても,それではWin32APIではない別物を使うことによって

>ゲームを作ることに集中できる

という状態に到達するためには一体どのくらいの労力と時間がかかるのでしょうか?
というトレードオフ的な話になる(少なくともしばらくは手段のために目的から離れる必要がある)
と思うのですが,他の手段を勧めている方はそこらへんの事柄についてはどうお考えなのでしょう?


…という話もありますけども,
それ以前に主題(現状の問題,質問内容)に関しての話をしないのは何なのでしょうか.
他の物を使うことになれば今の問題点は今のコードごと消滅するのだから語るに値しないということでしょうか.

>非常に個人的な問題ですが、私は「標準 Windows API」というサイトでWindowsプログラムを勉強し始めたので
>その延長上で記述したいと思っていて、

という事情はこの場では尊重されないということですか.

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 滑らかな画面スクロール(ゲームプログラミング)

#14

投稿記事 by softya(ソフト屋) » 5年前

こちらでも論議されていますが、様々なことを理解しないとWin32APIではゲームを作る場合に支障が出ると思います。
http://dixq.net/forum/blog.php?u=950&b=5617
それらをほとんど解消できるならDXライブラリを利用するメリットは大きいと思います。
Win32APIを使いこなしたいという理由が主たる目的であるならWin32APIを使うことは正しいと思います。
そうでないなら、新たな学習コストを掛けたほうがバグ等の発生率や生産性で私は勝ると思っています。

私のは視点はできるだけ容易にC言語でゲームを完成させることで、Win32APIを使いこなすことではありません。
なので、Win32APIのスムーズ・スクロールの追求は眼中にないと言えます。

ゲームを作ることが面倒でもWin32APIの学習が主目的なら、私の意見は無視して頂いて結構です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#15

投稿記事 by ISLe() » 5年前

質問者さんが、将来DirectXやDXライブラリにスムーズに移行するための応用など二の次にしてウィンドウズの都合に合わせて作りたい、ゲーム自体はオマケでWin32 APIプログラミングに集中したい、ということでしたら、わたしの意見は無視してください。

わたしの投稿は、ゲーム本編を構成するコードと、ウィンドウズと対話するためのコードを、物理的に距離を置くことで、ゲーム本編のプログラミングと、ウィンドウズと対話する部分のプログラミングそれぞれに集中できる状況を作るべきだという提案です。


既にuasoさんが指摘してますが、WM_KEYDOWN はキーリピート間隔で発生します。
キーが押されたかどうかのフラグ変数を用意し、
ウィンドウプロシージャのWM_KEYDOWNでフラグを立て、WM_KEYUPでフラグを寝かせる
というのが常套手段だとわたしは認識しています。

ウィンドウプロシージャの中に静的変数でフラグを用意したりなどはプログラミングスタイルとしてももってのほか
そもそもウィンドウプロシージャはゲームと一対一に対応するとは限らないので将来に禍根を残すような先入観は排除すべきです。


GDIを使うな、というのも固執しているように見えるのは気のせいでしょうか。
GDIはDirectXやDXライブラリを使うより難しいのでしょうか。
そもそもDirectXやDXライブラリを使えば解決する問題なのでしょうか。
DXライブラリでCheckHitKeyとか使えば解決するでしょうけど、それでは回答になっていないのでは。

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#16

投稿記事 by ISLe() » 5年前

softya(ソフト屋) さんが書きました:こちらでも論議されていますが、様々なことを理解しないとWin32APIではゲームを作る場合に支障が出ると思います。
http://dixq.net/forum/blog.php?u=950&b=5617
それらをほとんど解消できるならDXライブラリを利用するメリットは大きいと思います。
Win32APIを使いこなしたいという理由が主たる目的であるならWin32APIを使うことは正しいと思います。
そうでないなら、新たな学習コストを掛けたほうがバグ等の発生率や生産性で私は勝ると思っています。

私のは視点はできるだけ容易にC言語でゲームを完成させることで、Win32APIを使いこなすことではありません。
なので、Win32APIのスムーズ・スクロールの追求は眼中にないと言えます。
リンク先で書いているとおり、GDIだから発生するという問題では無いので、DirectXやDXライブラリを使っても解消できない(できるとは限らない)というのがわたしの意見です。
GDIを使っていて発生した問題なのだから、GDIを使ったまま解決すべき。
そうでなければ何が原因かを曖昧にしてしまうだけではないでしょうか。

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#17

投稿記事 by ISLe() » 5年前

オフトピック
ウィンドウプロシージャに原因があるとはっきりした途端にGDI否定派の方々はだんまりなのでしょうか。
何も言わずに去るのは禁止などと質問者には厳しいのに、常連回答者の方々はあいかわらずですね。
>質問者さん
usaoさんのサンプルコードは、キーを押されているかどうかに関係なくスクロールするわけですが
ここに、ウィンドウプロシージャでキーが押されたかどうかを判定して、オン・オフの情報(だけ)をメッセージループ側に届けるよう仕組みを作ることになります。

わたしが提案しているのは(最初から)そういう部分のことです。

わたしの意見は要らないようなので、具体的な方法はあなたの信用する方に教えて貰ってください。
ただし、他のひとが言うからと同じ内容の意見を容易に受け入れたりはしないでくださいね。
そのような態度はあなたの人間性を貶めることになりますよ。

cattail
記事: 75
登録日時: 6年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#18

投稿記事 by cattail » 5年前

win32APIで2DスクロールRPGを作ったことがあります。
キー入力は、タイマー割り込みの中で、
if(GetAsyncKeyState('W') & 0x8000){return 0;}
のようにしていました。
特に引っかかりはありませんでしたよ。
でも、タイマー割り込みの中なので注意は必要です。
このRPGはクリア時間20時間以上でしたが、特に問題はありませんでした。
GetAsyncKeyStateがwin32APIとして認められるなら、
問題は解決と思います。
是非、試してみて!

アバター
へにっくす
記事: 630
登録日時: 8年前
住所: 東京都

Re: 滑らかな画面スクロール(ゲームプログラミング)

#19

投稿記事 by へにっくす » 5年前

なぜマルチスレッドにする必要があるのでしょうか?
ハンドルを作成したスレッドで制御や破棄をするべきで、他のスレッドがそのハンドルを触るべきではありません。
コードを見る限り、この原則に反してますのでマルチスレッドにするのはやめた方がよいと思いますが。
※この場合のハンドルとは、No.1のコードで言うHWND、HDC、HBITMAP、HANDLEなどすべてです。
 たとえばcommon->hOriginalDCはWinMain関数で作成してますが、このcommon->hOriginalDCを別スレッドMain関数で使用しているのは問題です。
 私なら絶対こういったコードは組みません。どんな不具合が出るか分かったもんじゃないしね。
written by へにっくす

table_in_trace
記事: 12
登録日時: 5年前
住所: 大阪

Re: 滑らかな画面スクロール(ゲームプログラミング)

#20

投稿記事 by table_in_trace » 5年前

> みけCAT 様

>> メイン処理をスレッド内で行っている事に関してはごちゃごちゃしているとは感じておりませんのでご安心ください。
> 「納得してください」ならまだわかりますが、「ご安心ください」というのはなんか違う気がしましたが…気のせいだろうか?

私の質問に対してISLe()様に「納得して」もらう必要はどこにも無いと思います。
というより、ISLe()様は「”私(質問者)自身が”、”コードを整理できていない(ごちゃごちゃしている)”から
これが解決できたら質問内容に対する問題ももっとはっきりわかるようになりますよ。」
という意味合いでごちゃごちゃの根本原因について言及してくださったのだと理解しました。
なぜならこのコメントは私の質問に対する答えだからです。

そういう意味で”私は”ごちゃごちゃしているとは「感じておりません」と返答しております。


>> また「引っ掛かり」が発生する要因になっているとも考えておりません。
> 「考えておりません」というのは、ただの勘、もしくは思考停止ですか?
> それともきちんと根拠を持って否定しているのですか?
> (確かに今回の場合はMain関数にはほぼ初期化と片付けのコードしかないので、あまり関係なさそうだとは思いますが…)

みけCAT様が既に仰っているとおり、Main関数では入力に対するコードは記載しておりませんし
Mainスレッド起動およびその起動確認以降はメッセージループの処理しか行っておりません。
「根拠をもって」というのはこれ以上の根拠が必要ですか?
必要だと思っているのはただの勘ですか?

私の考えも「ただの勘、もしくは思考停止ですか?」と言われれば強く否定できません。
自分なりの根拠を持って判断した事を以って「ただの勘」と言われるのであれば
コミュニケーションの大部分は「ただの勘」になるでしょう。
(これも私のただの勘ですが)

また、考えが間違っていて、その間違いが質問の解決を妨げているのであれば
そこを追求して頂けるのは質問者として非常に助かりますが
現状みけCAT様の発言の意図を掴みかねている状況です。


> usao 様

> ところで「引っかかり」というのは
> ・マス1から隣のマス2まで移動するアニメーションの間になにかしら引っかかる
> ・そうではなくて,マス1→マス2→マス3 という連続移動の際に,
>  マス2に到達した後でマス3へ移動開始するまでに時間がかかる場合がある
> のどちら(あるいは両方?)なのでしょうか.

確かに私の書き方ではこの部分の詳細が不明でした。
今回の質問は前者の方です。

それにしても、現状「WM_KEYDOW」の発生タイミングについてはあえて無視
(というか今回の件とは直接関係が無いと思って確認を後回しにしていました)
していたので、もしかしたらこの辺りが悪因になっているような気もしてきました。
優先順位は高くはないと思っていますが、発生タイミングについては確認しようと思います。


> softya(ソフト屋) 様

> Win32APIの勉強をしたいのか、ゲームを作りたいのかで変わりますが、目的と手段は混同しない様にしてください。
> どちらが目的で、どちらが手段ですか?

「① Win32 APIの勉強」、「② ファミコンレベルのrpgを作る」両方目的です。
優先順位としては①の方が高いです。
ただし、自分には難易度が高すぎると判断した場合は①を取り下げて
「別方式のコードの勉強」を目的に切り替える事もありえると思っています。

「目的と手段は混同しない様にしてください。」と仰いますが
今行っているプログラムは趣味ですので、私がやりたいと思ったことがすなわち目的です。
もし仮に最初のきっかけが「ゲームを作る事」を目的に始めた事であっても
私が「Win32 APIで作りたい」と思った時点でこれも目的に含まれます。

> Win32API自体が既に20年の歴史を超えるレガシーなインターフェイスです。
> マイクロソフトは.NETなど何度もWin32APIを無くそうとしてきましたし、今後もチャンスが有れば表面から徹底的に隠すことは厭わないでしょう。
> ※ もし、Windows8がうまく軌道に乗っていたらWin32→WinRTとメインAPIが切り替わる予定でした。
> なので、私はWin32APIに固執される理由は余り無い、どちらかと言うとしないほうが良いと思っています。

なるほどそれは知りませんでした。
Win32 APIでコードを書けなくなる(or 書きにくくなる)というのは少しショックです。
ただ、今のところ他の方法に切り替えるつもりは御座いません。


> ISLe() 様

> ウィンドウプロシージャの中に静的変数でフラグを用意したりなどはプログラミングスタイルとしてももってのほか
> そもそもウィンドウプロシージャはゲームと一対一に対応するとは限らないので将来に禍根を残すような先入観は排除すべきです。

勉強不足ですいません。
ウィンドウプロシージャの中に静的変数でフラグを用意する事を避けるべき理由は何なのでしょうか?
また、ウィンドプロシージャがゲームと一対一に対応しない場合というのはどのようなパターンがあるのでしょうか?
上記は私にとっては初耳なので、コードの記述方式を変更すべきと判断する可能性が浮上してきました。
説明が面倒であれば、その辺りに触れているサイトなど教えて頂けると助かります。
よろしくお願いします。

> GDIを使っていて発生した問題なのだから、GDIを使ったまま解決すべき。
> そうでなければ何が原因かを曖昧にしてしまうだけではないでしょうか。

私も基本的には、現状発生した原因を特定して、これを回避した記述方法を模索したいというのが希望ですが
「そうは言っても別の手段を採った方が良いよ」というのも私にとっては大切な意見ですし
なにより当初の希望では私には無理と判断した場合の選択肢を広げることにもなりますので
私の前提を超えるコメントをして下さった方には非常に感謝しておりますし
この掲示板としては特に問題ではないと思います。
もちろんISLe()様のコメントも私の知らない情報が多数あり凄く感謝しています。

> ウィンドウプロシージャに原因があるとはっきりした途端にGDI否定派の方々はだんまりなのでしょうか。
> 何も言わずに去るのは禁止などと質問者には厳しいのに、常連回答者の方々はあいかわらずですね。

高々2~3日書込みが無いからと言ってすぐに「立去った」と判断するのは如何なものでしょうか

> usaoさんのサンプルコードは、キーを押されているかどうかに関係なくスクロールするわけですが
> ここに、ウィンドウプロシージャでキーが押されたかどうかを判定して、オン・オフの情報(だけ)をメッセージループ側に届けるよう仕組みを作ることになります。
> わたしが提案しているのは(最初から)そういう部分のことです。
> わたしの意見は要らないようなので、具体的な方法はあなたの信用する方に教えて貰ってください。
> ただし、他のひとが言うからと同じ内容の意見を容易に受け入れたりはしないでくださいね。
> そのような態度はあなたの人間性を貶めることになりますよ。

ISLe()様の意見が要らないという風に伝わってしまったのであれば本当にすいません。
私は誰からのコメントも拒絶するつもりはありません。
基本的には今のところMain関数からMainスレッドを起動し、ゲーム構成の大部分はここで記述し、
メインループでは入力に対する応答を記載しようという大枠を変えるつもりはありません。
(Sleepを使う場合など、コールバック関数内でも必要に応じてスレッドを起動すべきかもしれないとは思っています)
”今のところ”というのは、このやり方が致命的に問題の解決を妨げているとは”今のところ”考えていないからです。
今後の議論や試行錯誤の中でこの考え方は変わるかもしれませんし、
それがISLe()様が初めから仰っている事と同じ事になる可能性は否定できませんが
それは現時点では私が理解できていない事に起因するためです。
言い換えれば”同じ内容の意見を受け容れる”可能性はありますが
”容易に”に対しては”私が理解・納得できれば”という前提が入ります。


> cattail 様

なるほど、この関数を使えば大量の static な key state 変数を宣言しなくても済みそうですね。
元々個人的には入力に対応したタイミングで描画させたいと思っていたのですが
コメントを読んでいると入力に関わらず所定の時間間隔で描画するのが一般的なようですね。
どちらにしても、教えて頂いた関数は凄く使いやすそうなので参考にさせて頂きます。
ありがとうございます。


> へにっくす 様

ご指摘ありがとうございます。
確かに Main 関数と Main スレッドをほぼ同じレベルで扱っているのはよろしくないのかもしれませんね。
正直マルチスレッドにする必要性があるかどうかは良くわかっていません。
思想としては、メインループはただただ入力を待つだけにしたかったというところです。

ところで、へにっくす様が仰る原則を守る場合、スレッドを起動する前に作成されたウィンドウへの描画には
スレッド内では行えない事になってしまうように思うのですが、この考えは正しいですか?
(今回でいうと、 hMainWindow を Main スレッドに教えないと hMainDC も GetDC(hMainWindow) もできないため)
もしくはそれ自体が NG 行為なのでしょうか?
勉強不足で申し訳ありませんが教えてもらえると助かります。

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#21

投稿記事 by ISLe() » 5年前

とりあえず「Win32 ゲームプログラミング」をキーワードにネットを検索してみてはいかがでしょう。

回答者個人の意見に傾ける耳はなくとも、検索して見付けたサイトがみんな同じ書き方をしているなら、それに倣おうという気も湧くのではないでしょうか。

アバター
へにっくす
記事: 630
登録日時: 8年前
住所: 東京都

Re: 滑らかな画面スクロール(ゲームプログラミング)

#22

投稿記事 by へにっくす » 5年前

僕の玩具はC言語 さんが書きました:ところで、へにっくす様が仰る原則を守る場合、スレッドを起動する前に作成されたウィンドウへの描画には
スレッド内では行えない事になってしまうように思うのですが、この考えは正しいですか?
はい、その通りです。別スレッドで起動しているMain関数で使わないでください。
1つのハンドルに対し複数のスレッドが使うタイミングを全然考慮していないですよね。
たとえるなら1つのキャンパスに複数の人がいろいろ絵を描画しようとしてるのと同じですよ。
分かりますよね? 普通なら喧嘩になる 笑
制御する方法を知らないのなら使わないことです。
マルチスレッドにする理由が「メインループはただただ入力を待つだけにしたかった」というのでは私としてはNGです。
written by へにっくす

cattail
記事: 75
登録日時: 6年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#23

投稿記事 by cattail » 5年前

入力に関わらず所定の時間間隔で描画すると、
RPGだとすると、海辺の波とか、川面とか滝、そう主人公の足踏みとか、動かせるよ。
リアルタイムで飛んでいくミサイルなんかをやってみるとメッチャ興奮します!
割り込みでなくても、ループでもいいですよね!
うーん!プログラムって楽しい!

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#24

投稿記事 by ISLe() » 5年前

へにっくす さんが書きました:
僕の玩具はC言語 さんが書きました:ところで、へにっくす様が仰る原則を守る場合、スレッドを起動する前に作成されたウィンドウへの描画には
スレッド内では行えない事になってしまうように思うのですが、この考えは正しいですか?
はい、その通りです。別スレッドで起動しているMain関数で使わないでください。
1つのハンドルに対し複数のスレッドが使うタイミングを全然考慮していないですよね。
たとえるなら1つのキャンパスに複数の人がいろいろ絵を描画しようとしてるのと同じですよ。
分かりますよね? 普通なら喧嘩になる 笑
制御する方法を知らないのなら使わないことです。
同一のスレッドコンテキストで処理する必要があるという話はわたしがNo.6で既にしてるんですよね。
ハンドルの扱いとかあちこちに散らばってごちゃごちゃしている(これからもっとひどくなる)からまず根本的に対処すべきと。

それに対して、質問者さんはNo.8で、ごちゃごちゃしてないし不具合の原因にもなってない、という返答をしていらっしゃいます。



ウィンドウメッセージはそのウィンドウを作成したスレッドに対して投げられるのでウィンドウを作ったスレッドごとにメッセージループを回さないとウィンドウプロシージャが回らない。
#ウィンドウはウィンドウを作成したスレッドのコンテキストと結ばれる。
ウィンドウから取得するデバイスコンテキストはとうぜんスレッドに依存する。

デスクトップは普遍ではないので、デスクトップにコンパチなハンドルはデスクトップが変化したら作り直さなければいけない。
同様の理由でデバイスコンテキストは必要なときに作って(要求して)使い終わったらすぐに削除(解放)する。
ビットマップはDIBであればデスクトップ(というかデバイス)に依存しない。

Win32で作るならダイアログや子ウィンドウを使うのも自然だろう。
子ウィンドウのメッセージが親ウィンドウのウィンドウプロシージャに流れる場合もある。
上記したスレッドウィンドウのコンテキストの関係も影響する。
ウィンドウプロシージャとウィンドウは一対一でないし、ゲームコンテンツはウィンドウとすら一対一でない。

ふつうに長年Win32でウィンドウアプリ作っているひとでも知らないことが多いと思います。
特にゲームプログラムというのはいろんな制約に引っ掛かりやすい。
とはいえ、ゲーム本編部分の独立性を高めることを意識してコードを書いてさえいれば、制約の影響をほとんど受けないし、GDIだのそうでないだのなんてことも些細な問題です。

イベントドリブンやマルチスレッドはいまでもふつうに使われるので、そういうものの扱い方をいまのうちに覚えておくのは悪くない。

Win32についてさらに詳しいことを知りたいのなら、インサイドウィンドウズなどの技術書を読み込んでください。
そこまでウィンドウズの中身を知らなくても、ゲーム作る上での作法としてのレベルで知ってれば十分だとわたしは思いますけどね。

まあ、質問者さんは、わたしなどとても及ばない頭脳をお持ちのようなので心配なんてしませんよ。

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#25

投稿記事 by ISLe() » 5年前

質問者さんがわたしを信用するかどうかは質問者さんの自由なのと同じく
わたしが質問者さんを信用するかどうかはわたしの自由です。
それが対等ということですよね。

この掲示板に対しても以前から主張していることですが、わたしの興味対象はトピックの中身です。
わたしはトピックの主旨に沿った情報を含む投稿を心掛けています。
それ以外の部分にばかり目を向ける方が跡を絶ちませんがね。

table_in_trace
記事: 12
登録日時: 5年前
住所: 大阪

Re: 滑らかな画面スクロール(ゲームプログラミング)

#26

投稿記事 by table_in_trace » 5年前

自己解決しました。
どうやらhMapDCのサイズが大きすぎた事が原因だったようです。
スクロールするたびにhMapDCからhOriginalDCにコピーしていましたが
hOriginalDCより周囲1マス分大きいデバイスコンテキストを用意して
スクロールはここからhOriginalDCにコピーするようにしました。

ご相談に乗って頂いた皆様ありがとうございました。


> ISLe() 様

ISLe()様の仰っている事は私にはレベルが高すぎるようです。
せめてコミュニケーションが取れる程度のレベルがあれば良かったのですが
それも適わないようで残念です。

table_in_trace
記事: 12
登録日時: 5年前
住所: 大阪

Re: 滑らかな画面スクロール(ゲームプログラミング)

#27

投稿記事 by table_in_trace » 5年前

先ほど解決したと書きましたが、もう一度起動して動かしてみるとやはり引っ掛かりとチカチカするような感じがあり
どうやらマップサイズが原因ではなかったようです。

皆様から頂いたコメントにまだ試していない方法がいくつもありますので、理解できる部分から1つずつ実効して確認していきたいと思っています。
ただ、下記①、②のようなプログラムを作りたいという思いがあり、この条件を満たすような解決方法に辿り着けるか不明ですが
もし解決したら原因を報告させて頂きます。
(既に解決済みにしてしまっていますので質問を重ねる事は控えます)

①キー入力があった場合のみ処理を行う(入力が無い場合は常に待機する)
②キー入力があった場合に即座に処理を開始できる状態にする

先ほどの書込みと重複しますが
ご相談に乗って頂いた皆様ありがとうございました。

ISLe()

Re: 滑らかな画面スクロール(ゲームプログラミング)

#28

投稿記事 by ISLe() » 5年前

table_in_trace さんが書きました:ISLe()様の仰っている事は私にはレベルが高すぎるようです。
せめてコミュニケーションが取れる程度のレベルがあれば良かったのですが
それも適わないようで残念です。
いえいえ、わたしにはこんな複雑なコードは書けませんし一日とて向き合っていられません。
もっとシンプルなコードで実装します。

No.24に、デバイスコンテキストは必要なときに用意して使い終わったらすぐに破棄する、と書きましたけど、箇条書きは読み取るのが難しいですか?
デバイスコンテキストを必要なときだけ使うようにすれば、処理的に単なるビットマップ同士の画像転送になるのですが。
#GDIの特殊性は薄れ汎用性は高く且つ見た目はシンプルになる。

少なくともNo.8のお返事からはコミュニケーションを取ろうという意志は微塵も感じませんでした。
わたしの意見に対する疑問と否定しかなく論破してみろと言わんばかりですからね。
こちらもこちらの判断でコミュニケーションできる相手かどうかは見ています。

cattail
記事: 75
登録日時: 6年前

Re: 滑らかな画面スクロール(ゲームプログラミング)

#29

投稿記事 by cattail » 5年前

こんばんわ!
滑らかなスクロール以前に、
①と②があるなら、
それができるようにやってみるといいです。
それが出来たら滑らかなスクロールをやってみる。
自分は一つ一つやっていったほうが分かりやすかったです。
だって、色々やると、何が何だか分からなくなりますしね。

僕なんかベーシックで同じコードを何度もコピーしまくって作ったゲームが
雑誌に載ってこの道です!
今でも勉強しまくりです。
お互いがんばりましょう。
ゲーム、いいよね。

table_in_trace
記事: 12
登録日時: 5年前
住所: 大阪

Re: 滑らかな画面スクロール(ゲームプログラミング)

#30

投稿記事 by table_in_trace » 5年前

かなり期間が開いてしまいましたが、最終報告をさせて頂きます。

結果から言いますと、真の原因を突き止めることは出来ませんでした。
しかしながら1つの推測はできました。
恐らくですが、私の感じていた違和感は「ティアリング」という現象だと思います。

この現象はWin32 APIでは解決が不可能なようです。
これを解決するには垂直同期(vsync同期)を採る必要があるらしく、この時点で私のコンセプトから外れてしまいますので
解決自体は放棄しました。
その代わり、リフレッシュレートに合わせて描画タイミングを調整する事と、再描画の処理をStretchBltからBitBltに変更する事で
体感的にはかなり違和感を抑制できたと思います。

ご相談に乗って頂いた皆様ありがとうございました。
一人で思い悩んでるだけでは恐らくここまで辿り着けなかったと思います。

閉鎖

“C言語何でも質問掲示板” へ戻る