C++中为Spell添加可传自定义参数的函数指针并调用方案
问题描述
现有Spell类通过vector<function<void()>> _spell_effects存储技能效果,SpellManager在创建Spell时绑定固定参数的lambda作为效果。但调用InvokeEffect时无法传入自定义参数,所有效果只能用预设值。需要重构代码,实现调用技能效果时能传入自定义参数。
解决方案
1. 修改Spell类的效果存储与调用逻辑
把原有的无参function改成支持接收参数列表的类型,用function<void(vector<any>)>统一处理,这样调用时可以传入任意类型的参数。
修改Spell.h中的定义:
#include <any> #include <vector> #include <functional> class Spell { // 原有属性(duration、cooldown等)保留 std::vector<std::function<void(std::vector<std::any>)>> _spell_effects; public: void SetSpellEffects(std::vector<std::function<void(std::vector<std::any>)>> spell_effects) { _spell_effects = spell_effects; } // 重构InvokeEffect,支持传入自定义参数 void InvokeEffect(size_t index, std::vector<std::any> params = {}) { if (index < _spell_effects.size()) { _spell_effects[index](params); } } };
2. 调整SpellManager中添加效果的方式
在AddSpellEffects里,把lambda改成接收vector<any>参数,内部解析参数后传递给实际的效果函数:
void SpellManager::AddSpellEffects(Spell* spell) { std::vector<std::function<void(std::vector<std::any>)>> effects; // 火球基础效果:解析玩家、敌人列表参数 effects.push_back([this](std::vector<std::any> params) { if (params.size() < 2) return; PlayerCharacter* player = std::any_cast<PlayerCharacter*>(params[0]); std::vector<Character*>* enemies = std::any_cast<std::vector<Character*>*>(params[1]); this->Fireball_Default(player, *enemies); }); // 火球2级效果:无参数直接调用 effects.push_back([this](std::vector<std::any>) { this->Fireball_Level2(); }); // 火球3级效果:解析伤害参数,无参数时用默认值 effects.push_back([this](std::vector<std::any> params) { int damage = 5; if (!params.empty()) { damage = std::any_cast<int>(params[0]); } this->Fireball_Level3(damage); }); spell->SetSpellEffects(effects); }
3. 调用时传入自定义参数
在业务代码里,根据不同效果的需求传入对应参数:
// 调用火球基础效果,传入玩家和敌人列表 std::vector<std::any> default_params; default_params.push_back(player); default_params.push_back(&_enemies); player->GetActives()[0]->InvokeEffect(0, default_params); // 调用火球3级效果,传入自定义伤害值10 std::vector<std::any> level3_params; level3_params.push_back(10); player->GetActives()[0]->InvokeEffect(2, level3_params); // 调用火球2级效果,无需参数直接调用 player->GetActives()[0]->InvokeEffect(1);
可选优化:类型安全封装
如果担心any的类型不安全问题,可以为每个技能效果定义专属参数结构体:
// 定义火球基础效果的参数结构体 struct FireballDefaultParams { PlayerCharacter* caster; std::vector<Character*>* targets; }; // 修改对应的lambda effects.push_back([this](std::vector<std::any> params) { if (params.empty()) return; FireballDefaultParams* p = std::any_cast<FireballDefaultParams*>(params[0]); this->Fireball_Default(p->caster, *p->targets); }); // 调用时传入结构体 FireballDefaultParams params{player, &_enemies}; player->GetActives()[0]->InvokeEffect(0, {¶ms});
内容的提问来源于stack exchange,提问作者crvenkapavica
相关产品推荐
相关产品推荐

