​参考地址​

先看​​py​​实现的​​火球/闪电​​技能.用​​协程​​更函数式,而​​面向对象​​则要​​存储​​中间状态.

#创建实例
定义 技能实例跑函数(实例,用户,技能数据,目标,目标位置,完成函数):
#此处置`中回调`
产生 任务置退出回调(完成函数)
#...
从 常见.游戏时间 导入 游戏时间
初化时间=游戏时间.现在时间
对 技能步 在 步列表:
步开始时间=游戏时间.现在时间
#...
#1,处理任务
如 技能步.转换类型==转换技能步.转换类型时期:
如 长度(技能步.转换动作组列表)>0:
动作组=技能步.转换动作组列表[0]
对 i 在 区间(技能步.转换数):
#产生休息
产生 休息任务(技能步.转换时期)
中值=干花费技能(技能数据,用户,实例)
如 不 中值:

干一转换技能(技能数据,技能步,动作组,用户,实例,目标标识,目标位置)

#2,导弹技能
异如 技能步.转换类型==转换技能步.转换类型导弹到目标:
如 长度(技能步.转换动作组列表)>0:
动作组=技能步.转换动作组列表[0]
对 i 在 区间(技能步.转换数):
#产生休息
产生 休息任务(技能步.转换时期)
中值=干花费技能(技能数据,用户,实例)
如 不 中值:

#子协程(导弹处理函数)
任务标识=产生 新任务(导弹处理函数(技能数据,实例,用户,技能步,动作组,目标标识,目标位置))
实例.加子任务标识(任务标识)

#3,导引技能
异如 技能步.转换类型==转换技能步.转换类型导引到目标:
如 长度(技能步.转换动作组列表)>0:
#...
对 i 在 区间(技能步.转换数):
#产生休息
产生 休息任务(技能步.转换时期)
中值=干花费技能(技能数据,用户,实例)
如 不 中值:

干一转换技能(技能数据,技能步,动作组,用户,实例,第一目标.对象标识,第一目标.取位置())
起始位置=技能步.导引信息.取目标位置(用户,开始标识,起始位置)[0]
尾位置=技能步.导引信息.取目标位置(用户,第一目标.对象标识,第一目标.取位置())[0]
尾标识=第一目标.对象标识
#子协程(导引处理函数)
任务标识=产生 新任务(导引处理函数(技能数据,实例,用户,技能步,起始位置,尾标识,尾位置))
起始位置=尾位置
开始标识=尾标识
实例.加子任务标识(任务标识)

第一目标=无
如 导引目标列表:
弹索引=随机.随机区间(0,长度(导引目标列表))
第一目标=导引目标列表.弹(弹索引)
如 不 第一目标:


现在时间=游戏时间.现在时间
步过时间=现在时间-步开始时间
需要休息时间=技能步.步总时间-步过时间
如 需要休息时间>0:
产生 休息任务(需要休息时间)

实例.一步完成时(技能步)

如 技能数据.延时尾时间>0:
产生 休息任务(技能数据.延时尾时间)

#等待完成子.
对 任务标识 在 实例.子任务列表:
产生 等待任务(任务标识)

实例.任务标识=0

实现简单,由多个​​技能步​​来配置,​​对​​循环执行​​技能步​​,处理多种​​技能​​.根据​​技能步.转换类型​​来分别处理:​​休息/导弹/引导​​等.

上面导弹技能,按​​固定速度逼近​​,利用​​产生​​实现每帧执行一次的效果.

#处理导弹
定义 导弹处理函数(技能数据,实例,用户,技能步,动作组,目标标识,目标位置):
效果=实例.创建效果(技能步.导弹信息.导弹飞行路径)
效果.置缩放(技能步.导弹信息.缩放导弹)

当前目标位置,是有效目标=技能步.导弹信息.取目标位置(用户,目标标识,目标位置)
起始位置=技能步.导弹信息.取开始位置(用户,目标标识,目标位置)

是达到目标=假
从 常见.游戏时间 导入 游戏时间
初化时间=游戏时间.现在时间
当 真:
#...
飞距离=技能步.导弹信息.飞速度*游戏时间.消逝时间

如 飞距离<总距离:
起始位置+=飞方向*3维数学.向量(飞距离,飞距离,飞距离)
效果.置位置(起始位置)
异:
是达到目标=真


#产生,直到下一帧
产生

效果.消灭()

如 是达到目标:
目标列表=技能数据.取目标列表(用户.转换器,目标标识,目标位置)
对 目标 在 目标列表:
动作组.干(用户.转换器,目标)

然后是​​引导(闪电)​​​类技能.利用好​​产生 休息任务​​就可以了.

#处理`引导`,闪电.
定义 导引处理函数(技能数据,实例,用户,技能步,起始位置,目标标识,目标位置):
效果=实例.创建效果(技能步.导引信息.导引飞行路径)
效果.置缩放(技能步.导引信息.导引缩放)
效果.置位置(起始位置)

效果.置导引尾位置(目标位置-起始位置)
#休息
产生 休息任务(技能步.导引信息.导引时间)
效果.消灭()

现在,用​​C++20​​来实现.

//测试协程
m调度器.创建任务20([实例]()->r工作室::逻辑::协恢复任务c++20{
r工作室::逻辑::i预定任务*任务=r协本任务();
任务->置中函数([](常 r工作室::逻辑::协中对象*){
//这里处理返回函数.
});

对(动&技能步:步列表)
{
动 步开始时间=g游戏->取时管().取时间硬件毫秒();
开关(技能步.转换类型)
{
若 转换技能步::转换类型时期:
{
如(技能步.转换动作组列表.大小()>0)
{
动&动作组=技能步.转换动作组列表[0];
对(整 i=0;i<技能步.转换数;i++)
{
协待 r工作室::逻辑::协任务::休息(技能步.转换时期);
极 中值=干花费技能(技能数据,用户,实例);
如(!中值)
{
协中 r工作室::逻辑::协无效;
}
干一转换技能(技能数据,技能步,动作组,用户,实例,目标标识,目标位置);
}
}
}
断;
若 转换技能步::转换类型导弹到目标:
{
如(技能步.转换动作组列表.大小()>0)
{
动&动作组=技能步.转换动作组列表[0];
对(整 i=0;i<技能步.转换数;i++)
{
协待 r工作室::逻辑::协任务::休息(技能步.转换时期);
极 中值=干花费技能(技能数据,用户,实例);
如(!中值)
{
协中 r工作室::逻辑::协无效;
}
动 任务标识=协待 r工作室::逻辑::协任务::创建任务(真,[&技能步]()->r工作室::逻辑::协恢复任务c++20{
动 当前目标位置=技能步.导弹信息.取目标位置(用户,目标标识,目标位置);
动 起始位置=技能步.导弹信息.取开始位置(用户,目标标识,目标位置);

极 是达到目标=假;
动 初化时间=g游戏->取时管().取时间硬件毫秒();
动 上次=初化时间;

{
动 现在时间=g游戏->取时管().取时间硬件毫秒();
动 消逝时间=现在时间-上次;
上次=现在时间;
如(现在时间-初化时间>=技能步.导弹信息.长飞时间)
{
断;
}

动 当前目标位置=技能步.导弹信息.取目标位置(用户,目标标识,目标位置);

r工作室::数学::向量3 飞方向=当前目标位置-起始位置;
动 总距离=飞方向.正规化();
动 飞距离=技能步.导弹信息.飞速度*消逝时间;
如(飞距离<总距离)
{
起始位置+=飞方向*飞距离;
}

{
是达到目标=真;
断;
}

协待 r工作室::逻辑::协任务::下一帧{};
}当(真);
如(是达到目标)
{
//计算损失,
}

});
实例.加子任务标识(任务标识);
}
}
}
断;
若 转换技能步::转换类型导引到目标:
{
//忽略.
}
断;
默认:
断;
}

动 现在时间=g游戏->取时管().取时间硬件毫秒();
动 步过时间=现在时间-步开始时间;
动 需要休息时间=技能步.步总时间-步过时间;
如(需要休息时间>0)
{
协待 r工作室::逻辑::协任务::休息(需要休息时间);
}

实例.一步完成时(技能步);
}

如(技能数据.延时尾时间>0)
{
协待 r工作室::逻辑::协任务::休息(技能数据.延时尾时间);
}

对(动 线标:实例.子任务列表)
{
协待 r工作室::逻辑::协任务::等待完成任务(线标,10000);
}
});

可见,​​协程​​的优点有:

​序号​

优点

​1​

不会有大量抽象,基于过程实现​​主体功能​​即可

​2​

更易实现数据驱动

​3​

避免过多​​回调​​,干扰主体逻辑.

自动处理​​栈​​变量等,已经算不错了.