gamemaker吧 关注:13,566贴子:94,154

【设计】扫雷RPG复刻设计

只看楼主收藏回复

一楼百度
二楼上图和简介
三楼设计内容
如果有机会,上部分源程序,不过这个游戏的“重写”不是用gm做的,有兴趣的可以在gm上试试~
声明:这个游戏不是我原创,只是我玩过之后想实现,
要玩这个游戏,可以尝试下面的链接,
http://www.hojamaka.com/2010/06/%25E3%2583%259E%25E3%2583%25A2%25E3%2583%258E%25E3%2582%25B9%25E3%2582%25A4%25E3%2583%25BC%25E3%2583%2591%25E3%2583%25BC/
以下内容仅供学习用,不要乱用=。=、


IP属地:上海1楼2011-05-30 15:56回复

    如上图,进入上面的链接,可以看到上面的图,简单介绍一下,
    最上面一行是HP LV EX NE 以及T
    当然不是惠普,包包什么(一点不好笑。。。),
    这些都是勇者(真的是勇者么?)的生命,等级,经验,到下一级的经验和时间。
    这个游戏里,你扮演勇者,去探寻地图上的各个角落,你可能会碰到各种怪物,你可能会被他们打败,也可能寻找到最终的魔王并将其消灭!
    你的生命是很关键的变成0的时候就会死掉,
    你的等级是你实力的象征,遇到比你等级低的和与你等级相同的怪物,你都可以毫不费力的将它们消灭,
    经验值会告诉你离下一级有多远,
    时间到9999就会不动=。=、
    中间部分是地图部分,格子下面可能隐藏着怪物,也可能啥都没有,
    你要一个一个揭开格子,消灭所有怪物,
    小心,恶魔就在那里,
    怪物有不同的等级,而地图上的数字是周围8格中怪物的等级之和,
    算出那些弱小的怪物的位置,优先灭掉他们吧,
    下面是当前地图里怪物的等级以及对应的个数,要都消灭掉才可以赢得勇者的称号!
    上吧,勇士,名誉就在前方。
    右下角的clear可以重开游戏~


    IP属地:上海2楼2011-05-30 16:05
    回复
      嗯,下面我们来开始设计,
      我先放出第一版的设计,这个是缺陷很大的版本,我们将在讨论的过程中发现那些最初设计上的问题,以及如何修正~
      首先,我用的是perl脚本语言,具体语法就不讲了,一些简单代码一看也懂的,我也会讲解,主要看数据结构的设计和游戏流程设计,
      第一版的数据结构设计:
      use constant INIT_HERO => {
           'hp'                 => undef,
           'level'              => undef,
           'exp'                => undef,
           'exp_to_level_up'    => undef,
      };
      上面是初始化勇者,怪物和地图的基本数据结构,
      勇者的hp,level,exp和exp_to_next_level,
      前三个都是一个数字,hp初始化视情况定,我的是10,level为1,exp为0,
      最后的exp_to_next_level是一个比较特别的值,在这里我要讲第一个设计上的问题,
      第一版设计中,我把exp_to_next_level做成了一个哈希(hash),就是一个键值对的数据结构(这样在这个数据结构中,提供key值(=>前面的)就可以获得value(=>后面的)),如下:
               1 => 5,
               2 => 7,
               3 => 10,
               4 => 15,
               5 => 20,
               6 => 25,
               7 => 30,
               8 => 40,
               9 => 50,
      最初这样做的目的是,将每个等级升级所需的经验对应如此,这样在每一级的时候可以清晰找到升级所需的经验,但这个设计有一个明显的问题就是,把一个不变的数据设计到一个变动的数据中了,这在某些情况下是可取的,但是大多数情况下,把一些静态的或者在游戏初始化阶段确定的常量放在人物的变动的属性中,不是一件好事情,
      不把框架结构放到实体里,这也是面向对象在创建一个对象的时候要做到的事情,
      这样,我在第二版里,把这个数据结构单独拿出来,做成了一个单独的哈希,
      而把经常会变动的数据,封在了勇者的体内,包括hp,level和exp。
      这个问题其实比较浅显,但是,不亲手做,我就没办法体会到和发现到其中的问题。
      接下来初始化怪物,
      use constant INIT_MONSTER => {
           'level'              => undef,
           'exp'                => undef,
           'show_type'          => undef,
      };
      接下来初始化地图,
      use constant INIT_MAP => {
           'length'             => undef,
           'width'              => undef,
           'monster'            => undef,
      };
      以及最后生成map_matrix数据结构,
      这里是第一版的最大设计问题所在,我们在四楼接着讲,


      IP属地:上海3楼2011-05-30 16:29
      回复
        首先,
        初始化地图INIT_MAP,
        length是地图长度,width是地图宽度,那么地图总格数就是他们的乘积,
        monster是怪物的等级以及对应的个数,
        在我的第一版中,我暂定一个难度,把length和width设为10,那么总的格子数就是100个,而monster定为了下面的哈希,
                 1 => 15,
                 2 => 10,
                 3 => 8,
                 4 => 5,
                 5 => 4,
                 6 => 3,
                 7 => 2,
                 8 => 1,
                 9 => 1,
        这个哈希的含义是,前面等级的怪物,在地图中有对应后面的个数,
        这三个属性作为地图本身的信息,生成的时候便赋值,是没有问题的,接下来,我们来生成地图中的怪物列表,
        如果不想影响连贯的阅读思维可以先看“题外话结束的分界线”后面的内容,
        ——————————————题外话的分界线——————————
        说一些题外话,一般考虑生成地图基本信息有多种方法,
        在一个地图很大,但是怪物很稀疏的地图中,我们可以考虑将大地图简化成一个简单的数据结构,而在怪物的信息中加上其他大地图中的坐标,
        在一个怪物比较多的地图中,按上面的方法来做的话,我们就要考虑这样做的意义,我们在地图初始化的时候,并不需要把那么多的怪物的信息都读取一遍,我们只需要知道那里是不是有个怪物就可以了,而上面的方法会使初始化变得没有效率,所以我们把一个格子是不是有怪物的信息放在这个格子上,而这个信息可能只是简单的有或者无,更复杂的时候可能会有怪物的等级,或者更聪明的办法,是放一个指向某个怪物的指针,或者引用,
        当然具体情况具体分析,
        这个游戏中,我们并没有把坐标放到相应的怪物的体内,而是把怪物用作一个格子的“属性”,后来证实这个方法不好,而改成了,把怪物的最少的信息放到格子中,第二版中,放的是一个等级。
        —————————————题外话结束的分界线—————————
        我们把上面地图初始化的monster中的内容取出来,每一个键值对拿来,对值做一个循环,初始化怪物,也就是INIT_MONSTER,
        我们把键的内容(1~9的等级),作为怪物的level,生成对应的exp,对应的show_type(这个值在最初的设计中被设计用来指定怪物显示的样子,但是最后,简化了设计之后这个值没有使用),这个我们得到了“等级1,经验2的1级怪物”15个,“等级2,经验4的2级怪物”10个,等等,我们把这些怪物放进一个列表,这时候他们是一串糖葫芦,在地图中还没有特定的位置,
        生成地图中特定位置的方法就是,对这个列表进行循环,每一次循环,我们要获得一个0~99的随机数,如果这个随机数已经出现过(这个判断基于标记,有多种方法),那么重新获得一个随机数,然后根据随机数把怪物放到地图的固定位置,
        我用的方法是,一个随机数出现过的哈希,
        举例:
        循环{
        第一步,取得一个怪物,
        第二步,取随机数,判断这个数是否在随机数的哈希中存在,如果存在,重做第二步,不存在,去第三步,
        第三步,将这个随机数在哈希中设为存在,
        第四步,根据这个随机数,例如83,将怪物放到map_matrix这个2维数据的(83%10,int(83/10))这个坐标中,
        }
        这样循环结束,所有怪物在map_matrix这个阵列中都有了一个特定的位置,
        之后,对map_matrix进行遍历,把每一个格子(不含怪物)置为一个数,这个数是周围八个格子中有的怪物的等级之和,
        设计到这里,问题接二连三的出现了,
        首先是map_matrix这个数据结构的内容怪异,其中包含怪物的信息和非怪物的信息,再者,没有一个标记位显示一个格子是不是被访问过了,
        第二个问题很容易解决,但是为了编码简单我还是又做了一个和这个2维数组一样长宽的2维数组来存放每个格子是否被访问的信息,
        第一个问题就比较麻烦了,不仅仅使我在编码的时候要考虑这个格子是怪物还是非怪物,在要考虑更多的数据上的问题,
        本来想设计一个数据结构来存放所有信息,反而弄巧成拙,
        拙在于下面几点:
        1,一个2维数组中各个格子中有不同的数据结构,
        2,怪物的信息明显重复出现,这是个数据上的冗余,
        3,怪物所处的位置,很明显没有办法显示周围怪物的等级之和,这在原来的游戏中是有的,
        4,调试繁琐,
        等等问题,
        遇到上面的问题,让我更加清晰,明白了,数据结构要简洁,不然很让人头疼,
        五楼接着说。。。


        IP属地:上海4楼2011-05-30 17:06
        回复
          其实,上面已经讲了最基本的设计过程,包括如何生成怪物,如何将怪物放到地图中,等等,这些基本的算法将游戏初始化后,就可以开始玩了,
          由于perl暂时没有良好的图形界面,我将游戏的内容输出在了命令行中,
          显示如下,很简陋:

          有显示勇者的基本信息,有地图信息,为了方便确认还加了横纵坐标=。=、
          输入相应坐标,就可以打开相应格子,
          简单算法介绍为,
          1,如果这个格子已经打开,那么什么都不做,
          2,如果这个还没打开,那么将其置为打开,
          3,如果里面是怪物,判断怪物等级是不是比勇者高,如果高,扣掉一定hp,判断勇者hp是否小于0,如果小于0,判定勇者死亡,如果低不扣hp,之后给勇者加经验,判断是否升级,等一系列操作,
          4,如果里面不是怪物,那么这个格子就会是个数字,0,或者其他,如果是0,说明周围8个格子没有怪物,那么依次点击周围8个格子,做和现在的格子相同的事情(类似递归),如果不是0,那么把这个数字显示出去,
          基本的游戏判断就是这些了,再就是怪物死光的时候报胜利,中途输入Q就退出,之类的了,


          IP属地:上海5楼2011-05-30 17:16
          回复
            上面把第一版的数据结构和一些算法设计已经讲了一遍,基本就是这些,第一版的数据结构问题很大,需要重写,
            下面是第二版的数据结构,
            首先是初始化后的地图的内容,地图map_matrix为一个2维数组,每一个单元格的内容是一个哈希:
            {
                monster_level => (0为无monster),
                num           => (周围8格怪物level之和),
                show_flag     => (1为显示,0不显示,初始全0),
            }
            这样,初始化地图的时候,只需要知道每个等级的怪物对应有多少只,就可以直接生成上面的地图,
            要获得对应的怪物的信息的时候,可以去下面的变量里找:
            monsters =>{
                1 => {
                   level => 1(同key值),
                    [damage => (扣hp,也可以不要,可以根据等级来判断),]
                   exp => 1(杀死后给勇者提供多少经验),
                   [count => (这个变量可以显示地图里的怪物有多少只,有对应怪物死掉的时候可以要减少,这个变量是否放在这里还是一个疑问,现状就是逻辑上说得过去,不过还是有点怪,但不是大问题了,不想放这里的话,可以做成一个单独的哈希),]
                }
                2 => {……}
                 ……
                 9   => {……}
            }
            这样,我们只需要从地图里找怪物的等级,就可以到这个哈希里找对应怪物的信息了,
            勇者的数据也包括两部分,一部分是基本数据
            hero =>{
                hp => ,
                level => ,
                exp => ,
            }
            以及到下一级的经验
            exp_to_next_level =>{
                1 => 20,
                2 => 40,
                ……
                8 => 200,
            }
            具体的数字还要具体设计,这里的数字只是参考。
            除此之外,用一个变量存游戏开始的时间,在结束的时候,可以看你用了多少时间。
            另外,还可以在达到某个格子的时候,将战斗内容显示出来,比如,显示,5级的勇者遇到了4级的哥布林,直接秒杀,获得多少经验,升到6级这样的内容,会使过程更有趣更互动,等等。。。


            IP属地:上海6楼2011-05-30 17:33
            回复
              嗯,上面就基本上是全部了,第二版设计好了还在编码,
              等第二版编码好了我就放代码,第一版就算了,比较烂=。=、


              IP属地:上海7楼2011-05-30 17:37
              回复
                有问题可以回帖,也可以pm我~我会以相同的方式回复,
                欢迎好的建议,我也可以把代码改得更好~~


                IP属地:上海8楼2011-05-30 17:39
                回复
                  perl……


                  IP属地:上海9楼2011-05-30 17:58
                  回复
                    第二版再改,把monster改为两个简单的哈希(或者三个),
                    第一个哈希,以等级为key,经验为值,
                    第二个哈希,以等级为key,地图中的怪物个数为值,
                    这样的好处是第一个哈希一般不会变,第二个经常会变动,
                    还可以弄第三个哈希,是用来存放对应怪物的显示信息的,这个专门用来显示,在不同的实现过程中处理的过程会不大相同~


                    IP属地:上海10楼2011-05-31 13:41
                    回复
                      补充好处就是,这两个简单的数据结构用各种不同的语言都更容易实现了,
                      也使编码变简洁了,


                      IP属地:上海11楼2011-05-31 13:44
                      回复
                        补充一点,今天琢磨了一下怪物对英雄造成伤害的公式,
                        怪物等级*(怪物等级-勇者等级),应该是这个,
                        还有勇者升级的经验应该等于或者略小于当前等级的怪物提供的经验乘以这种怪物的总个数,


                        IP属地:上海12楼2011-05-31 14:00
                        回复
                          插楼是支持的一种表示!


                          IP属地:河南13楼2011-05-31 16:27
                          回复


                            IP属地:上海14楼2011-05-31 20:55
                            回复
                              源代码这里发了几次没发出来,就发我空间了,
                              http://hi.baidu.com/freeboynil/blog/item/cd47a2fd5fe799e5fc037ffc.html


                              IP属地:上海15楼2011-06-03 09:10
                              回复