D言語でPlatinum
そろそろステージデータを使ったゲーム作りをしたいと思って作ってみた。
マップエディタはいつものように、「Platinum」
http://www.hyperdevice.net/
import std.file; /** * 2次元マップ<br> * ハッシュテーブルによる実装 */ class Layer2D { public: /** * データテーブル */ int[int] data; /** * 幅 */ int width; /** * 高さ */ int height; public: /** * コンストラクタ * @param width 幅 * @param height 高さ * @param data データ */ this(int width, int height, char[] data) { this.width = width; this.height = height; foreach(i, d; data) { if(d != 0) { this.data[i] = cast(int)d; } } } /** * 座標を指定して値を取得 * @param x, y 座標 */ int get(int x, int y) { if(x < 0 || width <= x || y < 0 || height <= y) return -1; // 場合によっては例外吐いてもいいかも if(y*width+x in data) { return data[y*width+x]; } return 0; } /** * デバッグ出力 */ void dump() { for(int j = 0; j < height; j++) { for(int i = 0; i < width; i++) { printf("%d", get(i, j)); } printf("\n"); } } } /** * FMF読み込みクラス */ class FMFLoader { public: /** * 識別文字「FMF_」 */ char[] identifier; /** * ヘッダを除いたデータサイズ */ int datasize; /** * マップの幅 */ int width; /** * マップの高さ */ int height; /** * チップの幅 */ int chipwidth; /** * チップの高さ */ int chipheight; /** * レイヤー数 */ int layercount; /** * データのbit数(8/16) */ int bitcount; /** * レイヤー配列 */ Layer2D[] layerArray; private: char[] _file; int _ptr; public: /** * コンストラクタ<br> * TODO: マップデータは8bitのみ * @param filepath FMFファイル * @throw ファイルフォーマット例外 */ this(char[] filepath) { _file = cast(char[])read(filepath); _ptr = 0; identifier = _file.dup[0..4]; // ファイル識別子 [4byte] if(identifier != "FMF_") { throw new Error("Invalid FMF format (" ~ filepath ~ ")"); } _ptr += 4; datasize = readLong(); // ヘッダを除いたサイズ [4byte] width = readLong(); // マップの幅 [4byte] height = readLong(); // マップの高さ [4byte] chipwidth = readByte(); // チップの幅 [1byte] chipheight = readByte(); // チップの高さ [1byte] layercount = readByte(); // レイヤー数 [1byte] bitcount = readByte(); // データのbit数(8/16) [1byte] layerArray = new Layer2D[layercount]; for(int i = 0; i < layercount; i++) { Layer2D layer = new Layer2D(width, height, _file[_ptr.._ptr+width*height]); layerArray[i] = layer; _ptr += width*height; } } /** * 指定レイヤーを取得する * @param id レイヤーID * @return 2次元マップ */ Layer2D getLayer(int id) { if(id < 0 || id >= layercount) return null; return layerArray[id]; } /** * デバッグ出力 */ void dump() { printf("identifier='" ~ identifier ~ "' datasize=%d (w,h)=(%d,%d) chip(x,y)=(%d,%d) layer=%d bit=%d\n", datasize, width, height, chipwidth, chipheight, layercount, bitcount); foreach(i, layer; layerArray) { printf("Layer-%d\n", i); layer.dump(); } } private: /** * 1byte読み込み */ int readByte() { if(_ptr - 1 >= cast(int)_file.length) return -1; int result = _file[_ptr]; _ptr += 1; return result; } /** * 4byte読み込み */ int readLong() { if(_ptr - 4 >= cast(int)_file.length) return -1; int result = _file[_ptr] + (_file[_ptr+1] << 8) + (_file[_ptr+2] << 16) + (_file[_ptr+3] << 24);; _ptr += 4; return result; } } void main() { FMFLoader fmf = new FMFLoader("map.fmf"); fmf.dump(); }
まー、やっていることは、
http://d.hatena.ne.jp/kenmo/20060509
とだいたい同じ。
あと、Layer2Dがハッシュテーブルになっているのは、
例えば、シューティングで敵出現情報をマップに埋め込む場合、
多くの部分が「0(存在しない)」になるため、メモリの節約となるからです。
……まー、そんなに気にする必要はないかもしれませんが。
注意点は、8bitデータのみ対応、です。
おまけ情報
あと、Platinumのちょっとしたテクニックはこちら。
http://d.hatena.ne.jp/kenmo/20060522