查看: 69|回复: 0

[转载发布] 【教程】如何制作储物箱

[复制链接]
  • TA的每日心情
    开心
    前天 09:55
  • 签到天数: 37 天

    连续签到: 3 天

    [LV.5]常住居民I

    2028

    主题

    32

    回帖

    7260

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    0
    卡币
    5184
    OK点
    16
    积分
    7260
    发表于 同元一千年八月八日(秋) | 显示全部楼层 |阅读模式
    相关问题:
    https://rpg.blue/thread-486363-1-1.html

    示意图:


    解决这个问题,通常的做法是创建一个Scene类,然后用事件call这个类,就跟使用商店一样。上面的示意图也就是我们所想要的效果:整个场景分为4部分,当左下或者右下窗口激活时,按下空格来交换队伍里的物品和储物箱里的物品。
    接下来我会仔细的讲解该如何写这个脚本。对于RGSS的初学者来说,可以当作写Scene的教程。这个教程会逐步完善场景类所需的各种内容,并且每完成一小部分就会展示一下效果。

    【第一节:场景类的基本结构】
    首先创建一个模块,以避免跟其他的脚本同名,后续的所有类的定义都是在这个模块里进行。这里使用提问者的名字Taeckle作为模块名。
    接下来创建场景的类Scene_Storage。这个场景的类需要包括:

    1. main方法,在范例里,main方法被拆分成了3部分:create_windowsscene_loopdispose_windows
    create_windows 用来创建4个窗口,使用几个比较基础的窗口类作为place holder,这里只是用来检查窗口位置是否正确,此方法会在后面的步骤里被新的定义覆盖:RUBY 代码
    1. # ----------------------------------------- #
    2. # Help Window (640 x 64)                    #
    3. # ----------------------------------------- #
    4. # Menu Window (640 x 64)                    #
    5. # --------------------+-------------------- #
    6. # Item Window Party   | Item Window Storage #
    7. #    (320 x 352)      |    (320 x 352)      #
    8. # --------------------+-------------------- #
    9. def create_windows
    10.   # Help Window
    11.   @help_window = Window_Help.new
    12.   # Horizontal Command Window
    13.   @menu_window = Window_Selectable.new(0, 64, 640, 64)
    14.   # Item Window left: Party items
    15.   @item_window_party = Window_Selectable.new(0, 128, 320, 480 - 64 * 2)
    16.   # Item Window right: Storage items
    17.   @item_window_storage = Window_Selectable.new(320, 128, 320, 480 - 64 * 2)
    18. end
    复制代码


    scene_loop 直接照抄RGSS的内容。dispose_windows使用RGSS3的风格,将属于Scene的所有Window类的实例对象关闭。

    由于scene_loop里呼叫了update方法,所以还需要创建一个空的update方法。

    2. 数据的处理,这个场景涉及到RGSS以外的数据。所以需要定义数据的类型Data,以及场景所需的实例变量@data
    考虑到具体要解决的问题是储物箱,所以该场景要占用一个全局变量来存储数据,把这个变量的ID传给场景的initialize方法。顺便传递了储存箱最大能装的数量作为第2个参数。
    RUBY 代码
    1. def initialize(data_vid, item_max_size = 99)
    2.   @scene_class = $scene.class
    3.   @item_max_size = [item_max_size, 99].min
    4.   if !$game_variables[data_vid].is_a?(Data)
    5.     $game_variables[data_vid] = Data.new
    6.   end
    7.   @data = $game_variables[data_vid]
    8. end
    复制代码

    在initialize方法里,会检测传入的全局变量是否为Data类型,如果不是就初始化一下,然后绑定此全局变量。

    储物箱应该要提供存入和取出两个方法。定义storefetch两个空方法,其参数是要存储的东西和数量(默认为1)

    最终脚本如下:RUBY 代码下载
    1. # encoding: utf-8
    2. module Taeckle
    3.   @version = "0.1"
    4.   classData
    5.   end
    6.   class Scene_Storage
    7.     attr_reader :data
    8.     def initialize(data_vid, item_max_size = 99)
    9.       @scene_class = $scene.class
    10.       @item_max_size = [item_max_size, 99].min
    11.       if !$game_variables[data_vid].is_a?(Data)
    12.         $game_variables[data_vid] = Data.new
    13.       end
    14.       @data = $game_variables[data_vid]
    15.     end
    16.     def main
    17.       create_windows
    18.       scene_loop
    19.       dispose_windows
    20.     end
    21.     # layout
    22.     # ----------------------------------------- #
    23.     # Help Window (640 x 64)                    #
    24.     # ----------------------------------------- #
    25.     # Menu Window (640 x 64)                    #
    26.     # --------------------+-------------------- #
    27.     # Item Window Party   | Item Window Storage #
    28.     #    (320 x 352)      |    (320 x 352)      #
    29.     # --------------------+-------------------- #
    30.     def create_windows
    31.       # Help Window
    32.       @help_window = Window_Help.new
    33.       # Horizontal Command Window
    34.       @menu_window = Window_Selectable.new(0, 64, 640, 64)
    35.       # Item Window left: Party items
    36.       @item_window_party = Window_Selectable.new(0, 128, 320, 480 - 64 * 2)
    37.       # Item Window right: Storage items
    38.       @item_window_storage = Window_Selectable.new(320, 128, 320, 480 - 64 * 2)
    39.     end
    40.     def update
    41.     end
    42.     def scene_loop
    43.       Graphics.transition
    44.       # 主循环
    45.       loopdo
    46.         # 刷新游戏画面
    47.         Graphics.update
    48.         # 刷新输入信息
    49.         Input.update
    50.         # 刷新画面
    51.         update
    52.         # 如果画面切换就中断循环
    53.         if$scene != self
    54.           break
    55.         end
    56.       end
    57.       # 准备过渡
    58.       Graphics.freeze
    59.     end
    60.     def dispose_windows
    61.       self.instance_variables.eachdo |name|
    62.         obj = self.instance_variable_get(name)
    63.         obj.disposeif obj.is_a?(Window)
    64.       end
    65.     end
    66.     def store(item, number = 1)
    67.     end
    68.     def fetch(item, number = 1)
    69.     end
    70.   end
    71. end
    复制代码


    【第二节:测试工程】
    创建一个空白的工程,并且将写好的scene_storage_base.rb插入到脚本编辑器的main前。根据具体的需求,创建如下自动事件:

    按F12执行,进入新游戏后,自动执行本事件,就会进入到Scene_Storage里了。这个时候场景里还是一片空白:


    【第三节:数据结构】
    接下来我们需要完善Data类,以及storefetch两个方法。ruby允许随时打开一个类添加新的内容,也允许覆盖原来的同名方法。

    1. Data类是存储在箱子里的物品、武器等。所以Data类可以直接套用Game_Party的部分内容:
    RUBY 代码
    1. classData
    2.   attr_reader :item
    3.   attr_reader :weapons
    4.   attr_reader :armors
    5.   def initialize
    6.     @items = {}
    7.     @weapons = {}
    8.     @armors = {}
    9.   end
    10.   # ...
    11. end
    复制代码
    复制粘贴Game_Party的item_number, weapon_number, armor_number, gain_item, gain_weapon, gain_armor这6个方法即可。
    由于拥有完全相同的6个方法和对应的数据结构,Game_Party和Data的实例在某些地方可以互相替换。详见后面的@bind_data部分。

    2. store方法,需要根据传入的变量的不同类型(item/weapon/armor),来选择调用指定的方法。此外,当箱子或者队伍的背包已经满了的时候,就不能继续放入物品,定义一个函数来判断这种情况:
    RUBY 代码
    1. def can_store?(num_party, num_storage, number)
    2.   num_party - number >= 0 && num_party - number = 0 && num_storage + number  0
    3.         @items[item_id] = [[item_number(item_id) + n, 0].max, 99].min
    4.       end
    5.     end
    6.     #--------------------------------------------------------------------------
    7.     # ● 增加武器 (减少)
    8.     #     weapon_id : 武器 ID
    9.     #     n         : 个数
    10.     #--------------------------------------------------------------------------
    11.     def gain_weapon(weapon_id, n)
    12.       # 更新 hash 的个数数据
    13.       if weapon_id > 0
    14.         @weapons[weapon_id] = [[weapon_number(weapon_id) + n, 0].max, 99].min
    15.       end
    16.     end
    17.     #--------------------------------------------------------------------------
    18.     # ● 增加防具 (减少)
    19.     #     armor_id : 防具 ID
    20.     #     n        : 个数
    21.     #--------------------------------------------------------------------------
    22.     def gain_armor(armor_id, n)
    23.       # 更新 hash 的个数数据
    24.       if armor_id > 0
    25.         @armors[armor_id] = [[armor_number(armor_id) + n, 0].max, 99].min
    26.       end
    27.     end
    28.   end
    29.   class Scene_Storage
    30.     def store(item, number = 1)
    31.       # RPG::Item
    32.       if item.is_a?(RPG::Item)
    33.         num_party = $game_party.item_number(item.id)
    34.         num_storage = @data.item_number(item.id)
    35.         if can_store?(num_party, num_storage, number)
    36.           $game_party.lose_item(item.id, number)
    37.           @data.gain_item(item.id, number)
    38.           returntrue
    39.         end
    40.       end
    41.       # RPG::Weapon
    42.       if item.is_a?(RPG::Weapon)
    43.         num_party = $game_party.weapon_number(item.id)
    44.         num_storage = @data.weapon_number(item.id)
    45.         if can_store?(num_party, num_storage, number)
    46.           $game_party.lose_weapon(item.id, number)
    47.           @data.gain_weapon(item.id, number)
    48.           returntrue
    49.         end
    50.       end
    51.       # RPG::Armor
    52.       if item.is_a?(RPG::Armor)
    53.         num_party = $game_party.armor_number(item.id)
    54.         num_storage = @data.armor_number(item.id)
    55.         if can_store?(num_party, num_storage, number)
    56.           $game_party.lose_armor(item.id, number)
    57.           @data.gain_armor(item.id, number)
    58.           returntrue
    59.         end
    60.       end
    61.       returnfalse
    62.     end
    63.     def fetch(item, number = 1)
    64.       store(item, -number)
    65.     end
    66.     def can_store?(num_party, num_storage, number)
    67.       num_party - number >= 0 && num_party - number = 0 && num_storage + number  0
    68.           @data.push($data_items[i])
    69.         end
    70.       end
    71.       # 在战斗中以外添加武器、防具
    72.       unless$game_temp.in_battle
    73.         for i in1...$data_weapons.size
    74.           if@bind_data.weapon_number(i) > 0
    75.             @data.push($data_weapons[i])
    76.           end
    77.         end
    78.         for i in1...$data_armors.size
    79.           if@bind_data.armor_number(i) > 0
    80.             @data.push($data_armors[i])
    81.           end
    82.         end
    83.       end
    84.       # Sort by description
    85.       if@data.first.respond_to?(:desc)
    86.         @data.sort! { |a, b| a.desc  b.desc}
    87.       end
    88.       # 如果项目数不是 0 就生成位图、重新描绘全部项目
    89.       @item_max = @data.size
    90.       if@item_max > 0
    91.         self.contents = Bitmap.new(width - 32, row_max * 32)
    92.         for i in0...@item_max
    93.           draw_item(i)
    94.         end
    95.       end
    96.     end
    97.     #--------------------------------------------------------------------------
    98.     # ● 描绘项目
    99.     #     index : 项目编号
    100.     #--------------------------------------------------------------------------
    101.     def draw_item(index)
    102.       item = @data[index]
    103.       case item
    104.       whenRPG::Item
    105.         number = @bind_data.item_number(item.id)
    106.       whenRPG::Weapon
    107.         number = @bind_data.weapon_number(item.id)
    108.       whenRPG::Armor
    109.         number = @bind_data.armor_number(item.id)
    110.       end
    111.       ifself.active
    112.         self.contents.font.color = normal_color
    113.       else
    114.         self.contents.font.color = disabled_color
    115.       end
    116.       x = 4
    117.       y = index * 32
    118.       rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    119.       self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    120.       bitmap = RPG::Cache.icon(item.icon_name)
    121.       opacity = self.contents.font.color == normal_color ? 255 : 128
    122.       self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    123.       self.contents.draw_text(x + 28, y, 212, 32, item.name, 0)
    124.       self.contents.draw_text(x + 240, y, 16, 32, ":", 1)
    125.       self.contents.draw_text(x + 256, y, 24, 32, number.to_s, 2)
    126.     end
    127.     #--------------------------------------------------------------------------
    128.     # ● 刷新帮助文本
    129.     #--------------------------------------------------------------------------
    130.     def update_help
    131.       @help_window.set_text(self.item == nil ? "" : self.item.description)
    132.     end
    133.   end
    134. end
    复制代码

    将这段脚本添加到F11脚本编辑器里,效果如图:

    范例如下:


    使用的小技巧:
    1. 由于数据存储在全局变量里,会跟随存档一起存下来。
    2. 场景绑定不同的变量就会对应不同的储物箱。
    3. 如果预先设置好变量的内容,就可以做到储物箱在第一次打开时就有东西了。
    1. $game_variables[2] = Taeckle::Data.new$game_variables[2].gain_item(1, 1)复制代码
    复制代码
    4. 设置可以存储的物品上限为0,并且在箱子里的每件物品数量恰好为1,此时箱子里的物品只能取出不能放回。
    5. 可以在条件分歧里使用脚本里检查箱子里的内容:
    1. $game_variables[2].item_number(1) > 0复制代码
    复制代码

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

    本帖子中包含更多资源

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

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

    使用道具 举报

    ahome_bigavatar:guest
    ahome_bigavatar:welcomelogin
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

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

    GMT+8, 2024-5-12 02:39 , Processed in 0.051849 second(s), 42 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

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