RMXP脚本解析(二十九):Game_Map

目录

Game_Map类代码解析

关于角色朝向与判断是否通行的函数

关于@events与其初始化


无需多言,很轻松就能知道这是个管理游戏地图的类。本类在游戏中对应且仅对应全局变量$game_map,因为在游戏中仅仅能存在一张地图,也就是角色所在的地图。

Game_Map类代码解析

#==============================================================================

# ■ Game_Map

#------------------------------------------------------------------------------

#  处理地图的类。包含卷动以及可以通行的判断功能。

# 本类的实例请参考 $game_map 。

#==============================================================================

class Game_Map

    #--------------------------------------------------------------------------

    # ● 定义实例变量

    #--------------------------------------------------------------------------

    attr_accessor :tileset_name             # 元件 文件名

    attr_accessor :autotile_names           # 自动元件 文件名

    attr_accessor :panorama_name            # 全景 文件名

    attr_accessor :panorama_hue             # 全景 色相

    attr_accessor :fog_name                 # 雾 文件名

    attr_accessor :fog_hue                  # 雾 色相

    attr_accessor :fog_opacity              # 雾 不透明度

    attr_accessor :fog_blend_type           # 雾 混合方式

    attr_accessor :fog_zoom                 # 雾 放大率

    attr_accessor :fog_sx                   # 雾 SX ##SX为x方向的自动滚动速度

    attr_accessor :fog_sy                   # 雾 SY ##同上

    attr_accessor :battleback_name          # 战斗背景 文件名

    attr_accessor :display_x                # 显示 X 坐标 * 128

    attr_accessor :display_y                # 显示 Y 坐标 * 128

    attr_accessor :need_refresh             # 刷新要求标志

    attr_reader   :passages                 # 通行表

    attr_reader   :priorities               # 优先表

    attr_reader   :terrain_tags             # 地形标记表

    attr_reader   :events                   # 事件

    attr_reader   :fog_ox                   # 雾 原点 X 坐标

    attr_reader   :fog_oy                   # 雾 原点 Y 坐标

    attr_reader   :fog_tone                 # 雾 色调

    #--------------------------------------------------------------------------

    # ● 初始化条件

    #--------------------------------------------------------------------------

    def initialize

      @map_id = 0

      @display_x = 0

      @display_y = 0

    end

    #--------------------------------------------------------------------------

    # ● 设置

    #     map_id : 地图 ID

    #--------------------------------------------------------------------------

    def setup(map_id)

      # 地图 ID 记录到 @map_id 

      @map_id = map_id

      # 地图文件装载后、设置到 @map 

      @map = load_data(sprintf("Data/Map%03d.rxdata", @map_id)) ##sprintf的定义可以参考C语言中的sprintf,就是格式化字符串

      # 定义实例变量设置地图元件信息

      tileset = $data_tilesets[@map.tileset_id] ##获取本地图使用的图块实例RPG::Tileset

      @tileset_name = tileset.tileset_name ##以下参照RPG::Tileset的定义

      @autotile_names = tileset.autotile_names

      @panorama_name = tileset.panorama_name

      @panorama_hue = tileset.panorama_hue

      @fog_name = tileset.fog_name

      @fog_hue = tileset.fog_hue

      @fog_opacity = tileset.fog_opacity

      @fog_blend_type = tileset.fog_blend_type

      @fog_zoom = tileset.fog_zoom

      @fog_sx = tileset.fog_sx

      @fog_sy = tileset.fog_sy

      @battleback_name = tileset.battleback_name

      @passages = tileset.passages

      @priorities = tileset.priorities

      @terrain_tags = tileset.terrain_tags

      # 初始化显示坐标

      @display_x = 0 ##地图的初始化显示坐标,改变其可以使地图滚动

      @display_y = 0

      # 清除刷新要求标志

      @need_refresh = false

      # 设置地图事件数据

      @events = {}

      for i in @map.events.keys ##@map.events是一个关于RPG::Event的哈希表

        @events[i] = Game_Event.new(@map_id, @map.events[i]) ##实例化事件

      end

      # 设置公共事件数据

      @common_events = {}

      for i in 1...$data_common_events.size

        @common_events[i] = Game_CommonEvent.new(i)

      end

      # 初始化雾的各种信息

      @fog_ox = 0 ##雾的原点

      @fog_oy = 0

      @fog_tone = Tone.new(0, 0, 0, 0) ##Tone是有关色调的RGSS内部类 ##雾原本的颜色

      @fog_tone_target = Tone.new(0, 0, 0, 0) ##记忆雾的颜色(用于变更还原雾的色调)

      @fog_tone_duration = 0 ##雾变色持续的时间

      @fog_opacity_duration = 0 ##透明度变更持续的时间

      @fog_opacity_target = 0 ##同上,记忆雾的透明度

      # 初始化滚动信息

      @scroll_direction = 2  ##滚动方向 

      @scroll_rest = 0 ##滚动中,剩余的滚动长度

      @scroll_speed = 4 ##滚动速度

    end

    #--------------------------------------------------------------------------

    # ● 获取地图 ID

    #--------------------------------------------------------------------------

    def map_id

      return @map_id

    end

    #--------------------------------------------------------------------------

    # ● 获取宽度

    #--------------------------------------------------------------------------

    def width

      return @map.width

    end

    #--------------------------------------------------------------------------

    # ● 获取高度

    #--------------------------------------------------------------------------

    def height

      return @map.height ##请注意这里的height不是像素而是图块的行数

    end

    #--------------------------------------------------------------------------

    # ● 获取遇敌列表

    #--------------------------------------------------------------------------

    def encounter_list

      return @map.encounter_list

    end

    #--------------------------------------------------------------------------

    # ● 获取遇敌步数

    #--------------------------------------------------------------------------

    def encounter_step

      return @map.encounter_step

    end

    #--------------------------------------------------------------------------

    # ● 获取地图数据

    #--------------------------------------------------------------------------

    def data

      return @map.data

    end

    #--------------------------------------------------------------------------

    # ● BGM / BGS 自动切换

    #--------------------------------------------------------------------------

    def autoplay

      if @map.autoplay_bgm

        $game_system.bgm_play(@map.bgm)

      end

      if @map.autoplay_bgs

        $game_system.bgs_play(@map.bgs)

      end

    end

    #--------------------------------------------------------------------------

    # ● 刷新

    #--------------------------------------------------------------------------

    def refresh

      # 地图 ID 有效

      if @map_id > 0

        # 刷新全部的地图事件

        for event in @events.values

          event.refresh

        end

        # 刷新全部的公共事件

        for common_event in @common_events.values

          common_event.refresh

        end

      end

      # 清除刷新要求标志

      @need_refresh = false ##可能是在标志为真时调用此方法

    end

    #--------------------------------------------------------------------------

    # ● 向下滚动

    #     distance : 滚动距离

    #--------------------------------------------------------------------------

    def scroll_down(distance)

      @display_y = [@display_y + distance, (self.height - 15) * 128].min ##15为屏幕的高度(图块单位),128为滚动一格display_*变动的值

    end

    #--------------------------------------------------------------------------

    # ● 向左滚动

    #     distance : 滚动距离

    #--------------------------------------------------------------------------

    def scroll_left(distance)

      @display_x = [@display_x - distance, 0].max ##合法性验证(上同下同)

    end 

    #--------------------------------------------------------------------------

    # ● 向右滚动

    #     distance : 滚动距离

    #--------------------------------------------------------------------------

    def scroll_right(distance)

      @display_x = [@display_x + distance, (self.width - 20) * 128].min ##20为屏幕的宽度

    end 

    #--------------------------------------------------------------------------

    # ● 向上滚动

    #     distance : 滚动距离

    #--------------------------------------------------------------------------

    def scroll_up(distance)

      @display_y = [@display_y - distance, 0].max

    end

    #--------------------------------------------------------------------------

    # ● 有效坐标判定

    #     x          : X 坐标

    #     y          : Y 坐标

    #--------------------------------------------------------------------------

    def valid?(x, y)

      return (x >= 0 and x < width and y >= 0 and y < height)

    end

    #--------------------------------------------------------------------------

    # ● 可以通行判定

    #     x          : X 坐标

    #     y          : Y 坐标

    #     d          : 方向 (0,2,4,6,8,10)

    #                  ※ 0,10 = 全方向不能通行的情况的判定 (跳跃等)

    #     self_event : 自己 (判定事件可以通行的情况下)

    #--------------------------------------------------------------------------

    def passable?(x, y, d, self_event = nil) ##如果是在地图上移动,移动一次会调用两次本过程,分别是角色目前的位置是否可通过、角色的目标位置是否可通过

      # 被给予的坐标地图外的情况下

      unless valid?(x, y)

        # 不能通行

        return false

      end

      # 方向 (0,2,4,6,8,10) 与障碍物接触 (0,1,2,4,8,0) 后变换

      bit = (1 << (d / 2 - 1)) & 0x0f ##<<是移位操作 ##11110&****0

      # 循环全部的事件

      for event in events.values

        # 自己以外的元件与坐标相同的情况

        if event.tile_id >= 0 and event != self_event and

           event.x == x and event.y == y and not event.through ##Game_Event.@through 是否能被穿透的标记

          # 如果障碍物的接触被设置的情况下

          if @passages[event.tile_id] & bit != 0 ##这个事件对应的图块id的通行表与障碍物的方向

            # 不能通行

            return false

          # 如果全方向的障碍物的接触被设置的情况下

          elsif @passages[event.tile_id] & 0x0f == 0x0f ##0X0F是全方向不可通行(0x01+0x02+0x04+0x08)=(11110)2

            # 不能通行

            return false

          # 这以外的优先度为 0 的情况下

          elsif @priorities[event.tile_id] == 0 ##优先度是显示的优先度,与能否通行无关

            # 可以通行

            return true

          end

        end

      end

      # 从层按从上到下的顺序调查循环

      for i in [2, 1, 0] ##三个图层

        # 取得元件 ID

        tile_id = data[x, y, i] ##本坐标上的第i图层上的地图元件

        # 取得元件 ID 失败

        if tile_id == nil

          # 不能通行

          return false

        # 如果障碍物的接触被设置的情况下

        elsif @passages[tile_id] & bit != 0 

          # 不能通行

          return false

        # 如果全方向的障碍物的接触被设置的情况下

        elsif @passages[tile_id] & 0x0f == 0x0f

          # 不能通行

          return false

        # 这以外的优先度为 0 的情况下

        elsif @priorities[tile_id] == 0

          # 可以通行

          return true

        end

      end

      # 可以通行

      return true

    end

    #--------------------------------------------------------------------------

    # ● 茂密判定

    #     x          : X 坐标

    #     y          : Y 坐标

    #--------------------------------------------------------------------------

    def bush?(x, y)

      if @map_id != 0

        for i in [2, 1, 0]

          tile_id = data[x, y, i]

          if tile_id == nil

            return false

          elsif @passages[tile_id] & 0x40 == 0x40 ##茂密标志0x40

            return true

          end

        end

      end

      return false

    end

    #--------------------------------------------------------------------------

    # ● 柜台判定

    #     x          : X 坐标

    #     y          : Y 坐标

    #--------------------------------------------------------------------------

    def counter?(x, y)

      if @map_id != 0

        for i in [2, 1, 0]

          tile_id = data[x, y, i]

          if tile_id == nil

            return false

          elsif @passages[tile_id] & 0x80 == 0x80 ##柜台标志0x80

            return true

          end

        end

      end

      return false

    end

    #--------------------------------------------------------------------------

    # ● 获取地形标志

    #     x          : X 坐标

    #     y          : Y 坐标

    #--------------------------------------------------------------------------

    def terrain_tag(x, y)

      if @map_id != 0

        for i in [2, 1, 0]

          tile_id = data[x, y, i]

          if tile_id == nil

            return 0

          elsif @terrain_tags[tile_id] > 0

            return @terrain_tags[tile_id]

          end

        end

      end

      return 0

    end

    #--------------------------------------------------------------------------

    # ● 获取指定位置的事件 ID

    #     x          : X 坐标

    #     y          : Y 坐标

    #--------------------------------------------------------------------------

    def check_event(x, y)

      for event in $game_map.events.values 

        if event.x == x and event.y == y

          return event.id

        end

      end

    end

    #--------------------------------------------------------------------------

    # ● 滚动开始

    #     direction : 滚动方向

    #     distance  : 滚动距离

    #     speed     : 滚动速度

    #--------------------------------------------------------------------------

    def start_scroll(direction, distance, speed)

      @scroll_direction = direction 

      @scroll_rest = distance * 128 

      @scroll_speed = speed 

    end

    #--------------------------------------------------------------------------

    # ● 滚动中判定

    #--------------------------------------------------------------------------

    def scrolling?

      return @scroll_rest > 0

    end

    #--------------------------------------------------------------------------

    # ● 开始变更雾的色调

    #     tone     : 色调

    #     duration : 时间

    #--------------------------------------------------------------------------

    def start_fog_tone_change(tone, duration) ##duration是持续的帧数

      @fog_tone_target = tone.clone ##tone是一个RGB+颜色浓度(灰)的数组

      @fog_tone_duration = duration 

      if @fog_tone_duration == 0 ##如果执行完毕

        @fog_tone = @fog_tone_target.clone ##还原雾的颜色 ##啊 五彩斑斓的雾

      end

    end

    #--------------------------------------------------------------------------

    # ● 开始变更雾的不透明度

    #     opacity  : 不透明度

    #     duration : 时间

    #--------------------------------------------------------------------------

    def start_fog_opacity_change(opacity, duration) ##同上

      @fog_opacity_target = opacity * 1.0

      @fog_opacity_duration = duration

      if @fog_opacity_duration == 0

        @fog_opacity = @fog_opacity_target

      end

    end

    #--------------------------------------------------------------------------

    # ● 刷新画面

    #--------------------------------------------------------------------------

    def update

      # 还原必要的地图

      if $game_map.need_refresh ##前后呼应

        refresh

      end

      # 滚动中的情况下

      if @scroll_rest > 0

        # 滚动速度变化为地图坐标系的距离

        distance = 2 ** @scroll_speed ##也就是地图滚动速度为速度值*2 图块/帧

        # 执行滚动

        case @scroll_direction

        when 2  # 下

          scroll_down(distance)

        when 4  # 左

          scroll_left(distance)

        when 6  # 右

          scroll_right(distance)

        when 8  # 上

          scroll_up(distance)

        end

        # 滚动距离的减法运算

        @scroll_rest -= distance

      end

      # 更新地图事件

      for event in @events.values

        event.update

      end

      # 更新公共事件

      for common_event in @common_events.values

        common_event.update

      end

      # 处理雾的滚动

      @fog_ox -= @fog_sx / 8.0 ##滚动速度为此方向上的自动滚动速度/8 图块/帧 ##可以看出初始化的雾是向右滚动的

      @fog_oy -= @fog_sy / 8.0

      # 处理雾的色调变更

      if @fog_tone_duration >= 1

        d = @fog_tone_duration

        target = @fog_tone_target

        @fog_tone.red = (@fog_tone.red * (d - 1) + target.red) / d ##颜色的变化是均匀的,也就是 变更颜色与逐渐衰弱的原本颜色的混合

        @fog_tone.green = (@fog_tone.green * (d - 1) + target.green) / d

        @fog_tone.blue = (@fog_tone.blue * (d - 1) + target.blue) / d

        @fog_tone.gray = (@fog_tone.gray * (d - 1) + target.gray) / d

        @fog_tone_duration -= 1

      end

      # 处理雾的不透明度变更

      if @fog_opacity_duration >= 1

        d = @fog_opacity_duration

        @fog_opacity = (@fog_opacity * (d - 1) + @fog_opacity_target) / d ##同上

        @fog_opacity_duration -= 1

      end

    end

  end

关于角色朝向与判断是否通行的函数

本类中用于判断能否通行的方法passable?对于角色(事件)的一次行动(上下左右走动)会调用两次(在Game_Character中),第一次其参数d1为[0,2,4,6,8,10],用于判断;第二次其参数d2为[0,1,2,4,8,0](d2=10-d1),用于判断角色在目标点图块的此方向是否可通行。

至于RPG::Tileset类的属性passages如何判断通行度等参数,可以查看前文中关于本类的解析。对于passages而言,我们先将其转换为八位二进制,然后与目标数进行与操作,就可知其是否满足条件。

关于@events与其初始化

如图:

@map先使用Map**.rxdata里的RPG::Event对象集合赋值,之后遍历@map根据其中的对象属性生成Game_Event对象放入@events内。

所以@events是Game_Event对象的集合。

猜你喜欢

转载自blog.csdn.net/qq_34013974/article/details/122317227