【DxLib LoadGraph メモリ削減】「なんかどんどんメモリが増えていく」を解消する

classでキャラを用意し、
class内でLoadGraphを使用する。

ごく普通の光景だが、
同じ敵を複数用意したときは、
どんどんキャラの絵を読み込み、
無駄にメモリを浪費してしまう。

それを避けるための策を
講じてみる。

一度読んだ絵を覚えておく

こうすけ
すでに読んだ絵を
もう一度読まないようにしたい。

そんな時は、
LoadGraphをするとき

「絵の名前」と
「キャラ番号」を
紐づけて覚えておくんだ。

それを配列に登録しておく。

次にLoadGraphをするとき、
「絵の名前」がその中にあれば、
紐づけた「キャラ番号」を返すだけ。

無ければ普通にLoadGraphをし、
「絵の名前」と「キャラ番号」を
配列に登録して、
その「キャラ番号」を返す。

そのような関数を作るのがいい。

nono
なるほど、
配列は固定だと使いにくいので、
前に習った「std::vector」で
プログラミングするのがいいのかな
こうすけ
一旦std::vectorを使って
プログラミングしようかな。

WindowsのUNICODE対応のため、
文字にTCHARが使用されており、
ちゃんとプログラミングしないと、
SJISとUNICODEが対応できなくなるんだ。

DxLibで使用できるC++ソースファイル

再度読まなくする関数

#include <vector>
/**
 * キャラ構造体
 */
struct ImageData
{
	TCHAR pathName[ MAX_PATH ] = { '\0' };
	int imageNo = -1;
	int counter = 0;
};

/// 構造体の配列
std::vector< ImageData > images;

/**
 * キャラ読み込み
 * @param name : ファイル名
 * @return 絵の番号
 */
int LoadGraphEx( const TCHAR* name )
{
	for ( auto& img : images )
	{
		if ( _tcscmp( img.pathName, name ) == 0 )
		{
			img.counter++;
			return img.imageNo;
		}
	}

	ImageData dat;

	_tcsncpy_s( dat.pathName, name, MAX_PATH-1 );
	dat.imageNo = LoadGraph( name );
	dat.counter = 1;

	images.push_back( dat );

	return dat.imageNo;
}

/**
  キャラ使用終了
  @param no : 絵の番号
*/
void DeleteGraphEx( int no )
{
	if ( no < 0 )
		return;

	for ( auto itr=images.begin(); itr!=images.end(); ++itr )
	{
		auto& img = *itr;
		if ( img.imageNo == no )
		{
			if ( --img.counter <= 0 )
			{
				DeleteGraph( img.imageNo );
				images.erase( itr );
				break;
			}
		}
	}
}

 

こうすけ
LoadGraphEx() と、
DeleteGraphEx()を
用意したよ。

今使っているLoadGraph()を
LoadGraphEx()に変更すれば、
同じ絵は読み込まず、
前に読んだ番号と同じものを
返すようにしている。

あと、DeleteGraph()を
DeleteGraphEx()に変更すれば、
使用しない絵はこれで解放できる。

まだ使っている場合は
解放しない。

nono
なんか、
普段見慣れないものが
ありますね…。

挙げていきます~

わかりにくい箇所のソースコードの説明

 

for ( auto& img : images )
こうすけ
これは、「範囲for」といわれる文。
C++11から使うことができる。

配列名を : の右に書くと、
その前の変数に順に入ってくれる。

autoは自動的に型を推測し

&がついてるので、
imagesの中の変数そのものを指す。

参照の関連記事

通常関数に渡すのは、値です。 参照渡しというのは、 その値を入れている入れ物を 渡す方法で、入れ物の中には、 別の数を入れて値を変更することができます。   通常の関数は「値渡し」関数int Func( int[…]

 


 

if ( _tcscmp( img.pathName, name ) == 0 )
こうすけ
これは、Windows専用関数。

C++のstrcmpを、
SJIS用、UNICODE用に
切り替えてくれる。

文字列シリーズすべて、
「_tcs」を前に
つけるような形になる。

上の文は、
img.pathNameと、
nameが同じかなら
次の文を実行します。
という意味です。

 


 

for ( auto itr=images.begin(); itr!=images.end(); ++itr )
{
	auto& img = *itr;

 

nono
for分なのは見るとわかるんですが…。
その後の

auto itr=images.begin() 

は、一体何なのかわかりません。

こうすけ
これはイテレータという
ポインタみたいなもので、
それを「++itr」で動かして、
image.end()の最後まで進みませます。

最後までいってなければ、
imgの中に、イテレータで
刺している内容を入れます。

要するに次の文と全く動作は変わりません。

 

for ( int i=0; images.size(); ++i )
{
	auto& img = images[i];

この方法だと、
イメージを削除するときは、
itrが無いので、
以下のように行います。

images.erase( images.begin() + i );

全国いつでも、どこでも受けられるオンライン説明会

 

可変長配列の仕組みについては、以下もご参考にしてみてください。

関連記事

固定配列から動的配列へこうすけC++では標準で配列があるけど、 これは固定の長さの配列です。これは次のようにプログラミングするよ。 可変長の配列// 固定長[…]

 

 

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