| 
 
| 赞 | 5 |  
| VIP | 620 |  
| 好人卡 | 38 |  
| 积分 | 70 |  
| 经验 | 125468 |  
| 最后登录 | 2015-7-27 |  
| 在线时间 | 1666 小时 |  
 Lv4.逐梦者 
	梦石0 星屑6955 在线时间1666 小时注册时间2008-10-29帖子6710 
 | 
| 
本帖最后由 后知后觉 于 2009-8-18 12:12 编辑
x
加入我们,或者,欢迎回来。您需要 登录 才可以下载或查看,没有帐号?注册会员  
 有说漏的说错的谢谢指出
 本文的目的就是帮助想了解战斗系统的作者~
 
 正文:
 写脚本的最初就是要先有个构思形成一个流程
 然后根据这个流程一点一点的去做去改
 
 
 
 1.了解默认战斗系统
 要把默认系统改成CP的 首先要了解默认系统的流程
 先是进入 def main 初始化一系列的对象
 然后进入 start_phase1
 这个回合 1 处理的是 战斗事件中 0 回合要执行的事件
 然后通过 def update 来执行事件
 如果没有事件执行就进入 update_phase1
 进入后先判断胜负 然后进入选择 战斗/逃跑的 start_phase2
 很多人都对这个回合很不爽~
 选择战斗就进入 输入命令的 start_phase3
 选择逃跑就进入逃跑处理 逃跑失败就直接跳过输入命令的回合3
 而直接进入 进行后台数据处理&前台动画播放 的主回合(回合4)
 执行完回合4以后就会进入 胜负判断 然后决定是进入回合2
 还是进入回合5
 回合5是只有战斗胜利了才会进入的处理得到经验 金钱 宝物的回合
 def update这个方法先是要进行一些事件等等的判断 处理
 然后才会进入 @phase 分支的回合 刷新
 就是那些def update_phasex_xxxx的方法
 而主回合(回合4)的流程是 先执行战斗事件
 然后进入步骤1和步骤2
 这2个步骤都是处理后台数据的
 步骤3到步骤5都是前台动画的显示
 步骤6是公共事件
 如果是回合4发生了BUG 一个DEBUG的方法是
 在各个方法的定义里加上p命令
 比如
 def update_phase4_step1
 p "1"
 def update_phase4_step2
 p "2"
 def update_phase4_step3
 p "3"
 
 默认系统的大致流程大概就是这样 如果还有什么不明白的可以看看这篇教程
 http://rpg.blue/viewthread.php?t ... B%E7%A6%BE%E8%A5%BF
 
 
 
 
 2.开始改成CP制
 思路:1.创建战斗者的CP值属性
 2.创建CP槽的增加的回合
 3.把满足输入命令的角色 进入回合3进入命令输入
 4.把输入了命令的战斗者进入回合4
 5.绘制CP槽的显示
 
 1.创建战斗者的CP属性
 找到Game_Battler 1
 class Game_Battler
 #--------------------------------------------------------------------------
 # ● 定义实例变量
 #--------------------------------------------------------------------------
 attr_accessor   :cp                    # 步数
 #--------------------------------------------------------------------------
 # ● 初始化对像
 #--------------------------------------------------------------------------
 在这一行下对实例变量进行初始化
 def initialize
 @cp = 0
 …………
 end
 #--------------------------------------------------------------------------
 # ● 确定动作速度
 #--------------------------------------------------------------------------
 行动的顺序完全根据战斗者的agi来决定
 def make_action_speed
 @current_action.speed = agi
 end
 end
 
 
 2.创建CP增长回合
 首先我们要先建立一些变量
 找到Scene_Battle 1 的 def main 的
 $game_troop.setup(@troop_id)
 这一行是设置敌人队伍 在这一行下面开始初始化我们要新建的东西
 #为了不混乱 新建一个数组 类似于 @action_battlers 数组
 @now_battlers = []
 初始化CP槽的最大值 当达到这个值时该战斗者就获得行动权
 @now_maxspeed = 0
 @把现在的所有战斗者放进新建的@now_battlers数组里
 set_now_battlers
 #获取CP槽的最大值 我这定义的是 所有战斗者的中最大agi的40倍
 set_now_maxspeed
 #初始化所有战斗着的CP为0
 clear_battlers_cp
 #把获得了行动权的战斗者放进这个数组里
 @input_action_battlers = []
 # 生成CP窗口
 @cp_window = Window_Cp_Bar.new
 
 相关方法的定义内容:
 要用的东西创建好了 就改创建增长过程了复制代码  #--------------------------------------------------------------------------
  # ● 设置当前的所有战斗者
  #--------------------------------------------------------------------------
  def set_now_battlers
    @now_battlers = []
    for enemy in $game_troop.enemies
      @now_battlers.push(enemy)
    end
    for actor in $game_party.actors
      @now_battlers.push(actor)
    end
    @now_battlers.delete(nil)
  end
  #--------------------------------------------------------------------------
  # ● 获取所有战斗者的速度最大值的 40倍
  #--------------------------------------------------------------------------
  def set_now_maxspeed
    @now_maxspeed = 0
    for battler in @now_battlers
      if @now_maxspeed < battler.agi
        @now_maxspeed = battler.agi
      end
    end
    @now_maxspeed *= 40
  end
  #--------------------------------------------------------------------------
  # ● 初始化所有战斗者的 CP 值为 0
  #--------------------------------------------------------------------------
  def clear_battlers_cp
    for battler in @now_battlers
      battler.cp = 0
    end
  end
既然很多人都不喜欢 选择 战斗/逃跑 这个回合
 那我们就把这个 @phase2改成我们要的把
 进入这个回合先执行start_phase2 然后进入update_phase2
 根据流程先改start_phase2
 #--------------------------------------------------------------------------
 # ● 开始 CP 回合
 #--------------------------------------------------------------------------
 def start_phase2
 @phase = 2
 @actor_index = -1
 @active_battler = nil
 @actor_command_window.active = false
 @actor_command_window.visible = false
 $game_temp.battle_main_phase = false
 # 初始化所有角色的行动命令
 $game_party.clear_actions
 # 考虑到 敌人变身和一些宠物系统更换了宠物
 #导致当前战斗者发生了变化,所有设置一次当前的战斗者进新数组
 set_now_battlers
 # 设置CP草最大值
 set_now_maxspeed
 # 初始化获得行动权的战斗者数组
 @input_action_battlers = []
 end
 这个方法执行完后就会回到
 Graphics.update
 Input.update
 然后进入update执行到尾部 根据@phase的值 执行update_phase2
 #--------------------------------------------------------------------------
 # ● 刷新画面 增加 CP
 #--------------------------------------------------------------------------
 def update_phase2
 # 增长所有战斗者的CP值
 add_battlers_cp
 # 刷新显示CP草的窗口
 @cp_window.refresh(@now_maxspeed)
 # 把获得了行动权的战斗者放进 行动数组里
 set_input_action_battlers
 # 如果行动数组不为空
 if @input_action_battlers.size > 0
 # 开始输入行动命令
 start_phase3
 return
 end
 end
 
 相关方法的定义内容:
 #--------------------------------------------------------------------------
 # ● 数据处理 增加 CP
 #--------------------------------------------------------------------------
 def add_battlers_cp
 for battler in @now_battlers
 next if battler.nil?
 next if battler.dead?
 next if battler.hidden
 next if battler.cp >= @now_maxspeed
 battler.cp += battler.agi
 end
 end
 #--------------------------------------------------------------------------
 # ● 设置输入命令的战斗者
 #--------------------------------------------------------------------------
 def set_input_action_battlers
 for battler in @now_battlers
 if battler.cp >= @now_maxspeed
 @input_action_battlers.push(battler)
 end
 end
 # 这一段是从 Scene_Battle 4 弄过来的 是决定战斗者的行动顺序的
 if @input_action_battlers.size > 0
 for battler in @input_action_battlers
 battler.make_action_speed
 end
 if @input_action_battlers.size > 1
 @input_action_battlers.sort! {|a,b|
 b.current_action.speed - a.current_action.speed }
 end
 end
 end
 
 3.把满足如数命令的角色 进入回合3进入命令输入
 进入输入命令 回合3
 回合3需要修改的只有2个方法
 #--------------------------------------------------------------------------
 # ● 转到输入下一个角色的命令
 #--------------------------------------------------------------------------
 def phase3_next_actor
 # 开始循环
 begin
 if @active_battler != nil
 @active_battler.blink = false
 end
 如果 @actor_index的值已经达到了获得行动权战斗者数组的
 # 最后的单元号
 if @actor_index == @input_action_battlers.size-1
 # 消耗这些战斗着的CP值
 # 其实吧 这个东西不应该在这里消耗
 # 因为在这里消耗的话就意味着 攻击/特技/物品/防御 消耗的是同样的CP了
 # 不过话又说回来 很多人都是这样设置的。。。
 for battler in @input_action_battlers
 # 消耗的CP值就是CP槽的最大值
 battler.cp -= @now_maxspeed
 end
 @cp_window.refresh(@now_maxspeed)
 # 命令输入完了就进入 回合4
 start_phase4
 # 结束这个方法
 return
 end
 # 当上面的这个条件分歧不满足的情况下 就推进 行动数组的索引
 @actor_index += 1
 # 代入战斗者
 @active_battler = @input_action_battlers[@actor_index]
 @active_battler.blink = true unless @active_battler.is_a?(Game_Enemy)
 # 如果战斗者是敌人
 if @active_battler.is_a?(Game_Enemy)
 # 先初始化这个敌人的行动命令
 @active_battler.current_action.clear
 # 设置这个敌人的行动命令
 # 或许放在这里设置有点不大好 。。就先放这里好了
 # 如果想要写传说中的 AI 的话
 # 搜索 def make_action
 # 对这个方法进行修改
 @active_battler.make_action
 end
 # 这个循环直到@active_battler为角色和这个角色可以输入命令的时候才结束
 end until (@active_battler.is_a?(Game_Actor) and @active_battler.inputable?)
 # 设置命令窗口 然后就开始给角色输入命令了
 phase3_setup_command_window
 end
 #--------------------------------------------------------------------------
 # ● 转向前一个角色的命令输入
 #--------------------------------------------------------------------------
 def phase3_prior_actor
 begin
 if @active_battler != nil
 @active_battler.blink = false
 end
 # 如果索引是数组的头部
 if @actor_index == 0
 # 重新开始回合3的流程
 start_phase3
 # 结束这个方法
 return
 end
 @actor_index -= 1
 @active_battler = @input_action_battlers[@actor_index]
 @active_battler.blink = true unless @active_battler.is_a?(Game_Enemy)
 # 这个循环直到@active_battler为角色和这个角色可以输入命令的时候才结束
 end until (@active_battler.is_a?(Game_Actor) and @active_battler.inputable?)
 phase3_setup_command_window
 end
 
 4.把输入了命令的战斗者进入回合4
 就以目前的CP消耗的方法来说
 回合4要修改的部位只有一个
 把 start_phase4 简化成这样即可
 #--------------------------------------------------------------------------
 # ● 开始主回合
 #--------------------------------------------------------------------------
 def start_phase4
 @phase = 4
 $game_temp.battle_turn += 1
 # 搜索全页的战斗事件
 for index in 0...$data_troops[@troop_id].pages.size
 # 获取事件页
 page = $data_troops[@troop_id].pages[index]
 # 本页的范围是 [回合] 的情况下
 if page.span == 1
 # 设置已经执行标志
 $game_temp.battle_event_flags[index] = false
 end
 end
 @actor_index = -1
 @active_battler = nil
 @actor_command_window.active = false
 @actor_command_window.visible = false
 $game_temp.battle_main_phase = true
 # 把获得了行动权的战斗者转给 @action_battlers
 @action_battlers = @input_action_battlers
 @phase4_step = 1
 end
 
 做到这里就应该可以运行了,只是看不见CP的视觉效果
 
 5.绘制CP槽的显示
 绘制窗口个人认为是写脚本的基础,我就不多言了
 我写了2种风格的CP_Bar
 下面这个要根据使用的素材的规格调整相关参数或算法复制代码#==============================================================================
# ■ Window_Cp
#==============================================================================
class Window_Cp < Window_Base
  #--------------------------------------------------------------------------
  # ● 初始化对像
  #--------------------------------------------------------------------------
  def initialize
    super(0, 416, 640, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    self.opacity = 0
    refresh
  end
  #--------------------------------------------------------------------------
  # ● 刷新
  #--------------------------------------------------------------------------
  def refresh(now_maxspeed = 999)
    self.contents.clear
    actors = $game_party.actors
    return if actors.size == 0
    for i in 0...actors.size
      x = i * 160 + 4
      self.contents.fill_rect(x, 0, 96, 16, Color.new(255, 255, 255, 255))
      self.contents.fill_rect(x+1,1,94, 14, Color.new(0,   0,   0,   255))
      cp = [now_maxspeed, actors[i].cp].min
      cp_w = (cp.to_f / now_maxspeed) * 94.0
      cp_w = Integer(cp_w)
      self.contents.fill_rect(x+1,1,cp_w, 14, Color.new(0, 255, 0, 255))
    end
  end
end
最后说一下让 攻击/特技/物品/防御 消耗不同CP值的改法复制代码
#==============================================================================
# ■ Window_Cp_Bar
#==============================================================================
class Window_Cp_Bar < Window_Base
  #--------------------------------------------------------------------------
  # ● 初始化对像
  #--------------------------------------------------------------------------
  def initialize
    super(0, 0, 640, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    self.opacity = 0
    setup_battlers
    self.z -= 70
    @viewport = Viewport.new(0,0,640,480)
    @viewport.z = self.z + 10
    @sprite_cp_bar = Sprite.new(@viewport)
    @sprite_cp_bar.bitmap = RPG::Cache.picture("Cp_Bar.png")
    @sprite_cp_bar.z = self.z + 10
    @sprite_cp_bar.x = 390
    @sprite_cp_bar.y = 8
    @sprites = []
    12.times{@sprites.push(RPG::Sprite.new(@viewport))}
    refresh
  end
  #--------------------------------------------------------------------------
  # ● 获取战斗者
  #--------------------------------------------------------------------------
  def setup_battlers
    @actors = $game_party.actors
    @enemies = $game_troop.enemies
  end
  #--------------------------------------------------------------------------
  # ● 释放
  #--------------------------------------------------------------------------
  def dispose
    super
    @sprite_cp_bar.bitmap.dispose
    @sprite_cp_bar.dispose
    return if @sprites.size == 0
    for sprite in @sprites
      sprite.dispose
    end
    @viewport.dispose
  end
  #--------------------------------------------------------------------------
  # ● 刷新
  #--------------------------------------------------------------------------
  def update
    super
    @viewport.update
    for sprite in @sprites
      sprite.update
    end
  end
  #--------------------------------------------------------------------------
  # ● 描绘
  #--------------------------------------------------------------------------
  def refresh(now_maxspeed = 999)
    for i in 0...4
      actor = @actors[i]
      if actor.nil?
        if @sprites[i].bitmap != nil
          @sprites[i].bitmap.dispose
          @sprites[i].bitmap = nil
        end
        @sprites[i].visible = false
        next
      end
      battler_name = actor.battler_name
      battler_hue = actor.battler_hue
      @sprites[i].bitmap = RPG::Cache.battler(battler_name, battler_hue)
      @sprites[i].zoom_x = (24.0 / @sprites[i].bitmap.width)
      @sprites[i].zoom_y = (24.0 / @sprites[i].bitmap.height)
      @sprites[i].ox = @sprites[i].bitmap.width / 2
      @sprites[i].oy = @sprites[i].bitmap.height
      cp = [now_maxspeed, actor.cp].min
      cp_x = (cp.to_f / now_maxspeed) * 182.0
      cp_x = Integer(cp_x)
      @sprites[i].x = cp_x + 425
      @sprites[i].y = 26
      @sprites[i].z = cp
      if actor.dead? or actor.hidden
        @sprites[i].visible = false
      else
        @sprites[i].visible = true
      end
    end
    for i in 4...12
      enemy = @enemies[i - 4]
      if enemy.nil?
        if @sprites[i].bitmap != nil
          @sprites[i].bitmap.dispose
          @sprites[i].bitmap = nil
        end
        @sprites[i].visible = false
        next
      end
      battler_name = enemy.battler_name
      battler_hue = enemy.battler_hue
      @sprites[i].bitmap = RPG::Cache.battler(battler_name, battler_hue)
      @sprites[i].zoom_x = (24.0 / @sprites[i].bitmap.width)
      @sprites[i].zoom_y = (24.0 / @sprites[i].bitmap.height)
      @sprites[i].ox = @sprites[i].bitmap.width / 2
      @sprites[i].oy = 0
      cp = [now_maxspeed, enemy.cp].min
      cp_x = (cp.to_f / now_maxspeed) * 182.0
      cp_x = Integer(cp_x)
      @sprites[i].x = cp_x + 425
      @sprites[i].y = 38
      @sprites[i].z = cp
      if enemy.dead? or enemy.hidden
        @sprites[i].visible = false
      else
        @sprites[i].visible = true
      end
    end
  end
end
这些东西就要在Scene_Battle 4 里完成了
 找到
 #--------------------------------------------------------------------------
 # ● 刷新画面 (主回合步骤 2 : 开始行动)
 #--------------------------------------------------------------------------
 def update_phase4_step2
 # 如果不是强制行动
 unless @active_battler.current_action.forcing
 # 限制为 [敌人为普通攻击] 或 [我方为普通攻击] 的情况下
 if @active_battler.restriction == 2 or @active_battler.restriction == 3
 # 设置行动为攻击
 @active_battler.current_action.kind = 0
 @active_battler.current_action.basic = 0
 end
 # 限制为 [不能行动] 的情况下
 if @active_battler.restriction == 4
 # 清除行动强制对像的战斗者
 $game_temp.forcing_battler = nil
 # 移至步骤 1
 @phase4_step = 1
 return
 end
 end
 # 清除对像战斗者
 @target_battlers = []
 # 行动种类分支
 case @active_battler.current_action.kind
 when 0  # 基本
 make_basic_action_result
 when 1  # 特技
 make_skill_action_result
 when 2  # 物品
 make_item_action_result
 end
 # 移至步骤 3
 if @phase4_step == 2
 @phase4_step = 3
 end
 end
 #--------------------------------------------------------------------------
 # ● 生成基本行动结果
 #--------------------------------------------------------------------------
 def make_basic_action_result
 # 攻击的情况下
 if @active_battler.current_action.basic == 0
 # 设置攻击 ID
 @animation1_id = @active_battler.animation1_id
 @animation2_id = @active_battler.animation2_id
 # 行动方的战斗者是敌人的情况下
 if @active_battler.is_a?(Game_Enemy)
 if @active_battler.restriction == 3
 target = $game_troop.random_target_enemy
 elsif @active_battler.restriction == 2
 target = $game_party.random_target_actor
 else
 index = @active_battler.current_action.target_index
 target = $game_party.smooth_target_actor(index)
 end
 end
 # 行动方的战斗者是角色的情况下
 if @active_battler.is_a?(Game_Actor)
 if @active_battler.restriction == 3
 target = $game_party.random_target_actor
 elsif @active_battler.restriction == 2
 target = $game_troop.random_target_enemy
 else
 index = @active_battler.current_action.target_index
 target = $game_troop.smooth_target_enemy(index)
 end
 end
 # 设置对像方的战斗者序列
 @target_battlers = [target]
 # 应用通常攻击效果
 for target in @target_battlers
 target.attack_effect(@active_battler)
 end
 return
 end
 # 防御的情况下
 if @active_battler.current_action.basic == 1
 # 帮助窗口显示"防御"
 @help_window.set_text($data_system.words.guard, 1)
 return
 end
 # 逃跑的情况下
 if @active_battler.is_a?(Game_Enemy) and
 @active_battler.current_action.basic == 2
 #  帮助窗口显示"逃跑"
 @help_window.set_text("逃跑", 1)
 # 逃跑
 @active_battler.escape
 return
 end
 # 什么也不做的情况下
 if @active_battler.current_action.basic == 3
 # 清除强制行动对像的战斗者
 $game_temp.forcing_battler = nil
 # 移至步骤 1
 @phase4_step = 1
 return
 end
 end
 
 
 就在这里面改,具体应该怎么做,你自己去想想!……
 而且还可以精确到根据特技/物品的ID来区别 消耗不同程度的CP值
 只看不做是永远也学不会的~!
 
 
 
 3.附工程一个(只做教学参考用)
 
  CP制战斗系统v1.2.rar
(196.69 KB, 下载次数: 2070) 
 
 更新日志:
 v1.2
 解决了防御无效的问题
 先找到 def start_phase2
 下面有这样的一行
 $game_party.clear_actions
 把这一行【剪切】到这个战斗系统的 def main这一行去
 这一行是在Scene_Battle 1里的
 然后在def start_phase3这一行下面加一行
 @input_action_battlers.each{|battler|battler.current_action.clear}
 
 v1.1
 修正CP_Bar窗口的Z值问题
 对窗口内的sprite统一指定了一个视口viewport
 | 
 |