パズルのように画像を分割しようと思いましたがうまくいきません

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

パズルのように画像を分割しようと思いましたがうまくいきません

#1

投稿記事 by SAI » 8年前

いつもお世話になっております。
今回はDXライブラリを使って作成中のゲームで、スクリーンショットを撮り、それをパズルのようにバラバラにしようと思ったのですが、どうしてもうまくいかなくて質問しました。
プログラミングは趣味でやってる程度なので、DXライブラリやC++にはあまり詳しくないです。
一応OSはwindows7、コンパイラはVC++の2008です。

一部改変しましたが、ここまで作りました。プログラム全部だと膨大なので、一部だけ載せます。

考え方としては、まずスクリーンショットを撮り、空のスクリーンを作ってマスクし、そこにスクリーンショットを描画してピースを取り出し、それを切り取って12個のハンドルに分けて12ピース作るというものです。
あと少しのところまでいったのですが、画像を切り出すときにDerivationGraph関数を使ってもGetDrawScreenGraph関数を使っても、puzzlegraph[0]を描画したさいに本来透過されるべき部分が黒くなってしまいます。(透過フラグをFALSEにした場合。TRUEではそもそも描画すらされません)
空のグラフィックから作ったはずなのになぜ黒くなってしまうのでしょう。
コメント部が大量にあるのは、作ったけどうまくいかないから1つだけで試すために他を無効にしたからです。

コード:

{
	int mask[4];
	int puzzlegraph[12];
int screenshot = MakeGraph( 640 , 480 ) ;	//空のグラフィック
		int sagyouba = MakeScreen( 640 , 480 ) ;	//空のグラフィック

		// 画面データの取りこみ
		GetDrawScreenGraph( 0 , 0 , 640 , 480 , screenshot ) ;

		//作業場に描画指定
		SetDrawScreen(sagyouba);

		// マスク画面を作成します
		CreateMaskScreen() ;
		// マスクデータをロードします
		mask[0] = LoadMask( ".\\puzzlemask1.png" ) ;
		mask[1] = LoadMask( ".\\puzzlemask2.png" ) ;
		mask[2] = LoadMask( ".\\puzzlemask3.png" ) ;
		mask[3] = LoadMask( ".\\puzzlemask4.png" ) ;

		
		// ロードしたマスクデータを画面の左上に描画
		DrawMask( 0 , 0 , mask[0] , DX_MASKTRANS_BLACK ) ;
		//スクリーンショットを描画
		DrawGraph( 0 , 0 , screenshot , TRUE ) ;
		//マスクを黒く塗りつぶす
		FillMaskScreen(0) ;

		//画像を切り出す
		puzzlegraph[0] = DerivationGraph( 0, 0, 200, 200, sagyouba ) ;
//		puzzlegraph[0]  = MakeGraph( 200 , 200 ) ;
//		GetDrawScreenGraph( 0, 0, 200, 200, puzzlegraph[0] ) ;
		puzzlegraph[2] = DerivationGraph( 290, 0, 460, 200, sagyouba ) ;
		puzzlegraph[8] = DerivationGraph( 0, 280, 180, 480, sagyouba ) ;
		puzzlegraph[10] = DerivationGraph( 290, 310, 580, 480, sagyouba ) ;

/*
		// ロードしたマスクデータを画面の左上に描画
		DrawMask( 0 , 0 , mask[1] , DX_MASKTRANS_BLACK ) ;
		//スクリーンショットを描画
		DrawGraph( 0 , 0 , screenshot , TRUE ) ;
		//画像を切り出す
		puzzlegraph[1] = DerivationGraph( 120, 0, 340, 160, sagyouba ) ;
		puzzlegraph[3] = DerivationGraph( 400, 0, 640, 150, sagyouba ) ;
		puzzlegraph[9] = DerivationGraph( 110, 290, 350, 480, sagyouba ) ;
		puzzlegraph[11] = DerivationGraph( 470, 280, 640, 480, sagyouba ) ;
		//マスクを黒く塗りつぶす
		FillMaskScreen(0) ;

		// ロードしたマスクデータを画面の左上に描画
		DrawMask( 0 , 0 , mask[2] , DX_MASKTRANS_BLACK ) ;
		//スクリーンショットを描画
		DrawGraph( 0 , 0 , screenshot , TRUE ) ;
		//画像を切り出す
		puzzlegraph[4] = DerivationGraph( 0, 150, 190, 340, sagyouba ) ;
		puzzlegraph[6] = DerivationGraph( 290, 120, 520, 390, sagyouba ) ;
		//マスクを黒く塗りつぶす
		FillMaskScreen(0) ;

		// ロードしたマスクデータを画面の左上に描画
		DrawMask( 0 , 0 , mask[3] , DX_MASKTRANS_BLACK ) ;
		//スクリーンショットを描画
		DrawGraph( 0 , 0 , screenshot , FALSE ) ;
		//画像を切り出す
		puzzlegraph[5] = DerivationGraph( 120, 90, 340, 380, sagyouba ) ;
		puzzlegraph[7] = DerivationGraph( 450, 80, 640, 350, sagyouba ) ;
	
*/
		// 描画先画面を裏にする
		SetDrawScreen( DX_SCREEN_BACK ) ;
		//マスク終了
		InitMask() ;
		DeleteMaskScreen();
//		DeleteGraph(screenshot);
//		DeleteGraph(sagyouba);
}
このやり方で果たしてできるのか、それとも他に簡単なやり方があるのか、わかる方がいらっしゃったら教えていただきたいです。
それではよろしくお願いします。
添付ファイル
puzzlemask3.png
4つ目が添付できませんのでマスクを3つ添付します。
puzzlemask3.png (4.25 KiB) 閲覧数: 1144 回
puzzlemask2.png
puzzlemask2.png (5.97 KiB) 閲覧数: 1144 回
puzzlemask1.png
puzzlemask1.png (5.46 KiB) 閲覧数: 1144 回
Alea jacta est !

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

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#2

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

出来ればコンパクトな再現コードを作ってもらうと調べ易いのでお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
SAI
記事: 115
登録日時: 9年前
住所: はひほーひ

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#3

投稿記事 by SAI » 8年前

失礼しました。
再現コードはこちらです。
透過フラグをTRUEにしてもFALSEにしても描画されてるので、TRUEにしたら見えないというのは別の原因があるようです。

また、あれから色々試行錯誤してみたところ、どうもMakeScreen関数で作ったスクリーンに描画すると、はじめから黒く塗りつぶされているために透過しないのではないかと思います。
そのため、今はDrawBlendGraph関数でどうにかできないか検討中です。

コード:

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
		 LPSTR lpCmdLine, int nCmdShow )
{
   	    ChangeWindowMode(TRUE);
    if( DxLib_Init() == -1 ) return -1 ;
         // 描画先画面を裏にする
        SetDrawScreen( DX_SCREEN_BACK ) ;
        SetTransColor( 0 ,0 , 0 ) ;  //これを使ってもすけません
        int mask[4];
        int puzzlegraph[12];
        int screenshot = MakeGraph( 640 , 480 ) ;   //空のグラフィック
        int sagyouba = MakeScreen( 640 , 480 ) ;    //空のグラフィック

        DrawBox( 0, 0 , 640 , 480 , GetColor(255,0,0) , TRUE) ;	//背景
 
        // 画面データの取りこみ
        GetDrawScreenGraph( 0 , 0 , 640 , 480 , screenshot ) ;
           
        DrawBox( 0, 0 , 640 , 480 , GetColor(0,0,255) , TRUE) ;	//背景書き換える

        //作業場に描画指定
        SetDrawScreen(sagyouba);
 
        // マスク画面を作成します
        CreateMaskScreen() ;
        // マスクデータをロードします
        mask[0] = LoadMask( "puzzlemask1.png" ) ;

        
        // ロードしたマスクデータを画面の左上に描画
        DrawMask( 0 , 0 , mask[0] , DX_MASKTRANS_BLACK ) ;
        
         //スクリーンショットを描画
        DrawGraph( 0 , 0 , screenshot , TRUE ) ;
 
        //画像を切り出す
        puzzlegraph[0] = DerivationGraph( 0, 0, 200, 200, sagyouba ) ;
//      puzzlegraph[0]  = MakeGraph( 200 , 200 ) ;
//      GetDrawScreenGraph( 0, 0, 200, 200, puzzlegraph[0] ) ;
 
        // 描画先画面を裏にする
        SetDrawScreen( DX_SCREEN_BACK ) ;
        //マスク終了
        InitMask() ;
        DeleteMaskScreen();

   	// 裏画面を使用
	SetDrawScreen( DX_SCREEN_BACK ) ;

	DrawRotaGraph( 300 , 200 , 1 , 0, puzzlegraph[0] , TRUE ) ;
	DrawRotaGraph( 300 , 400 , 1 , 0, puzzlegraph[0] , FALSE ) ;

    ScreenFlip() ;
    WaitKey();
	// DXライブラリ使用の終了処理
	DxLib_End() ;

	// ソフトの終了
	return 0 ;
}

それではよろしくお願いします。
Alea jacta est !

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

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#4

投稿記事 by h2so5 » 8年前

根本的な問題として、
CreateMaskScreen()の戻り値を無視していませんか?


失礼。戻り値は関係ないですね(´・ω・`)

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

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#5

投稿記事 by h2so5 » 8年前

SetTransColor( 0 ,0 , 0 ) ;
と指定していますが、どこに黒い色があるのでしょうか?

アバター
SAI
記事: 115
登録日時: 9年前
住所: はひほーひ

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#6

投稿記事 by SAI » 8年前

できた!!ついにできましたよ!!
DrawBlendGraph関数が大当たりでした!
マスクをやめてスクリーンショットとパズルの元マスク画像12枚をBorderParam =254で12回描画してあたかも個別の画像のように扱うことができました!

一緒に悩んでいただいた皆さん、本当にありがとうございました。

これはタイトル画面で使う予定なので問題ありませんが、大きな画像を12回描画したら処理が重そうですので、もっといいやり方があったら教えてただきたいです。
それでは解決マークをつけさせていただきます。
Alea jacta est !

アバター
SAI
記事: 115
登録日時: 9年前
住所: はひほーひ

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#7

投稿記事 by SAI » 8年前

>h2so5さん
黒い色は、パズルのかけらを描画した際にもともとMakeScreen関数によるものと思われる黒い部分を無効にできないかと思って使ってみました。(透過されれば解決なので)

追記:
日本語変ですね。パズルのかけらにはもともとMakeScreen関数によるものと思われる黒い部分が一緒に描画されているので、それを無効にできないかと思いました。
Alea jacta est !

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

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#8

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

たぶん、うまく行かないのはアルファ・チャンネルの関係だと予想は出来ましたが、DXライブラリのソースコードを追いかけないと分かりそうにないので追求は諦めました。
DerivationGraph()の時にSetTransColor()の値が無視されていると思われます。

一番高速に処理するには、最初にパズルパーツに分割しておくのが良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
SAI
記事: 115
登録日時: 9年前
住所: はひほーひ

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#9

投稿記事 by SAI » 8年前

>softyaさん
ご協力ありがとうございます。

>一番高速に処理するには、最初にパズルパーツに分割しておくのが良いと思います。
これはパズルパーツの画像を最初に用意しておいた方がいいということですよね?
しかし、スクリーンショットをバラバラにするので、パズルの画像を容易するのが不可能なので、パズル型のマスクを使って試みた次第です。
Alea jacta est !

ISLe
記事: 2645
登録日時: 9年前
連絡を取る:

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#10

投稿記事 by ISLe » 8年前

DXライブラリでは取り込んだ画像のアルファ値が弄れないので自前でマスク合成するしかないですね。

コード:

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

	int mask[4];
	int puzzlegraph[12];
	int puzzlemask[12];
	int screenshot = MakeGraph( 640 , 480 );
	int sagyouba1 = MakeScreen( 640 , 480 );
	int sagyouba2 = MakeScreen( 640 , 480 );

	DrawBox( 0, 0 , 640 , 480 , GetColor(255,0,0) , TRUE) ;
	GetDrawScreenGraph( 0 , 0 , 640 , 480 , screenshot ) ;
	DrawBox( 0, 0 , 640 , 480 , GetColor(0,0,255) , TRUE) ;

	CreateMaskScreen() ;
	mask[0] = LoadMask( "puzzlemask1.png" );

	// 合成したい画像
	// 合成したい部分以外を黒にする(ビット0で埋める)
	SetDrawScreen(sagyouba1);
	DrawMask( 0 , 0 , mask[0] , DX_MASKTRANS_BLACK ) ;
	DrawGraph( 0 , 0 , screenshot , TRUE );
	puzzlegraph[0] = DerivationGraph( 0, 0, 200, 200, sagyouba1 );

	// 合成るために使うマスク画像
	// 合成したい部分以外を黒にする(ビット0で埋める)
	// 合成したい部分は白にする(ビット1で埋める)
	SetDrawScreen(sagyouba2);
	DrawMask( 0 , 0 , mask[0] , DX_MASKTRANS_BLACK ) ;
	DrawBox( 0, 0 , 640 , 480 , GetColor(255,255,255) , TRUE );
	puzzlemask[0] = DerivationGraph( 0, 0, 200, 200, sagyouba2 );
 
	InitMask() ;
	DeleteMaskScreen();

    SetDrawScreen( DX_SCREEN_BACK ) ;

	// 合成したい部分を抜く
	SetDrawBlendMode(DX_BLENDMODE_SUB, 255);
    DrawRotaGraph( 300 , 200 , 1 , 0, puzzlemask[0] , FALSE ) ;

	// 抜いた部分に加算合成
	SetDrawBlendMode(DX_BLENDMODE_ADD, 255);
    DrawRotaGraph( 300 , 200 , 1 , 0, puzzlegraph[0] , FALSE ) ;

	SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 255);

    ScreenFlip() ;
    WaitKey();
    DxLib_End() ;

    return 0 ;
}

アバター
SAI
記事: 115
登録日時: 9年前
住所: はひほーひ

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#11

投稿記事 by SAI » 8年前

>ISLeさん
回答ありがとうございます。
マスクも一緒にくりぬいて減算ブレンドということでしょうか。こんなやり方があるのですね。
勉強になりました!
Alea jacta est !

ISLe
記事: 2645
登録日時: 9年前
連絡を取る:

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#12

投稿記事 by ISLe » 8年前

SAI さんが書きました:マスクも一緒にくりぬいて減算ブレンドということでしょうか。こんなやり方があるのですね。
こんなやり方というかマスク合成としては王道的なやり方だと思います。

せっかくなのでパラメータをいじった応用コードを書いてみました。

コード:

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

	int mask[4];
	int puzzlegraph[12];
	int puzzlemask[12];
	int screenshot = MakeGraph( 640 , 480 );
	int sagyouba1 = MakeScreen( 640 , 480 );
	int sagyouba2 = MakeScreen( 640 , 480 );

	DrawBox( 0, 0 , 640 , 480 , GetColor(255,0,0) , TRUE) ;
	GetDrawScreenGraph( 0 , 0 , 640 , 480 , screenshot ) ;

	CreateMaskScreen() ;
	mask[0] = LoadMask( "puzzlemask1.png" );

	// 合成したい画像
	// 合成したい部分以外を黒にする(ビット0で埋める)
	SetDrawScreen(sagyouba1);
	DrawMask( 0 , 0 , mask[0] , DX_MASKTRANS_BLACK ) ;
	DrawGraph( 0 , 0 , screenshot , TRUE );
	puzzlegraph[0] = DerivationGraph( 0, 0, 200, 200, sagyouba1 );

	// 合成るために使うマスク画像
	// 合成したい部分以外を黒にする(ビット0で埋める)
	// 合成したい部分は白にする(ビット1で埋める)
	SetDrawScreen(sagyouba2);
	DrawMask( 0 , 0 , mask[0] , DX_MASKTRANS_BLACK ) ;
	DrawBox( 0, 0 , 640 , 480 , GetColor(255,255,255) , TRUE );
	puzzlemask[0] = DerivationGraph( 0, 0, 200, 200, sagyouba2 );
 
	InitMask() ;
	DeleteMaskScreen();

    SetDrawScreen( DX_SCREEN_BACK ) ;

    for(int i=0; i<255; ++i){
		ClearDrawScreen();
		DrawBox( 0, 0 , 640 , 480 , GetColor(0,0,255) , TRUE) ;

		// 合成したい部分を抜く
		SetDrawBlendMode(DX_BLENDMODE_SUB, i);
	    DrawRotaGraph( 300 , 200 , 1-.5*(255-i)/255 , PHI*2*i/255, puzzlemask[0] , FALSE ) ;

		// 抜いた部分に加算合成
		SetDrawBlendMode(DX_BLENDMODE_ADD, i);
	    DrawRotaGraph( 300 , 200 , 1-.5*(255-i)/255 , PHI*2*i/255, puzzlegraph[0] , FALSE ) ;

		SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 255);

	    ScreenFlip() ;
	}

    WaitKey();
    DxLib_End() ;

    return 0 ;
}

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

Re: パズルのように画像を分割しようと思いましたがうまくいきません

#13

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

この手法、パソコン系で昔は良く使いましたね。

【追記】
正確には昔の手法はAND・OR合成ですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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