这段时间在为网游教程找一个相匹配的地图编辑器,虽然几乎每个游戏都有地图编辑器,但我却未能找到比较满意的,绝大部分的地图编辑器都是不公开的,还有很大一部分地图编辑器都是只能在指定的游戏中使用的,剩下的只有歪瓜劣枣了。我找了几个候选的,mappy,hust,gridarta,并分别试用了下:
mappy,功能强大,支持种类多,支持多层,问题是,它怎么就不支持层透明呢?新建一个层就看不到下面的层了,还有,地图分块,是按照竖向排列的,无法在原始图上选择,结果超级的浪费眼睛不说,还是黑灯瞎火的。放弃掉。值得一提的是,这个有pro版,需要花钱的,我没钱,不知道情况如何。反正被我第一个pass掉了。
hust,应该是国产的,版本号挺高,4.2了,我创建了一个比较大的图,512×512的,这下悲剧了,地图块8×8的,太小了,想要放大?我没有找到明显的地方。只支持方块,无斜视角。我个人比较偏好斜视角的,但苦于素材难找,觉得方块的也将就着吧。但也不要大图无法创建啊。尝试了几下,考虑到身体健康,只好放弃了(非常不甘心,我本来期望挺高的)。
gridarta,我其实下载的是daimonin的mapmaker,考虑到编译环境等等,在用之前,我已经做好了失败的准备,甚至考虑着自己也写一个了。结果发现还不错,直接可以了,还附带有大量的资源(可惜没有我最想要的外景的资源,比如房子什么的)。斜45度,支持插件操作,默认保存的都是文本,本来准备写一个数据转换的,但又一想,先看看插件如何吧。然后看它的README,才发现原来是gridarta啊,里面已经有了一个插件了,看了下代码,java的,但关于这方面的文档几乎没有,gridarta也找到(或许我粗心)。只好将gridarta的代码svn co了,然后大致的浏览,分析下各个部件的作用,而外国人写的java项目,代码的位置都变态的深,模块又多,让我狂点鼠标。然后写个测试的插件,折腾了一天,大约明白怎么回事了,然后今天,写了下数据的导出。稍后给出源代码。总算是找到一个比较满意的了:
下面是插件的代码:
//input your beanshell Code
import net.sf.gridarta.model.gameobject.GameObject;
import net.sf.gridarta.model.io.RecursiveFileIterator;
import net.sf.gridarta.model.map.validation.ErrorCollector;
import net.sf.gridarta.model.map.validation.errors.ValidationError;
void log(String message) {
print(message);
}
void inttobyte(byte[] abyte, int offset, int param) {
abyte[offset+0] = (byte)((param>>24)&0xFF);
abyte[offset+1] = (byte)((param>>16)&0xFF);
abyte[offset+2] = (byte)((param>>8)&0xFF);
abyte[offset+3] = (byte)((param)&0xFF);
}
void processMap(String outFile)
{
map = mapManager.getCurrentMap();
if (map == null) {
log(mapPath + ":");
log("- cannot load map file "+mapFile);
return;
}
Vector out_object = new Vector();
Vector cell_object = new Vector();
mapmode = map.getMapModel();
archtype = mapmode.getMapArchObject();
DataOutputStream dos = new DataOutputStream(new FileOutputStream(outFile));
Iterator it = mapmode.getAllGameObjects().iterator();
while(it.hasNext()) {
gameobject = it.next();
/*
log(""+gameobject.getMapX()+","+gameobject.getMapY()+"="+gameobject.getFaceObjName()+",bestName="
+gameobject.getBestName()+",["+gameobject.getMinX()+","+gameobject.getMinY()+","+gameobject.getMaxX()
+","+gameobject.getMaxY()+"],archetype.folder="+gameobject.getArchetype().getEditorFolder()+",Archename="+gameobject.getAnimName());
*/
String name;
if (gameobject.getAnimName() != null) {
name = gameobject.getArchetype().getEditorFolder()+gameobject.getAnimName()+".ani";
} else
name = gameobject.getArchetype().getEditorFolder()+gameobject.getFaceObjName()+".png";
int found = -1;
for (int i = 0; i < out_object.size(); i++) {
String temp = (String)(out_object.elementAt(i));
if (name.equals(temp)) {
found = i;
break;
}
}
if (found == -1) {
found = out_object.size();
out_object.addElement(name);
}
byte[] buf = new byte[4];
inttobyte(buf, 0, gameobject.getMapX());
for (int i = 0; i < 4; i++) {
cell_object.addElement(buf[i]);
}
inttobyte(buf, 0, gameobject.getMapY());
for (int i = 0; i < 4; i++) {
cell_object.addElement(buf[i]);
}
inttobyte(buf, 0, found);
for (int i = 0; i < 4; i++) {
cell_object.addElement(buf[i]);
}
buf = null;
}
int length = cell_object.size();
length += 4;//cell_object.size
length += 4;//out_object.size
for (int i = 0; i < out_object.size(); i++) {
length += 4; //string_length
length += ((String)out_object.elementAt(i)).length();
}
length += 8;//mapx, mapy
length += 4;//crc32
byte[] out = new byte[length];
int index = 4;
inttobyte(out, index, archtype.getMapSize().getWidth());
index += 4;
inttobyte(out, index, archtype.getMapSize().getHeight());
index += 4;
inttobyte(out, index, out_object.size());
index += 4;
for (int i = 0; i < out_object.size(); i++) {
String temp = (String)(out_object.elementAt(i));
int slength = temp.length();
inttobyte(out, index, slength);
index += 4;
System.arraycopy(temp.getBytes(), 0, out, index, slength);
index += slength;
}
inttobyte(out, index, cell_object.size());
index += 4;
for (int i = 0; i < cell_object.size(); i++) {
out[index] = (byte)(cell_object.elementAt(i));
index++;
}
dos.write(out, 0, length);
dos.close();
out = null;
list = null;
mapManager.release(map);
log("process over!!");
}
String mapDefaultFolder = globalSettings.getMapsDirectory().getPath();
String rootDirectory = mapDefaultFolder;
log(rootDirectory);
String OutFile = outFile.length() == 0 ? "temp.bin" : outFile;
processMap(OutFile);
简单说下使用方法,在菜单中选择编辑插件,新建一个插件,然后添加一个String类型的变量,命名为outFile,在code里面贴上上面的代码,然后打开一个地图,运行新建的插件,会将数据导出为二进制的。文件的结构如下:
{CRCCode:32,
MapWidth:32,
MapHeight:32,
object_num:32,
obj_list:[
{file_name_length:32,
file_name_string: file_name_length
}
],
cell_num:32,
cell: [
{cell_x:32,
cell_y:32,
cell_object_index:32
}]
}
上面的内容中,CRCCode未添加,只保留了空间,改天找下java的crc代码加上。我将动画的后缀名命名为.ani,图像的为png,其他的可能有些错误(比如event或者msg或者ai之类的),到时候再说了。现在仅作为一个参考。