找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 43|回复: 1

[经验] 【简易物品栏与界面交互】代码与思路分享

[复制链接]
发表于 昨天 19:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

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

×
1.jpg 2.jpg


萌新最近在用renpy制作游戏,其中有解谜部分,于是研究出了一个简单的物品栏功能。
虽然尚未完善,但大体功能已经完成,见有许多同学需要,故先分享,以供参考与学习。
相关工程(暂未上传github,先用网盘分享了)
因为是边做游戏边造轮子,所以把物品栏功能单独分离出来塞新工程里了
相关工程   提取码: 2026

代码部分:

物品类定义:
[RenPy] 纯文本查看 复制代码
# 物品类定义

init -1 python:
    """ 基础物品类 """
    class InventoryItem:
        def __init__(self, id, name, description, image_path, 
                        usable=False, combinable=False, examine_text=None):
            self.id = id                    # id
            self.name = name                # 名称
            self.description = description  # 简介
            self.image_path = image_path    # 物品图标路径
            self.usable = usable            # 是否可使用
            self.combinable = combinable    # 能否被组合(也许会用到)
            self.examine_text = examine_text or description  # 检查文本
            
            # 运行时状态
            self.selected = False #是否被选中
            self.quantity = 1 # 物品数量(应该不会用到)
            
        # 用于debug时返回物品的id与名称
        def __repr__(self):
            return f"Item({self.id}: {self.name})"
        def __str__(self):
            return self.name
            
        # 检查 返回物品的简介与详细文本
        def examine(self):
            return self.examine_text
        def description(self):
            return self.description
        
        # 使用物品 待完善,target 是目标对象或另一物品
        def use(self, target=None):
            return False  # 子类重写

    """ 文档物品类 (未完善,使用后呼出文档相关的界面)"""
    class DocumentItem(InventoryItem):
        def __init__(self, id, name, description, image_path, 
                        content="", examine_text=None, screen_name=None):
            super().__init__(id, name, description, image_path,
                            usable=True, combinable=False, examine_text=examine_text)

            self.content = content  # 文档内容
            self.screen_name = screen_name # 交互后展示的界面
            
        def examine(self):
            return self.content

        def show(self):
            if screen_name:
                renpy.show_screen(self.screen_name)
        def close(self):
            if screen_name:
                renpy.hide_screen(self.screen_name)



# 物品栏类定义
    """ 物品栏 """
    class Inventory:
            def __init__(self, max_slots=8):
                self.items = {}          # id -> Item 字典
                self.max_slots = max_slots # 最大物品数 根据实际需要更改,俺这里是8
                self.selected_item = None  # 当前选中的物品
            
            # 添加物品
            def add(self, item):
                if len(self.items) >= self.max_slots:
                    return False
                
                if item.id in self.items:
                    # 可堆叠物品处理
                    self.items[item.id].quantity += 1
                else:
                    self.items[item.id] = item
                return True
            
            # 移除物品
            def remove(self, item_id):
                if item_id in self.items:
                    self.items[item_id].quantity -= 1
                    if self.items[item_id].quantity <= 0:
                        del self.items[item_id]
                    # 如果物品被选中时移除,则取消选中状态
                    if self.selected_item and self.selected_item.id == item_id:
                        self.selected_item = None
                    return True
                return False

            def clear(self):
                self.items.clear()
                self.select_item = None
            
            # 检查是否拥有物品
            def has(self, item_id):
                return item_id in self.items
            # 获取物品
            def get(self, item_id):
                return self.items.get(item_id)
            # 选中/取消选中物品
            def select(self, item_id):

                if item_id is None:
                    if self.selected_item:
                        self.selected_item.selected = False
                        self.selected_item = None
                    return None
                
                # 如果重复选中则取消选中状态
                if self.selected_item and self.selected_item.id == item_id:
                    # 取消选中
                    self.items[item_id].selected = False
                    self.selected_item = None
                    return None
                else:
                    # 清除之前选中
                    if self.selected_item:
                        self.selected_item.selected = False
                    # 设置新选中
                    self.selected_item = self.items.get(item_id)
                    if self.selected_item:
                        self.selected_item.selected = True
                    return self.selected_item
                
            # 组合物品(未实现,有需要可以完善)
            # def combine(self, item1_id, item2_id, result_id):
            #     item1 = self.get(item1_id)
            #     item2 = self.get(item2_id)
                
            #     #判断双方是否可以组合
            #     if not (item1 and item2 and item1.combinable and item2.combinable):
            #         return None
                    
            #     #判断是否在配方表里
            #     if "这里判断是否有这个配方"
            #         # 移除原材料
            #         self.remove(item1_id)
            #         self.remove(item2_id)
            #         # 添加结果(需要在某处定义所有物品的创建逻辑)
            #         return result_id
            #     return None
            
            # 清除选中状态
            def clear_selection(self):
                if self.selected_item:
                    self.selected_item.selected = False
                    self.selected_item = None

init -1 python:
    def select_item(inventory, item):
        if item is None:
            return None
        return inventory.select(item.id)
    def check_item(inventory):
        if inventory.select_item.id:
            return inventory.select_item.id


# ============================================
# 全局物品栏
# ============================================

    # 全局物品栏
    inventory = Inventory(max_slots=12)
    
    # 物品数据库
    def create_item(item_id):
        items_test = {
            "paper": InventoryItem(
                "paper",
                "皱巴巴的纸条",
                "你忘了是谁给你的",
                "images/items/paper.png",
                usable=True
            ),
            "knife": InventoryItem(
                "knife",
                "小刀",
                "锋利的水果刀",
                "images/items/knife.png",
                usable=True
            )
        }
        return items_test.get(item_id, None)


物品栏界面(screen)

[RenPy] 纯文本查看 复制代码
#物品栏
screen inventory_screen():
    modal True
    zorder 100
    
    add Solid("#000000cc")
    
    # 物品栏面板
    frame:
        xalign 0.5
        yalign 0
        xsize 0.75
        ysize 500
        
        vbox:
            xalign 0.5
            spacing 30

            # 标题
            text "物品栏" size 30 xalign 0.5

            # 物品网格
            grid 8 1:
                spacing 15
                xalign 0.5
                
                # 遍历所有物品槽位
                for i in range(8):
                    $ curItem = list(inventory.items.values())[i] if i < len(inventory.items) else None
                    
                    button:
                        xsize 150
                        ysize 150
                        background Frame("#a29d81", 10, 10)

                        # 选中变色
                        if curItem and curItem.selected:
                            background Frame("#e22e2ea7", 10, 10)

                        action [
                            Function(select_item,inventory,curItem),
                            renpy.restart_interaction #重新启动当前交互行为
                        ]

                        if curItem:
                            vbox:
                                xalign 0.5
                                yalign 0
                                spacing 10
                                
                                # 物品图标
                                add curItem.image_path xalign 0.5
                                # 数量(大于1时显示)
                                if curItem.quantity > 1:
                                    text str(curItem.quantity) size 40 xalign 1.0 offset (10,-45) color "#3a1919" outlines [(2,"#d5a209",0,0)]
                                # 物品名称
                                text curItem.name size 24 xalign 0.5        

            #物品简介:
            if inventory.selected_item:
                frame:
                    background None
                    xalign 0.5
                    xysize(0.8,0.5)
                    text inventory.selected_item.description:
                        align (0.5,0.5)

        # 操作区域(可自行完善)
        
        hbox:
            xalign 0.5
            yalign 1.0
            spacing 20
            
            # 检查按钮
            if inventory.selected_item:
                textbutton "检查":
                    action NullAction()
            # 使用按钮
            if inventory.selected_item:
                textbutton "使用":
                    action [
                        SetVariable("using_item", inventory.selected_item),
                        SetVariable("default_mouse","item"),
                        Hide("inventory_screen")
                    ]
            # 关闭按钮
            textbutton "关闭":
                action [
                    Hide("inventory_screen")
                ]


关于交互界面:

[RenPy] 纯文本查看 复制代码
default using_item = None

default door_open = 0

# 物品栏按钮
screen inventory_button():
    zorder 50
    
    textbutton "打开背包":
        text_color "#000000"
        text_hover_color "#ff0000"
        pos (0.05, 0.1)
        action Show("inventory_screen")

screen house_screen:
    frame:
        xysize(1980,1080)
        background None
        if door_open==0:
            add "images/house1.png" #背景
        else:
            add "images/house2.png"

        if not inventory.has("knife"):
            imagebutton:
                pos(100,0.8)
                idle "images/items/knife.png"
                focus_mask True
                action Jump("pickup")

        #门
        button:
            idle_background None
            pos(1050,250)
            xysize(500,600)
            if using_item is not None:
                if (str(using_item.id)=="knife") and door_open==0:
                    action [SetVariable("using_item", None),Jump("knife_door")]
                elif(str(using_item.id)=="paper"):
                    action [SetVariable("using_item", None),Jump("paper_door")]
            else:
                if door_open==0:
                    action Jump("check_door")
                else:
                    action Jump("check_open")

        # 使用物品模式下的特殊处理
    if using_item:
        # 显示当前使用的物品图标跟随鼠标
        text "使用物品模式(右键取消)" pos (0.5,0.9) color "#4fbe33" size 48
        # 点击空白处取消使用
        key "mouseup_3" action [SetVariable("using_item", None), renpy.restart_interaction]



# 游戏在此开始。

label start:
    $ door_open = 0
    # 初始化物品栏(测试用)
    python:
        inventory.clear()
        inventory.add(create_item("paper"))
    show screen inventory_button
    call screen house_screen with dissolve
    jump house

label house:
    show screen house_screen
    window hide
    $ renpy.pause(hard=True)
    jump house
label check_door:
    show screen house_screen
    "好丑的门"
    jump house
label check_open:
    show screen house_screen
    "你不能出去,因为这只是个演示项目\n并不是一个完整版游戏"
    jump house
label pickup:
    python:
        inventory.add(create_item("knife"))
    show screen house_screen
    "你把刀捡了起来"
    jump house
label knife_door:
    show screen house_screen
    "门被劈开了"
    $ door_open=1
    jump house
label paper_door:
    show screen house_screen
    "你把纸揉成一团丢向门,然后又捡了回来....."
    jump house


其他:
这是萌新的第二个帖子(不会写帖子)所以排版会很糟糕
因为只是个简易代码,所以很多东西并不是很完善,可以根据需要以此扩展
使用物品功能只是草草在代码上实现,实际上可以通过切换鼠标样式弄出更好的演出效果
物品类方面还可以继续扩展,实现解谜游戏那样的组合或查看功能(没写完)
界面交互方面的代码感觉不够完美,仅供参考

评分

参与人数 1活力 +300 干货 +3 收起 理由
被诅咒的章鱼 + 300 + 3 感谢分享!

查看全部评分

 楼主| 发表于 昨天 19:23 | 显示全部楼层
通过网盘分享的文件:test_bag.rar
链接: https://pan.baidu.com/s/149PJRsxk1wxnnh45BJwoyA?pwd=2026 提取码: 2026
回复 支持 抱歉

使用道具 举报

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

本版积分规则

小黑屋|手机版|RenPy中文空间 ( 苏ICP备17067825号 )

GMT+8, 2026-5-4 17:15 , Processed in 0.025822 second(s), 10 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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