找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 282|回复: 0

[教程] 【功能组件】全随机游戏核心

[复制链接]
发表于 2026-4-24 23:45:08 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 Maz马 于 2026-5-18 01:20 编辑

全随机游戏就是肉鸽Rogue了...

26/5/17 重构了类和变量的命名风格,让局部变量语义更清晰一些,代码应该更干净健壮了

组件可以对接的功能
1随机取名,随机属性的角色
2随机取名,随机属性的道具
3随机地点,发生随机事件
4随机房间,放置随机家具
...
组件本身是定义了随机组装的规则而不是生产具体的对象
所以这是一个核心

                               
登录/注册后可看大图


在使用上需要自行设计接收者,可以是类,也可以是函数
这里主要还是提供一个“心脏”提供一个思路

如果只想使用,完全不关心内部
你只要知道,在配置好树图后,系统提交给你的是
一枚 随机种子

格式为字典:
{"units":单元列表,"nodes":节点列表,"votes":投票字典}
系统不知道你的节点内容,单元内容,给哪个tag投票
只根据你设计的路径图进行收集组装。

过去的思路是写表,在结构简单时还行
随机创建角色
但一旦可能性变多,分支复用,写表穷举就会十分臃肿
然后就演变成以下

第一部分:RG系统(直接复制为一个文件)
[RenPy] 纯文本查看 复制代码
# ============== 节点加权随机器 ================
# @ Maz马

# 简单理解 节点系统,图或者树取决于节点的组织方式

# RG_node ➡ RG_node     RG_node ➡ RG_unit
#         |                      |
#         ➡ RG_node             ➡ RG_unit
#         |                      |
#         ➡ RG_node             ➡ RG_unit

# 你可以视作你在玩大富翁,你通过投骰子 随机选择路径 到达 下一个地点(节点)
#
# 你到达这个地点,在人堆里选一个人对话(单元),他会告诉你"你变强了,也变高了"(投票➡{"强":1,"高":1})
#
# 重复这个过程直到你到达终点,你就会记录下 你去过的地点,和谁说过话,都说过什么
#
# 也就是一枚 包含了多种预设信息的 随机种子

# 随机种子注册表单 不建议直接访问
default _RG_SYS = {}
init python:
    import random
    class RG_unit:
        def __init__(self,_name,_roll=None,_node=None,_vote=None):
            self._name = _name             # 名称
            self._roll = _roll or 1        # 权重 数值越大概率越大,正数非0
            self._node = _node             # 所属节点(NODE对象)
            
            self._vote = _vote or {}       # 投票字典/词缀系统 {tags:value}
    class RG_node:
        def __init__(self,_name,_roll=None,_units=None,_parents=None,_childs=None):
            self._name = _name             # 名称
            self._roll = _roll or 1        # 权重 数值越大概率越大,正数非0
            self._units = _units or []     # 关联单元(UNIT对象池)
                                                          
            self._parents = _parents or [] # 父级节点(NODE对象池)
            self._childs = _childs or []   # 子级节点(NODE对象池)
    class RG_seed:
        def __init__(self,_units=None,_nodes=None):
            self._units = _units or []     # 收集到的单元(UNIT对象池)
            self._nodes = _nodes or []     # 收集到的节点(NODE对象池)
        @property # 随机种子
        def _seed(self):
            votes = {}
            for unit in self._units:
                if not unit._vote:
                    continue
                for k,v in unit._vote.items():
                    votes[k] = votes.get(k,0) + v
            # 创建种子
            result = {}
            result["units"] = [unit._name for unit in self._units]
            result["nodes"] = [node._name for node in self._nodes]
            result["votes"] = votes
            return result
    # 树图管理器
    class RG_graph:
        def __init__(self,_name,_registry):
            self._name = _name             # 树图名称

            self._node_pool = {}           # 节点表 NODE名 -> NODE对象
            self._unit_pool = {}           # 单元表 NODE名 -> UNIT对象列表

            self._cache_roots = []         # 所有根    [str,str...]
            self._cache_paths = []         # 节点路径  [str,str...]
            self._cache_index = {}         # 路径索引  {str:[str...]}

            self._registry = _registry     # 注册表单 {_name:{_id:_seed}}
        # 接入随机种子注册表单
        def set_graph(self):
            if self._name not in self._registry:
                self._registry[self._name] = {}
            print(f"※ 已接入ID:{self._name} 的树图")
        
        # 节点和单元一旦被删除或覆盖,会导致种子无法追溯
        # 虽然不会发生错误,但会在流程调试困难
        # 所以不提供删除方法,但可以断连孤立,不参与树图业务

        # 节点创建 关联 断连
        def set_node(self,_node_name,_roll=None):
            if _node_name not in self._node_pool:
                self._node_pool[_node_name] = RG_node(_node_name,_roll=_roll)
        def link_node(self,_node_name,_node_names):
            for k in _node_names:
                if k not in self._node_pool:
                    continue
                if self._node_pool[_node_name] not in self._node_pool[k]._parents:
                    self._node_pool[k]._parents.append(self._node_pool[_node_name])
                if self._node_pool[k] not in self._node_pool[_node_name]._childs:
                    self._node_pool[_node_name]._childs.append(self._node_pool[k])
        def unlink_node(self,_node_name,_node_names):
            if _node_name not in self._node_pool:
                return
            for k in _node_names:
                if k not in self._node_pool:
                    continue
                if self._node_pool[_node_name] in self._node_pool[k]._parents:
                    self._node_pool[k]._parents.remove(self._node_pool[_node_name])
                if self._node_pool[k] in self._node_pool[_node_name]._childs:
                    self._node_pool[_node_name]._childs.remove(self._node_pool[k])
        # 单元创建 关联 断连
        def set_unit(self,_node_name,_unit_names):
            # _unit_names 格式允许混合使用
            # [_name,_name...]
            # 或
            # [(_name,_roll,_vote),(_name,_roll,_vote)...]
            # 或
            # [(_name,_roll,_vote),[_name,_roll,_vote]...]
            if _node_name not in self._node_pool:
                print(f"!!!节点'{_node_name}'不存在,请先创建节点")
                return
            if _node_name not in self._unit_pool:
                self._unit_pool[_node_name] = []
            exist = {unit._name for unit in self._unit_pool[_node_name]}
            for i in _unit_names:
                if isinstance(i,(tuple,list)):
                    i1 = i[0]
                    i2 = i[1] if len(i) > 1 else None
                    i3 = i[2] if len(i) > 2 else None
                    if i2:
                        if not isinstance(i2,(int,float)):
                            print(f"!!!单元'{i1}'的权重不是数值,忽略该写入")
                            i2 = None
                    if i3:
                        if not isinstance(i3,dict):
                            print(f"!!!单元'{i1}'的投票字典不是字典类型,忽略写入")
                            i3 = None
                        else:
                            for k,v in i3.items():
                                if not isinstance(v,(int,float)):
                                    print(f"!!!单元'{i1}'的投票字典中键'{k}'的值'{v}'不是数值,忽略该键值对")
                                    # 设为0忽略
                                    i3[k] = 0
                else:
                    i1 = i
                    i2 = None
                    i3 = None
                if i1 not in exist:
                    self._unit_pool[_node_name].append(RG_unit(i1,_roll=i2,_vote=i3))
        def link_unit(self,_node_name=None):
            # 关联单个节点和节点下所有单元
            if _node_name:
                if _node_name not in self._unit_pool:
                    print(f"??? 节点'{_node_name}'下没有任何关联单元")
                    return
                if _node_name in self._unit_pool:
                    self._node_pool[_node_name]._units = self._unit_pool[_node_name]
                    for unit in self._unit_pool[_node_name]:
                        unit._node = self._node_pool[_node_name]
            # 关联所有节点和节点下所有单元
            else:
                for k in self._node_pool:
                    if k not in self._unit_pool:
                        print(f"??? 节点'{k}'下没有任何关联单元")
                for k in self._unit_pool:
                    self._node_pool[k]._units = self._unit_pool[k]
                    for unit in self._unit_pool[k]:
                        unit._node = self._node_pool[k]
        def unlink_unit(self,_node_name,_unit_names):
            if _node_name not in self._unit_pool:
                return
            for i in _unit_names:
                # 遍历副本
                for unit in self._unit_pool[_node_name][:]:
                    if unit._name == i:
                        self._unit_pool[_node_name].remove(unit)
                        break
            # 同步更新节点表
            if _node_name in self._node_pool:
                self._node_pool[_node_name]._units = self._unit_pool.get(_node_name,[])

        # 打印报告 用缓存打印树图结构(无报错)
        def _path_check(self):
            print(f"======= {self._name}树图报告 =======")
            print("!!!    注意核对根节点    !!!")
            print("!!!根节点不正常则环位于根 !!!")
            print()
            print("!!!     注意核对路径     !!!")
            print("!!!不检测*跳过节点*的逆向环!!!")
            if self._cache_roots:
                print(f"共 {len(self._node_pool)} 个节点,{len(self._cache_roots)} 个根节点")
                print()
                for i in self._cache_roots:
                    print(f"根节点: {i}")
            else:
                print("!!! 未找到根节点  !!!")
            if self._cache_paths:
                print(f"共 {len(self._cache_paths)} 条路径")
                print()
                for i,p in enumerate(self._cache_paths,1):
                    print(f"{i:3}. {' → '.join(p)}")
            else:
                print("!!! 未找到路径  !!!")
                print("请先调用 _path_update() 构建缓存")
                print("如果已经缓存,则节点未进行连接")
            print("====================================")
            print("\n\n\n")
        # 深度优先搜索/DFS 从指定节点出发 检测环 并 收集路径
        def _path_dfs(self,node,path,paths,visit):
            if node._name in visit:
                loop = path[visit[node._name]:] + [node._name]
                print(f"!!!检测到环: {' → '.join(loop)}")
                return
            visit[node._name] = len(path)
            # 每次加入节点
            path.append(node._name)
            # 开始递归
            # path [1]➡[1,2]➡[1,2,3]
            # paths []
            if node._childs:
                for child in node._childs:
                    self._path_dfs(child,path,paths,visit.copy())
            # 递归到最深处后把路径加入路径列表
            # path [1,2,3]
            # paths [[1,2,3]]
            else:
                paths.append(path.copy())
            # 弹出最后一个节点,检查2除了3能不能继续,逐级回退检查
            # paths [[1,2,3]]
            path.pop()
        # 遍历树图 报告错误,初始化缓存
        def _path_update(self):
            # 清空旧缓存
            self._cache_roots = []
            self._cache_paths = []
            self._cache_index = {}
            # 遍历节点池,锁定根,缓存根
            for node in self._node_pool.values():
                if not node._parents:
                    self._cache_roots.append(node._name)
                    # 从根开始,DFS检测,缓存路径
                    self._path_dfs(node,[],self._cache_paths,{})
            # 缓存索引 {节点:[包含节点的路径]}
            for path in self._cache_paths:
                for k in path:
                    if k not in self._cache_index:
                        self._cache_index[k] = []
                    self._cache_index[k].append(path)
            # 输出缓存信息
            self._path_check()
           
        # 随机游走
        def _random_root(self,_node_name):
            # 追溯到根,返回根到节点路径
            current = self._node_pool[_node_name]
            path = [current]
            while current._parents:
                # 权重随机父节点
                weight_nodes = [node._roll for node in current._parents]
                current = random.choices(current._parents,weights=weight_nodes,k=1)[0]
                path.insert(0,current)
            return path
        def _random_path(self,_node_name):
            # === 追溯,逆向树随机 ===
            root_to_current = self._random_root(_node_name)
            current = root_to_current[-1]
            select_nodes = root_to_current.copy()
            select_units = []
            for node in root_to_current:
                # 按权重随机收集单元
                if node._units:
                    weight_units = [unit._roll for unit in node._units]
                    select_units.append(random.choices(node._units,weights=weight_units,k=1)[0])
            
            # === 延伸,正向树随机 ===
            while current._childs:
                weight_nodes = [node._roll for node in current._childs]
                current = random.choices(current._childs,weights=weight_nodes,k=1)[0]
                select_nodes.append(current)
                # 按权重随机收集单元
                if current._units:
                    weight_units = [unit._roll for unit in current._units]
                    select_units.append(random.choices(current._units,weights=weight_units,k=1)[0])
            
            return RG_seed(_units=select_units,_nodes=select_nodes)
              
        # 对外接口
        def obj_random(self,_id,_node_name=None):
            # _id 从 随机种子注册表单 提取 结果对象 的 唯一标识
            if not self._cache_roots:
                print("!!!未初始化 树图")
                return
            if _node_name and _node_name not in self._node_pool:
                print(f"!!!节点'{_node_name}'不存在,请先创建节点")
                return
            if not _node_name:
                _node_name = random.choice(self._cache_roots)
            # 存储 随机种子 到 随机种子注册表单
            self._registry[self._name][_id] = self._random_path(_node_name)._seed
            return self._registry[self._name][_id]
        def obj_del(self,_id):
            if _id not in self._registry[self._name]:
                print("!!!未记录的id,删除无效")
                return
            del self._registry[self._name][_id]
            return
        def obj_get(self,_id):
            if _id not in self._registry[self._name]:
                print("!!!未记录的id,请先创建随机种子")
                return
            return self._registry[self._name].get(_id)
        def obj_ids(self):
            ids = list(self._registry[self._name].keys())
            print(f"树图 '{self._name}' 中共有 {len(ids)} 个随机种子: {ids}")
            return ids


第二部分 需要编写的部分:
[RenPy] 纯文本查看 复制代码
init python:
    # 命令式编写树图
    def init_tree1():
        # _()是支持多语言,可以不写。内部逻辑是原字符串,不会因为翻译导致系统错误。
        
        # 创建姓名树
        store.RGcnchar = RG_graph(_name="中文姓名",_registry=_RG_SYS)
        store.RGcnchar.set_graph()
        # ==================== 注册节点 ====================
        # 这一步注册你的节点,_roll是概率,数值越大出现的概率越大,不填则默认1,也就是均等概率
        store.RGcnchar.set_node(_("角色"))
        # 4/4+7的概率生成男角色,7/4+7的概率生成女角色
        store.RGcnchar.set_node(_("男"),_roll=4)
        store.RGcnchar.set_node(_("女"),_roll=7) 
        
        store.RGcnchar.set_node(_("男前名"))
        store.RGcnchar.set_node(_("男中名"))
        store.RGcnchar.set_node(_("男后名"))

        store.RGcnchar.set_node(_("女前名"))
        store.RGcnchar.set_node(_("女中名"))
        store.RGcnchar.set_node(_("女后名"))
        # ================ 回调绑定节点父子关系 ================
        # 树:绑定时,节点只有一个父级节点。输出风格被逐级影响,需要追溯唯一路径的结构

        # 连接节点,_node_names代表这个节点可以前往哪个节点
        store.RGcnchar.link_node(_("角色"),_node_names=[_("男"),_("女")])
        
        store.RGcnchar.link_node(_("男"),_node_names=[_("男前名")])
        store.RGcnchar.link_node(_("女"),_node_names=[_("女前名")])
        
        store.RGcnchar.link_node(_("男前名"),_node_names=[_("男中名")])
        store.RGcnchar.link_node(_("女前名"),_node_names=[_("女中名")])
        store.RGcnchar.link_node(_("男中名"),_node_names=[_("男后名")])
        store.RGcnchar.link_node(_("女中名"),_node_names=[_("女后名")])
        # ===================== 注册单元 =======================
        # 注册节点的内容单元,经过这个节点得到的东西,节点可以无单元
        store.RGcnchar.set_unit(_("男前名"),[
            _("赵"),_("钱"),_("孙"),_("李"),_("周"),_("吴"),_("郑"),_("王"),
            _("冯"),_("陈"),_("蒋"),_("沈"),_("韩"),_("杨"),_("朱"),_("秦"),
            _("许"),_("何"),_("吕"),_("张"),_("孔"),_("曹"),_("魏"),_("陶"),
            _("姜"),_("韦"),_("马"),_("袁"),_("柳"),_("史"),_("姚"),_("汪"),
            _("朱"),_("董"),_("梁"),_("杜"),_("阮"),_("蓝"),_("贾"),_("童"),
            _("武"),_("司马"),_("上官"),_("欧阳"),_("夏侯"),_("诸葛"),_("东方"),
            _("公孙"),_("宇文"),_("长孙"),_("慕容")])
        store.RGcnchar.set_unit(_("女前名"),[
            _("赵"),_("钱"),_("孙"),_("李"),_("周"),_("吴"),_("郑"),_("王"),
            _("冯"),_("陈"),_("蒋"),_("沈"),_("韩"),_("杨"),_("朱"),_("秦"),
            _("许"),_("何"),_("吕"),_("张"),_("孔"),_("曹"),_("魏"),_("陶"),
            _("姜"),_("韦"),_("马"),_("袁"),_("柳"),_("史"),_("姚"),_("汪"),
            _("朱"),_("董"),_("梁"),_("杜"),_("阮"),_("蓝"),_("贾"),_("童"),
            _("武"),_("司马"),_("上官"),_("欧阳"),_("夏侯"),_("诸葛"),_("东方"),
            _("公孙"),_("宇文"),_("长孙"),_("慕容")])
        
        # 允许便捷录入,但必须按照 _name字符,_roll数值,_vote字典 的顺序,否则忽略
        store.RGcnchar.set_unit(_("男中名"),[
            _("伯"),_("仲"),_("叔"),_("季"),_("子"),_("作"),_("文"),_("武"),
            _("元"),_("宇"),_("冠"),_("世"),_("震"),_("晓"),_("克"),_("轩"),
            _("昂"),_("光"),_("修"),_("柯"),_("云"),[_(""),15,{}]])
        # 例如 这里有22个字,空字符串的概率15,也就是15/15+22-1的概率生成 赵柔 这种没有中间字的名字
        store.RGcnchar.set_unit(_("女中名"),[
            _("温"),_("婉"),_("绮"),_("诗"),_("润"),_("涵"),_("曼"),_("玉"),
            _("元"),_("语"),_("言"),_("怜"),_("惜"),_("清"),_("雨"),_("文"),
            _("汶"),_("嫣"),_("芷"),_("初"),_("乐"),[_(""),15]])
        # 可以在 投票字典 里给任意词条投任意票,随机种子只执行收集、携带、统计,不管携带物的作用
        store.RGcnchar.set_unit(_("男后名"),[
            _("杰"),_("和"),_("祖"),_("雄"),_("长"),_("德"),_("儒"),[_("冲"),1,{"令狐冲就是个没有道德观念的SB":10}],
            _("高"),_("龙"),_("炎"),_("霖"),_("彻"),_("南"),_("爽"),[_("过"),1,{"杨过帅":10086,"杨过强":100}],
            _("谋"),_("晏"),_("天"),_("农"),_("坤")])
        store.RGcnchar.set_unit(_("女后名"),[
            _("柔"),_("珊"),_("怡"),_("容"),_("婷"),_("梦"),_("卿"),_("岚"),
            _("清"),_("琴"),_("瑶"),_("璇"),_("萱"),_("琪"),_("晴"),_("彤"),
            _("若"),_("凤"),_("稚"),_("乐"),_("然")])
        # ================= 节点与内容绑定关联 ===================
        # 注册顺序必须先set_node再set_unit,连接则无所谓,但必须先set再link

        # link_unit(节点名) 关联目标节点和节点下单元,无参则关联所有节点,单元
        store.RGcnchar.link_unit()
        # ====== 刷新树图数据,检测结构是否健康,在控制台输出 =======

        # 必须在连接变更后调用,因为性能消耗比较高,所以不封装,请记得手动调用
        store.RGcnchar._path_update()
        # 控制台输出树图结构,仅查看缓存,不刷新数据
        store.RGcnchar._path_check()
    def init_tree2():
        # 创建道具树
        store.RGitem = RG_graph(_name="修仙道具",_registry=_RG_SYS)
        store.RGitem.set_graph()
        # ==================== 注册空节点 ====================
        store.RGitem.set_node(_("道具"))

        store.RGitem.set_node(_("秘籍"))
        store.RGitem.set_node(_("药品"))
        
        store.RGitem.set_node(_("天阶"),_roll=0.05)
        store.RGitem.set_node(_("地阶"),_roll=0.15)
        store.RGitem.set_node(_("玄阶"),_roll=0.30)
        store.RGitem.set_node(_("黄阶"),_roll=0.50)
        
        store.RGitem.set_node(_("极品"),_roll=0.10)
        store.RGitem.set_node(_("上品"),_roll=0.20)
        store.RGitem.set_node(_("中品"),_roll=0.30)
        store.RGitem.set_node(_("下品"),_roll=0.40)
        
        store.RGitem.set_node(_("功法"),_roll=1.0)
        store.RGitem.set_node(_("身法"),_roll=1.0)
        store.RGitem.set_node(_("武技"),_roll=1.0)
        store.RGitem.set_node(_("战技"),_roll=1.0)
        
        store.RGitem.set_node(_("九品"),_roll=0.35)
        store.RGitem.set_node(_("六品"),_roll=0.30)
        store.RGitem.set_node(_("三品"),_roll=0.20)
        store.RGitem.set_node(_("一品"),_roll=0.15)
        
        store.RGitem.set_node(_("丹药"),_roll=0.50)
        store.RGitem.set_node(_("灵植"),_roll=0.50)
        # ================ 回调绑定节点父子关系 ================
        # 有向无环图:绑定时,节点有多个父级节点。

        # 输出风格不被逐级影响,只有递进关系的
        store.RGitem.link_node(_("道具"),_node_names=[_("秘籍"),_("药品")])
        
        store.RGitem.link_node(_("秘籍"),_node_names=[_("天阶"),_("地阶"),_("玄阶"),_("黄阶")])
        
        store.RGitem.link_node(_("天阶"),_node_names=[_("极品"),_("上品"),_("中品"),_("下品")])
        store.RGitem.link_node(_("地阶"),_node_names=[_("极品"),_("上品"),_("中品"),_("下品")])
        store.RGitem.link_node(_("玄阶"),_node_names=[_("极品"),_("上品"),_("中品"),_("下品")])
        store.RGitem.link_node(_("黄阶"),_node_names=[_("极品"),_("上品"),_("中品"),_("下品")])
        
        store.RGitem.link_node(_("极品"),_node_names=[_("功法"),_("身法"),_("武技"),_("战技")])
        store.RGitem.link_node(_("上品"),_node_names=[_("功法"),_("身法"),_("武技"),_("战技")])
        store.RGitem.link_node(_("中品"),_node_names=[_("功法"),_("身法"),_("武技"),_("战技")])
        store.RGitem.link_node(_("下品"),_node_names=[_("功法"),_("身法"),_("武技"),_("战技")])
        
        store.RGitem.link_node(_("药品"),_node_names=[_("九品"),_("六品"),_("三品"),_("一品")])
        
        store.RGitem.link_node(_("九品"),_node_names=[_("丹药"),_("灵植")])
        store.RGitem.link_node(_("六品"),_node_names=[_("丹药"),_("灵植")])
        store.RGitem.link_node(_("三品"),_node_names=[_("丹药"),_("灵植")])
        store.RGitem.link_node(_("一品"),_node_names=[_("丹药"),_("灵植")])
        # ===================== 注册内容 =======================
        store.RGitem.set_unit(_("天阶"),[_("大天衍"),_("无极"),_("万象"),_("九转"),_("四象")])
        store.RGitem.set_unit(_("地阶"),[_("阴阳"),_("梵天"),_("破军"),_("八荒"),_("天罡")])
        store.RGitem.set_unit(_("玄阶"),[_("两仪"),_("星月"),_("七杀"),_("镇狱"),_("地煞")])
        store.RGitem.set_unit(_("黄阶"),[_("孤峰"),_("崩山"),_("沧澜"),_("断水"),_("叠浪")])
        
        store.RGitem.set_unit(_("极品"),[_("真龙"),_("白虎"),_("朱雀"),_("真武"),_("鲲鹏")])
        store.RGitem.set_unit(_("上品"),[_("赤炎"),_("寒霜"),_("风雷"),_("穿云"),_("金刚")])
        store.RGitem.set_unit(_("中品"),[_("游龙"),_("伏虎"),_("贪狼"),_("长春"),_("灵蛇")])
        store.RGitem.set_unit(_("下品"),[_("一"),_("九"),_("十三"),_("二十四"),_("三十六"),""])
        
        store.RGitem.set_unit(_("功法"),[_("法"),_("经"),_("诀"),_("功"),_("残篇")])
        store.RGitem.set_unit(_("身法"),[_("变"),_("纵"),_("步"),_("遁"),_("闪")])
        store.RGitem.set_unit(_("武技"),[_("破"),_("斩"),_("掌"),_("拳"),_("指")])
        store.RGitem.set_unit(_("战技"),[_("术"),_("击"),_("剑"),_("刀"),_("枪")])
        
        store.RGitem.set_unit(_("九品"),[_("还魂"),_("断肠"),_("妖"),_("仙"),_("异域")])
        store.RGitem.set_unit(_("六品"),[_("金"),_("银"),_("暴血"),_("聚灵"),_("破境")])
        store.RGitem.set_unit(_("三品"),[_("固本"),_("培元"),_("金创"),_("提气"),_("补神")])
        store.RGitem.set_unit(_("一品"),[_("练气"),_("筑基"),_("回气"),_("益血"),_("治愈")])
        
        store.RGitem.set_unit(_("丹药"),[_("丹"),_("散"),_("汤"),_("液"),_("药")])
        store.RGitem.set_unit(_("灵植"),[_("叶"),_("花"),_("草"),_("果"),_("根")])
        # ================= 节点与内容绑定关联 ===================
        store.RGitem.link_unit()
        # ====================== 检测报告 =======================
        store.RGitem._path_update()
    # 在renpy完全启动后再初始化树图
    config.start_callbacks += [init_tree1,init_tree2,init_tree3]


第三部分 使用方法:
[RenPy] 纯文本查看 复制代码
# 使用方法
label RGUSE_test1:
    # 随机种子格式为 {"units":单元列表,"nodes":节点列表,"votes":投票字典}
    # 系统只负责生成和存储,不负责你如何使用
    
    # 用 xxx.obj_random("任意字符") 取得随机种子
    $ a = RGcnchar.obj_random('随机1')
    # 用 xxx.obj_random("任意字符",节点名) 取得定向随机种子
    $ b = RGcnchar.obj_random('随机1',"男")
    # 因为使用的是不同的树图,所以用同样的字符也没问题
    $ c = RGitem.obj_random('随机1')
    # 因为使用的是一样的树图,所以用同样的字符会覆盖原来的种子
    $ d = RGcnchar.obj_random('随机1')
    # 用 xxx.obj_get(_id) 获取已创建的种子
    $ e = RGcnchar.obj_get('随机1')
    # 用 xxx.obj_del(_id) 删除已创建的种子
    $ f = RGcnchar.obj_del('随机1')
    # 用 xxx.obj_ids()    查看所有已创建的随机种子ID
    $ g = RGcnchar.obj_ids()
    return


第四部分 高级业务类拓展:
[RenPy] 纯文本查看 复制代码
# 接收随机种子的例子
init python:
    # 道具类
    class Item:
        def __init__(self,name=None,kind=None,level=None,price=None,buff=None,atk=None,**kwargs):
            self.name = name
            self.kind = kind
            self.level = level
            self.price = price
            self.buff = buff
            self.atk = atk
        # 按你自己希望的方式解析种子,只在调用方法时覆盖属性
        def use_seed(self,seed):
            # 读取种子投票字典的词条,翻译成实际数据
            self.price = seed["votes"].get("价格",0)*20
            self.buff =  seed["votes"].get("燃烧",0)
            self.atk =   seed["votes"].get("攻击",0)
            
            # 把种子的单元列表组合起来,翻译多语言当作名字 (北冥+神+功)
            self.name = renpy.translate_string("".join(seed["units"]))
            # 把种子的节点列表倒数第1个节点,翻译多语言当作种类(道具》天阶》极品》功法,取功法)
            self.kind = renpy.translate_string("".join(seed["nodes"][-1]))
            # 把种子的节点列表第2个节点开始,赋予颜色,翻译多语言当作级别(天阶+极品+功法)
            result = renpy.translate_string("".join(seed["nodes"][1:]))
            if self.price <= 200:
                pass
            elif self.price <= 400:
                result = "{color=#39FF14}" + result + "{/color}"
            elif self.price <= 600: 
                result = "{color=#00BFFF}" + result + "{/color}"
            elif self.price <= 800:
                result = "{color=#BF00FF}" + result + "{/color}"
            elif self.price <= 900:
                result = "{color=#FF3333}" + result + "{/color}"
            elif self.price <= 1000:
                result = "{color=#FFBF00}" + result + "{/color}"
            self.level = result
            return
    # 角色类
    class Char:
        def __init__(self,_name=None,_kind=None,**kwargs):
            self._name =  _name
            self._kind =  _kind
        # 需要多语言时,使用装饰器进行一层包装,实际使用还是a.name或a.kind,但实际修改则是修改a._name
        @property
        def name(self):
            if self._name == None:
                return
            elif isinstance(self._name,list):
                return "".join(renpy.translate_string(item) for item in self._name)
            else:
                return renpy.translate_string(self._name)
        @property
        def kind(self):
            return renpy.translate_string(self._kind)
        def use_seed(self,seed):
            self._name = seed["units"].copy()   #孙+伯+符
            self._kind = seed["nodes"][1]       #角色》男》男前名》男中名》男后名,取男
    
    # 原生角色类  用 猴子补丁 注入种子方法
    def use_seed(self,seed):
        self._name = seed["units"].copy()
    def adv_set_name(self,value):
        self._name = value
    def adv_cover_name(self):
        if self._name is None:
            return
        if isinstance(self._name, list):
            return "".join(renpy.translate_string(item) for item in self._name)
        else:
            return renpy.translate_string(self._name)
    # 新增覆盖属性
    ADVCharacter._name = None
    # 注入方法
    ADVCharacter.use_seed = use_seed
    # 注入覆盖方法
    ADVCharacter.name = property(adv_cover_name,adv_set_name)

# 使用方法
label RGUSE_test2:
    # 取得随机种子
    $ a = RGcnchar.obj_random('随机1')
    # 创建原生角色
    $ xx = Character("测试角色")
    # 调用解析种子的方法,更新这个对象的数据一次
    $ xx.use_seed(a)
    "现在xx的数据是解析种子得到的,名字是[xx.name]"
    # 创建上面接收种子的示例对象
    $ b = Char(_name="默认数据",_kind="默认数据")
    # 调用解析种子的方法,更新这个对象的数据一次
    $ b.use_seed(a)
    "现在b的数据是解析种子得到的,名字是[b.name],类别是[b.kind]"
    # 可以重复覆盖
    $ b._name = "后续覆盖"
    "解析种子不影响你的修改,只是赋值了一次,名字是[b.name],类别是[b.kind]"
    return


注意,此处只是数据实现,假设要批量的,自动管理多角色、多道具
请查阅 多数据管理技巧

#点击头像 查看我写的更多屎
粉身碎骨浑不怕,要留答辩在人间


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

本版积分规则

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

GMT+8, 2026-5-18 01:33 , Processed in 0.017725 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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