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

Project1

 找回密码
 注册会员
搜索
楼主: 禾西
打印 上一主题 下一主题

解读默认战斗系统脚本

 关闭 [复制链接]

Lv2.观梦者

梦石
0
星屑
908
在线时间
212 小时
注册时间
2006-10-8
帖子
293
11
发表于 2008-3-3 16:22:53 | 只看该作者
re:主题:《解读默认战斗系统脚本(Scene_Battle 2部分)》
我强烈支持!
分析得好透彻
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
82 小时
注册时间
2006-1-28
帖子
996
12
发表于 2008-3-4 16:12:11 | 只看该作者
re:主题:《解读默认战斗系统脚本(Scene_Battle 2部分)》
收下来研究了,谢谢LZ
回复 支持 反对

使用道具 举报

Lv3.寻梦者 (暗夜天使)

精灵族の天使

梦石
0
星屑
1697
在线时间
3038 小时
注册时间
2007-3-16
帖子
33731

开拓者贵宾

13
发表于 2008-3-4 21:49:26 | 只看该作者
re:主题:《解读默认战斗系统脚本(Scene_Battle 2部分)》 [LINE]1,#dddddd[/LINE]很多东西的语法都很明了。
.index类初始化都是-1,我方逃跑的时候占用了整个回合数(这很明显)。另外,为-1的话就不会显示光标(这个方法在选择类很常用)
其实小数点这个使用很广泛,一个是调用函数,带回返回值。
一个是调用某个类里面的某个变量。
执行.new其实就是
执行这个Scene类的installize函数。
如果有main函数的话,执行main函数在这里定义:
在main函数里面有一句
  while $scene != nil
    $scene.main
  end
就是执行的他。
Scene类调用的window类都是在各自的窗口下进行的。
xxx=window_xxx.new(按照window类里面的描述建立一个窗口)
xxx.active = true/false 这个窗口活动/不活动(不活动的话,光标无法对准焦点)
xxx.visible = true/false 窗口可见/不可见(不可见的话会自动消失)
xxx.x,xxx.y,xxx.z坐标
xxx.contents.opabity 透明度
xxx.font.size/color 字体颜色/大小
xxx.back_opaticy 背景透明度
xxx.skin = 窗口的界面,默认为系统
xxx.dispose窗口整个释放,不可再调用
一次建立整个窗口/释放整个窗口有利于系统的运行,不容易出错。
回复 支持 反对

使用道具 举报

Lv3.寻梦者

酱油的

梦石
0
星屑
1020
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

14
 楼主| 发表于 2008-3-4 21:55:16 | 只看该作者
re:主题:《解读默认战斗系统脚本(Scene_Battle 2部分)》
以下引用精灵使者于2008-3-4 13:49:26的发言:

很多东西的语法都很明了。
.index类初始化都是-1,我方逃跑的时候占用了整个回合数(这很明显)。另外,为-1的话就不会显示光标(这个方法在选择类很常用)
其实小数点这个使用很广泛,一个是调用函数,带回返回值。
一个是调用某个类里面的某个变量。
执行.new其实就是
执行这个Scene类的installize函数。
如果有main函数的话,执行main函数在这里定义:
在main函数里面有一句
while $scene != nil
   $scene.main
end
就是执行的他。

不知道精靈是針對哪段的評價,禾西看得一頭霧水……
禾西自然知道.new的用法和main方法調用等等。!=o=a
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

Lv3.寻梦者 (暗夜天使)

精灵族の天使

梦石
0
星屑
1697
在线时间
3038 小时
注册时间
2007-3-16
帖子
33731

开拓者贵宾

15
发表于 2008-3-4 21:59:55 | 只看该作者
re:主题:《解读默认战斗系统脚本(Scene_Battle 2部分)》 [LINE]1,#dddddd[/LINE]好像是整个脚本的评价。
有些不懂的地方我想要讲一下。例如你跳过去的index = -1等。
还有一些就是对于Scene的窗口控制部分的解释。
据说,如果临时生成窗口或者销毁窗口的话,会引起系统不稳定(我的游戏里就碰到了)
还有,小数点的用法值得商榷。
那个除了是方法调用变量之外,还可以调用函数(引用值),取得返回值。
这个就在前面的类中定义
class A
def a(b)
c = b
return c
end
end
class B
p A.a(D)
END
这样会取得返回值D。
另外new好像是一个内部量,隐含的要执行 installize函数……(ruby内定义)
p.s.顺手合并两贴。
回复 支持 反对

使用道具 举报

Lv3.寻梦者

酱油的

梦石
0
星屑
1020
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

16
 楼主| 发表于 2008-3-3 13:51:01 | 只看该作者
本帖最后由 后知后觉 于 2009-12-29 16:14 编辑

主题:《解读默认战斗系统脚本(Scene_Battle 2部分)》 原帖
文章太长,上一贴写不下。而且沙发被人抢了,所以只好发第二贴。
如果管理员看到的话,最好把两贴合并。

上文提要:

5.进行战斗
    # 回合分支
    case @phase
    when 1  # 自由战斗回合
      update_phase1
    when 2  # 同伴命令回合
      update_phase2
    when 3  # 角色命令回合
      update_phase3
    when 4  # 主回合
      update_phase4
    when 5  # 战斗结束回合
      update_phase5
    end

完毕!
具体参照原帖地址:
解读默认战斗系统脚本(Scene_Battle 1部分)
================================================================================

接下来要说的是「回合分枝」这部分的内容,应该是最多人感到有兴趣的地方,也是战斗画面脚本最重要的地方。从Scene_Battle 2一直写到Scene_Battle 4,用了3页。

那么,首先还是全局了解一下内容:

1.首先我们要理解这个:

    # 回合分支
    case @phase
    when 1  # 自由战斗回合-(实际是「敌人出现」和「战斗事件设置」的回合)
      update_phase1
    when 2  # 同伴命令回合-(实际是「战」或「逃」的选择回合)
      update_phase2
    when 3  # 角色命令回合-(实际是选择「战斗行动」的回合)
      update_phase3
    when 4  # 主回合-(真正的战斗开始)
      update_phase4
    when 5  # 战斗结束回合-(结束战斗)
      update_phase5
    end

上面说了,当@phase等于哪个,就update哪个回合。

2.整体行动步骤表意
         start_phase1(遇见敌人)
                  ┃
                  ┃  更新_phase1
                  ┆
     ┎┈  start_phase2(选择战斗或者逃跑)
     ┃   ┃                    更新 phase2
     ┃返 ┃                case 指令窗口光标位置
     ┃回 ┃                ┃┆                ┃
     ┃   ┃                ┃┃(战)            ┃(逃)
     ┃战 ┃                ┆┃                ┆
     ┃或 ┃            start_phase3    update_phase2_escape
     ┃逃 ┃           (选择行动)             (进行逃跑判断)
     ┃   ┃                 ┃            ┃            ┃  
     ┃选 ┃ 更新 phase3     ┃            ┃(成功)      ┃(失败)
     ┃择 ┃                 ┆            ┆            ┃  
     ┃   ┃        phase3_next_actor   返回地图         ┃
     ┃   ┃                (下个角色)                   ┃
     ┃   ┃                 ┃                          ┃  
     ┃   ┃                 ┆                          ┃
     ┃   ┗━━━┈    start_phase4(主战斗)   ┈━━━━┛
     ┃                      ┃
     ┃     phase4回合结束   ┃更新 phase4
     ┗━━━━━━━━━━━┫
                             ┃if judge(判断为战斗结束) = true
                             ┆
                        start_phase5(结束战斗)
                             ┃
                             ┃update_phase5
                             ┆
                         返回地图

3.phase4的运作。
phase4(主战斗回合)也同样的有一个非常复杂的判断以及行动过程。里面也有的「回合」分枝:
  def update_phase4
    case @phase4_step
    when 1
      update_phase4_step1
    when 2
      update_phase4_step2
    when 3
      update_phase4_step3
    when 4
      update_phase4_step4
    when 5
      update_phase4_step5
    when 6
      update_phase4_step6
    end
  end

这个暂时知道一下运作原理,到时候回头看。

现在开始单独的行动回合解读:

(Scene_Battle 1完结,进入Scene_Battle 2)


1.phase1-「敌人出现」和「战斗事件设置」的回合
  def start_phase1
    # 转移到回合 1
    @phase = 1
    # 清除全体同伴的行动
    $game_party.clear_actions
    # 设置战斗事件
    setup_battle_event
  end

这里的语句不多,意义也只有简单的两点
01.清除全体同伴的行动($game_party.clear_actions)
这个……我也不明白为甚么要在这里清除全体同伴的行动。囧rz
战斗结束以后不清除,留在下一次战斗开始的时候清除。大概是作者在「战」或「逃」的选择窗口以外的另一个恶趣味吧……

02.设置战斗事件(setup_battle_event)
在战斗开始的瞬间启动无条件的战斗事件,比如一开始敌人的说话之类。

此外,禾西曾经遇过一个问题。就是:「怎么在战斗开始之前付予角色某个状态」
但是禾西的回答是在start_phase1这个方法下面添加脚本语句,但是最后答案选定为在main脚本22行以前(渐变发生以前)添加语句。
这里到底有甚么不一样呢?
不如我们做个实验

我们分别「main脚本22行以前」和「start_phase1以降」处添加两段语句。
01.main脚本22行以前
    $game_party.actors[0].add_state(1) # 角色1添加战斗不能的状态


02. start_phase1中
    $game_party.actors[1].add_state(1) if $game_party.actors[1] !=nil # 如果角色2存在就添加战斗不能的状态


结果我们看到,角色1从最初开始就「死掉了」。(战斗图没有显示)
而角色2就是在战斗开始的瞬间莫明其妙地也「死掉了」。(战斗图片从有变成无)

之所以造成这个效果,我们还是可以用「看戏」的比喻。在main的22行以前,舞台上布幕还没有拉开(所有的窗口都还没有生成),因此,这个时候所有的动作都是隐藏的,不可见的。除非我们走去后台(查看脚本),否则我们对现在发生的事情一无所知。而运行到55行,也就是真正调用start_phase1这个语句的时候,布幕已经被打开。所有的行动都是公开的且可见的(除非你用手段把它隐藏起来)。

因此,两者的差别就在于显示与不显示。当我们善用这个微少微少的差异,就可以有一些特别的效果哦!

而接下来,由于这里把@phase设为1,因此update当中会自动调用update_phase1的方法:
  def update_phase1
    # 胜败判定
    if judge
      # 胜利或者失败的情况下 : 过程结束
      return
    end
    # 开始同伴命令回合
    start_phase2
  end

这个语法没有任何作用。==凸,单单为了迎合其它phase(回合)的格式。
当中调用了两个方法:
01.如果judge = true,结束战斗
之所以会出现这个判断,大概是因为有某些人需要「一回合」的战斗。所谓的「一回合」战斗,就是指在开始的时候调用战斗事件,然后结束战斗(击败敌人或者被敌人击败)。这样的情况下,下面的语句就全部没有用途。因此这里有return把它结束掉。

02.start_phase2(开始「战」或「逃」的画面)
意义在于开始「战」或「逃」的选择。

提问区里面有不少人提到怎么去除「战」或「逃」的选择画面。有些人弄得很复杂,其实只要在这段脚本中的「2」改为「3」,脚本就在自动跳过「战」或「逃」的选择,直接开始选择「战斗行动」。不過,当我們按下Esc键的時候,依然会「战」或「逃」的选择。因此我们还要把
Scene_Battle 3
line:58
        # 开始同伴指令回合
        start_phase2

中2改3(当然说明最好也改一下)。
这样,「战」或「逃」的选择回合就永远离开我们了。






2.phase2-「战」或「逃」的选择回合
  def start_phase2

  end

这个回合生成了「战」或「逃」的选项。

不过说是生成也不太恰当。因为其实如果你还记得,这个「战」或「逃」的窗口早在main脚本的37行当中已经生成了(提醒一下,我们现其实在处main方法中的update解释语句当中,也就是63行的位置),不过当时这个窗口被隐藏了起来而已。

通过这个语句
    # 有效化同伴指令窗口
    # 「战」或「逃」的选择活动 = true
    @party_command_window.active = true
    # 「战」或「逃」的选择可视 = true
    @party_command_window.visible = true


马上就把「战」或「逃」的选择窗口显示出来,让我们看到「窗口」出现的假相。不过实际上,这个窗口一直都存在在我们的屏幕当中。


至于
    # 无效化角色指令窗口
    @actor_command_window.active = false
    @actor_command_window.visible = false

作用就是关闭角色的指令窗口。如果你还记得的话,我们在main底下的34行出现过同样的语句。这个窗口应该被关闭而且隐藏起来了才对啊!这里是不是对此一举呢?
答案是:否。
要解开这个问题,我们稍微偷步一下,跑到
Scene_Battle 3
line:58
这里出现了
        # 开始同伴指令回合
        start_phase2

这是甚么意思呢?
其实,这里是一个返回语法。根据上面的图示,在选择「战斗」以后,我们会进入选择战斗行动的选择回合。
但是,在这里我们可以「反悔」(逃跑则没有)。我们可以按下Esc键或者X键返回到「『战』或『逃』的选项画面」(也就是上面这个语句,在按下Esc后重新回到phase2)。但是,这里出现了一个问题。(预知:)因为在phase3(选择战斗行动)当中,角色的指令窗口会被打开。如果直接返回到phase2(「战」或「逃」的选择回合)没有重现隐藏,那么指令窗口就会仍然存在。

让我们再做个实验,直接去除
Scene_Battle 2
line:41
    # 无效化角色指令窗口
    @actor_command_window.active = false
    @actor_command_window.visible = false

然后测试战斗。

当我们选择了「战斗」以后再按下Esc,我们会发现新生成的指令窗口真的没有消失而是很无理头地显示在屏幕当中。
如果我们把删去的语法重新加回去,再次地测试一下。唔,这次好了。当我们反悔的时候,指令窗口消失了(其实是隐藏了)。一切又回到纯正的phase2界面,一点phase3出现过的痕迹都没有。

在下面,我们看到
    # 清除主回合标志
    $game_temp.battle_main_phase = false

这个语法的作用就如同注释一样,当我们处在「主战斗回合」的时候他就会为true,而不是的话就会为false
我知道这样说很废,作者这么无聊设置个这样的变量有什么用呢?
让我们全局收索
    $game_temp.battle_main_phase

我们发现一共有五个地方出现了他的身影。三个处在Scene_Battle当中为他赋值,另外两个是if分歧。我想我们找到需要的东西了。

查看两个if分歧,一个处在Sprite_Battler,另外一个处在Window_BattleStatus。
在Sprite_Battler
line:67
      # 不是主状态的时候稍稍降低点透明度
      if $game_temp.battle_main_phase
        self.opacity += 3 if self.opacity < 255
      else
        self.opacity -= 3 if self.opacity > 207
      end
    end

就如注释所说(迷音:又是「如注释所说」,要你干嘛!),设置这个变量(含有.字眼的其实是方法,但是方法可以当作变量。上面说过,还记得吧?)的目的是调节透明度。作用似乎是使得战斗画面更加美观一点|||。
想要测试实际效果的话就把当中的3改改为其他数字。在脚本Window_BattleStatus中也是一样语句,所以就不赘言了。

    # 清除全体同伴的行动
    $game_party.clear_actions

因为根据上面的表意图可以得知,结束phase4的回合后又会返回到phase2,所以清除全体同伴的行动。
phase2到phase4的关系:

    ┏┄  phase2
    ┃ 逃(失败)  战
    ┃  ┃      ┃
    ┃  ┆      ┆
    ┗ pahse4 <= phase3


不过要说不清除的话会发生甚么错误,这个我也不清楚。即使删除了也没有遇到甚么问题。知道的同学告诉一下。

    # 不能输入命令的情况下
    unless $game_party.inputable?
      # 开始主回合
      start_phase4
    end

这个判读是用在自动战斗的(中了某种状态而不受控制地战斗),当全体都不受控制时(unless $game_party.inputable?),会自动转跳phase4(主战斗回合)。

    # 设置角色为非选择状态
    @actor_index = -1
    @active_battler = nil

设置角色为非选择状态,但是其实下面会众多语句把角色设置为非选择状态。这里的作用基本上等于零==(不排除有某些我没有注意到的情况)。

    # 转移到回合 2
    @phase = 2

告诉update语法自动调用update_phase2,不用再说了吧?不明白的从头再看,最先位置写得很清楚了。


  def update_phase2
    # 按下 C 键的情况下
    if Input.trigger?(Input::C)
    end
  end

update_phase2只有一个判断语句,就是不断地监视我们C键盘,等待我们做出「战」或「逃」的选择。

当我们按下C键或者Space(空格),程序就会根据指令窗口光标停留的位置决定接下来的动作
      # 同伴指令窗口光标位置分支
      case @party_command_window.index
      when 0  # 战斗
      when 1  # 逃跑
      end
      return

这里使用了一个case语法,用法等于if。
以下两个句子是一样的。
  if a == 1
    p "a"
  elsif a == 2
    p "b"
  end
  case a
  when 1
    p "a"
  when 2
    p "b"
  end

当我们的光标(这里用index表示)停留在0(战斗)的位置
就会调用:

        # 演奏确定 SE
        $game_system.se_play($data_system.decision_se)
        # 开始角色的命令回合
        start_phase3

记得上面表意图中,phase2有两个分歧吗?现在我们就进入phase3(选择角色行动)的分歧

而另外,要是我们选择了「逃跑」,就会调用:
        # 不能逃跑的情况下
        if $game_temp.battle_can_escape == false
          # 演奏冻结 SE
          $game_system.se_play($data_system.buzzer_se)
          return
        end
        # 演奏确定 SE
        $game_system.se_play($data_system.decision_se)
        # 逃走处理
        update_phase2_escape

这里有一个分歧:
        if $game_temp.battle_can_escape == false
          return
        end

当我们的战斗是不可逃跑的,系统会播放禁止的音乐,然后结束方法。也就是说如果战斗是不可逃的,我们只能一定选择「战斗」才行。

如果这场战斗是可以逃跑的,我们不会直接逃跑。而会进入另一个phase2的分歧:update_phase2_escape
这个方法在下面可以遇到,作用是判断是否逃跑成功,以及进行相应的动作。
return

结束方法。我们不需要另外一个分歧。

  def update_phase2_escape
    # 逃跑成功判定
    success = rand(100) < 50 * actors_agi / enemies_agi

    # 成功逃跑的情况下
    if success

    else

    end
  end

上面说了,这里是「判断逃跑是否成功并作出相应的动作」的方法。

内部语句大致只有引用当中的两句。一句「success = rand(100) < 50 * actors_agi / enemies_agi」是用来算出是否成功的。
跟下面的句法相同:
    if rand(100) < (50 * actors_agi / enemies_agi)
      success = true
    else
      success = false
    end

当中的enemies_agi数值,是根据
line:89
    # 计算敌人速度的平均值
    enemies_agi = 0
    enemies_number = 0
    for enemy in $game_troop.enemies
      if enemy.exist?
        enemies_agi += enemy.agi
        enemies_number += 1
      end
    end
    if enemies_number > 0
      enemies_agi /= enemies_number
    end

算出的。
其中调用了初始化变量的方法:
    enemies_agi = 0 # 为enemies_agi 先赋值为 0
    enemies_number = 0 # 为enemies_number 先赋值为 0

因为后面使用到
        enemies_agi += enemy.agi
        enemies_number += 1

如果不初始化的话会出现NoMethodError「undefined methodfor Nil:NilClass」

    for enemy in $game_troop.enemies
      if enemy.exist?
        enemies_agi += enemy.agi
        enemies_number += 1
      end
    end

for ×× in ××
end
是一个循环语句,目的是取得敌人队伍中所有敌人的agi(速度)数值,然后全部加在enemies_agi 这个变量之上。
同时,enemies_number 是记录敌人的数量的变量。每当取得一个敌人的agi数值增加1。

之所以这样做,是因为

    # 如果敌人数量大於0
    if enemies_number > 0
      # 「总agi数值」除以「敌人数目」
      enemies_agi /= enemies_number
      # 求得敌人单体的平均速度
    end

如同注释。

这样子,我们就得到了敌人的平均速度。己方的平均速度用了同样的方法,所以就不说了。

当我们获得了enemies_agi(敌人单体平均速度)和actors_agi(己方角色平均速度)。然后我们就可以根据
success = rand(100) < 50 * actors_agi / enemies_agi

来计算成功与否。默认是用rand(100)(在0 ~ 99当中随机抽调「一」个数)来跟「50 * actors_agi / enemies_agi」的结果比较。
如果左边小於右边的话,就成功。

由这里可以知道,如果角色的平均速度是敌人的2倍以上的话,成功率是100%的(因为rand(100)最大也就是99而已)。

接下来,如果成功(if success)
      # 演奏逃跑 SE
      $game_system.se_play($data_system.escape_se)
      # 还原为战斗开始前的 BGM
      $game_system.bgm_play($game_temp.map_bgm)
      # 战斗结束
      battle_end(1)

重点讲一下battle_end(1)

我们一直有意地漠视这个语句(因为在这之前,一直没有太大的用途。)
现在调用到了。我们就查看一下里面有甚么东西。
Scene_Battle 1
line:136
  def battle_end(result)

  end

这个其实是战斗结束的语法。由于某个原因,而被人挪到Scene_Battle 1去(因为在Scene_Battle 1的line:295行有调用。用作中断战斗的后续行为。当时我们没有具体看。)

防止大家忘记了数字的意义,再次重申一下:
  #--------------------------------------------------------------------------
  # ● 战斗结束
  #     result : 結果 (0:胜利 1:失败 2:逃跑)
  #--------------------------------------------------------------------------
用作告诉事件战斗的结果,然后进行事件的分歧。

里面定义了一些东西,不过注释写得很清晰。所以勿用赘言

  def battle_end(result)
    # 清除战斗中标志
    $game_temp.in_battle = false
    # 清除全体同伴的行动
    $game_party.clear_actions
    # 解除战斗用状态
    for actor in $game_party.actors
      actor.remove_states_battle
    end
    # 清除敌人
    $game_troop.enemies.clear
    # 如果调用战斗返回调用不为nil
    if $game_temp.battle_proc != nil
      # 告诉程序战斗的结果
      $game_temp.battle_proc.call(result)
      # 清空战斗返回调用
      $game_temp.battle_proc = nil
    end
    # 返回到地图画面
    $scene = Scene_Map.new
  end

想说一下的是actor.remove_states_battle,调用的是Game_Battler 2,206行以降的remove_states_battle方法。里面定义了:

  def remove_states_battle
    for i in @states.clone
      if $data_states.battle_only
        remove_state(i)
      end
    end
  end

如果角色身上中了的状态是在战斗以后会自动解除的(在数据库-状态-解除条件当中设置),调用这个方法就会把该种状态解除掉。

    $scene = Scene_Map.new

开头忘记说:$scene = ×××.new 表示切换屏幕画面。
当$scene发生改变的时候,main 方法当中的loop do 循环会自动结束,然后释放(dispose)所有窗口。

OK,返回Scene_Battle 2的126行,继续刚才的话题。
如果逃跑失败。程序会清空全体角色的行动,然后开始phase4(主战斗回合)
      # 清除全体同伴的行动
      $game_party.clear_actions
      # 开始主回合
      start_phase4

这里全体同伴角色的行动都被清空,在这样的情况下开始phase4的话,我方角色是不会有任何动作的。但是敌方会,因为敌人的行动是在phase4当中start_phase4里设置的。这样子,我方队员只有挨打的份。
如果希望在逃跑失败的时候添加对话,比如说逃跑,我们可以在这里(start_phase4以前)添加一个语句:
      @help_window.set_text("逃走失败", 1)
      @help_window.visible = true
      @wait_count = 20
      if @wait_count == 0
        @help_window.visible = false
      end

这样子我们就会看到逃跑失败的时候,画面上出现「逃跑失败」的字眼了。每一 @wait_count 好像等于 1/40秒,具体上有差异,可以调到自己喜欢时长。

phase2的解说就到此为止

(注:phase3和phase4的语句都没有出现在Scene_Battle 2当中,但是这里顺带讲一下)
3.phase3-选择战斗动作的回合
这个回合是选择行动类型的回合。画面上会生成指令窗口,然后选择「攻击,技能,物品」等指令,然后选择敌人,开始战斗。
具体因为非常复杂。这里只要假象一下有一个类似这样的语句

  def start_phase3
    # 转移到回合 3
    @phase = 3
  end
  def update_phase3
    # 开始主回合
    start_phase4
  end

就可以了。我们下一帖再说。

4.phase4-主战斗的回合
这个是战斗的主要回合。复杂程度超乎平常。我们将来会花费新一贴的来讲解。
这里幻想一下出现了这样的语句:

  def start_phase4
    # 转移到回合 4
    @phase = 4
  end
  def update_phase4
    if judge # 如果不需要继续战斗
      # 结束战斗
      start_phase5
    else # 如果需要继续战斗
      # 返回「战」或「逃」的选择
      start_phase2
    end
  end

这里调用了一个judge的方法(判断是否战斗结束)。
如果judge为true(战斗结束)
我们就会进入phase5(战斗结束,获得经验,战利品的回合。)
如果敌人还存在,而且我方也还有人。,udge就会为false。这个时候我们需要继续战斗。所以会进入phase2(「战」或「逃」的选择),形成一个循环。
详细的以后再说。

5.phase5-战斗结束,获得经验,战利品的回合。
  def start_phase5

  end

这里定义了三样东西
01.演奏音乐
    # 演奏战斗结束 ME
    $game_system.me_play($game_system.battle_end_me)
    # 还原为战斗开始前的 BGM
    $game_system.bgm_play($game_temp.map_bgm)


02.获得物品

03.显示获得经验與战利品的窗口
    # 生成战斗结果窗口
    @result_window = Window_BattleResult.new(exp, gold, treasures)
    # 设置等待计数
    @phase5_wait_count = 100

先说一说03部分。
战斗结果的窗口是调用Window_BattleResult这个脚本。如果要修改显示的內容,就可以在refresh方法当中修改。比如不显示经验(禾西的恶趣味)。

@phase5_wait_count = 100 这个是用来告诉画面不要刷新,暂时冻结画面的计时器变量。在update_phase5当中使用。
01部分没有甚么好说。

至于02,我多多少少又有点诟病。原因是我认为把「获得物品」的计算方法「锁」在这里不是很好。我之所以说「锁」,是因为这个语句正好位于start_phase5的中部。很多人都欢喜修改战后获得物品的脚本,但是因为这个语句正好位于update_phase5的中间位置,使得我们不能用alias或者main(脚本main)前插件的方法修改。
如果这里的所有语句浓缩成一个方法,比如:
    # 取得战利品
    get_trophies

然后再在下面定义
  def get_trophies

  end

我觉得会好很多。

废话就到此为止。-o-
在02部分
line:147
我们首先初始化了我们需要的数据
    # 初始化 EXP、金钱、宝物
    exp = 0
    gold = 0
    treasures = []

如同上面说的,要是不初始化而直接用来「+= -= *= /= ……」的话就会发生NoMethodError「undefined methodfor Nil:NilClass」

然后下面是一个循环
    # 循环
    for enemy in $game_troop.enemies

    end


如果不是隐藏的敌人
      # 敌人不是隐藏状态的情况下
      unless enemy.hidden

把设置当中敌人战败后的能获得的经验和金钱全部加载在exp(experience的缩写,表示「经验,经历」)gold(金,引申为「金钱,钱财」)两个变量当中。

        # 获得 EXP、增加金钱
        exp += enemy.exp
        gold += enemy.gold

        # 出现宝物判定
        if rand(100) < enemy.treasure_prob
        end

因为默认的数据库当中击败一个敌人只会出现一件宝物(战利品),所以这里理所当然地只有一个判断。
如同上文所说,rand(100)是表示随机抽取一个0 ~ 99的数字,如果默认的机率(enemy.treasure_prob)比这个数字大的话,就会获得战利品。
下面虽然出现了三个if语法,但是其实做的只是一件东西:如果不是设定为没有物品获得。那么就把物品的数据添加到treasures当中去。因为treasures是数组,而$data_××s[enemy.××_id]不是,因此用treasures.push(××)的方法。这个是把新的项目添加到数组尾部的语法。
          if enemy.item_id > 0
            treasures.push($data_items[enemy.item_id])
          end
          if enemy.weapon_id > 0
            treasures.push($data_weapons[enemy.weapon_id])
          end
          if enemy.armor_id > 0
            treasures.push($data_armors[enemy.armor_id])
          end

    # 限制宝物数为 6 个
    treasures = treasures[0..5]

只保留treasures的前6项数据,其他的自动删除。
用途只是恶趣味而已,原因不明。不喜欢的随意把5改为更高。


    # 获得 EXP
    for i in 0...$game_party.actors.size
      actor = $game_party.actors
    end

利用循环把actor变量赋值为己方队友的任何一人

如果角色的.cant_get_exp?为false(可以获得经验)-(如果角色中了不能获得经验的状态.cant_get_exp?就会为true,这个可以在数据库-状态当中设定。战斗不能是默认的不能获得经验状态。)
那么就获得经验。
      if actor.cant_get_exp? == false
        last_level = actor.level
        actor.exp += exp
      end

last_level 记录了角色获得经验前的等级

        if actor.level > last_level
          # 显示升级的提示
          @status_window.level_up(i)
        end

如果角色当前的等级(actor.level)比获得经验前的等级(last_level)高,就显示升级的提示。


    # 获得金钱
    $game_party.gain_gold(gold)
    # 获得宝物
    for item in treasures
      case item
      # 当宝物的父类是物品
      when RPG::Item
        # 调用获得物品的方法
        $game_party.gain_item(item.id, 1)
      # 当宝物的父类是武器
      when RPG::Weapon
        # 调用获得武器的方法
        $game_party.gain_weapon(item.id, 1)
      # 当宝物的父类是防具
      when RPG::Armor
        # 调用获得防具的方法
        $game_party.gain_armor(item.id, 1)
      end
    end

具体可以在Game_Party 当中搜索含有gain字眼的语句。

因为当前的
    @phase = 5
所以update自动调用update_phase5的方法
    # 等待计数大于 0 的情况下
    if @phase5_wait_count > 0
      # 减少等待计数
      @phase5_wait_count -= 1

这个时候画面是静止的,用来播放战斗后的音乐

然后
      # 当等待计数为 0 的情况下
      if @phase5_wait_count == 0
        # 显示结果窗口
        @result_window.visible = true
        # 清除主回合标志
        $game_temp.battle_main_phase = false
        # 刷新状态窗口
        @status_window.refresh
      end
      # 结束方法
      return


让玩家看清楚他们获得了甚么东西。这个画面会一直停留。直到玩家按下C键或者Space(空格)为止。


最后,当玩家按下C键或Space
    # 按下 C 键的情况下
    if Input.trigger?(Input::C)
      # 战斗结束
      battle_end(0)
    end

整个战斗过程结束。
调用战斗结束的方法,返回0(战斗胜利)
释放所有窗口,返回地图。
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

Lv3.寻梦者

酱油的

梦石
0
星屑
1020
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

17
 楼主| 发表于 2008-3-4 22:17:50 | 只看该作者
哦,原來如此。弄得禾西惶恐不已……某些地方禾西似乎講得不太清楚。補充一下基本知識也好讓人容易讀懂。多謝精靈的幫忙。

另外,對於第二點。
据说,如果临时生成窗口或者销毁窗口的话,会引起系统不稳定(我的游戏里就碰到了)

很不幸地告訴妳,這個我也有遇到過了……Orz
當時我打算把指令選擇的窗口抽離出來,用的時候就create不用的時候就dispose,然後根據任務Id改變指令內容。結果dispose的地方出錯……整個遊戲跳出。==!
但是話說回頭,默認腳本當中使用了很多臨時生成的窗口,幷在不使用的時候釋放。禾西也幫人寫過這樣的腳本。在help當中更新窗口并隨時生成隨時釋放(根據index的位置)。效果似乎很好,暫時也沒有聽人家反映出現問題。因此,只能歸結於運氣。某些腳本(比如默認戰鬥畫面)不適闔使用這個手段。

但是技能選擇畫面和物品選擇畫面都是隨時生成的。我想,應該可以辦到。至於代價,應該是內存吧?

唔,另外……不能給我前面四樓嗎……==我想連在一齊寫啊。但是當初忘記預定樓層了
囧rz
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
46
在线时间
10 小时
注册时间
2007-5-27
帖子
2558

第1届Title华丽大赛新人奖

18
发表于 2008-3-5 00:01:31 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

Lv3.寻梦者 (暗夜天使)

精灵族の天使

梦石
0
星屑
1697
在线时间
3038 小时
注册时间
2007-3-16
帖子
33731

开拓者贵宾

19
发表于 2008-3-5 01:30:02 | 只看该作者
以下引用禾西于2008-3-4 14:17:50的发言:
很不幸地告訴,這個我也有遇到過了……Orz
[本贴由作者于 2008-3-4 14:19:04 最后编辑]

orz……又一个把我看成大姐的……
临时不显示的窗口,让他的active(活动)和visible都为false就可以了……
只有以后永久不用的才把他dispose掉……
尽量减少他的次数才对……
另外,似乎前面4楼那个要求好像满足不了……
另外,一些临时窗口可以在开始生成的时候一起生成,销毁的时候一起销毁,这样的话稳定性比较高一些。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
30 小时
注册时间
2007-8-17
帖子
54
20
发表于 2008-3-5 02:45:07 | 只看该作者
好文啊,好文。希望再多解读几个类
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-11-16 06:53

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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