重现那款曾经为之痴迷的游戏[1] -- 从资源开始
2008-07-22 14:15
141 查看
预谋
决定开发流星学院是在2008年04月12日的星期六早上。那时还在成都出差,躺在床上就突发奇想要重现这个游戏。这个游戏虽然很“弱智”,可当时我和我LP还玩得蛮起劲的。我就想啊:要是做出来了以后在家里,大家一起玩,重温一下当年的那种打到装备时候的兴奋啊,也蛮不错的。所以起床后马上就开始动手做。
我这人就是有这个毛病,如果想玩什么就不能只是想想而已,一定要动手去做。
那么,第一件事,就是要获得此游戏中的图片、声音等资源素材,没有这些什么都是空谈。
分析
从狗狗上找到了当年那版客户端,下载下来,游戏程序目录下的文件开始分析。
资源文件类型有 *.tex *.ani *.ini *.wav *.midi
声音文件格式是midi和wav,这个是现成的,可以直接利用。
*.tex这个根据名称来猜测,应该就是texture
*.ani这个猜测应该就是animation
*.ini貌似是加密了的配置文件,记事本打开全是乱码,暂时不管
这个游戏是2D的,通过IDA反汇编客户端发现使用DirectDraw实现,那么图像资源应该都是图片纹理,如果是动画的话最可能是纹理动画。游戏目录下的*.tex文件应该就是图片纹理,*.ani应该是动画。
用二进制编辑器打开几个*.tex文件分析,发现。不是标准的图像格式,没有BMP头,也没有JPG/PNG的那些节标记,也不像是压缩过(相邻的N字节有很多相同的),所以我猜测这应该是一种自定义的BMP文件,签名有一个自定义头,后面就是RGB数据.
如何分界呢,这个自定义的BMP头是多大?从哪里开始才是RGB数据区?
这个比较容易算出来。首先用二进制编辑器打开一个场景背景图,这个背景图是800*600, RGB表示一个像素常用的就是16位/24位/32位(在心中默念咒语100遍祈祷是24位的RGB,处理起来最简单),用800*600*像素字节数计算出各种可能的RGB数据区大小,与实际文件大小相近的既是。(如果是从内存中某个对象DUMP出来的,也可能被内存对齐影响,)
RGB16 = 800 * 600 * 2 = 960000bytes
RGB24 = 800 * 600 * 3 = 1440000bytes
RGB32 = 800 * 600 * 4 = 1920000bytes
而实际的文件大小是960032,看来是采用的RGB16格式,文件头是32bytes,没有内存对齐。
确定了文件头范围,就该确定表示图片大小在文件头中的最可能的位置了。
比对了数个文件后,确认此位置既是长宽值的保存位置。
像素格式就不用分析了,直接写了一个小程序,读取这个文件,用GDI+拿各种RGB16格式都试一次填充到Image对象,然后输出正常的图像文件,看正常的就是的了。 最后确定,此图像是ARGB4444格式,这种格式很少见啊,我只在PSP和NDS的平台上看到过这种图像的使用,毕竟在不透明情况下色彩总数太少了。
分析完tex文件,就接着分析ani文件。分析ani文件还真是花了我一番功夫,主要是在边界范围的确定上,没有任何可以精确量化的计算过程,完全凭借自己的直觉和10多次尝试,最后终于提取出所有的动画格式了。不啰嗦过程了,我描述不清,帖代码。
void CViewerDlg::ProcessFile(CString strFile)
{
CFile file;
if( !file.Open( strFile, CFile::modeRead, NULL) )
{
AfxMessageBox( strFile );
return;
}
file.Seek( 0, CFile::begin);
int nIndex = 0;
while(true)
{
if( file.GetPosition() >= file.GetLength() - 1 )
break;
file.Seek( 0x18, CFile::current);
unsigned __int32 ulImgWidth = 0;
file.Read( &ulImgWidth, sizeof(ulImgWidth));
unsigned __int32 ulImgHeight = 0;
file.Read( &ulImgHeight, sizeof(ulImgHeight));
ulImgHeight += 1;
unsigned __int32 ulDataSizePerLine = 0;
file.Read( &ulDataSizePerLine, sizeof(ulDataSizePerLine));
file.Seek( 0x4, CFile::current);
Bitmap bmp( ulImgWidth, ulImgHeight, PixelFormat32bppARGB);
Graphics gp(&bmp);
gp.Clear(Color::Transparent);
BYTE * pSrc = new BYTE[ulDataSizePerLine];
for( UINT y = 0; y < bmp.GetHeight() - 1; y++)
{
Rect rect( 0, y, bmp.GetWidth(), 1);
if( file.Read( pSrc, ulDataSizePerLine) <= 0 )
break;
BitmapData stBmpData = {0};
if( bmp.LockBits( &rect, ImageLockModeWrite, PixelFormat32bppARGB, &stBmpData) == Ok )
{
LPDWORD pDest = (LPDWORD)stBmpData.Scan0;
for( UINT x = 0; x < bmp.GetWidth(); x++)
{
WORD wPixel = pSrc[2*x] | pSrc[2*x + 1] << 8;
pDest [x] = Convert4444(wPixel);
}
bmp.UnlockBits(&stBmpData);
};
}
delete [] pSrc;
CLSID pngClsid;
GetEncoderClsid( L"image/png", &pngClsid);
nIndex++;
CString strTemp;
strTemp.Format( _T("%s.%d.png"), strFile, nIndex);
bmp.Save( strTemp, &pngClsid);
}
file.Close();
}
提取
分析完成后就可以开始批量提取了,没什么技术含量。就是在分析的基础上写提取工具。只是在提取tex文件的过程中,发现有些图片提取出来的图片完全乱色了。
回过头重新分析,居然有2种RGB格式 565和4444,而在文件头中有一个值标明了此文件RGB值类型
今次就写到这里,如果你是这款游戏的开发者/策划者,并偶然看到此贴,请与我联系:) 我需要一点数值设计的资料。
决定开发流星学院是在2008年04月12日的星期六早上。那时还在成都出差,躺在床上就突发奇想要重现这个游戏。这个游戏虽然很“弱智”,可当时我和我LP还玩得蛮起劲的。我就想啊:要是做出来了以后在家里,大家一起玩,重温一下当年的那种打到装备时候的兴奋啊,也蛮不错的。所以起床后马上就开始动手做。
我这人就是有这个毛病,如果想玩什么就不能只是想想而已,一定要动手去做。
那么,第一件事,就是要获得此游戏中的图片、声音等资源素材,没有这些什么都是空谈。
分析
从狗狗上找到了当年那版客户端,下载下来,游戏程序目录下的文件开始分析。
资源文件类型有 *.tex *.ani *.ini *.wav *.midi
声音文件格式是midi和wav,这个是现成的,可以直接利用。
*.tex这个根据名称来猜测,应该就是texture
*.ani这个猜测应该就是animation
*.ini貌似是加密了的配置文件,记事本打开全是乱码,暂时不管
这个游戏是2D的,通过IDA反汇编客户端发现使用DirectDraw实现,那么图像资源应该都是图片纹理,如果是动画的话最可能是纹理动画。游戏目录下的*.tex文件应该就是图片纹理,*.ani应该是动画。
用二进制编辑器打开几个*.tex文件分析,发现。不是标准的图像格式,没有BMP头,也没有JPG/PNG的那些节标记,也不像是压缩过(相邻的N字节有很多相同的),所以我猜测这应该是一种自定义的BMP文件,签名有一个自定义头,后面就是RGB数据.
如何分界呢,这个自定义的BMP头是多大?从哪里开始才是RGB数据区?
这个比较容易算出来。首先用二进制编辑器打开一个场景背景图,这个背景图是800*600, RGB表示一个像素常用的就是16位/24位/32位(在心中默念咒语100遍祈祷是24位的RGB,处理起来最简单),用800*600*像素字节数计算出各种可能的RGB数据区大小,与实际文件大小相近的既是。(如果是从内存中某个对象DUMP出来的,也可能被内存对齐影响,)
RGB16 = 800 * 600 * 2 = 960000bytes
RGB24 = 800 * 600 * 3 = 1440000bytes
RGB32 = 800 * 600 * 4 = 1920000bytes
而实际的文件大小是960032,看来是采用的RGB16格式,文件头是32bytes,没有内存对齐。
确定了文件头范围,就该确定表示图片大小在文件头中的最可能的位置了。
比对了数个文件后,确认此位置既是长宽值的保存位置。
像素格式就不用分析了,直接写了一个小程序,读取这个文件,用GDI+拿各种RGB16格式都试一次填充到Image对象,然后输出正常的图像文件,看正常的就是的了。 最后确定,此图像是ARGB4444格式,这种格式很少见啊,我只在PSP和NDS的平台上看到过这种图像的使用,毕竟在不透明情况下色彩总数太少了。
分析完tex文件,就接着分析ani文件。分析ani文件还真是花了我一番功夫,主要是在边界范围的确定上,没有任何可以精确量化的计算过程,完全凭借自己的直觉和10多次尝试,最后终于提取出所有的动画格式了。不啰嗦过程了,我描述不清,帖代码。
void CViewerDlg::ProcessFile(CString strFile)
{
CFile file;
if( !file.Open( strFile, CFile::modeRead, NULL) )
{
AfxMessageBox( strFile );
return;
}
file.Seek( 0, CFile::begin);
int nIndex = 0;
while(true)
{
if( file.GetPosition() >= file.GetLength() - 1 )
break;
file.Seek( 0x18, CFile::current);
unsigned __int32 ulImgWidth = 0;
file.Read( &ulImgWidth, sizeof(ulImgWidth));
unsigned __int32 ulImgHeight = 0;
file.Read( &ulImgHeight, sizeof(ulImgHeight));
ulImgHeight += 1;
unsigned __int32 ulDataSizePerLine = 0;
file.Read( &ulDataSizePerLine, sizeof(ulDataSizePerLine));
file.Seek( 0x4, CFile::current);
Bitmap bmp( ulImgWidth, ulImgHeight, PixelFormat32bppARGB);
Graphics gp(&bmp);
gp.Clear(Color::Transparent);
BYTE * pSrc = new BYTE[ulDataSizePerLine];
for( UINT y = 0; y < bmp.GetHeight() - 1; y++)
{
Rect rect( 0, y, bmp.GetWidth(), 1);
if( file.Read( pSrc, ulDataSizePerLine) <= 0 )
break;
BitmapData stBmpData = {0};
if( bmp.LockBits( &rect, ImageLockModeWrite, PixelFormat32bppARGB, &stBmpData) == Ok )
{
LPDWORD pDest = (LPDWORD)stBmpData.Scan0;
for( UINT x = 0; x < bmp.GetWidth(); x++)
{
WORD wPixel = pSrc[2*x] | pSrc[2*x + 1] << 8;
pDest [x] = Convert4444(wPixel);
}
bmp.UnlockBits(&stBmpData);
};
}
delete [] pSrc;
CLSID pngClsid;
GetEncoderClsid( L"image/png", &pngClsid);
nIndex++;
CString strTemp;
strTemp.Format( _T("%s.%d.png"), strFile, nIndex);
bmp.Save( strTemp, &pngClsid);
}
file.Close();
}
提取
分析完成后就可以开始批量提取了,没什么技术含量。就是在分析的基础上写提取工具。只是在提取tex文件的过程中,发现有些图片提取出来的图片完全乱色了。
回过头重新分析,居然有2种RGB格式 565和4444,而在文件头中有一个值标明了此文件RGB值类型
今次就写到这里,如果你是这款游戏的开发者/策划者,并偶然看到此贴,请与我联系:) 我需要一点数值设计的资料。
相关文章推荐
- 重现那款曾经为之痴迷的游戏[2] -- 程序基本框架
- libgdx游戏引擎教程(四) 游戏正式开始,资源异步加载(附源码)
- 拍七游戏 许多人都曾经玩过“拍七”游戏。 规则是:大家依次从1开始顺序数数,数到含有7或7的倍数的要拍手或其它规定的方式表示越过 (比如:7,14,17等都不能数出),下一人继续数下面的数
- 追逐自己的梦想----------辅助制作第八课:利用SetWindowsHook将进程注入游戏主线程来解决资源冲突的问题
- 一个最简单GAL游戏资源文件黑盒分析(二)
- unity3d学习笔记(十四)--NGUI用Sprite动画和屏幕自适应制作游戏开始场景
- 那些曾经活在独立游戏里的独行侠们
- 仿CS游戏源码取消资源分
- 游戏地图分块加载资源篇——切图工具
- Unity3D 开发ios时困扰多时游戏开始画面图片的分辨率
- 学习游戏制作从哪里开始
- 游戏大厅 从基础开始(6)--绕回来细说聊天室(中)之女仆编年史1
- 【资源管理】游戏资源的压缩、打包与补丁更新
- 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程01: 资源导入》
- 游戏开始界面
- Android学习笔记(10)-开始做一个数独游戏[中]
- silverlight游戏设计(二)资源管理篇(上)--实现一个多任务资源下载器
- Unity 提取游戏资源之ktx转换实现浅析
- 牛牛举办了一场数字游戏,有n个玩家参加这个游戏,游戏开始每个玩家选定一个数,然后将这个数写在纸上(十进制数,无前缀零),然后接下来对于每一个数字将其数位按照非递减顺序排列,得到新的数,新数的前缀零将被
- J2ME射击游戏实现示例(含源代码和资源)