`
rcfalcon
  • 浏览: 228064 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

金庸群侠传资源压缩数据结构研究

 
阅读更多

金庸群侠传是智冠科技90年代出品的精品DOS游戏,

 

其资源压缩包格式紧凑而科学,这里我们一起学习一下其数据结构。并且编写一个能够读取解析它的程序,

 

 

 

以下是我对 Hdgrp资源文件解包的运行结果展示

 


 

下面我们看一下资源类型:

 

其资源包括 idx和grp文件,idx记录了各个资源的索引、grp(group pictures?)存储了具体数据。

 

另外以Mmap.col作为整体的调色板,存储各种颜色数据。

 

idx文件每4个byte为一个section,每个section记录一个资源图片的endoffset,即又是下一个资源图片的startoffset。

 

----------

int32  |  endoffset

 

grp文件,以idx文件为基准,按offset区间划分存储图片,每个图片资源:

 

---------

int16 | w

int16 | h

int16 | x (不知道有什么用)

int16 | y(不知道有什么用)

以下h行,每行支持多个section,每个section数据结构

----------

int8 | 该行字节数

[section]

int8 | t 透明像素点个数

int8 | nt 非透明像素点个数

nt * int8 | 该点对应调色板数据,如1,则对应调色板第一个颜色值

 

 

调色板文件Mmap.col

一共256*3 byte,256色,每个颜色按rgb 除以4存放,按顺序存放

----------

byte | r

byte | g

byte | b

 

这样就可以解每个资源文件了。下面是部分核心的C#代码,我使用WPF的bitmapimage进行渲染。

 

 

 

 

 

    class GameResource
    {
        #region 单例
        static public GameResource Instance
        {
            get
            {
                if(_instance==null){
                    _instance = new GameResource();    
                }
                return _instance;
            }
        }

        static GameResource _instance = null;
        private GameResource()
        {
            ImageFiles = new Dictionary<string, List<Image>>();
        }
        #endregion

        public Dictionary<string, List<Image>> ImageFiles;
    }

    .............
        /// <summary>
        /// 初始化调色板
        /// </summary>
        public void InitColors() 
        {
            FileStream f = new FileStream("data/Mmap.col", FileMode.Open);
            BinaryReader reader = new BinaryReader(f);
            for (int i = 0; i < 256; ++i)
            {
                byte[] color = reader.ReadBytes(3);
                for (int j = 0; j < color.Length; ++j)
                {
                    color[j] = (byte)((int)color[j] * 4);
                }
                colorMap[i] = color;
            }
            reader.Close();
            f.Close();
        }

        Dictionary<int, byte[]> colorMap = new Dictionary<int, byte[]>();

        private BitmapImage ReadImage(BinaryReader reader, int length)
        {
            int w = reader.ReadInt16();
            int h = reader.ReadInt16();
            int x = reader.ReadInt16();
            int y = reader.ReadInt16();

            List<System.Windows.Media.Color> colors = new List<System.Windows.Media.Color>();
            colors.Add(System.Windows.Media.Colors.Blue);
            colors.Add(System.Windows.Media.Colors.Green);
            colors.Add(System.Windows.Media.Colors.Red);
            
            BitmapPalette palette = new BitmapPalette(colors);
            PixelFormat pf = PixelFormats.Bgra32;

            int stride = (w * pf.BitsPerPixel + 7) / 8;
            byte[] pixels = new byte[h * stride];
            for (int i = 0; i < pixels.Length; ++i)
            {
                pixels[i] = 0x00;
            }
            int p = 0;
            try
            {
                for (int i = 0; i < h; ++i) //H行
                {
                    p = i * w * pf.BitsPerPixel / 8;
                    int count = reader.ReadByte(); //该行字节数
                    int offset = 0;

                    while (offset < count)
                    {
                        int transparentPixs = reader.ReadByte(); //透明像素个数
                        offset++;
                        p += transparentPixs * pf.BitsPerPixel / 8;
                        int nonTransPix = reader.ReadByte(); //非透明像素个数
                        offset++;
                        for (int j = 0; j < nonTransPix; ++j)
                        {
                            int colorKey = reader.ReadByte();

                            pixels[p] = colorMap[colorKey][2]; //b
                            p++;
                            pixels[p] = colorMap[colorKey][1]; //g
                            p++;
                            pixels[p] = colorMap[colorKey][0]; //r
                            p++;
                            pixels[p] = 0xFF; //a
                            p++;

                            offset++;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(p.ToString());
            }
            
            BitmapSource image = BitmapSource.Create(
                w,
                h,
                96,
                96,
                pf,
                palette,
                pixels,
                stride);
            PngBitmapEncoder encoder = new PngBitmapEncoder();
            
            MemoryStream memoryStream = new MemoryStream();
            BitmapImage bImg = new BitmapImage();
            encoder.Frames.Add(BitmapFrame.Create(image));
            encoder.Save(memoryStream);

            bImg.BeginInit();
            bImg.StreamSource = new MemoryStream(memoryStream.ToArray());
            bImg.EndInit();

            memoryStream.Close();
            return bImg;
        }

        public List<Image> LoadImages(string filename)
        {
            List<Image> rst = new List<Image>();
            FileStream f = new FileStream(filename + ".idx", FileMode.Open);
            BinaryReader reader = new BinaryReader(f);

            FileStream gf = new FileStream(filename + ".grp", FileMode.Open);
            BinaryReader greader = new BinaryReader(gf);
            try
            {
                int startOffset = 0;
                while (f.CanRead)
                {
                    int endOffset = reader.ReadInt32();
                    Image image = new Image();
                    image.Source = ReadImage(greader, endOffset-startOffset);
                    rst.Add(image);
                    startOffset = endOffset;
                }
            }
            catch (Exception e)
            {

            }
            greader.Close();
            gf.Close();
            reader.Close();
            f.Close();
            return rst;
        }

        public void LoadResource(string filename)
        {
            GameResource.Instance.ImageFiles.Add(filename, LoadImages(filename));
        }

..................
 

 

 

 

 

  • 大小: 126.6 KB
分享到:
评论

相关推荐

    基于C++和Lua的经典游戏《金庸群侠传》复刻版设计源码

    本《金庸群侠传》复刻版项目基于C++和Lua开发,包含483个文件,其中包括370个H头文件、47个C源文件、19个C++源文件、12个A库文件、5个AM文件、3个DSP文件、3个VCPROJ文件、2个LA文件、1个GITIGNORE文件和1个CHANGE...

    金庸群侠传OL1.0易语言模拟器全套资料+模块

    金庸群侠传OL1.0易语言服务端模拟器+所需模块+开发资料+所需工具等 本模拟器理论支持 所有金庸群侠传OL1.0版客户端 简繁体。 本模拟器为【半成品】 本模拟器目前底层基础开发完毕,可以登陆游戏,其他还未开发,有...

    《金庸群侠传》Windows版含源代码

    《金庸群侠传》Windows版含源代码是一款由个人开发者使用Delphi集成开发环境和SDL库编写的桌面游戏。这款游戏以金庸先生的武侠世界为背景,深受金庸小说爱好者的喜爱。开发者开放源代码,让其他程序员有机会研究、...

    金庸群侠传DOS.rar

    《金庸群侠传》是由河洛工作室开发,智冠科技在1996年发行的经典武侠RPG游戏。游戏自由度非常高,玩家可以选择不同的路线和任务,体验丰富的武侠世界。 【基本玩法】 选择角色属性:游戏开始时,玩家需要选择角色的...

    金庸群侠传X完整攻略

    金庸群侠传X完整攻略,让你重新找回当年玩金庸群侠传,武林群侠传的感动。有些特殊的剧情或场景只能依靠特定的人物或某些不太强力的队友来闯,所以插科打诨的小宝可能也需要上战场噢,所以努力的练好每一个队友吧。

    dotnet-金庸群侠传XSilverlight版

    《金庸群侠传X Silverlight版》是一个基于.NET框架,使用Silverlight技术开发的武侠角色扮演游戏。在本文中,我们将深入探讨.NET开发环境、Silverlight技术及其在游戏开发中的应用,以及如何从项目源码...

    自己用vc写的金庸群侠传

    在描述中提到“先传一个资源,再贴代码上来”,这可能意味着作者将提供游戏的可执行文件(金庸群侠传.exe)以及源代码供其他人学习和研究。通过分析和阅读源代码,开发者可以了解游戏的架构、逻辑以及C++在游戏开发...

    金庸群侠源码

    《金庸群侠传》是一款深受武侠爱好者喜爱的游戏,其源码对于编程爱好者尤其是对游戏开发感兴趣的VC++程序员来说,是一份宝贵的参考资料。本源码可能包含了一系列与游戏设计、图形渲染、用户交互、数据存储等多个方面...

    金庸群侠传架设视频教程.mp4

    金庸群侠传架设视频教程

    C++程序设计:C++复刻金庸群侠传以SDL2为基础实现的2D游戏引擎.zip

    C++程序设计:C++复刻金庸群侠传以SDL2为基础实现的2D游戏引擎 这是一个以SDL2为基础实现的2D游戏框架,同时相当于提供了一个使用该框架制作DOS游戏金庸群侠传移植版的范例。有问题先看根目录说明。

    自己写的一段小游戏《金庸群侠传》

    在提供的"金庸群侠传.rar"压缩包中,可能包含了源代码、资源文件(如图像、音频)、配置文件以及可能的编译或构建脚本。通过研究这些内容,我们可以深入理解游戏的开发过程,学习到如何将一个概念转化为实际可玩的...

    jy3-mirror:金庸群侠传3重制版代码库替代

    《金庸群侠传3重制版》是一款深受玩家喜爱的游戏,其源代码库的镜像版本被命名为“jy3-mirror”。这个项目的主要目的是为原版游戏提供一个持续更新和维护的代码库,以支持社区的进一步开发和个性化定制。在这款游戏...

    kys-cpp:《金庸群侠传》 c ++复刻版,已完工

    《金庸群侠传》是一款深受玩家喜爱的经典角色扮演游戏,基于金庸先生的武侠小说世界。这个名为“kys-cpp”的项目是该游戏的C++复刻版,已完工,意味着开发工作已经完成,玩家可以体验到用现代编程语言重新打造的武侠...

    金庸群侠改版攻略

    金庸群侠改版攻略,用户小伙伴能迅速打怪,且能知道在哪里能升级

    HeroesOfJinYong:DOS游戏“金庸群侠传”的重新实现

    重新实现DOS游戏The legend of Jin Yong Heroes(金庸群侠传) 如何建造 安装cmake和C ++编译器(GCC / Clang或MSVC) 第一次您需要克隆项目: git clone --recurse-submodules ...

    金庸群侠传-文字MUD游戏jyqx.zip

    循环结构:游戏使用 while 循环,直到玩家猜对为止。玩家每次猜测后,根据猜测的数字与目标数字的大小关系,给出相应的提示,并根据猜测结果决定下一步的操作。 用户输入处理:通过 Console.ReadLine() 获取用户...

    易语言服务端框架MYSQL+TCP通信+多线程

    易语言后端服务框架,需要用到TCP协议,MYSQL数据库的可以使用这个框架。完美实现多线程并发交互,抗超高并发。使用简单,只需在收到数据后指定位置写代码即可。框架自动进行负载均衡调用处理线程池与MYSQL连接池。

    侠客行MRP格式山寨软件!!

    侠客行MRP格式山寨软件!!帮你们提供优质的服务!!

Global site tag (gtag.js) - Google Analytics