本帖最后由 SailCat 于 2022-2-27 08:40 编辑
@spriteset.actor_sprites #队伍的角色精灵
@spriteset.actor_sprites.battler #队伍的战斗者
首先更正一下,这样做可不行,因为@actor_sprite没有暴露给外面,要么用反射去取,要么自己定义actor_sprites方法或者attr_reader
内部的脚本我也琢磨的差不多了,当初写SEP core的时候真的是把每一个类(包括RPG模块的内部类)掰下来看,我的心得是,看一个类需要看它的父类,但是不需要看它的子类
首先sprite_battler里面给battler传的是nil这也没什么问题,nil的战斗者没有图像,透明度就是默认的0,而0透明度是不会执行任何效果操作的
默认的Spriteset_Battle中对于同伴战斗者是锁死了4个人,但对于敌方战斗者实际上是用循环插入的,不到8人计为实际人数,超过8人的扩展也很方便,直接对Game_Troop动刀子就可以了
为什么锁死,首先编辑器里方方面面都不允许你超过4个人,其次战斗中有战斗解释器,允许你替换队员(这里主要是指加入)如果不锁死4个,而是像敌方那样用循环插入,不改解释器就没法实现战斗中加入新队员
如果要实现3人制战斗,自主换人战斗,5人制战斗,人数没有上限的战斗,就并不是只改那个连续4行的Sprite_Battler.new(...)就可以了的,需要连锁修改很多东西。若没有修改好,那是会有bug。
至于Game_Battler,那就是个数据栏,没有任何画面表现的部分,只是为屏幕上的内容提供画面表现所需的数据,和Game_Screen性质一样。
这两个类都是可以存到存档里的,而众所周知Bitmap类和Sprite类是没法dump的。因此一个简单的结论就是Game_XX并不会包含画面表现。
SEP的战斗类扩展插件中分成了“战斗静态增强”和“战斗动态增强”两个部分,分野就是凡是对Game_Battler及其衍申类(Game_Actor, Game_Enemy, Game_Party, Game_Troop, Game_Actors, Game_BattleAction)的都是静态增强,动态增强则必须要去动Sprite_Battler和Spriteset_Battle
所以静态类增强插件中也可能包括一些大幅度修改Scene_Battle的内容,比如攻击范围拓展,几乎重写了这个类里涉及phase3的所有部分,但因为这过程中没有对战斗者精灵做任何处理,所以依然算成静态增强。
再说一下继承的事情
Game_Battler是一个基本类,但这个类不在战斗中实际使用,实际使用的都是Game_Actor和Game_Enemy,你对战斗中的任何一个战斗者调用is_a?(Game_Actor)和is_a?(Game_Enemy)总会有一个返回true
如果说后作的话,像VA更是只定了一个纯接口,连处理功能都欠的Game_BattlerBase(其实我并不知道这样做的意义是什么)
而这种设计的好处,就是你可以将那些公共的处理放在Game_Battler里面,只把很少数的敌我有区分的处理拿出来放到两个继承类当中
贴一段这两天弄的自动状态(XP特有功能)的代码
#-------------------------------------------------------------------------- # ● 获取额外状态(非附身但有效) #-------------------------------------------------------------------------- def extra_states # 自身来源特性数据的自动状态 set = features(feature_list(true), [], :auto_state_set) # 自身习得特技的自动状态 set.concat(feature(learned_skills, [], :auto_state_set)) # 自己的非排除性光环 set.concat(aura_states(0, 2)) # 本方其他人的光环 set.concat(feature(friends_unit.members - [self], []) {|battler| battler.aura_states(0, 1, 2, 3)}) # 本方全队的光环 set.concat(friends_unit.aura_states(0, 2)) # 对方战斗者作用于本方的光环 set.concat(feature(opponents_unit.members, []) {|battler| battler.aura_states(2, 3, 4)}) # 对方全队作用于本方的光环 set.concat(opponents_unit.aura_states(2, 4)) # 地图生效的光环(继承对象定义该方法) set.concat(active_map_auras) # 开关生效的光环(继承对象定义该方法) set.concat(active_switch_auras) # 数据单项化,排除无效数据 set.uniq! set.reject! {|i| $data_states[i].nil?} # 连锁 [+] 状态的处理 loop do last_size = set.size set = set.inject(set) {|a, i| a | $data_states[i].plus_state_set} break if last_size == set.size end # 排除 HP 0 的状态后返回 set.reject {|i| $data_states[i].zero_hp} end
#--------------------------------------------------------------------------
# ● 获取额外状态(非附身但有效)
#--------------------------------------------------------------------------
def extra_states
# 自身来源特性数据的自动状态
set = features(feature_list(true), [], :auto_state_set)
# 自身习得特技的自动状态
set.concat(feature(learned_skills, [], :auto_state_set))
# 自己的非排除性光环
set.concat(aura_states(0, 2))
# 本方其他人的光环
set.concat(feature(friends_unit.members - [self], []) {|battler|
battler.aura_states(0, 1, 2, 3)})
# 本方全队的光环
set.concat(friends_unit.aura_states(0, 2))
# 对方战斗者作用于本方的光环
set.concat(feature(opponents_unit.members, []) {|battler|
battler.aura_states(2, 3, 4)})
# 对方全队作用于本方的光环
set.concat(opponents_unit.aura_states(2, 4))
# 地图生效的光环(继承对象定义该方法)
set.concat(active_map_auras)
# 开关生效的光环(继承对象定义该方法)
set.concat(active_switch_auras)
# 数据单项化,排除无效数据
set.uniq!
set.reject! {|i| $data_states[i].nil?}
# 连锁 [+] 状态的处理
loop do
last_size = set.size
set = set.inject(set) {|a, i| a | $data_states[i].plus_state_set}
break if last_size == set.size
end
# 排除 HP 0 的状态后返回
set.reject {|i| $data_states[i].zero_hp}
end
这段代码写在Game_Battler当中,在Game_Actor和Game_Enemy中根本就不再重定义,直接调就完了。但是对于自动状态中,地图和开关生效的效果我方和敌方的判定确实是有区别的,那把这两块切出来定义到Game_Actor和Game_Enemy里面就完事了。
但这样做确实是会存在一个问题,我的注释里写了“继承对象定义该方法”,表明在父类中这是一个虚方法(C#叫abstract关键字)但实际使用的对象肯定定义了,那就意味着如果你再从Game_Battler分支出其他类,也必须定义这个方法,否则父类这个方法运行会报NoMethodError
所以VA的Game_BattlerBase的意义,其实就是把这些虚方法全部都写了默认接口,让它返回一个东西,以免报错。但如果确有必要,我在XP中,搁Game_Battler里写也可以。
最后说一说Game_Battler还能扩展什么,其实很简单
Game_Actor:数据源是RPG::Actor,阵营属于我方,接受Game_Party的控制
Game_Enemy:数据源是RPG::Enemy,阵营属于敌方,接受Game_Troop的控制
然后你顺着这个思路下去:
召唤兽系统:Game_Summon:数据源是RPG::Actor,阵营属于我方,不接受Game_Party的控制,自主行动
宠物系统:Game_Pet: 数据源是RPG::Enemy,阵营属于我方,接受Game_Party的控制
被囚禁带到战场上的队员:Game_Prisoner:数据源是RPG::Actor,阵营属于敌方,接受Game_Troop的控制(你可以给他加行动限制等)
养成怪系统:Game_Minion:数据源是RPG::Class,阵营属于我方,接受Game_Party的控制
器魂系统:Game_Soul:数据源是RPG::Weapon/RPG::Armor,阵营属于你随便吧…… |