描画まわりの処理についての質問 【1フレーム前の画面を写す】

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ふじまる

描画まわりの処理についての質問 【1フレーム前の画面を写す】

#1

投稿記事 by ふじまる » 13年前

どうも以前GraphFilter関数の件でトピックを立てたたふじまるです。

今プログラミングしているゲームで、ESCAPキーを押してゲームを終了させる際に前の画面をキャプチャし、ぼかし効果をかけるという処理をプログラミングしています。(ぶっちゃけると東方プロジェクトの一時停止状態のように画面をとめてぼかしをかけたいのです)
しかし、どうも1フレーム前の画像を描画するという処理がうまくいきません。


いま組んでるプログラムの簡略化したものを張ります。

コード:

#include "DxLib.h"
int fpscount=0;
int fps_ave=0;
int wait_term=0;
int gamemode=1;
int Handle =0;

void wait_fanc()
{
    static int t=0;
    wait_term = GetNowCount()-t;
    if(16-wait_term>0)
		Sleep(16-wait_term);
    t=GetNowCount();
	return;
}

void fps_Update()
{
    int i;
    static int t=0,f[60];

    f[fpscount%60]=GetNowCount()-t;
    t=GetNowCount();
    if(fpscount%60==59)
	{
        fps_ave=0;
        for(i=0;i<60;i++)
            fps_ave+=f[i];
        fps_ave/=60;
    }
    return;
}

void fps_Draw()
{
    if(fps_ave!=0)
	{
        DrawFormatString(0,20,GetColor(255,255,255),"%.1fFPS",1000.0/(double)fps_ave);
        DrawFormatString(0,40,GetColor(255,255,255),"%dms"  ,fps_ave);
	}
	DrawFormatString(0,60,GetColor(255,255,255),"%dms wait"  ,16-wait_term);
	return;
}

int mainloop()
{
	if(Handle == 0)
	{
		Handle = LoadGraph( "画像/キャラクタ00.png" ) ;
	}
	static int Screen=MakeScreen(640,480);
	static int CapScreen=MakeScreen(640,480);

	SetDrawScreen( Screen );

	fps_Update();
	fpscount++;
	wait_fanc();
	switch(gamemode)
	{
		case 1:
			if( CheckHitKey( KEY_INPUT_2 ) == 1) gamemode = 2;
			if( CheckHitKey( KEY_INPUT_3 ) == 1) gamemode = 3;
			break;
		case 2:
			if( CheckHitKey( KEY_INPUT_1 ) == 1) gamemode = 1;
			if( CheckHitKey( KEY_INPUT_3 ) == 1) gamemode = 3;
			break;
		case 3:
			if( CheckHitKey( KEY_INPUT_1 ) == 1) gamemode = 1;
			if( CheckHitKey( KEY_INPUT_2 ) == 1) gamemode = 2;
			break;
		default:
			break;
	}
	if( CheckHitKey( KEY_INPUT_ESCAPE ) == 1)
	{
       //ESCAPEキーを押すとここでゲームモードがdefaultになり終了する
		gamemode = 5;
	}


	ClearDrawScreen();
	DrawGraph(0,0,Handle,FALSE);
	fps_Draw();
	switch(gamemode)
	{
		case 1:
			DrawFormatString(320,240,GetColor(255,0,255),"mode 1");
			break;
		case 2:
			DrawFormatString(320,240,GetColor(255,0,255),"mode 2");
			break;
		case 3:
			DrawFormatString(320,240,GetColor(255,0,255),"mode 3");
			break;
		default:
			ClearDrawScreen();
			DrawGraph( 0, 0, CapScreen, FALSE ) ;
			break;
	}


	CapScreen = Screen;
	SetDrawScreen( DX_SCREEN_BACK ) ;
	DrawGraph( 0, 0, Screen, FALSE ) ;

	return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK ) return -1;
	ChangeWindowMode(TRUE);
	if( DxLib_Init() < 0 ) return -1 ;

	while( ProcessMessage()==0 && ScreenFlip()==0 && ClearDrawScreen()==0)
	{
		if( mainloop() != 0 ) break;
	}

	DxLib_End() ;
	return 0 ;
}
と、こんな感じでMakeScreenで画面を2つ作成し、片方に画像などを乗っける→片方は随時コピー→DX_SCREEN_BACKにて描画 という処理をさせています。

しかし、実行してみるとぜんぜんうまくいきません。画面真っ暗になります。

MakeScreenやSetDrawScreen、DX_SCREEN_BACKの動きや仕組みがよくわからないのでそこが原因かと以下のようなプログラムを書きました。

コード:

#include "DxLib.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	int Handle =0;
	ChangeWindowMode(TRUE);
	if( DxLib_Init() < 0 ) return -1 ;

	while(CheckHitKey( KEY_INPUT_ESCAPE ) == 0 && ScreenFlip()==0)
	{
		static int Screen=MakeScreen(640,480);
		static int CapScreen=MakeScreen(640,480);
		SetDrawScreen( Screen );
		if(Handle == 0)
		{
			Handle = LoadGraph( "画像/キャラクタ00.png" ) ;
			DrawGraph(0,0,Handle,FALSE);
		}
		CapScreen = Screen;
		GraphFilter( CapScreen, DX_GRAPH_FILTER_GAUSS, 16, 70000 ) ;
		SetDrawScreen( DX_SCREEN_BACK ) ;
		DrawGraph( 0, 0, CapScreen, FALSE ) ;
		WaitKey() ;
	}

	DxLib_End() ;
	return 0 ;
}
こちらの方を見るときちんとCapScreen=Screenが働いているみたいで一度描画した画像を使いまわして表示してくれます。


上のプログラムのどこら辺がおかしいかご教授いただけませんでしょうか?
また、こういった描画処理の一般的な処理法やもっとうまいやり方がありましたらご教授お願いいたします。

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

Re: 描画まわりの処理についての質問 【1フレーム前の画面を写す】

#2

投稿記事 by h2so5 » 13年前

CapScreen = Screen でスクリーンがコピーされていると思っているようですが、
同じハンドルを指してるだけでコピーはされていません。

ふじまる

Re: 描画まわりの処理についての質問 【1フレーム前の画面を写す】

#3

投稿記事 by ふじまる » 13年前

お返事ありがとうございます。
h2so5 さんが書きました:CapScreen = Screen でスクリーンがコピーされていると思っているようですが、
同じハンドルを指してるだけでコピーはされていません。
とのことですが、ポインタのようにアドレスだけ送っているということでしょうか?
だとしたらなぜこうなるのでしょう。(不勉強がふがいないです)

もう少し調べたところGetDrawScreenGraphという関数がDxLibにあることがわかりました。
上のプログラムを
CapScreen=Screen;
から
GetDrawScreenGraph(0,0, 640,480, CapScreen);
に変更することで予定通りの挙動、ボタンを押した直前の画像を表示させることができました(追加でフレーム数を表示させて確認しました)


下のプログラムで動いたのでそのまま代入できるかと思っていたのですが・・・
だれかもう少し詳しく内部でどういうことをしてるか教えてくれる方が来てくれるとうれしいですね。

とりあえず代価案ができましたので、解決ということにさせていただきます。
ありがとうございました。

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

Re: 描画まわりの処理についての質問 【1フレーム前の画面を写す】

#4

投稿記事 by h2so5 » 13年前

ふじまる さんが書きました: 下のプログラムで動いたのでそのまま代入できるかと思っていたのですが・・・
だれかもう少し詳しく内部でどういうことをしてるか教えてくれる方が来てくれるとうれしいですね。

コード:

#include "DxLib.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    int Handle =0;
    ChangeWindowMode(TRUE);
    if( DxLib_Init() < 0 ) return -1 ;
 
    while(CheckHitKey( KEY_INPUT_ESCAPE ) == 0 && ScreenFlip()==0)
    {
        static int Screen=MakeScreen(640,480);
        static int CapScreen=MakeScreen(640,480);

        /*
        Screen に描画
        */
        SetDrawScreen( Screen );

        if(Handle == 0)
        {
            Handle = LoadGraph( "画像/キャラクタ00.png" ) ;
            DrawGraph(0,0,Handle,FALSE);
        }

        /*
        CapScreen に Screen のハンドルが代入される。
        以降、11行目で作成した元の CapScreen のハンドルは一度も使われない。
        */
        CapScreen = Screen;

        /*
        CapScreen に フィルタをかける。
        CapScreenには Screen のハンドルが代入されているので、Screenにフィルタがかかる。
        */
        GraphFilter( CapScreen, DX_GRAPH_FILTER_GAUSS, 16, 70000 ) ;
        SetDrawScreen( DX_SCREEN_BACK ) ;

        /*
        CapScreen を描画する。
        CapScreenには Screen のハンドルが代入されているので、Screenが描画される。
        */
        DrawGraph( 0, 0, CapScreen, FALSE ) ;
        WaitKey() ;
    }
 
    DxLib_End() ;
    return 0 ;
}

ふじまる

Re: 描画まわりの処理についての質問 【1フレーム前の画面を写す】

#5

投稿記事 by ふじまる » 13年前

なるほど、そのままScreenのハンドルを使ってるので予定通りの挙動をしているように見えるんですね。

勉強になりました。ありがとうございます!

閉鎖

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