【C++DXLib 原因と対応】
CLASSを使ったら絵が出なくなった

絵が出ない

ののか
ん~
クラスを使ったら
なぜかDXライブラリで
絵が出なくなった…
こうすけ

絵が出ない?

LoadGraphで指定している絵は、
指定位置に存在していますか?

ののか
はい、クラスを使う前までは
出てました。今回は、
以下でクラスを利用したものを
少し改良を加えてます。
利用したソースの元

新規プロジェクトを作成する 今回は機能を落とした「04.Anim」よりコピーして「09.ClassTest」を作成してください。 プロジェクト作成の方法は、「【簡単に新規Classをプロジェクトに追加する】」を参照[…]

 

ののか
以下がこちらで
改造したソースです。
コンストラクタってのを
本で見たので
それ使って初期化しました。

 

Player.h


#pragma once
class Player
{
	enum class DIR : int
	{
		// 使用する絵(chara_act.png)の順番に合わせておく
		DOWN = 0,
		LEFT,
		RIGHT,
		UP,

		NUM,
	};

public:
	Player();	//< コンストラクタ(これで初期化できるらしい)

	void Init();   //< 初期処理
	void Update(); //< 更新処理
	void Draw();   //< 描画処理
	void Exit();   //< 終了処理

	int SetDir( DIR dir ) { act_dir = dir; } //< 方向設定
	int GetWidth() { return WIDTH; }	//< 横サイズ
	int GetHeight() { return HEIGHT; }  //< 縦サイズ

	float x, y;    //< 表示座標

protected:
	static const int ACT_DIR_SLIDE = 3;
	static const int ACT_DIR_NUM = 4;
	static const int ACT_IMG_NUM = ACT_DIR_SLIDE * ACT_DIR_NUM;
	static const int WIDTH = 32;
	static const int HEIGHT = 32;
	static const int ACT_SPEED = 20;
	int act_img[ ACT_IMG_NUM ];       //< イメージ

	// 0,1,2,1 の4種類 [0~3]までにするために用意
	static const int MAX_MOTION_INDEX = 4; 
	// アニメーション変換テーブル
	const int act_motion[ MAX_MOTION_INDEX ] = { 0, 1, 2, 1, };

	int act_index = 0;
	int act_wait = ACT_SPEED;

	DIR act_dir = DIR::DOWN;

	void loadData();
	void exitData();
};

 

Player.cpp


#include "DxLib.h"
#include "Player.h"

// コンストラクタ
Player::Player()
{
	// ここですべて初期化してみる
	Init();	
}

// 初期処理
void Player::Init()
{
	loadData();

	int act_wait = ACT_SPEED;
	x = 0;
	y = 0;
}

//< 更新処理
void Player::Update()
{
	// キー情報を取得する
	int input = GetJoypadInputState( DX_INPUT_KEY_PAD1 );
	// キーで移動させる
	if ( input & PAD_INPUT_RIGHT )
	{
		x++;
		act_dir = DIR::RIGHT;
	}
	if ( input & PAD_INPUT_LEFT )
	{
		x--;
		act_dir = DIR::LEFT;
	}
	if ( input & PAD_INPUT_UP )
	{
		y--;
		act_dir = DIR::UP;
	}
	if ( input & PAD_INPUT_DOWN )
	{
		y++;
		act_dir = DIR::DOWN;
	}

	// アクション
	if ( --act_wait <= 0 )
	{
		act_index++;
		act_index %= MAX_MOTION_INDEX;
		act_wait = ACT_SPEED;
	}
}

// 描画処理
void Player::Draw()
{
	int motion_index = act_motion[ act_index ];

	// 自分のキャラを表示する
	DrawGraph( x, y, act_img[ motion_index + (int)act_dir * ACT_DIR_SLIDE ], TRUE );
}

// 終了処理
void Player::Exit()
{
	exitData();
}

void Player::loadData()
{
	LoadDivGraph( "chara_act.png", ACT_IMG_NUM, ACT_DIR_SLIDE, ACT_DIR_NUM, WIDTH, HEIGHT, act_img );
}

void Player::exitData()
{
	for ( int i = 0; i < ACT_IMG_NUM; i++ )
	{
		DeleteGraph( act_img[ i ] );
	}
}

 

test.cpp

#include "DxLib.h"
#include "Player.h"

// プレイヤーをグローバルに配置。
// コンストラクタで自動でロード
Player player;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	//======================================================
	// ウインドウ設定とDXライブラリの初期化
	//======================================================
	const int SCREEN_WIDTH	= 800;		//< スクリーン横の大きさ
	const int SCREEN_HEIGHT = 600;		//< スクリーン縦の大きさ

	// Windowsモードにする
	ChangeWindowMode(TRUE);
	// 画面サイズの設定
	SetGraphMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32);
	// DXライブラリ初期化
	if (DxLib_Init() == -1)
	{
		//初期化に失敗
		return -1;
	}
	// ダブルバッファモード
	SetDrawScreen(DX_SCREEN_BACK);
	//======================================================
	// ゲーム部分
	//======================================================
	//------------------------------------------------------
	// ゲーム初期化部分
	//------------------------------------------------------
	// プレイヤーの初期処理(これはならないはず)
	// player.Init();

	player.x = ( SCREEN_WIDTH - player.GetWidth() ) / 2;    //< 画面の中心
	player.y = ( SCREEN_HEIGHT - player.GetHeight() ) / 2;	//< 画面の中心
	

	//------------------------------------------------------
	// メインループ部分
	//------------------------------------------------------
	while (ProcessMessage() == 0)
	{
		//裏画面消す
		ClearDrawScreen();

		player.Update();

		player.Draw();

		//裏画面を表画面を入れ替える
		ScreenFlip();
	}

	// プレイヤー終了
	player.Exit();

	//======================================================
	// DXライブラリ終了とプログラム終了
	//======================================================
	DxLib_End();
	return 0;
}
広告
ののか
作成したタイミングでコンストラクタで動くはずなので、
ロードは自動的におこなわれますよね。だからInit()はクラスを作った時に来るはず。でもなぜか表示されません…
こうすけ
そういう場合は、
いったんデバッガーで見るのが定石ですデバッガーを使えないと
問題が起こった時に
エラーを修正できません。
広告

謎1 LoadDivGraphまでちゃんと来ているのか?

ここに来てない可能性はないか調査します。
ここにきてなければ当然キャラはロードされていません。

こんな場合は、来ているかどうか知りたい位置にカーソルを置き、F9を押すか、下で指定した位置をクリックします
この赤い点はブレークポイントとよばれます。この状態で「ローカルWindowsデバッガー」をクリックして実行してください。
ののか
来ています!
ここで止まってます
ロードされているのに
なぜ表示されないの?
こうすけ
ここには来ていますが、まだその行は実行してない。
進めるにはF10を押してください。
ののか
押すと矢印がひとつ進みました!
こうすけ
その行が実行され
次に進んだということですね。では次に気になるのは、
この時に正しくact_imgに読み込まれているのかですね。
広告

謎2  LoadDivGraphでact_imgを読み込めているのか?

ここが実行されたことを確認し、act_imgにカーソルを合わせてみてください。
act_imgの中身を確認できます。

※-1はキャラはロードできなかったことを示します。

ののか
なんで?
キャラも存在していますよ!
こうすけ
では、最後にどのようにここが呼ばれたのか、
「呼び出し履歴」(コールスタック)
というものを見てみましょう。

ここから不具合になったヒントや
答えを見つけることができます。

 

広告

謎3 どこから呼ばれているのか?

LoadDivGraphは、
グローバルに配置したPlayer player;
から呼ばれていたことがわかります。
こうすけ
このLoadDivGraphは、
グローバルに配置したPlayer player;
から呼ばれていたことがわかります。
ののか
あれ?
ここは変数とかを置くエリアでは?!
こうすけ
そうです。
配置したときに実行されるのがコンストラクタです。
よって、プログラムが走る前に来てしまっているのです。DXライブラリは、DxLib_Init()を行わないと、
LoadDivGraphは使うことができません。絵が出ない原因はここにあります。コンストラクタを
使わないようにするか、
以下の位置で
Playerを作ります。

test.cpp

#include "DxLib.h"
#include "Player.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	//======================================================
	// ウインドウ設定とDXライブラリの初期化
	//======================================================
	const int SCREEN_WIDTH	= 800;		//< スクリーン横の大きさ
	const int SCREEN_HEIGHT = 600;		//< スクリーン縦の大きさ

	// Windowsモードにする
	ChangeWindowMode(TRUE);
	// 画面サイズの設定
	SetGraphMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32);
	// DXライブラリ初期化
	if (DxLib_Init() == -1)
	{
		//初期化に失敗
		return -1;
	}
	// ダブルバッファモード
	SetDrawScreen(DX_SCREEN_BACK);
	//======================================================
	// ゲーム部分
	//======================================================
	//------------------------------------------------------
	// ゲーム初期化部分
	//------------------------------------------------------
	// プレイヤーをグローバルに配置。
	// コンストラクタで自動でロード
	Player player;

	// プレイヤーの初期処理(これはならないはず)
	// player.Init();

	player.x = ( SCREEN_WIDTH - player.GetWidth() ) / 2;    //< 画面の中心
	player.y = ( SCREEN_HEIGHT - player.GetHeight() ) / 2;	//< 画面の中心
	

	//------------------------------------------------------
	// メインループ部分
	//------------------------------------------------------
	while (ProcessMessage() == 0)
	{
		//裏画面消す
		ClearDrawScreen();

		player.Update();

		player.Draw();

		//裏画面を表画面を入れ替える
		ScreenFlip();
	}

	// プレイヤー終了
	player.Exit();

	//======================================================
	// DXライブラリ終了とプログラム終了
	//======================================================
	DxLib_End();
	return 0;
}
広告

まとめ

CLASSのコンストラクタでDXライブラリのコマンドは避ける必要がある
  • ブレークポイントを置くことで、プログラムが実行されているか確認できる
  • ブレークポイントで止めたとき、カーソルホバーで変数の内容を確認できる。
  • 呼び出し履歴より、どのようにして呼ばれたのかを確認して、不具合の答えを見つけます

以上はC++を使って「VisualStudio」で不具合を見つける基本的な方法です。
参考にしてください。

広告
広告
最新情報をチェック!