Rock8 マップエディター説明書



はじめに
このツールを使って起こる如何なる問題も開発者は一切責任を負いません。
全て自己責任の下お使いください。
このツールの二次配布を禁じます。

Contents
1. ファイルの新規作成・保存
2. エディット方法
3. エディター仕様
4. マップファイル仕様

ファイルの新規作成・保存
メニューから次の操作によってマップファイルの作成と保存をします。

・「新規マップ作成」
新規でマップを作成します。この操作では同時にマップチップファイルの指定を要求されます。

・「マップ読み込み」
既存のマップファイルを開きます。この操作では、最初にマップファイルを指定し、続いてマップチップファイルのを指定してください。

・「マップ保存」
開いているマップファイルを同名で上書き保存します。新規作成直後は保存するファイル名を指定するよう要求されます。

・「名前を付けて保存」
開いているマップファイルを名前を変更して保存します。保存するファイル名を指定してください。


エディット方法
基本的にはクリックのみの操作でマップを編集します。次の写真の用に左右二画面の構成となります。左画面には編集中のマップが表示されます。現在のカーソル位置は赤枠で囲まれます。右画面にはマップチップと当たり判定のチップが表示されます。それぞれ、選択中のマップチップと当たり判定チップが赤枠で囲まれます。右下のラジオボタンによって、編集モードをマップ表示編集モードからの当たり判定編集モードへ切り替えます。その他、写真中の番号部分をクリックすることで各種操作を行います。

(1) 左画面の明るくなった部分をクリックすると、選択中のマップチップが配置されます。 編集モード当たり判定の場合は選択中の当たり判定チップを配置します。クリックしたままマウスを動かせば連続して配置できます。また右クリックするとクリックした場所と同じマップチップが選択状態となります。ドット絵エディタの要領で操作してください。

(2) 左画面の上下左右の暗くなった部分をクリックすると、隣のマップ(16x15エリア)へ移動します。隣のマップが無い場合には新しくマップを準備するかを聞かれますので「はい」を選択して追加してください。

(3) クリックすることで選択中のマップチップを変更します。また同時に編集モードがマップ表示モードに変わります。

(4) クリックすることで選択中の当たり判定チップを変更します。また同時に編集モードが当たり判定モードに変わります。現状では左から4~8番目のチップはreserve領域としてあり選択できませ。

(5) 編集モードを切り替えます。


エディター仕様
現状の仕様を書き下します。今後のバージョンアップで機能は拡張される予定です。

・編集できるマップファイルは 16x15スクエアチップを一画面領域としてあります。
・領域は上記の(2)の操作によって上下左右に0x7FFFまで繋げられます。
・マップチップファイルは16x16スクエアドットを1チップとして16x16チップを並べた物を使ってください。
・マップチップファイルは256x256スクエアドットのpngファイルのみとします。
・「ヘルプ」メニューは飾りです。偉い人にはわからないそうです。
マップファイル仕様
マップファイルの現状の仕様を書き下します。今後のバージョンアップで機能は拡張される予定です。

・バイナリファイルとなります。 ・ファイルは一画面領域(16x15スクエアチップ)ごとにデータがまとまっています。 ・次のような構造になります。
Byte数c言語での型内容
ヘッダー部
16char[16] バージョン管理用のヘッダー文字列
"ROCKMAP_20081102"などが入ります
4int一画面領域の横幅(単位:チップ数)
現状では16が入ります
4int一画面領域の縦幅(単位:チップ数)
現状では15が入ります
以降は画面領域単位のデータ。繰り返し
4int画面領域のデータのID
一意に決まる画面領域のIDです。
1以上の値となります。
上下左右の隣り合う画面領域との接続先としても指定されます。
2short画面領域画面領域のX座標です。単位は1画面領域です
2short画面領域画面領域のY座標です。単位は1画面領域です
例えば画面領域IDが1の(X,Y)座標が(10,5)のとき、右隣の画面領域の座標は(11,5)となり、上隣の座標は(10,4)となります。新規作成時には最初の画面領域の座標が(0,0)となります。座標値は負の値も取りえます。
4int左隣の画面領域のIDです。
値が0の場合は左隣に画面領域が存在しないことを意味します。
4int右隣の画面領域のIDです。
値が0の場合は右隣に画面領域が存在しないことを意味します。
4int上隣の画面領域のIDです。
値が0の場合は上隣に画面領域が存在しないことを意味します。
4int下隣の画面領域のIDです。
値が0の場合は下隣に画面領域が存在しないことを意味します。
画面領域の横幅×縦幅
(現状16x15))
unsigned char*マップチップの番号が収められた配列です。配列の幅はファイルのヘッダー要素に収められた
(画面領域の横幅)×(画面領域の縦幅)
となります。配列の要素は画面領域の左上から右下へ向かって並べられます。収められているマップチップ番号はマップチップファイルの左上から順に右下へ向かって0番~255番となります。
画面領域の横幅×縦幅
(現状16x15))
unsigned char*当たり判定チップの番号が収められた配列です。配列の幅はファイルのヘッダー要素に収められた
(画面領域の横幅)×(画面領域の縦幅)
となります。配列の要素は画面領域の左上から右下へ向かって並べられます。収められている当たり判定チップ番号は0~15番となります。
以降にファイル読み込みのサンプルコードを添付します。
画面領域の(X,Y)座標を4byteでまとめて読み込んでいるのでご注意ください。 もちろんshortで別々に読んでくださって構いません。

//画面領域単位のデータ構造
struct OneMap{
	unsigned char *buf;	//マップチップデータ
	unsigned char *hit;	//当たり判定チップデータ
	int id;				//1から数える通し番号
	unsigned long pos;	//マップのx座標(下位word)とy座標(上位word)
	OneMap* left;		//左隣の画面領域のポインタ
	OneMap* right;		//右隣の画面領域のポインタ
	OneMap* up;			//上隣の画面領域のポインタ
	OneMap* down;		//下隣の画面領域のポインタ
	OneMap* next;		//リスト構造の次の要素へのポインタ
};


//画面領域の追加
OneMap* Map::new_OneMap(int mapsz_w, int mapsz_h, unsigned long pos){
	OneMap* a = new OneMap;
	OneMap* b;

	a->buf = new unsigned char[mapsz_w * mapsz_h];
	memset(a->buf, 0, mapsz_w * mapsz_h);
	a->hit = new unsigned char[mapsz_w * mapsz_h];
	memset(a->hit, 0, mapsz_w * mapsz_h);
	a->pos = pos;
	a->left = NULL;
	a->right = NULL;
	a->up = NULL;
	a->down = NULL;
	a->next = NULL;
	
	unsigned long pos_r = (pos & 0xFFFF0000) | ((pos + 1) & 0xFFFF);
	unsigned long pos_l = (pos & 0xFFFF0000) | ((pos - 1) & 0xFFFF);
	unsigned long pos_u = pos - 0x10000;
	unsigned long pos_d = pos + 0x10000;
	
//既存のマップとの関連付け
	if(m_fstOneMap){
		b = m_fstOneMap;
		
		while(1){
			
			if(b->pos == pos_r){
				b->left = a;
				a->right = b;
			}else if(b->pos == pos_l){
				b->right = a;
				a->left = b;
			}else if(b->pos == pos_d){
				b->up = a;
				a->down = b;
			}else if(b->pos == pos_u){
				b->down = a;
				a->up = b;
			}

			if(b->next == NULL){ break;}
			b = b->next;
		}
		a->id = b->id + 1;
		b->next = a;
	}else{
		m_fstOneMap = a;
		a->pos = 0;
		a->id = 1;
	}
	return a;
}

//マップファイルの読み込み
void Map::Load(const TCHAR* filename){

	OneMap* om;
	int ires;
	int id;
	unsigned long pos;
	char header[17];
	FILE *fp = _tfopen(filename, _T("rb"));
	if(fp==NULL){ return;}

	if(m_fstOneMap){
		clear_OneMap();
	}

//version
	fread(header, 16, 1, fp);
	header[16]='\0';
	if(strcmp(header, "ROCKMAP_20081102") != 0){ return;}

//mapsz
	fread(&m_mapsz_w, 4, 1, fp);
	fread(&m_mapsz_h, 4, 1, fp);
		

	while(fread(&id, 4, 1, fp) == 1){		//id;
		fread(&pos, 4, 1, fp);

		om = new_OneMap(m_mapsz_w, m_mapsz_h, pos);
		if(om->id != id){
			fclose(fp);
			TRACE(_T("error: id_difference, %d, %d\n"),om->id,id);
			return;
		}

		fread(&ires, 4, 1, fp);		//id of left OneMap
		fread(&ires, 4, 1, fp);		//id of right OneMap
		fread(&ires, 4, 1, fp);		//id of up OneMap
		fread(&ires, 4, 1, fp);		//id of down OneMap
		//順番どおりならnew_OneMapを使えばposによる関連付けで一致するはず
		
		fread(om->buf, m_mapsz_w * m_mapsz_h, 1, fp);
		fread(om->hit, m_mapsz_w * m_mapsz_h, 1, fp);

	}
	fclose(fp);

}