找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1021|回复: 7

[已解决] 随机创建角色

[复制链接]
发表于 2025-9-16 10:20:19 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 Maz马 于 2025-9-16 12:58 编辑

嗯,写轮子碰到挠头问题来抛史了
佬可以直接拉到最下方查看我的问题,我会写过程,因为目前的代码是使用十分邪门的方案...
我认为得说明一下,我是怎么得到这个方案的...

过程:
起因:想做一个肉鸽游戏,可以便捷的创建不同角色名的角色
思路是先定义一个姓名列表first_names,一个姓氏列表last_names,随机抽取并组合字串,然后创建角色实例
[RenPy] 纯文本查看 复制代码
init python:
    import random
    
    # 角色池
    role_data = {}  # {"角色ID": Character对象}
    
    # 名称池
    first_names = [_("艾玛"), _("诺亚"), _("奥利维亚")]
    last_names = [_("史密斯"), _("杰森"), _("威廉")]

(做的是西幻,姓氏在后,但这不重要)
这一步是没问题的,接下来随机生成,并添加进role_data = {} # {角色ID: Character对象}就好了
[RenPy] 纯文本查看 复制代码
#init python:
    #import random
    #上接
    def create_role(role_id):
        #懒加载,不存在id才创建,
        if role_id in role_data:
            return role_data[role_id]
        
        first_name = random.choice(first_names)
        last_name = random.choice(last_names)
        
        # 创建Character对象
        character = Character("first_name+last_name", dynamic=True)
        
        # 存储到角色池
        role_data[role_id] = character
        
        return character

此时碰到了问题,在反复调整下,运行会有三种情况,但具体过程怎么调的不太记得了,总结如下:

1.因为作用域问题丢失first_name、last_name,假设设为全局变量的话,那么每一个随机出来的角色,都得有对应的变量...
2.调整成character = Character(first_name+last_name)的话,character的name会立刻格式化成first_name+last_name的值,而不是引用到名称池,也就是_()多语言函数并不会起作用
3.用循环调整成character = Character("first_names[x]+last_names[y]", dynamic=True)的话,角色池role_data里的character对象
  实际上会全部指向同一个名称组合,因为x和y不是硬编码的值,又引回去了...如果用值拷贝的话,又回到第二点,会把表达式格式化成值,_()不起作用


属实是左右脑互博了...

然后就得出下面这个方案...
character = Character("first_names[x]+last_names[y]", dynamic=True)这种写法来解决第一点

renpy.translate_string()立即翻译一次这个函数来解决格式化和_()文本值计算的问题
(上一次用是手机组件匹配头像,大概是这样{renpy.translate_string(角色名):头像},也很邪门就是了,所以很有经验了

再创建一个字典来记录随机得到的first_name,last_name序列,保持随机性,用来硬编码,避免所有的character的名字指向同一个组合
最后,随机穷举一部分角色,看情况调用和维护角色池...



问题:不想穷举
因为我py基础真的很烂...虽然算是实现了,但是有没有什么办法(这太屎了,救一下
[RenPy] 纯文本查看 复制代码
init python:
    import random
    
    # 角色池
    role_data = {}  # {"角色ID": Character对象}
    
    # 名称池
    first_names = [_("艾玛"), _("诺亚"), _("奥利维亚")]
    last_names = [_("史密斯"), _("杰森"), _("威廉")]
    role_name_data = {}

    # 先随机生成索引字典
    for i in range(50):
        first_idx = random.randint(0, len(first_names) - 1)
        last_idx = random.randint(0, len(last_names) - 1)
        role_name_data[i] = (first_idx, last_idx)
    
    print(role_name_data)
        
    role_data[0] = Character("renpy.translate_string(first_names[role_name_data[0][0]]) + renpy.translate_string(last_names[role_name_data[0][1]])", dynamic=True)
    role_data[1] = Character("renpy.translate_string(first_names[role_name_data[1][0]]) + renpy.translate_string(last_names[role_name_data[1][1]])", dynamic=True)
    role_data[2] = Character("renpy.translate_string(first_names[role_name_data[2][0]]) + renpy.translate_string(last_names[role_name_data[2][1]])", dynamic=True)
    role_data[3] = Character("renpy.translate_string(first_names[role_name_data[3][0]]) + renpy.translate_string(last_names[role_name_data[3][1]])", dynamic=True)
    role_data[4] = Character("renpy.translate_string(first_names[role_name_data[4][0]]) + renpy.translate_string(last_names[role_name_data[4][1]])", dynamic=True)
    role_data[5] = Character("renpy.translate_string(first_names[role_name_data[5][0]]) + renpy.translate_string(last_names[role_name_data[5][1]])", dynamic=True)
    role_data[6] = Character("renpy.translate_string(first_names[role_name_data[6][0]]) + renpy.translate_string(last_names[role_name_data[6][1]])", dynamic=True)
    role_data[7] = Character("renpy.translate_string(first_names[role_name_data[7][0]]) + renpy.translate_string(last_names[role_name_data[7][1]])", dynamic=True)
    role_data[8] = Character("renpy.translate_string(first_names[role_name_data[8][0]]) + renpy.translate_string(last_names[role_name_data[8][1]])", dynamic=True)
    role_data[9] = Character("renpy.translate_string(first_names[role_name_data[9][0]]) + renpy.translate_string(last_names[role_name_data[9][1]])", dynamic=True)
    role_data[10] = Character("renpy.translate_string(first_names[role_name_data[10][0]]) + renpy.translate_string(last_names[role_name_data[10][1]])", dynamic=True)
    role_data[11] = Character("renpy.translate_string(first_names[role_name_data[11][0]]) + renpy.translate_string(last_names[role_name_data[11][1]])", dynamic=True)
    role_data[12] = Character("renpy.translate_string(first_names[role_name_data[12][0]]) + renpy.translate_string(last_names[role_name_data[12][1]])", dynamic=True)
    role_data[13] = Character("renpy.translate_string(first_names[role_name_data[13][0]]) + renpy.translate_string(last_names[role_name_data[13][1]])", dynamic=True)
    role_data[14] = Character("renpy.translate_string(first_names[role_name_data[14][0]]) + renpy.translate_string(last_names[role_name_data[14][1]])", dynamic=True)
    role_data[15] = Character("renpy.translate_string(first_names[role_name_data[15][0]]) + renpy.translate_string(last_names[role_name_data[15][1]])", dynamic=True)
    role_data[16] = Character("renpy.translate_string(first_names[role_name_data[16][0]]) + renpy.translate_string(last_names[role_name_data[16][1]])", dynamic=True)
    role_data[17] = Character("renpy.translate_string(first_names[role_name_data[17][0]]) + renpy.translate_string(last_names[role_name_data[17][1]])", dynamic=True)
    ......
    role_data[49] = Character("renpy.translate_string(first_names[role_name_data[49][0]]) + renpy.translate_string(last_names[role_name_data[49][1]])", dynamic=True)









评分

参与人数 1活力 +300 收起 理由
烈林凤 + 300 不是哥们

查看全部评分

 楼主| 发表于 2025-9-17 01:30:05 | 显示全部楼层
烈林凤 发表于 2025-9-16 21:14
一直版主版主叫多膈应,按群里的名字叫多好,老马)

回复 支持 1 抱歉 0

使用道具 举报

发表于 2025-9-16 21:14:57 | 显示全部楼层
Maz马 发表于 2025-9-16 12:56
版主说的对啊!我生成那么多Character干嘛
留一个当显示的接口,其他调数据就是了
包括其他属性一起打进表 ...

一直版主版主叫多膈应,按群里的名字叫多好,老马)
回复 支持 1 抱歉 0

使用道具 举报

 楼主| 发表于 2025-9-16 12:56:30 | 显示全部楼层
本帖最后由 Maz马 于 2025-9-21 22:19 编辑
烈林凤 发表于 2025-9-16 12:13
这一长串重复的代码给我看应激了,其实不太懂非要生成这么多Character(

版主说的对啊!我生成那么多Character干嘛
留一个当显示的接口,其他调数据就是了
包括其他属性一起打进表里,在history里也测试过了,没问题了!
这样的话,那么生成角色的函数就没必要随机50个了
可以动态生成,不需要穷举,也完美的避开了引用和变量值格式化的问题
我左脑攻击右脑了。
还有点"支持"不小心点成"抱歉"(sry)
已解决!
[RenPy] 纯文本查看 复制代码
init python:
    import random
    
    # 角色池
    role_data = {}
     
    # 名称池
    first_names = [_("艾玛"), _("诺亚"), _("奥利维亚")]
    last_names = [_("史密斯"), _("杰森"), _("威廉")]
 
    # 动态生成角色数据
    def generate_role_name(role_id):
        # 懒加载
        if role_id not in role_data:
            first_idx = random.randint(0, len(first_names) - 1)
            last_idx = random.randint(0, len(last_names) - 1)
            role_data[role_id] = (first_idx, last_idx)#可以扩展其他数据,同样用序列提取
        return role_id
 
default rc_data = 0     
default randomchar = Character("renpy.translate_string(first_names[role_data[rc_data][0]]) + renpy.translate_string(last_names[role_data[rc_data][1]])", dynamic=True)
 
# 使用预生成的角色
label start:
    # 使用角色0,如果不存在会自动生成
    $ rc_data = generate_role_name(0)
    randomchar "你好,我是角色0"
     
    $ rc_data = generate_role_name(1)
    randomchar "我是角色1"
    
    $ rc_data = generate_role_name(2)
    randomchar "我是新生成的角色2"
    return

回复 支持 1 抱歉 0

使用道具 举报

发表于 2025-9-16 12:13:10 | 显示全部楼层
这一长串重复的代码给我看应激了,其实不太懂非要生成这么多Character(
回复 支持 0 抱歉 1

使用道具 举报

发表于 2025-9-17 11:38:41 | 显示全部楼层
楼主开头的思路是正确的,用字典role_data = {} # {"角色ID": Character对象}保存随机角色。

根据这个思路做了点修改:
[RenPy] 纯文本查看 复制代码
init python:
    import random

    # 角色池
    role_data = {}

    # 名称池
    first_names = ["艾玛", "诺亚", "奥利维亚"]
    last_names = ["史密斯", "杰森", "威廉"]

    # 动态生成角色数据
    def generate_role_name(role_id):
        # 既然有变量作用域问题,那就引入全局变量
        global role_data, first_names, last_names
        if role_id not in role_data:
            first_name = random.choice(first_names)
            last_name = random.choice(last_names)
            role_data[role_id] = (Character(name=f"{first_name} {last_name}"))
        return role_id

default rc_data = 0
# default randomchar = Character("renpy.translate_string(first_names[role_data[rc_data][0]]) + renpy.translate_string(last_names[role_data[rc_data][1]])", dynamic=True)


label start:

    # 使用角色0,如果不存在会自动生成
    $ rc_data = generate_role_name(0)
    # randomchar "你好,我是角色0"
    role_data[rc_data] "你好,我是角色0"

    $ rc_data = generate_role_name(1)
    # randomchar "我是角色1"
    role_data[rc_data] "我是角色1"
     
    $ rc_data = generate_role_name(2)
    # randomchar "我是新生成的角色2"
    role_data[rc_data] "我是新生成的角色2"


另外,实际项目还需要在 role_data[role_id] = (Character(name=f"{first_name} {last_name}")) 这步之前进行一次检查,role_data中是否存在完全同名的角色,如果存在则返回已存在角色的id。
回复 支持 抱歉

使用道具 举报

 楼主| 发表于 2025-9-17 18:46:18 | 显示全部楼层
本帖最后由 Maz马 于 2025-9-17 18:56 编辑
被诅咒的章鱼 发表于 2025-9-17 11:38
楼主开头的思路是正确的,用字典role_data = {} # {"角色ID": Character对象}保存随机角色。

根据这个思路 ...

不是的,章鱼老师,这里实际上是多语言的问题
我指的作用域问题是
假如生成的是Character(name=f"{first_name} {last_name}"),这样的话名字会立即被计算,没有办法自动多语言
如果直接使用Character("first_name+last_name", dynamic=True),这里会出现作用域问题,因为first_name是函数内部的,出来之后会报变量未定义

主要问题是让Character的name引用回名称池(延迟求值),达到随机生成角色并且自动多语言

但我也认为字典使用{id:角色实例}的格式更加符合直觉以及数据管理,所以现在我修改成以下了
原生的char完全只当作ui显示的接口

最开始也考虑了查重的问题,但由于还在起草阶段,我慢慢写吧(QAQ
[RenPy] 纯文本查看 复制代码
init python:
    import random
    
    # 角色池
    role_data = {}#{id:存储数据的角色类}
     
    # 属性池
    sexes = [_("男"), _("女"), _("沃尔玛购物袋")]
    first_names_boy = [
        _("诺亚"), _("利亚姆"), _("奥利弗"), _("以利亚"), _("卢卡斯"), 
        _("马特奥"), _("利维"), _("阿瑟"), _("西奥多"), _("亨利"),
        _("亚历山大"), _("塞巴斯蒂安"), _("本杰明"), _("伊桑"), _("丹尼尔")]
    
    first_names_girl = [
        _("艾玛"), _("奥利维亚"), _("夏洛特"), _("索菲亚"), _("阿米莉亚"),
        _("伊莎贝拉"), _("米娅"), _("埃维莉娜"), _("卢娜"), _("艾娃"),
        _("哈珀"), _("吉安娜"), _("伊丽莎白"), _("埃莉诺"), _("斯卡利特")]
    
    last_names = [
        _("史密斯"), _("约翰逊"), _("威廉姆斯"), _("布朗"), _("琼斯"),
        _("米勒"), _("戴维斯"), _("加西亚"), _("罗德里格斯"), _("威尔逊"),
        _("马丁内斯"), _("安德森"), _("泰勒"), _("托马斯"), _("杰克逊")]

    # 测试用的临时角色类
    class testrole:
        def __init__(self, id, first_name, last_name, sex):
            self.id = id
            self.first_name = first_name
            self.last_name = last_name
            self.sex = sex
        #只是临时的,这里未来会写成完善的管理系统,此处仅测试名称引用以及多语言的问题

    # 调用或生成角色数据
    def generate_role_name(role_id):
        # 懒加载
        if role_id not in role_data:
            sex = random.choice(sexes)
            if sex == _("男"):
                first_name = random.choice(first_names_boy)
            elif sex == _("女"):
                first_name = random.choice(first_names_girl)
            else:
                first_name = random.choice(first_names_boy+first_names_girl)
            last_name = random.choice(last_names)
            role_data[role_id] = testrole(role_id,first_name,last_name,sex)

        #实际就是保持了引用的指向,在显示时才会延迟计算出角色名字,以适配多语言
        #真实的角色是testrole(),Character()相当于screen say(bushi
        return role_id
 
default rc_id = 0     
default randomchar = Character("renpy.translate_string(role_data[rc_id].first_name) + renpy.translate_string(role_data[rc_id].last_name)", dynamic=True)

# 使用预生成的角色
label start:
    $ rc_id = generate_role_name(0)
    randomchar "你好,我是角色0"
     
    $ rc_id = generate_role_name(1)
    randomchar "我是角色1"
    
    $ rc_id = generate_role_name(2)
    randomchar "我是新生成的角色2"
    return
回复 支持 抱歉

使用道具 举报

发表于 2025-9-18 12:07:06 | 显示全部楼层
楼主的做法并没有实现“创建”随机角色,而是修改角色名称为姓名的随机组合。
如果游戏只需要一个随机姓名的角色,这么搞没问题。如果游戏需要多个角色,这么搞一定会出问题。
比如,修改角色1的好感度,会发现角色2的好感度也变了。因为整个游戏从头到尾只有一个Character对象,只在显示对话时修改了say界面中的who而已。
回复 支持 抱歉

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-1 13:01 , Processed in 0.030053 second(s), 12 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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