ちょっとしたパズルゲームについて

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

ちょっとしたパズルゲームについて

#1

投稿記事 by 強い虫 » 13年前

初心者ながらパズルゲームを作ってみたのですが不具合が出てしまいます(エラーはなし)
Visual Studio C+ 2008 Express Editionを使用しています。
内容はまず640×480の絵を縦3横4に切り分け、ランダムに配置。(絵はmediaファイルのpicture.jpgで保存)
その後、①切り分けられたどこかの画像をクリックし、②入れ替えたい画像をクリックすることで①と②場所が入れ替わる
例:(①縦2横3の画像をクリック ②縦3横4の画像をクリック 場所が入れ替わる)
これを繰り返していき、最終的に正しい絵が完成するというものです
不具合の内容は、なぜか②のクリック時に画像が一回り大きくなってしまい、①の画像も同様に大きくなってしまい、その状態で入れ替えが発生するので、繰り返していくと絵自体がぐちゃぐちゃになってしまいます。
説明がへたで本当にすいません。 原因が全くわからない状態です。よろしくお願いします。
以下ソースコードです
pazzle.h

コード:

#include <windows.h>
#include <tchar.h>
#include <gdiplus.h>
#include <stdlib.h>
#include <time.h>

//定数の定義
//ウィンドウクラス名
const TCHAR *MYWNDCLASSNAME = _T("__LB_PAZZLE_WINDOW");
//ウィンドウサイズ
const int APPWINDOW_W = 640;
const int APPWINDOW_H = 480;
//カードサイズ
static const int CARDW = 160;
static const int CARDH = 160;
//カードの並べ方
static const int CARDCOL = 4;
static const int CARDROW = 3;
//カードの種類数
static const int CARDNUM = 12;

//置かれたカードの情報
struct CardInfo{
	int cardid;	//カードの番号
	BOOL opened; 
};
struct OpenedCardInfo{
	int cardid;	//カードの番号
	int col;	//列位置
	int row;	//行位置
};

//関数プロトタイプ宣言
LRESULT WINAPI MyWinProc(HWND, UINT, WPARAM, LPARAM);
HWND createMyWindow(HINSTANCE);
void render(HWND hWnd);
void clickCheck(HWND, int, int);
pazzle.cpp

コード:

#include "pazzle.h"

//パズル画像
Gdiplus::Bitmap *g_puzzle = NULL;
//カード情報
CardInfo g_cardinfosH[CARDROW];
CardInfo g_cardinfosW[CARDCOL];
int move = 0;
int checkx = 0;
int checky = 0;
int checkxx = 0;
int checkyy = 0;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hpInst,
				   LPSTR lpCmd, int nCmd)
{
	//GDI+のスタートアップ処理
	Gdiplus::GdiplusStartupInput gdiSI;	
	ULONG_PTR gdiToken;
	if(Gdiplus::GdiplusStartup(&gdiToken, &gdiSI, NULL )!=Gdiplus::Ok) 
		return 0;
	//画像データの読み込み
	g_puzzle = new Gdiplus::Bitmap(_T("media\\picture.jpg"));
	if( g_puzzle->GetLastStatus() != Gdiplus::Ok )
	{
		MessageBox(NULL,_T("画像ファイルが開けません"), 
			_T("パズル"), MB_OK); 
		return 0;
	}
	//カード情報初期化
	CardInfo hcards[CARDROW];
	CardInfo wcards[CARDCOL];
	ZeroMemory(g_cardinfosH, sizeof(g_cardinfosH));
	ZeroMemory(g_cardinfosW, sizeof(g_cardinfosW));
	ZeroMemory(hcards, sizeof(hcards));
	ZeroMemory(wcards, sizeof(wcards));

	for(int i=0; i<CARDROW; i++){
		hcards[i].cardid = i % CARDROW;
	}
	for(int i=0; i<CARDCOL; i++){
		wcards[i].cardid = i % CARDCOL;
	}
	//シャッフル開始
	srand( (unsigned int)time(NULL) );	//乱数の種

		for(int x=0; x<CARDROW; x++){
			int r;
			do{
				r = rand() % (CARDROW);
			}while(hcards[r].opened==TRUE);
			//シャッフル前配列からシャッフル後へ
			g_cardinfosH[x].cardid = hcards[r].cardid;
			hcards[r].opened = TRUE;	//抜いた印
		}

	for(int y=0; y<CARDCOL; y++){
			int r;
			do{
				r = rand() % (CARDCOL);
			}while(wcards[r].opened==TRUE);
			//シャッフル前配列からシャッフル後へ
			g_cardinfosW[y].cardid = wcards[r].cardid;
			wcards[r].opened = TRUE;	//抜いた印
		}

	HWND hWnd = createMyWindow(hInst);
	if( hWnd == NULL ) return 0;
	//ウィンドウの表示
	ShowWindow( hWnd, nCmd );
	UpdateWindow( hWnd );

	//メッセージループ
	MSG msg;
	BOOL bRet;
	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
		if (bRet == -1) {
			break;
		} else {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	//終了処理
	UnregisterClass( MYWNDCLASSNAME, hInst );
	delete g_puzzle;
	Gdiplus::GdiplusShutdown(gdiToken);
	return msg.wParam;
}

//クラス登録とウィンドウ作成
HWND createMyWindow(HINSTANCE hInst){
	//ウィンドウクラスの登録
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = MyWinProc;
	wc.cbClsExtra = 0L;
	wc.cbWndExtra = 0L;
	wc.hInstance = hInst;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = MYWNDCLASSNAME;
	wc.hIconSm = NULL;
	if( RegisterClassEx( &wc ) == 0 ) return 0; 

	//ウィンドウを中央に表示するための準備
	RECT deskRect;
	int width = APPWINDOW_W + GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
	int height = APPWINDOW_H + GetSystemMetrics(SM_CYFIXEDFRAME) * 2
		+ GetSystemMetrics(SM_CYCAPTION);
	GetWindowRect(GetDesktopWindow(), &deskRect);	//デスクトップサイズを取得

	//ウィンドウの作成
	return CreateWindowEx( 0, MYWNDCLASSNAME, 
		_T("パズル"),
		WS_OVERLAPPED| WS_SYSMENU | WS_MINIMIZEBOX, 
		deskRect.right/2 - width /2, deskRect.bottom/2 - height/2,
		width, height,
		NULL, NULL, hInst, NULL );

}

//ウィンドウプロシージャ
LRESULT WINAPI MyWinProc(HWND hWnd, UINT msg,
								WPARAM wParam, LPARAM lParam)
{
	switch(msg){
	case WM_DESTROY:		//プログラム終了時
		PostQuitMessage(0);	//WM_QUITを送出
		break;
	case WM_PAINT:
		render(hWnd);
		break;
	case WM_LBUTTONDOWN:
		clickCheck(hWnd, LOWORD(lParam), HIWORD(lParam));
		break;
	default:
		//その他メッセージの処理
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

//クリックチェック
void clickCheck(HWND hWnd, int mx, int my){
	//カード位置を調べる
	int col = mx / CARDW;
	int row = my / CARDH;

	if(move == 1){
	checkx = col;
	checky = row;
	move++;}
	
	else if(move == 2){
	checkxx = col;
	checkyy = row;
	InvalidateRect(hWnd, NULL, FALSE);}
}

//画面描画
void render(HWND hWnd){
	PAINTSTRUCT ps;
	HDC hDC = BeginPaint( hWnd, &ps );

	//画像表示
	Gdiplus::Graphics g(hDC);

	if(move == 0){
	int h = 0;
	int w = 0;
	for(int y=0; y < CARDROW; y++){
		for(int x=0; x < CARDCOL; x++){
			h = g_cardinfosH[y].cardid;
			w = g_cardinfosW[x].cardid;
			g.DrawImage(g_puzzle, x * CARDW, y * CARDH,	
				w * CARDW, h * CARDH, CARDW, CARDH, Gdiplus::UnitPixel);}}
	move++;}

	else if(move == 2){
		CardInfo hcards[CARDROW];
		CardInfo wcards[CARDCOL];
		int h = g_cardinfosH[checky].cardid;
		int w = g_cardinfosW[checkx].cardid;

		g.DrawImage(g_puzzle, checkxx * CARDW, checkyy * CARDH,	
			w * CARDW, h * CARDH, CARDW, CARDH, Gdiplus::UnitPixel);

		h = g_cardinfosH[checkyy].cardid;
		w = g_cardinfosW[checkxx].cardid;

		g.DrawImage(g_puzzle, checkx * CARDW, checky * CARDH,	
			w * CARDW, h * CARDH, CARDW, CARDH, Gdiplus::UnitPixel);

		hcards[checky].cardid = g_cardinfosH[checkyy].cardid;
		wcards[checkx].cardid = g_cardinfosW[checkxx].cardid;
		g_cardinfosH[checkyy].cardid = g_cardinfosH[checky].cardid;
		g_cardinfosW[checkxx].cardid = g_cardinfosW[checkx].cardid;
		g_cardinfosH[checky].cardid = hcards[checky].cardid;
		g_cardinfosW[checkx].cardid = wcards[checkx].cardid;

	move--;
	}
	//描画終了
	EndPaint( hWnd, &ps );
}

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

Re: ちょっとしたパズルゲームについて

#2

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

画像が無いと検証が手間ですのでお願いします。
あとインデントちゃんとされていません。バグの原因となるので修正されることをお勧めします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

強い虫

Re: ちょっとしたパズルゲームについて

#3

投稿記事 by 強い虫 » 13年前

申し訳ありませんでした。
pazzle.hの方は問題ないと思うのでpazzle.cppだけ修正しました。
画像の件ですが、リンクを貼ったのですが大丈夫ですか?

pazzle.cpp

コード:

#include "pazzle.h"

//パズル画像
Gdiplus::Bitmap *g_puzzle = NULL;
//カード情報
CardInfo g_cardinfosH[CARDROW];
CardInfo g_cardinfosW[CARDCOL];
int move = 0;
int checkx = 0;
int checky = 0;
int checkxx = 0;
int checkyy = 0;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hpInst,
				   LPSTR lpCmd, int nCmd)
{
	//GDI+のスタートアップ処理
	Gdiplus::GdiplusStartupInput gdiSI;	
	ULONG_PTR gdiToken;
	if(Gdiplus::GdiplusStartup(&gdiToken, &gdiSI, NULL )!=Gdiplus::Ok) 
		return 0;
	//画像データの読み込み
	g_puzzle = new Gdiplus::Bitmap(_T("media\\picture.jpg"));
	if( g_puzzle->GetLastStatus() != Gdiplus::Ok )
	{
		MessageBox(NULL,_T("画像ファイルが開けません"), 
			_T("パズル"), MB_OK); 
		return 0;
	}
	//カード情報初期化
	CardInfo hcards[CARDROW];
	CardInfo wcards[CARDCOL];
	ZeroMemory(g_cardinfosH, sizeof(g_cardinfosH));
	ZeroMemory(g_cardinfosW, sizeof(g_cardinfosW));
	ZeroMemory(hcards, sizeof(hcards));
	ZeroMemory(wcards, sizeof(wcards));

	for(int i=0; i<CARDROW; i++){
		hcards[i].cardid = i % CARDROW;
	}
	for(int i=0; i<CARDCOL; i++){
		wcards[i].cardid = i % CARDCOL;
	}
	//シャッフル開始
	srand( (unsigned int)time(NULL) );	//乱数の種

	for(int x=0; x<CARDROW; x++){
		int r;
		do{
			r = rand() % (CARDROW);
		}while(hcards[r].opened==TRUE);
		//シャッフル前配列からシャッフル後へ
		g_cardinfosH[x].cardid = hcards[r].cardid;
		hcards[r].opened = TRUE;	//抜いた印
	}

	for(int y=0; y<CARDCOL; y++){
		int r;
		do{
			r = rand() % (CARDCOL);
		}while(wcards[r].opened==TRUE);
		//シャッフル前配列からシャッフル後へ
		g_cardinfosW[y].cardid = wcards[r].cardid;
		wcards[r].opened = TRUE;	//抜いた印
	}

	HWND hWnd = createMyWindow(hInst);
	if( hWnd == NULL ) return 0;
	//ウィンドウの表示
	ShowWindow( hWnd, nCmd );
	UpdateWindow( hWnd );

	//メッセージループ
	MSG msg;
	BOOL bRet;
	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
		if (bRet == -1) {
			break;
		} else {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	//終了処理
	UnregisterClass( MYWNDCLASSNAME, hInst );
	delete g_puzzle;
	Gdiplus::GdiplusShutdown(gdiToken);
	return msg.wParam;
}

//クラス登録とウィンドウ作成
HWND createMyWindow(HINSTANCE hInst){
	//ウィンドウクラスの登録
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = MyWinProc;
	wc.cbClsExtra = 0L;
	wc.cbWndExtra = 0L;
	wc.hInstance = hInst;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = MYWNDCLASSNAME;
	wc.hIconSm = NULL;
	if( RegisterClassEx( &wc ) == 0 ) return 0; 

	//ウィンドウを中央に表示するための準備
	RECT deskRect;
	int width = APPWINDOW_W + GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
	int height = APPWINDOW_H + GetSystemMetrics(SM_CYFIXEDFRAME) * 2
		+ GetSystemMetrics(SM_CYCAPTION);
	GetWindowRect(GetDesktopWindow(), &deskRect);	//デスクトップサイズを取得

	//ウィンドウの作成
	return CreateWindowEx( 0, MYWNDCLASSNAME, 
		_T("パズル"),
		WS_OVERLAPPED| WS_SYSMENU | WS_MINIMIZEBOX, 
		deskRect.right/2 - width /2, deskRect.bottom/2 - height/2,
		width, height,
		NULL, NULL, hInst, NULL );

}

//ウィンドウプロシージャ
LRESULT WINAPI MyWinProc(HWND hWnd, UINT msg,
						 WPARAM wParam, LPARAM lParam)
{
	switch(msg){
	case WM_DESTROY:		//プログラム終了時
		PostQuitMessage(0);	//WM_QUITを送出
		break;
	case WM_PAINT:
		render(hWnd);
		break;
	case WM_LBUTTONDOWN:
		clickCheck(hWnd, LOWORD(lParam), HIWORD(lParam));
		break;
	default:
		//その他メッセージの処理
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

//クリックチェック
void clickCheck(HWND hWnd, int mx, int my){
	//カード位置を調べる
	int col = mx / CARDW;
	int row = my / CARDH;

	if(move == 1){
		checkx = col;
		checky = row;
		move++;}

	else if(move == 2){
		checkxx = col;
		checkyy = row;
		InvalidateRect(hWnd, NULL, FALSE);}
}

//画面描画
void render(HWND hWnd){
	PAINTSTRUCT ps;
	HDC hDC = BeginPaint( hWnd, &ps );

	//画像表示
	Gdiplus::Graphics g(hDC);

	if(move == 0){
		int h = 0;
		int w = 0;
		for(int y=0; y < CARDROW; y++){
			for(int x=0; x < CARDCOL; x++){
				h = g_cardinfosH[y].cardid;
				w = g_cardinfosW[x].cardid;
				g.DrawImage(g_puzzle, x * CARDW, y * CARDH,	
					w * CARDW, h * CARDH, CARDW, CARDH, Gdiplus::UnitPixel);}}
		move++;}

	else if(move == 2){
		CardInfo hcards[CARDROW];
		CardInfo wcards[CARDCOL];
		int h = g_cardinfosH[checky].cardid;
		int w = g_cardinfosW[checkx].cardid;

		g.DrawImage(g_puzzle, checkxx * CARDW, checkyy * CARDH,	
			w * CARDW, h * CARDH, CARDW, CARDH, Gdiplus::UnitPixel);

		h = g_cardinfosH[checkyy].cardid;
		w = g_cardinfosW[checkxx].cardid;

		g.DrawImage(g_puzzle, checkx * CARDW, checky * CARDH,	
			w * CARDW, h * CARDH, CARDW, CARDH, Gdiplus::UnitPixel);

		hcards[checky].cardid = g_cardinfosH[checkyy].cardid;
		wcards[checkx].cardid = g_cardinfosW[checkxx].cardid;
		g_cardinfosH[checkyy].cardid = g_cardinfosH[checky].cardid;
		g_cardinfosW[checkxx].cardid = g_cardinfosW[checkx].cardid;
		g_cardinfosH[checky].cardid = hcards[checky].cardid;
		g_cardinfosW[checkx].cardid = wcards[checkx].cardid;

		move--;
	}
	//描画終了
	EndPaint( hWnd, &ps );
}

強い虫

Re: ちょっとしたパズルゲームについて

#4

投稿記事 by 強い虫 » 13年前

ちゃんと貼れてませんでした。すいません。画像

アバター
bitter_fox
記事: 607
登録日時: 14年前
住所: 大阪府

Re: ちょっとしたパズルゲームについて

#5

投稿記事 by bitter_fox » 13年前

強い虫 さんが書きました:ちゃんと貼れてませんでした。すいません。画像
拡張子がhtmlなファイルは画像ファイルではなくhtmlファイルなのでimgタグを使用しても表示されません。
正しく画像ファイルを指定してください。
画像

また、プレビューを利用すれば意図したとおりに表示されるかを確認できますので利用ください。

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

Re: ちょっとしたパズルゲームについて

#6

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

必ずプレビューで動作を確認してくださいね。
これなら単なるリンクですのでアドレスだけ書いてもらえばOKです。
http://210.174.204.116/ca-dream/8mini1_3.html
問題は、これはテストに不向きですね。
グラフ用紙みたいなマス目があって各ゾーンに番号を振った専用画像をテスト用に用意したほうが良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

強い虫

Re: ちょっとしたパズルゲームについて

#7

投稿記事 by 強い虫 » 13年前

すいません。かなり探したんですが適した画像が見つからないんですがどうしたらいいですか?

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

Re: ちょっとしたパズルゲームについて

#8

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

強い虫 さんが書きました:すいません。かなり探したんですが適した画像が見つからないんですがどうしたらいいですか?
Windows付属のペイントで作れると思います。
この車の画像だと超高難度のジグソーみたいでテスト向きでは無いです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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