汎用フィールドクラス

最近、何時間もかけて更新しているので、
今日は軽めのネタで。
 
 
例えば、
テトリスリバーシなどのパズルゲームや、
SLGやRPGでのマップなどを作る際には、
必ず2次元のフィールドが必要となります。
 
そういった場合に使える、汎用のフィールドクラスを公開します。
(…まあ、なんてことはないですが…)
 
まずは、ヘッダファイル(Field.h)

#pragma once

/**
 * 汎用フィールドクラス
 */
class CField
{
private:
	int *m_field;
	int m_width;
	int m_height;
public:
	CField(void) {Init();}
	~CField(void) {Destroy();}

	void Resize(int width, int height);
	void Clear();
	int GetAt(int x, int y);
	void SetAt(int x, int y, int value);
	int *GetAddress(int x, int y);
	int GetWidth() { return m_width; }
	int GetHeight() { return m_height; }
private:
	void Init();
	void Destroy();
	bool IsRange(int x, int y);
};

#pragma onceっていうのは、VCだけにある特殊な指令で、
2重インクルードを避けるための指令です。
 
VC以外の環境の場合は、#ifdefに置き換えてくらはい。
 
で、CPPファイル(Field.cpp)

#include ".\field.h"

// ============================================================================
// 初期化処理
// ============================================================================
void CField::Init()
{
	m_width = 0;
	m_height = 0;
	m_field = 0;
}

// ============================================================================
// フィールドのリサイズ
// @param x, y サイズ
// ============================================================================
void CField::Resize(int x, int y)
{
	if(x < 1 || y < 1) return;
	Destroy();
	m_width = x;
	m_height = y;
	m_field = new int[x * y];
	Clear();
}

// ============================================================================
// フィールドのクリア
// ============================================================================
void CField::Clear()
{
	int *ptr = GetAddress(0, 0);
	for(int j = 0; j < m_height; j++)
	{
		for(int i = 0; i < m_width; i++)
		{
			*ptr = 0;
			ptr++;
		}
	}
}

// ============================================================================
// フィールドの破棄
// ============================================================================
void CField::Destroy()
{
	if(m_field != 0) delete[] m_field;
	Init();
}

// ============================================================================
// フィールドを取得
// @param x, y 座標
// ============================================================================
int CField::GetAt(int x, int y)
{
	if(!IsRange(x, y)) return 0;
	return m_field[m_width * y + x];
}

// ============================================================================
// フィールドに値を設定
// @param x, y 座標
// @param value 値
// ============================================================================
void CField::SetAt(int x, int y, int value)
{
	if(!IsRange(x, y)) return;
	m_field[m_width * y + x] = value;
}

// ============================================================================
// フィールドのアドレスを取得
// @param x, y 座標
// ============================================================================
int *CField::GetAddress(int x, int y)
{
	if(!IsRange(x, y)) return 0;
	return &m_field[m_width * y + x];
}

// ============================================================================
// 指定された座標が正常な範囲であるかをチェック
// @param x, y 座標
// ============================================================================
bool CField::IsRange(int x, int y)
{
	if(m_field == 0) return false;
	if(x > m_width - 1 || y > m_height - 1) return false;
	if(x < 0 || y < 0) return false;
	return true;
}

 
使い方は、こんな感じです。

CField field;
field.Resize(width, height);
int *ptr = field.GetAddress(0, 0);
for(int j = 0; j < field.GetHeight(); j++)
{
	for(int i = 0; i < field.GetWidth(); i++)
	{
		cout << *ptr << endl;
		ptr++;
	}
}