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

Project1

 找回密码
 注册会员
搜索

[已解决]【步骤1】准备行动update_phase4_step1,理解问题请教!

查看数: 4237 | 评论数: 9 | 收藏 0
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2019-5-26 20:07

正文摘要:

本帖最后由 miantouchi 于 2019-6-1 10:59 编辑 最近在研究Scene_Battle机制,遇到点问题,请教下,首先是看了RB的文字教程,并且这个脚本也有汉字的注释了,有些地方是道理性质的通过明白, 但是代码的实质指向 ...

回复

miantouchi 发表于 2019-5-30 21:34:09
本帖最后由 miantouchi 于 2019-10-16 22:11 编辑

思考了2天,刚刚有点头绪,赶紧发下。不对的对方,希望指正,我根据这些日子大家论坛的讲解指点,用流程彻底分析了下战斗界面流程以下。暂时今天写这么多,再修正,终于可以睡个好觉了
第一部分:敌方攻击导致我方致死情况

4-1很快过去

4-2
敌方攻击我方,计算出伤害值172.
此时:隐藏:false,死亡:false,伤害:172,战斗伤害标志:false
接着刷新@spriteset.update

此时:隐藏:false,死亡:true,伤害:172,战斗伤害标志:false

4-3敌方白闪攻击动画ID=0
此时赋值 @phase4_step = 4
@spriteset.update-------Sprite_Battler-update
因为@battler_visible =true,所以执行下面的
        # 白色闪烁 whiten后,设置@battler.white_flash = false
        此时:隐藏:false,死亡:true,伤害:172,战斗伤害标志:false
update_phase4-----------case @phase4_step-------- update_phase4_step4进入第四步
4-4我方被攻击动画
首先,赋值给 对象方动画id和命中
target.animation_id = @animation2_id
target.animation_hit = (target.damage != "Miss")
接着刷新@spriteset.update
因为@battler_visible =true,所以执行下面的
# 动画,因为此时动画ID = @animation2_id,有值
所以播放被攻击动画,播放后,把对像方动画id归0
此时:隐藏:false,死亡:true,伤害:172,战斗伤害标志:false

4-5我方被攻击显示数值字体。
此时因为第2步有伤害值172,!=nil
所以target.damage_pop = true把伤害标志变成true
接着刷新@spriteset.update
因为@battler_visible =true,所以执行下面的
#伤害因为此时damage_pop = true
所以播放damage动画,
damage设置nil,damage_pops和critical设置为false

接下来
死亡判断动画处(伤害值刚刚被设置为nil,并且已经死亡)此时成立
if @battler.damage == nil and @battler.dead?
播放collapse死亡消失动画。
最后设置@battler_visible = false

此时:隐藏:false,死亡:true,伤害:nil,战斗伤害标志:false

第二部分:接下来我方用技能复活阵亡的队员
4-1很快过去了
此时:隐藏:false,死亡:true,伤害:nil,战斗伤害标志:false
@battler_visible = false
4-2
我方使用复活技能复活队友,计算出恢复值-541.
此时:隐藏:false,死亡:false,伤害:-541.,战斗伤害标志:false
      @battler_visible = false
接着刷新@spriteset.update,等着因为上面都不成立,结果什么都没干

4-3
行动方(我方)动画不等于0,@animation1_id != 0
@active_battler.animation_id = @animation1_id
@active_battler.animation_hit = true
接着刷新@spriteset.update
此时:隐藏:false,死亡:false,伤害:-541.,战斗伤害标志:false
      @battler_visible = false
所以,这一步什么都没做

4-4
首先,赋值给 对象方(死亡队员)动画id和命中
target.animation_id = @animation2_id
target.animation_hit = (target.damage != "Miss")
接着刷新@spriteset.update

此时:隐藏:false,死亡:false,伤害:-541.,战斗伤害标志:false
      @battler_visible = false
所以,这一步什么都没做

4-5
此时因为第2步有恢复值-541,不等于空!=nil
所以damage_pop = true把伤害标志变成true(执行关键)
接着刷新@spriteset.update

此时:隐藏:false,死亡:false,伤害:-541.,战斗伤害标志:true
      @battler_visible = false
所以执行下面的:这一步当中,appear,animation,damage都成立了
接下来update这三个动画次数

第三部分,为什么去掉@battler.damage == nil or @battler.damage_pop会发生,战斗图先出现,施法和复活、伤害值动画后出来。

4-2运行之前:隐藏:false,死亡:true,伤害:nil.,战斗伤害标志:false
                   @battler_visible = false
4-2开始
我方使用复活技能复活队友,死亡变成false,血量恢复506不为空
此时:@battler_visible = false直接成立了
      隐藏:false,死亡:false,伤害:-506.,战斗伤害标志:false

接着刷新@spriteset.update,

因为只判断这两项,隐藏:false,死亡:false。appear人物出现了,鬼畜了
此时:@battler_visible = true

4-3开始
因为:@battler_visible = true
      隐藏:false,死亡:false,伤害:-506.,战斗伤害标志:false
      动画ID不等于nil
      显示我方施法动画(反复update)
4-4开始
因为:@battler_visible = true
      隐藏:false,死亡:false,伤害:-506.,战斗伤害标志:false
      动画ID不等于nil
      显示复活动画(反复update)
4-5开始(打开伤害开关)
因为:@battler_visible = true
      隐藏:false,死亡:false,伤害:-506.,战斗伤害标志:true
      显示恢复血量值(反复update)
所以造成,人物出现-施法动画-复活动画(被复活)-显示恢复血量

第四部分,我方人员中毒情况。
4-1这步
if @active_battler.hp > 0 and @active_battler.slip_damage?
      @active_battler.slip_damage_effect
      @active_battler.damage_pop = true
end
连续伤害判断成立。上面判断成立
4-1结束
接着刷新@spriteset.update
此时:隐藏:false,死亡:false,伤害:400(中毒扣的血量).,战斗伤害标志:true
      @battler_visible = true
下面判断成立
if @battler.damage_pop
        damage(@battler.damage, @battler.critical)
        @battler.damage = nil
        @battler.critical = false
        @battler.damage_pop = false
end
反复刷新damage动画,刷新完成后进入4-2
此时:隐藏:false,死亡:false,伤害:nil.,战斗伤害标志:false
所以4-1刷新部分就进行扣血了。
RyanBern 发表于 2019-5-29 19:30:35
miantouchi 发表于 2019-5-29 16:38
感谢RB的详细解答,看了你的分析后,我就加了些打印控制台,观察下战斗界面的运行流程。
第一:Step 5: ...

1. 进入战斗场景瞬间所有角色都要先出现一遍,这个不算在内。我们讨论的是一个角色被打死之后再复活,被打死之后 @battler_visible 是 false
2. 都包括,看相应源码定义。
3. 其实也没多长
RUBY 代码复制
  1. def appear
  2.       self.blend_type = 0
  3.       self.color.set(0, 0, 0, 0)
  4.       self.opacity = 0
  5.       @_appear_duration = 16
  6.       @_whiten_duration = 0
  7.       @_escape_duration = 0
  8.       @_collapse_duration = 0
  9.     end

这些全都只是定义一些数,并没有真正执行操作。真正执行操作的地方:
RUBY 代码复制
  1. def update
  2.       super
  3.       if @_whiten_duration > 0
  4.         @_whiten_duration -= 1
  5.         self.color.alpha = 128 - (16 - @_whiten_duration) * 10
  6.       end
  7.       if @_appear_duration > 0
  8.         @_appear_duration -= 1
  9.         self.opacity = (16 - @_appear_duration) * 16
  10.       end

根据预设的补间动画长度来修改不透明度。但是因为写在 update 中,每一帧只会 update 一次,完成这个动作要 16 帧。

点评

另外,每一帧只会 update 一次,完成这个动作要 16 帧,确实我数了下。 appera、闪烁、animation16次,@wait_count=8次,damage循环40次,伤害数字,死亡48次  发表于 2019-5-30 21:38
根据你的指点,这两天我详细的看了下整个战斗机制流程,确实你说的是对的,4-5appear,animation,damage进行了一系列设置复活队友。另外  发表于 2019-5-30 21:36
RyanBern 发表于 2019-5-29 14:00:54
本帖最后由 RyanBern 于 2019-5-29 14:18 编辑

来插一脚动画和人物出现顺序问题的说明。有关谁先谁后,我这边的结论是:人物淡入,动画显示,伤害显示这三者是同时出现的。这个是针对我方有人阵亡然后使用复活技能/物品的动画特效,一般的挨打特效不算在内。

因此楼主和菜刀的理解都是有点问题的。


下面代码是出现的判定
RUBY 代码复制
  1. unless @battler_visible
  2.       # 出现
  3.       if not @battler.hidden and not @battler.dead? and
  4.          (@battler.damage == nil or @battler.damage_pop)
  5.         appear
  6.         @battler_visible = true
  7.       end
  8. end

它判断的条件是:在 @battler_visible 为 false 的条件下,如果角色没有隐藏,没有阵亡,目前无伤害/正要显示伤害时,战斗图会出现。在这里比较有意思的是它并不是像菜刀所说“没有伤害要显示时”,而是“正要显示伤害时”。因此得到结论:阵亡队友出现和伤害显示是同时发生的。

至于为什么复活动画也会同时发生,这是因为 Sprite_Battler 里的判定:
RUBY 代码复制
  1. if @battler_visible
  2.       if @battler.animation_id != 0
  3.         animation = $data_animations[@battler.animation_id]
  4.         animation(animation, @battler.animation_hit)
  5.         @battler.animation_id = 0
  6.       end
  7.       # 这块开始显示伤害数值
  8.       if @battler.damage_pop
  9.         damage(@battler.damage, @battler.critical)
  10.         @battler.damage = nil
  11.         @battler.critical = false
  12.         @battler.damage_pop = false
  13.       end
  14.       # 其他刷新 ...
  15. end

只有 @battler_visible = true 时它才会去管动画的显示,否则就算你修改了 animation_id,这些判断也不会执行。
回顾一下 Scene_Battle 的第四阶段(phase 4),它有六个步骤:
Step 1:准备行动(公共事件,强制行为,中毒扣血,自然解除状态)
Step 2:开始行动(应用行动效果,消耗 SP,计算伤害,扣血)
Step 3:设置攻击方动画
Step 4:设置对象方动画
Step 5:设置显示伤害
Step 6:其他刷新

在这里我特别加上了设置二字,来表示在 Scene_Battle 里只是进行了某种设置,而真正执行与否要看 Sprite_Battler 对其的响应。为了说明角色出现,动画播放,伤害显示是在同一时间执行的,我们可以依次过一遍 phase 4 的六个步骤,看看里面究竟有哪些细节。
Step 1:准备行动。此时被复活方还处于 hp = 0 的状态,战斗图不显示(@battler_visible 为 false)
Step 2:开始行动。我方成员使用技能,此时回复量已经计算,角色被复活,但由于 damage 不是 nil 且 damage_pop 为 false,@battler_visible 仍旧为 false
Step 3:设置攻击方动画。这个正常显示。
Step 4:设置对象方动画。对象方 animation_id 被设置,但没有被播放。原因是 @battler_visible 为 false,导致 Sprite_Battler 不会去检测(见前面代码)
Step 5:设置显示伤害。对象方 damage_pop 设置为 true。按照 @battler_visible 修改的判定,只要角色没隐藏,没阵亡,并且有伤害要显示,它就会被设置为 true。一旦 @battler_visible 设置为 true,后面对动画和伤害显示的判定统统生效。因此在 Step 5 会同时发生:角色出现,动画显示,伤害显示。
Step 6:略


楼主的误区在于:没有分清哪些地方是设置,哪些地方是真正执行。在上面分析的 Step 5 中,它有几个关键的语句:appear,animation,damage,这些方法来自于父类 RPG::Sprite,楼主可以在 F1 中查看这个类的定义,你会发现 appear,animation,damage 所做的操作还是进行一系列设置!,而并非像楼主理解的:执行完 appear 一句之后,角色就已经出现了。
菜刀的误区在于:Step 4 虽然在 Step 5 前,但由于 @battler_visible 这个变量影响了 Step 4 的效果,导致 Step 4 的最终效果会延迟到 Step 5 才会执行。

点评

你说的step 5,@battler_visible 才变成true,我下午测试了下怎么感觉,一开始就是true了。  发表于 2019-5-29 16:39
没错, 复活的时候是一起发生的, 平时才是先播动画再显示伤害, 由于我的复活是让倒地的角色爬起来不是淡入, 所以我改动过了XD  发表于 2019-5-29 14:35
灯笼菜刀王 发表于 2019-5-28 00:01:33
本帖最后由 灯笼菜刀王 于 2019-5-28 00:07 编辑

  这就是XP默认的伤害显示调用方法 battler.damage != nil 且 battler.damage_pop == true

battler.damage 可以是数字,也可以是字符串, 它只是把伤害显示出来, 并没有实际扣血, 扣血操作是另外处理的,  到此,如果你能理解的话, 之前你一直无法想通的那个操作"复活的时候先播放玩动画再爬起来", 现在知道原因了没?

也可以通过让NPC运行这段脚本,.来让伤害显示在地图(scene map)上出现

$a = RPG::Sprite.new
$a.x,$a.y = 320,240
$a.damage("天下无敌",true)

不过, 直接运行这段脚本, 伤害显示是不动的, 因为没刷新, 和以前一样做法, 把 $a 拿到 scene map 里去刷新它, 就能看到完整的伤害展示了

然后,你说找不到scnene battler里的刷新?  以前不是了解过了, Sprite battler 是被 Spriteset battle 调用的,而 Spriteset battle 的实例被塞到 @spriteset 这个实变量里了, 它在哪里刷新, 自己搜索下咯

你可以 p @active_battler.index  看看它是什么, 它的定义在 game actor 和 game enemy 里,
角色不用管, 这句话主要是针对敌人的, 当战斗中断的时候(就像米兄说的,计时器导致战斗结束,事件结束战斗等原因), 敌人队伍清空, 这个时候敌人的index就会返回nil, 就此中断不再继续, 避免下面的hp无法操作而出错

----------------------
综合考试:
因为行走图(Sprite_Character)和战斗图(Sprite_Battler)是同一个爹, 所以它们的方法是可以共享的, 尝试改造下Sprite_Character, 让行走图也可以通过 damage_pop 来显示伤害吧


提示: 看它们update里的"#动画",对比下两者的不同点和相同点, 然后依样画葫芦试试

点评

我在楼下发了你留下来的题目,你是在NPC里面加了脚本变量吗?看看我做的,其实我做出来也不是太明白,报蒙做的。  发表于 2019-5-31 16:32
你留的综合考试,是主角走到NPC旁边按确定,主角身上出现9999这个伤害吗?  发表于 2019-5-31 16:07
测了几把游戏战斗流程,1处果然是状态太伤害数值显示,5处是普通攻击和技能显示的数值。  发表于 2019-5-28 16:29
本来想都给以下都解决了,但是发现研究了半天,第一个问题还是没有通过。楼下发了我分析的思路,但是找不出问题。  发表于 2019-5-28 13:36
miantouchi 发表于 2019-5-27 20:14:43
本帖最后由 miantouchi 于 2019-5-27 20:37 编辑
灯笼菜刀王 发表于 2019-5-26 22:33
1, 强制行动, 事件设置的, 具体去看"RMXP入门",不改造脚本的情况下要制作一些特殊战斗效果, 一般就是用它来 ...


今天头疼了一天,吃点药继续克。

1。今天从战斗事件里面找到了,简单体会了下
2.强制行动(立即行动的情况下),会让强制行动人员,在本轮第一个出手。
3,大概理解了就是,我方和敌方人员按速度从大到小排序存放在数组当中,然后依次通过shift方法取出前面的人,依次进行连续伤害、自然解除状态、刷新状态窗口,直到数组size为0,就进行下一回合。
4.(1)你说的搜索  def slip_damage_effect 这句, 这里有操作伤害(即@active_battler.damage != nil)是不是意思,执行def slip_damage_effect这个方法,就能证明是有伤害的,因为这个方法就是计算伤害值的。
   (2)Sprite_battler 的 update 是在什么时候调用的什么地方调用这个update刷新的,我怎么找不到?

最后一个作业,测试下了,用完技能,我方第一个人员会出现“天下无敌”字样。
a.damage_pop = false,就不会显示了,证明damage_pop是你上面说的显示开关,
例子中用于在我方人员身上显示,天下无敌的开关。

所以
# 连续伤害
    if @active_battler.hp > 0 and @active_battler.slip_damage?
      @active_battler.slip_damage_effect
      @active_battler.damage_pop = true
    end
这段代码,就是获取当前行动者如果HP>0并且这个行动者有连续伤害
那么计算slip_damage_effect伤害值,把这个人员身上的伤害的显示开关打开。

另外,最后一个问题。
@active_battler = @action_battlers.shift
    # 如果已经在战斗之外的情况下
    if @active_battler.index == nil
      return
    end

战斗之外的情况下是什么情况,比如我方和敌方攻击6人,我方4人、敌方2人,6个人开始都是未行动人员,挨个就行伤害处理了。
@active_battler.index == nil是啥情况?





点评

上面已经注释了“在战斗之外的情况下”,比如因为计时器导致战斗提前结束  发表于 2019-5-27 22:16
灯笼菜刀王 发表于 2019-5-26 22:33:43
本帖最后由 灯笼菜刀王 于 2019-5-26 22:59 编辑

1, 强制行动, 事件设置的, 具体去看"RMXP入门",不改造脚本的情况下要制作一些特殊战斗效果, 一般就是用它来实现

2, 强制行动(立即行动的情况下)会怎么表现, 了解了自然就能理解, 为什么这里要把行动者抽出来加到数组最前面

3, 你搜索@action_battlers, 可以看到在前面的步骤里, 把角色和敌人根据行动速度保存到这里

@active_battler = @action_battlers.shift   这句就是获得当前行动对象, 具体原理, 搜索F1, array 的 shift 方法, 结合上面的 @action_battlers 保存的内容去理解下, 然后下面的size == 0 就能理解了

@action_battlers.size == 0 就是 @action_battlers 的数组空了, 也就是所有角色和敌人都已经行动过了, 如果还没分出胜负, 就回到步骤3(角色操作指令)重头开始

4,  搜索  def slip_damage_effect 这句, 这里有操作伤害(即@active_battler.damage != nil), 而 damage_pop 就是伤害显示开关, 它的作用在 Sprite_battler 的 update 里体现, 用来让伤害的数字显示出来

这里显示的是异常状态的伤害, 也就是中毒的伤害, 同时,异常状态的持续回合数也在这里扣

这个步骤是确定好行动者, 初始化一些战斗用的临时变量, 并对行动者的异常状态进行操作

-------------------------------------------------------------
动手做作业:  
1, 随便找个技能, 让它关联一个公共事件

2, 公共事件内容,


3,战斗测试, 使用这个技能, 看效果





点评

继续分析,楼下回复了  发表于 2019-5-27 20:15
拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

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

GMT+8, 2024-11-23 08:44

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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