扫描二维码关注官方公众号
返回列表
+ 发新帖
查看: 118|回复: 0

[转载发布] 【RGSS教学】自制CP战斗系统

[复制链接]
累计送礼:
0 个
累计收礼:
0 个
  • TA的每日心情
    开心
    5 小时前
  • 签到天数: 114 天

    连续签到: 4 天

    [LV.6]常住居民II

    2338

    主题

    403

    回帖

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    6
    卡币
    10607
    OK点
    16
    推广点
    0
    同能卷
    0
    积分
    13376

    灌水之王

    发表于 2024-4-19 16:29:56 | 显示全部楼层 |阅读模式
    有说漏的说错的谢谢指出
    本文的目的就是帮助想了解战斗系统的作者~

    正文:
    写脚本的最初就是要先有个构思形成一个流程
    然后根据这个流程一点一点的去做去改



    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
       
        相关方法的定义内容:
    1.   #--------------------------------------------------------------------------  # ● 设置当前的所有战斗者  #--------------------------------------------------------------------------  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
    1. #==============================================================================# ■ 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  endend复制代码
    复制代码
    下面这个要根据使用的素材的规格调整相关参数或算法
    1. #==============================================================================# ■ 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  endend复制代码
    复制代码
    最后说一下让 攻击/特技/物品/防御 消耗不同CP值的改法
    这些东西就要在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.附工程一个(只做教学参考用)



    更新日志:
              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
                 本帖来自P1论坛作者后知后觉,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=128847  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    天天去同能,天天有童年!
    回复 送礼论坛版权

    使用道具 举报

    文明发言,和谐互动
    文明发言,和谐互动
    高级模式
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

    幸运抽奖

    社区每日抽奖来袭,快来试试你是欧皇还是非酋~

    立即查看

    聊天机器人
    Loading...

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2025-3-14 23:14 , Processed in 0.133483 second(s), 58 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

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