查看: 83|回复: 0

[转载发布] 【含思路讲解】存读档、场所移动时保存事件位置【2.0】

[复制链接]
  • TA的每日心情
    开心
    4 天前
  • 签到天数: 37 天

    连续签到: 3 天

    [LV.5]常住居民I

    2028

    主题

    32

    回帖

    7260

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    0
    卡币
    5184
    OK点
    16
    积分
    7260
    发表于 同元一千年八月六日(秋) | 显示全部楼层 |阅读模式
    许多人在制作游戏时会发现自己设置的事件移动在场所切换或者读档之后事件又恢复原位了。事实上我也觉得RM的有些机制还是很不符合我们的使用习惯的。但是为了存读档的效率和存档的大小又不能把所有地图的所有事件都全部存下来。不过,把事件位置和面朝方向存下来还是很方便的。(注意,这个脚本不能保存事件透明度变更和行走图变更,如果需要相关功能请自行修改

    当初我写这个脚本的时候其实只参考了Oksh的魔塔样板7822。结果等我写完在站上一搜发现其实有好多前辈对这个问题都已经有所研究了,而且大家的代码都颇为相似(毕竟一共也没几行,也没办法标新立异啊)。希望见到过类似东西的朋友不要冤枉我是抄袭的……

    先把代码发出来吧(插入在Main前):

    RUBY 代码
    1. class Game_Character
    2.   attr_accessor :direction
    3. end
    4. class Game_Event
    5.   attr_reader :page
    6. end
    7. class Game_Map
    8.   alias mapsave_game_map_initialize initialize
    9.   def initialize
    10.     mapsave_game_map_initialize
    11.     @event_pos = {}
    12.   end
    13.   def save_event_pos
    14.     returnunless@map
    15.     @event_pos[@map_id] = {}
    16.     for i in@map.events.keys
    17.       if@events[i].page
    18.         @event_pos[@map_id][i] = [@events[i].x, @events[i].y, @events[i].direction, @events[i].page.graphic.character_name]
    19.       end
    20.     end
    21.   end
    22.   def load_event_pos
    23.     returnunless@event_pos[@map_id]
    24.     for i in@map.events.keys
    25.       if@event_pos[@map_id][i]and@events[i].page
    26.         if@events[i].page.graphic.character_name == @event_pos[@map_id][i][3]
    27.           @events[i].moveto(@event_pos[@map_id][i][0], @event_pos[@map_id][i][1])
    28.           @events[i].direction = @event_pos[@map_id][i][2]
    29.         end
    30.       end
    31.     end
    32.   end
    33.   alias mapsave_game_map_setup setup
    34.   def setup(map_id)
    35.     save_event_pos
    36.     mapsave_game_map_setup(map_id)
    37.     load_event_pos
    38.   end
    39. end
    复制代码


    首先,我把Game_Character中原本在类外只读的@direction变为可以读写,这样就可以直接在外部修改事件的面朝方向了。(想来想去还是这样修改最简洁优美,感谢RyanBern大神的开导)

    为什么要这样“粗暴”地修改方向而不是使用turn_leftturn_right之类的方法呢?因为那几个方法中含有对@direction_fix,即【是否面向固定】的判断,如果该事件的当前事件页是默认【面向固定】的,那么读取的朝向信息就不能作用于这个事件。所以这里直接通过修改@direction来实现方向的变更。

    剩下的都是对Game_Map类的修改。在RGSS1中,Game_Map类只有一个实例就是$game_map(并不是像很多人想象得那样每张地图都有一个Game_Map的实例)。initialize方法只会在标题画面【开始新游戏】的时候调用一次。平时切换到场景的时候,是直接调用setup(map_id)方法,从数据库中读取地图内的所有信息存到$game_map中;而数据库在游戏过程中一般是不会被修改、也是不允许修改的,这就是为什么事件的位置在场所切换的时候不会被保存的原因。而在存档的时候,$game_map整个实例会被写入存档中。注意,在默认的RGSS1脚本中,$game_map保存当前地图上改变的一切信息(比如事件的移动和改变朝向等等),所以事件的位置理论上是不会复原的。但是读档的时候会校验游戏有没有被修改,如果被编辑器修改过,会把整个地图重新setup一次,以方便游戏作者的调试。

    有些人可能会问为什么独立开关能够在切换场景的时候保存下来呢?因为独立开关压根儿就没有存在Game_Map里,而是存在一个$game_self_switches对象当中,这个对象是全局的,每次存读档都会被保存而且场所切换的时候也不会受到任何影响。

    既然$game_map对象在存档、读档的时候会被保留下来,那么在$game_map中把我们需要的信息都保存下来就可以了。于是就有了我对Game_map.initialize的修改——在最后加上了一行对于@event_pos这个hash表的初始化。这个hash表的key是地图的id——一个整数,value是一个以事件id为键、事件位置和朝向这一数组为值的hash表(不知道能否理解,具体可以查看代码)。我们的@event_pos是全局的,要对每张地图都存储事件的位置,不然就达不到我们的目的了。

    不管怎么样,似乎问题都处在setup方法上。因为用setup加载一张新地图的时候,原来地图上的一切改变过的信息都销声匿迹了。我们要做的就是抢在setup加载新地图之前把原地图的所有事件位置和朝向都保存下来,然后在加载完新地图之后把以前保存下来的新地图的事件位置应用到新地图所有事件上面、恢复上次离开地图时它们的位置。这样看来,我重新定义的setup方法应该是很好理解的。

    最后就是save和load两个方法。首先在save方法:

    RUBY 代码
    1. returnunless@map
    复制代码


    等价于

    RUBY 代码
    1. returnif@map == nil
    复制代码


    这是考虑到游戏刚开始第一次加载地图的情况。

    RUBY 代码
    1. for i in@map.events.keys
    2.       if@events[i].page
    3.         @event_pos[@map_id][i] = [@events[i].x, @events[i].y, @events[i].direction, @events[i].page.graphic.character_name]
    4.       end
    5.     end
    复制代码


    这很容易理解,就是清空原数据,将当前的事件位置写入。如果当前事件不满足任何一个事件页的开启条件,那么它的面朝方向和位置没有意义(虽然朝向已经被坑爹地初始化为面向下方了)。为什么要把charater_name也记录下来呢?这在后面会讲到,为了避免BUG。

    然后再看load方法:

    RUBY 代码
    1. returnunless@event_pos[@map_id]
    复制代码


    同理。如果@event_pos[@map_id] == nil说明这张地图的事件位置没有被保存过(一般来说代表这张地图是第一次加载),此时就没办法读取事件位置了。

    RUBY 代码
    1. for i in@map.events.keys
    2.       if@event_pos[@map_id][i]and@events[i].page
    3.         if@events[i].page.graphic.character_name == @event_pos[@map_id][i][3]
    4.           @events[i].moveto(@event_pos[@map_id][i][0], @event_pos[@map_id][i][1])
    5.           @events[i].direction = @event_pos[@map_id][i][2]
    6.         end
    7.       end
    8.     end
    复制代码


    一个一个地还原事件的位置。注意到还原事件位置的条件是保存下来的character_name和事件当前的character_name相同;如果不这样判断一下,那么当游戏进程进行导致再次进入地图时引起事件页切换、而且切换前后的行走图都不一样了(可以理解为相当于换了一个事件,这是占用了同一个位置而已),那么原来的位置信息和朝向信息就可以舍去了。当然,这里的判断条件可以自行修改,按照自己的使用习惯即可。

    其实写了这么多还是为了看得懂的同学帮我查查有没有BUG什么的……毕竟对RGSS的代码钻研得不太多,这些东西都是自己一个一个发掘出来的。大家一起交流、增进讨论才能更高效率地学会这些脚本嘛!
                 本帖来自P1论坛作者gonglinyuan,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=383466  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
    天天去同能,天天有童年!
    回复 论坛版权

    使用道具 举报

    ahome_bigavatar:guest
    ahome_bigavatar:welcomelogin
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2024-5-14 21:14 , Processed in 0.060348 second(s), 41 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表