设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3420|回复: 9
打印 上一主题 下一主题

[原创发布] 地图菜单窗口插件2:多级菜单联合【送:角色创建】

[复制链接]

Lv5.捕梦者 (版主)

梦石
1
星屑
23963
在线时间
3338 小时
注册时间
2011-7-8
帖子
3925

开拓者

跳转到指定楼层
1
发表于 2017-2-22 23:12:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 guoxiaomi 于 2017-2-26 09:28 编辑

多级菜单联合

范例:
地图窗口纯净版+角色创建.zip (211.21 KB, 下载次数: 196)
示意图:

范例使用指南:
1. 复制除模板外的 4 个脚本。
2. 此脚本默认会占用数据库前 30 个角色,请把前 30 个角色的战斗图和行走图设置一下。
3. 此脚本默认占用全局变量 25 ,请在脚本【角色创建】的第 17 行左右修改
4. 尚未添加声音……看心情吧……
===================
2017/2/24 18:52 更新
5. 无视2,现在会占用数据库从 $Start_ID_CreateActor 开始的总共 $All_ID_CreateActor 个角色。
===================
原帖请看这里:

地图菜单窗口插件这个插件可以方便的在地图上弹出窗口,并接受用户的输入键进行处理,不太会用的作者可以直接调用公共事件,但是这个脚本本身有更丰富的用途。

为了不遗余力的推销我这个插件脚本(加上在6R刷存在感),我会继续编写这个插件的更多高级使用方法。

本期内容:

多级菜单联合使用

之前的脚本里提到,只能有一级的子菜单,那如果有多级的子菜单应该怎么办呢?当然没有问题,只需要在一个菜单的按键响应里调用另一个已经写好的菜单就行啦。这里还是拿一个具体的例子来着手做。于是我们来做一个“角色创建系统”吧!

大致实现以下功能:

1. 新增角色,子菜单是随机和确认,随机选项会产生姓名等基本属性。这里用随机而不是输入姓名也是为了方便制作……确认的话会把此角色加入到队伍里。

2. 删除角色,子菜单是当前队伍的所有角色,选中已经在队伍里的角色,删除此角色。

3. 修改角色,子菜单是当前队伍的所有角色,选择某一个特定的角色后,会出现2级子菜单,用来调整各种属性(此处就是多级菜单联合使用)

4. 确认退出,如果队伍人数正确,将已经创建好的角色加入队伍,开始游戏

首先我们分析思路:

1. 可以让玩家保存最多 8 个角色,但是队伍里只能有 4 个。众所周知,往数据库里写东西是很不正确的,所以提前在数据库里创建好 8 个角色,然后添加一个“小精灵”角色作为初始角色,让“小精灵”去触发角色制作事件。
2. 有一个数组用来保存当前已经创建好的角色对应数据库里的角色ID $all_saved_actor_ids = []。
  2.1 如果是新建角色,就给数组里添加数组 $all_saved_actor_ids 中不存在,但是在 1-8 之间的最小整数。如果数组$all_saved_actor_ids长度为 8,则显示角色已满,要删除部分角色。
  2.2 如果是删除角色,子菜单遍历$all_saved_actor_ids生成,按下确认键就把对应的ID从数组里去掉。如果数组$all_saved_actor_ids为空,显示“无角色”。
  2.3 如果是修改角色,子菜单遍历$all_saved_actor_ids生成,按下确认键打开新的属性锁定菜单。如果数组$all_saved_actor_ids为空,显示“无角色”。
3. 确认退出,选中时检查 $ary_saved_actors.size 是否为 4 。是的话就调用公共事件,将设置好的角色信息写入 actors.rxdata ,并且将“小精灵”踢掉,把几位角色都拉入队伍。最后开始游戏。

4. 数据,关于随机生成名字,我找到了一个很好的字符串,去掉字符串里的 '·' 然后随机选择连续的 n 个字就行了,注意到UTF-8里每个汉字是3个字符的位置:
RUBY 代码复制
  1. $name_str = "冰雪殇璃陌梦·爱樱沫渺·落璃琴依语·千梦然丝伤·可薇·茉殇黎·幽幻紫银·泪如韵影倾乐兰慕·凝羽冰蓝璃·泪伊如琉璃爱梦莲泪·冰雅泪落冰紫蝶梦·殇心樱语冰凌伊蝶梦如·璃紫陌悠千艳优墨阳云筱残·雪莲茉·伊文思·蕊夏清·碎墨音·芊乐梦黛怡·墨丽莎·梦灵苏魅香·紫蓝幽幻倾城萌美迷离·茉莉白嫩爱凤风魑·殇泪花如霜梦兰·萝莉心梦妖丽百千艳·瑰百合香珠合梦喃·泪伤梦雅爱之瑰·墨艳黎幻殇雪倩梦·情娜血清恋沫幽弥千月绯心丝梦灵蓝千月筱雪殇·希羽岚梦心殇雨樱琉璃舞韵倾雅·蕾玥瑷雅芸茜殇樱雪梦·曦魂梦月澪瑷琪欣泪·咝玥蓝·岚樱殇紫乐蝶雨·苏丽落雅馨瑷魅·音蕾琦洛凤之幽·蠫赬飖·风璃殇·颜鸢璃沫血伤·月冰灵希洛梦·玖兮恋琴爱·雨烟雪殇萌呗·血叶洛莉兰·凝羽冰蓝璃·泪伊如冰缈娅泪落冰花紫蝶梦珠·殇心樱语冰凌伊娜·洛丽塔紫心爱·蝶梦如璃紫陌悠千艳·优花梦冰玫瑰灵伤如爱·晶泪墨阳云筱残伤雅·琉璃爱梦莲泪·冰雪殇璃陌梦".gsub!(/·/,"")
  2.  
  3. def random_name(n)
  4.   start = rand($name_str.length / 3)
  5.   return $name_str[start*3..start*3+n*3-1]
  6. end


5. 接下来先制作主菜单和一级子菜单,实现添加角色的功能吧!(由于不能上传太多代码,这里隐去一些信息)
RUBY 代码复制
  1. class Interpreter
  2.   # 用于在事件脚本中调用的初始化方法
  3.   def init_plugin_CreateActor
  4.     $all_saved_actor_ids = []
  5.     $name_str = "...".gsub!(/·/,"")      
  6.   end  
  7.  
  8.   # 用于在事件脚本中调用的呼叫窗口方法
  9.   def call_mapmenu_CreateActor
  10.     ...
  11.     call_mapmenu('新增角色', '删除角色', '编辑角色', '开始游戏')
  12.     ...
  13.     $game_map.need_refresh = true
  14.   end
  15. end
  16.  
  17. class Game_Party
  18.   # 插件 Task 设置
  19.   alias _CreateActor_set_mapwindow_task set_mapwindow_task
  20.         def set_mapwindow_task
  21.     # 保留之前的 task 设置
  22.     _CreateActor_set_mapwindow_task
  23.     # 新的内容只有插件开启的时候会添加
  24.     if $plugin_CreateActor_enable
  25.       # 具体的 Task 设置
  26.       # 新增角色
  27.       if $all_saved_actor_ids.size == 8
  28.         name = "新增角色:角色已满@Return"
  29.         text = "角色已满 8 人,请先删除角色!"
  30.         @tasks_info.push Game_Task.new(name,text)
  31.       else
  32.         ...
  33.       end
  34.       # 删除和编辑角色
  35.       if $all_saved_actor_ids.empty?
  36.         ...
  37.       else
  38.         $all_saved_actor_ids.each do |id|
  39.           ...
  40.         end
  41.       end
  42.       # 开始游戏
  43.       if $all_saved_actor_ids.size == 4
  44.         ...
  45.       else
  46.         ...
  47.       end
  48.     end
  49.   end
  50. end
  51.  
  52. class Window_MapMenu < Window_Command
  53.   # 插件 按键响应 设置
  54.   alias _CreateActor_run_confirm run_confirm
  55.   def run_confirm(ary)
  56.     _CreateActor_run_confirm(ary)
  57.     if $plugin_CreateActor_enable
  58.       # -------------------------------------------------------
  59.       # 具体的 按键响应 设置
  60.       # ---------------------------------------------------------
  61.       # 从 '@' 选项中读取角色ID
  62.       if ary[2] =~ /ID\[(\d+)\]/
  63.         id = $1.to_i
  64.       end
  65.       # -------------------------------------------------------
  66.       if ary[0] == "新增角色"
  67.         # -------------------------------------------------------
  68.         if ary[1] == "随机生成"
  69.           $game_actors[id].name = random_name_CreateActor(4)
  70.         end
  71.         # -------------------------------------------------------
  72.         if ary[1] == "确认结果"         
  73.           $all_saved_actor_ids.push id         
  74.         end        
  75.       end
  76.       # -------------------------------------------------------
  77.       if ary[0] == "删除角色"
  78.         if $all_saved_actor_ids.size > 0
  79.           $all_saved_actor_ids.delete id
  80.         end
  81.       end
  82.       # -------------------------------------------------------
  83.       if ary[0] == "开始游戏"
  84.         if $all_saved_actor_ids.size == 4
  85.           ...
  86.         else
  87.  
  88.         end
  89.       end
  90.     end
  91.   end
  92.  
  93.   # 用于生成随机的名字
  94.   def random_name_CreateActor(n)
  95.     ...
  96.   end
  97. end



现在才是正题:【多级菜单的调用】
子菜单是锁定菜单,在“编辑角色”激活时可以使用,选中特定角色,按下右键会打开。子菜单的设置和主菜单几乎一样,略有不同的地方是,在修改 $wmm_position 前,要把这个值存起来,退出菜单后还原。
子菜单的部分代码,请注意 14 行和 23 行。
RUBY 代码复制
  1. class Interpreter
  2.   # 用于在事件脚本中调用的初始化方法
  3.   def init_plugin_LockAttributes
  4.     $lock_LockAttributes = [false] * 12
  5.     $max_LockAttributes = 4 # 最多锁定 4 个属性
  6.   end
  7.   # 用于在事件脚本中调用的呼叫窗口方法
  8.   def call_mapmenu_LockAttributes
  9.     # 初始化
  10.     init_plugin_LockAttributes if !$lock_LockAttributes
  11.     # 插件开启
  12.     $plugin_LockAttributes_enable = true
  13.     # 记录上一个窗口位置,设置窗口位置
  14.     last_position_LockAttributes = $wmm_position.clone
  15.     $wmm_position = {1=>[-100, -100, 100, 100], 2=>[0, 320, 160, 160], 3=>[160, 320, 480, 160]}
  16.     # 设置窗口透明度,nil会调用默认透明度
  17.     $wmm_backopacity = nil
  18.     # 呼叫菜单,请设置此插件需要呼叫的主菜单
  19.     call_mapmenu('锁定属性')
  20.     # 插件关闭
  21.     $plugin_LockAttributes_enable = false
  22.     # 还原到上一个窗口位置
  23.     $wmm_position = last_position_LockAttributes
  24.     # 刷新地图
  25.     $game_map.need_refresh = true
  26.   end
  27. end


主菜单中调用子菜单的方法,在 run_right 中:
RUBY 代码复制
  1. alias _CreateActor_run_right run_right
  2.   def run_right(ary)
  3.     _CreateActor_run_right(ary)
  4.     if $plugin_CreateActor_enable
  5.       # -------------------------------------------------------
  6.       if ary[0] == "编辑角色"
  7.         Interpreter.new(0,true).call_mapmenu_LockAttributes
  8.       end      
  9.     end
  10.   end

其实就是新建一个Interpreter对象,因为呼叫菜单的方法定义在了 Interpreter 中。仅此一句,十分简单。

范例已上传
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *

Lv1.梦旅人

梦石
0
星屑
50
在线时间
21 小时
注册时间
2017-2-11
帖子
16
2
发表于 2017-2-23 07:16:21 | 只看该作者
板凳。。。。

点评

更完了>_<,谢谢关注!  发表于 2017-2-24 11:28
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (版主)

梦石
1
星屑
23963
在线时间
3338 小时
注册时间
2011-7-8
帖子
3925

开拓者

3
 楼主| 发表于 2017-2-24 02:05:41 手机端发表。 | 只看该作者
已经写完了。

角色的设定是可以随机改变6个基础属性(生命魔法力量灵巧速度魔力)的基本值和随等级的增量。不同的职业,基础属性值的随机范围也不一样。可以创造8个角色,然后从里面选出4个开始游戏。当然这些都可以改。

二级子菜单的功能用于锁定某些属性的值,在随机的时候不发生变化,一共12个值可以锁定其中的4个。

等我稍作修改,解决了存档冲突的问题后,就会把范例发上来。


【存档冲突】

rmxp坑爹的一个地方是,Game_Actor有一堆base_xxx属性,是直接读取$data_actors[@actor_id].parameters的内容。所以如果要设置基本属性的增量值,在不修改原来的脚本的情况下,就必须把数据存入到data/actors.rxdata里。

存数据不是问题,问题是data/actors.rxdata这个文件是全存档共享的,这将导致,如果新建好角色之后存档1,开始新游戏再次新建角色,重新修改存档1里使用的角色,读取存档1之后角色的数据会发生变化。

为了避免这种情况的发生,有如下解决方案:
1. 向隔壁学习,只有一个存档位置。因为需要自定义角色的游戏,大多是rougelike类的游戏,只有一个存档,死了重来是可以接受的。
2. 游戏一开始就必须选择一个存档继续,然后在每个存档里用不同的默认角色。比如第1个存档位,创造的角色是第1-8个,第2个存档位创造的角色是第11-18个。这样改起来方便。而且很多游戏就是游戏开始时要先指定存档位置的。
3. 每次创建角色成功的时候,把创建的角色clone一个,压到$data_actors的底部,所以不会修改到已经创建好的角色。优点是好改,缺点就是如果玩家不停的成功创建角色,data/actors.rxdata可能会很大。其实并不是一个大的问题,因为正常的玩家不会创建成千上万个角色……
4. 在玩家创建角色前读取所有的存档,跳过已经在存档里的角色ID,这样也能保证不会修改原来的角色。(刚刚想出来的,感觉最合逻辑)
5. 更多……

其实我就想到了这么多,感觉4是比较合适的。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
21 小时
注册时间
2017-2-11
帖子
16
4
发表于 2017-2-24 11:41:53 | 只看该作者
我居然不是板凳....

点评

沙发,板凳后面是什么……  发表于 2017-2-24 11:51
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
21 小时
注册时间
2017-2-11
帖子
16
5
发表于 2017-2-24 11:56:29 | 只看该作者
luliang 发表于 2017-2-24 11:41
我居然不是板凳....

宝马!!!!!!!!!!!!= =ll
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1343
在线时间
1295 小时
注册时间
2012-8-4
帖子
749
6
发表于 2017-3-19 16:48:26 | 只看该作者
这样很好看但是还是有不少bug的


如果能整理到scene上面就好了
类似下面这个没有整合完毕的脚本

Project1.zip

214.42 KB, 下载次数: 73

回复 支持 反对

使用道具 举报

Lv5.捕梦者 (版主)

梦石
1
星屑
23963
在线时间
3338 小时
注册时间
2011-7-8
帖子
3925

开拓者

7
 楼主| 发表于 2017-3-19 17:21:35 | 只看该作者
本帖最后由 guoxiaomi 于 2017-3-19 21:12 编辑
夜狠简单 发表于 2017-3-19 16:48
这样很好看但是还是有不少bug的


窗口,菜单系统的bug,还是这个角色创造界面的bug?

以及不做成scene是有以下考虑:每次离开和返回 Scene_Map 都会有一堆麻烦事,所以干脆就在地图上死循环,死循环里套死循环~



我看了看工程里面的代码,使用了 $scene = Scene_Call_mapmenu.new(*args) 来呼叫窗口。

如果调用多级菜单,就必须记忆上一次调用的参数,返回的时候要再次呼叫窗口,目前的这个半成品暂时还没有做这个处理。感觉这样做的话就和 VA 的 SceneManager 很像了。

我写这个的初衷,就是为了尽可能把逻辑做得简单,所以只有 Window 和loop do ... end 结构,其他的都不去涉及。

死循环里套死循环,把地图窗口菜单和游戏本体的运行完全隔离开来,而需要交互的时候,就退出地图菜单打开开关,调用公共事件。这是我的“简单”逻辑。
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1343
在线时间
1295 小时
注册时间
2012-8-4
帖子
749
8
发表于 2017-3-19 23:14:41 | 只看该作者
guoxiaomi 发表于 2017-3-19 17:21
窗口,菜单系统的bug,还是这个角色创造界面的bug?

以及不做成scene是有以下考虑:每次离开和返回 Scen ...


嗯,就像VX差不多。工程里面是临时写的,目的大概是一开始生成所有窗口,部分一开始可见一部分不可见。然后按下确认键某些窗口可见时刷新该窗口需要刷新的内容。在该窗口按下返回时该窗口的可见状态又关闭。这个系统不错,期待完善!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-30 00:22

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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