游戏战斗逻辑:
AB阵容各5名英雄,根据出手顺序依次进行攻击或释放技能。部分技能在战斗开始时释放,部分技能在满足某种事件时释放。
我的技能设计思路是:
1、创建技能数据类:定义技能的完整数据。
2、创建技能释放类:用于配置技能和释放技能。
3、创建技能效果算法类:用于实现每一种技能效果的算法。(例如增减hp,atk,各种控制效果等…)
4、创建技能作用目标算法类:实现对每一种技能效果的作用目标的匹配。(攻击单个,多个,随机目标,或者特定目标)
由于每一个技能都包含数种效果:有的一种,有的两种,有的3种…数量不限。
我通过在技能配表里,将每一个技能的多种技能效果拆解出来,分别根据其释放时机,作用目标,作用效果,持续回合等一一对应。
例如一个技能有4种效果,通过拆解后可以得到4种技能效果的数据。包含作用目标,作用效果,持续回合等…
在技能释放脚本里,先讲单个技能拆解为多种技能效果,通过for循环依次执行这4种效果,成功实现对绝大多数技能的释放。
但是,这种实现思路无法做到对事件技能的配表数据标记读取,进行动态注册和释放。
例如技能1:攻击力增加30%,防御力增加30%,对流血目标额外造成50%伤害,且每有一个友军阵亡,增加自身20%攻击,10%暴击率,20%爆伤,直到战斗结束。
这个技能包含6种效果,2个事件。
如果按照我之前的设计思路,只能在技能配表里拆解得到6种技能效果,并不能让程序知道还有两个事件,且这两个事件分别对应哪几种技能效果。
前2种技能效果:攻击力增加30%,防御力增加30%,这两项为普通的技能效果,按之前的思路可以实现。
第3种技能效果:对流血目标额外造成50%伤害。这个需要给自身注册一个在造成伤害时判断被攻击目标是否流血增伤的事件,该事件调用的是第三项技能效果。
第4,5,6项技能效果:需要给自身注册一个监控全体敌人是否阵亡的事件,并施加第4,5,6种效果。
问题1:我如何让程序知道1个完整的技能里的多种技能效果,包含哪些事件技,并且每种事件技分别对应哪些效果。是改变技能配表结构吗?修改我之前的设计思路吗?有什么更好的实现思路?
问题2:该如何实现这种单个技能的多种效果里糅合着不同的事件技且还对应不同的效果?
对于问题1,可以将技能配表的数据结构进行调整,引入事件数据结构,将技能效果与事件一一对应。例如,定义技能效果的数据结构如下:
class SkillEffect {
int target; // 攻击目标类型
int effect; // 效果类型
int turns; // 持续回合数
float amount; // 数值
int event; // 事件类型
}
其中,event是事件类型,可以为0表示无事件,其他数字表示特定的事件类型。定义事件数据结构如下:
class SkillEvent {
int effectIndex; // 触发事件对应的技能效果索引
int event; // 事件类型
}
在技能配表数据中,可以将技能效果和事件数据分别存储在不同的数据结构中,例如:
class SkillData {
int id; // 技能ID
List<SkillEffect> effects; // 技能效果
List<SkillEvent> events; // 事件格数据
}
这样可以让程序知道一个完整的技能里的多种技能效果,包含哪些事件技,并且每种事件技分别对应哪些效果。
对于问题2,可以在释放技能的逻辑中,遍历每个技能效果,判断是否有事件技。如果有事件技,则将事件注册到相应的事件处理器中,事件处理器负责监控触发相应的事件,并执行对应的效果。可以使用观察者模式实现事件处理器。在技能释放脚本中,将所有技能效果注册到对应的事件处理器中,事件处理器负责监听比如"敌人流血增伤"、"阵亡增益"等事件,一旦事件触发,处理器便会通知对应的技能效果进行操作。
例如,对于技能1中的第3和第4、5、6个效果,可以分别定义事件为"敌人流血"和"友军阵亡",将其注册到事件处理器中,事件处理器监听相应的事件并通知对应效果生效。
class SkillEventProcessor {
map<int, list<int>> effectEventMap; // 技能效果与事件的映射表
map<int, SkillEventCallback> eventCallbackMap; // 每个事件类型对应的回调处理函数
void registerEffectWithEvent(int effectIndex, int event) {
if (effectEventMap.find(event) == effectEventMap.end()) {
effectEventMap[event] = list<int>();
}
effectEventMap[event].push_back(effectIndex);
}
void registerCallbackForEvent(int event, SkillEventCallback callback) {
eventCallbackMap[event] = callback;
}
void processEvent(int event, SkillEventData eventData) {
if (eventCallbackMap.find(event) != eventCallbackMap.end()) {
for (auto effectIndex : effectEventMap[event]) {
auto& effect = effects[effectIndex];
if (effect.event == event) {
eventCallbackMap[event](effect, eventData);
}
}
}
}
}
在技能释放脚本中,注册事件处理器,以及每个事件所对应的回调函数:
class MySkillScript {
SkillEventProcessor eventProcessor; // 注册事件处理器
// 注册事件和回调函数
void registerEventsAndCallbacks(SkillData skill) {
for (auto event : skill.events) {
eventProcessor.registerEffectWithEvent(event.effectIndex, event.event);
switch (event.event) {
case EVENT_ENEMY_BLEED:
eventProcessor.registerCallbackForEvent(EVENT_ENEMY_BLEED, [=](SkillEffect& effect, SkillEventData& data) {
if (data.target.isBleeding()) {
applyEffect(effect, data); // 对目标施加效果
}
});
break;
case EVENT_ALLY_DIED:
eventProcessor.registerCallbackForEvent(EVENT_ALLY_DIED, [=](SkillEffect& effect, SkillEventData& data) {
if (data.allyDied()) {
applyEffect(effect, data); // 对自身施加效果
}
});
break;
// 处理其他事件...
}
}
}
void castSkill(SkillData skill, list<Target> targets) {
registerEventsAndCallbacks(skill);
// 遍历技能效果
for (auto effect : skill.effects) {
if (effect.event == 0) {
applyEffect(effect, targets); // 直接对目标施加效果
}
}
}
void applyEffect(SkillEffect effect, list<Target> targets) {
// 根据效果的目标类型,从传入的目标列表中选择目标
auto targets = chooseTargets(effect.target, targets);
// 根据效果类型和数值,对目标施加效果
for (auto target : targets) {
switch (effect.effect) {
case EFFECT_INCREASE_ATTACK:
target.increaseAttack(effect.amount, effect.turns);
break;
case EFFECT_INCREASE_DEFENSE:
target.increaseDefense(effect.amount, effect.turns);
break;
case EFFECT_EXTRA_DAMAGE_TO_BLEEDING:
// 对流血目标施加额外伤害效果
auto eventData = SkillEventData(target);
eventProcessor.processEvent(EVENT_ENEMY_BLEED, eventData);
break;
// 处理其他效果...
}
}
}
}
通过这种设计思路,可以实现单个技能的多种效果里糅合着不同的事件技且还对应不同的效果。
一种实现方式如下:
在技能配表(Skill Data Class)中增加“事件(Event)”字段。每个技能效果(Skill Effect Class)可以包含一个或多个触发事件。比如,你的技能1可以设置两个事件,一个是"攻击事件",一个是"友军阵亡事件"。
技能效果类(Skill Effect Class)要增加一个"应用效果(ApplyEffect)"的方法,当满足条件(例如攻击时,或者友军阵亡时)时,执行具体的效果(例如增加攻击力,防御力等)。
在技能释放类(Skill Cast Class)中,读取技能配表数据,创建对应的技能效果实例,并将它们添加到持有技能的对象上。并且根据每个技能效果的事件注册到对应的事件监听器上。
在游戏逻辑中,当相关的事件触发时,例如角色攻击,友军阵亡,等等,调用所有注册的事件监听器,让它们处理自己的效果。
这样做的好处是,技能的设计非常灵活。技能效果和触发条件(事件)都可以独立配置,技能效果也可以在不同的技能中重复使用。
这里是一个简化版的伪代码实现:
// 技能效果类
public class SkillEffect {
public string Event { get; set; } // 触发事件
public Action<Hero, Hero> Effect { get; set; } // 技能效果
public void ApplyEffect(Hero caster, Hero target) {
Effect?.Invoke(caster, target);
}
}
// 技能类
public class Skill {
public List<SkillEffect> Effects { get; set; }
public void Cast(Hero caster, Hero target) {
foreach (var effect in Effects) {
caster.RegisterEvent(effect.Event, () => effect.ApplyEffect(caster, target));
}
}
}
// 英雄类
public class Hero {
private Dictionary<string, List<Action>> eventListeners = new Dictionary<string, List<Action>>();
public void RegisterEvent(string event, Action action) {
if (!eventListeners.ContainsKey(event)) {
eventListeners[event] = new List<Action>();
}
eventListeners[event].Add(action);
}
public void TriggerEvent(string event) {
if (eventListeners.ContainsKey(event)) {
foreach (var action in eventListeners[event]) {
action.Invoke();
}
}
}
// 其他代码...
}
在这个例子中,每当"攻击"或者"友军阵亡"事件触发时,相关的技能效果就会被应用。你要在合适的地方调用TriggerEvent
方法,例如在攻击方法或者死亡方法中。
看了一下,什么对流血目标增伤,这不就一个if的事吗,为什么要搞个事件单独触发一个运算呢
纯属个人观点,你可以参考一下
对于问题1:
你可以在技能配表里增加一些字段来标记每种技能效果是否包含事件技,以及事件技的类型和触发条件。然后在技能释放类里,根据这些字段来判断是否需要注册事件监听器,并且将对应的技能效果作为回调函数传入。这样就可以实现动态注册和释放事件技。
对于问题2:
你可以在每个事件监听器类里增加一个判断条件的方法,用于检查是否满足触发事件的条件。然后在每个回调函数里增加一个判断目标的方法,用于检查是否满足作用目标的条件。这样就可以实现不同的事件技对应不同的效果。
问题1:
在技能数据类中,为每个技能效果添加一个标记,用于表示该效果是否是一个事件技能。如果该效果是一个事件技能,则标记为 True,否则标记为 False。在技能数据类中,为每个事件技能添加一个事件处理函数,该函数在满足特定事件时被调用。在技能释放类中,根据技能数据类的信息,分别处理普通技能效果和事件技能。
问题2:
在技能释放类中,根据技能数据类的信息,分别处理普通技能效果和事件技能。对于普通技能效果,直接调用技能效果算法类进行处理;对于事件技能,先判断事件是否满足,如果满足则调用对应的事件处理函数进行处理。