Godot 3.5.1中动态调用自定义按品质随机选择方法失败的问题求助
Godot 3.5.1中动态调用自定义按品质随机选择方法失败的问题求助
嘿,我完全懂你现在的困扰!跟着教程搭好了基础的随机物品系统,想扩展成按抽到的品质来随机英雄,结果动态调用方法的时候直接翻车了对吧?咱们来一步步拆解问题,找到解决办法~
问题出在哪?
你用的call("RandomPicker.new().pick_random_" + Portrait1 + "(items_array)")写法是有问题的——call()方法只能调用当前节点对象的方法,没办法直接解析这种“创建实例+调用方法”的复合字符串。而且这种写法也很容易出错,比如拼写问题或者方法不存在时直接报错。
解决方案1:先实例化Picker,再动态调用方法
先创建RandomPicker的实例,再用call()调用它的对应方法,这样就符合Godot的方法调用规则了:
func _on_RollButton_pressed(): randomize() var picker = RandomPicker.new() # 先抽到品质 var Portrait1 = picker.pick_random_item(items_array) # 动态调用对应品质的抽取方法 var method_name = "pick_random_" + Portrait1 if picker.has_method(method_name): var champion = picker.call(method_name, items_array) # 这里处理抽到的英雄,比如赋值给UI之类的 print("抽到的", Portrait1, "英雄:", champion) else: print("警告:找不到对应品质的抽取方法 -> ", method_name)
这里加了has_method()检查,能避免因为拼写错误(比如你代码里写的item.commmon多了一个m!)或者没有定义对应方法导致的崩溃,更安全。
解决方案2:用通用方法替代多个重复的pick函数(更推荐)
你现在写了pick_random_item、pick_random_Common等多个逻辑几乎一样的方法,其实可以合并成一个通用的“按品质抽取”方法,这样以后加新品质(比如Epic、Legendary)也不用写新方法,维护起来轻松很多:
第一步:修改RandomItem.gd,用统一的品质字段代替单个布尔值
把原来的export(bool) var common: bool = false改成通用的品质字符串(或者用枚举更规范,不过字符串更直观):
extends Resource class_name RandomItem export(String) var VALUE export(int) var PICK_CHANCE: int = 1 export(bool) var can_be_picked: bool = true export(String) var quality: String # 比如填"Common"、"Uncommon"、"Rare"等
第二步:在RandomPicker.gd里写通用的抽取方法
extends Node class_name RandomPicker export(Array, Resource) var items_list: Array = [] # 原来的随机抽品质方法保留 func pick_random_item(items_array: Array = items_list): var chosen_value = null if items_array.size() > 0: var overall_chance: int = 0 for item in items_array: if item.can_be_picked: overall_chance += item.PICK_CHANCE var random_number = randi() % overall_chance var offset: int = 0 for item in items_array: if item.can_be_picked: if random_number < item.PICK_CHANCE + offset: chosen_value = item.VALUE break else: offset += item.PICK_CHANCE return chosen_value # 新增:按指定品质随机抽取的通用方法 func pick_random_by_quality(target_quality: String, items_array: Array = items_list): var chosen_value = null if items_array.size() == 0: return chosen_value # 1. 计算该品质下所有可抽物品的总权重 var overall_chance: int = 0 for item in items_array: if item.quality == target_quality and item.can_be_picked: overall_chance += item.PICK_CHANCE # 如果该品质没有可抽物品,直接返回 if overall_chance == 0: print("没有可抽取的", target_quality, "品质英雄!") return chosen_value # 2. 生成随机数 var random_number = randi() % overall_chance # 3. 遍历抽取对应品质的物品 var offset: int = 0 for item in items_array: if item.quality == target_quality and item.can_be_picked: if random_number < item.PICK_CHANCE + offset: chosen_value = item.VALUE break else: offset += item.PICK_CHANCE return chosen_value
第三步:调用的时候就超简单啦
func _on_RollButton_pressed(): randomize() var picker = RandomPicker.new() # 先抽品质 var current_quality = picker.pick_random_item(items_array) # 再按品质抽英雄 var chosen_champion = picker.pick_random_by_quality(current_quality, items_array) print("抽到品质:", current_quality, ",对应英雄:", chosen_champion) # 这里把英雄赋值到UI上即可
额外小建议
- 可以把RandomPicker设置成AutoLoad单例,这样不用每次点击都
new()一个实例,不仅更高效,还能统一管理物品列表,避免重复加载资源。 - 检查拼写!你代码里的
if item.commmon:多了一个m,这种小错误很容易导致逻辑失效,一定要注意~
备注:内容来源于stack exchange,提问作者Jellyfish
相关产品推荐
相关产品推荐

