任务系统概述
玩过游戏的朋友们都知道,游戏任务这个玩意。大部分的游戏都有任务,比如玩家升到多少级,杀掉多少个怪,抽多少次卡等等,一般完成了任务会给予玩家一些奖励。
任务给了玩家一个清晰的目标,可以非常方便的引导玩家进行游戏流程。精心设计的任务会获得玩家的一致好评,重复枯燥的任务就会招致厌烦。个人理解的任务概念:所有需要保存进度,并且满足一定条件会触发后续操作的设计,都可以概括到任务的范畴中。
任务类型
常见的任务类型有,普通任务,每日任务,主线任务,支线任务,成就任务,循环任务,隐藏任务,活动任务等。虽然任务通用的数据结构不变,但是不同类型的任务都细微的区别。先来看任务的通用数据结构,即普通任务。
数据结构
任务在配置表的通用数据结构为,任务id,任务类型,任务名称,任务内容,任务条件,奖励。在服务器端的通用数据结构为,任务id,任务类型,任务进度,任务状态。任务id是任务唯一标识。任务类型需要存储是因为不同类型的任务策划一般会配置在不同的配置表中,方便查找。任务进度是任务达成的关键。任务状态记录任务的各种状态,进行任务管理。任务条件与奖励这些不需要保存在服务端,因为可以用任务id找到相应的数据。如果策划给任务设计了解锁操作,那么任务的状态有,未解锁,已解锁,已接取,已完成,已领取奖励,已过期这6种,如果没有设计解锁操作,那么未解锁,已解锁这2种状态可以合并为未接取。
任务状态机
不同类型的任务,任务状态的转变流程不一样,为了更直观的说明不同任务的区别,这里列一下不同高类型任务的状态机。
- 普通任务
普通任务,一般只完成一次,没有其他特殊之处。
2. 每日任务,每周任务,限时活动任务
限时的每日每周任务,会在过期之后,重新接取,并重置进度。
3. 主线任务,支线任务
主线与支线任务,一般都有其后续任务。后续任务的接取一般是前一个任务已完成。当然也存在主线任务由隐藏任务触发,或者多个其他主线任务完成时触发。
3. 成就任务
成就任务主要是为了展示玩家在游戏中取得的各项最高的数值。所以每一个阶段需要继承上一个成就的进度。
4. 循环任务
循环任务在领取奖励之后,会自动再次接取,并且任务进度清零。
- 隐藏任务
隐藏任务,玩家是看不到的,也没有相应的奖励,只是作为游戏中各个系统的触发器。还需要注意任务的接取流程,如果策划给任务设置了接取条件,那么需要客户端配合检查此任务是否可以接取。
任务条件
不同游戏,任务的主要区别在于任务条件的复杂度。这里根据自身经验,分享一种任务条件的数据结构,可以满足大部分任务条件的应用场景。
数据 | 说明 |
---|---|
id | 此任务条件的唯一标识 |
model_name | 任务模型名称 |
desc | 任务条件的描述 |
progress_type | 进度类型,指明进度的修改方式 |
condition | 与进度有关的单一条件,满足此条件表示任务完成 |
default | 任务进度初始值,一般为0 |
filter | 满足此筛选条件,进度才能以一定方式修改 |
单看这个表格一头雾水,先来举个例子: 累计在强化史诗装备中消耗1000金币
数据 | 说明 |
---|---|
id | 1001 |
model_name | consume_num_add |
desc | 累计在强化史诗装备中消耗1000金币 |
progress_type | add |
condition | {"consume_num" , ">=", 1000} |
default | 0 |
filter | {{"consume_type", "=", "strengthen"},{"quality", "=", "史诗"}} |
进度类型为累计型,如果此次强化消耗了20金币,如果通过筛选条件验证,则将进度值增加20。
过滤条件是强化史诗装备
, 可以分解为消费类型为强化
and 装备品质为史诗
,这两个条件的关系为 and,需同时满足,在filter的数据格式中表现为{条件1, 条件2}
。
完成条件为进度值 大于等于 1000,进度值属性名称为 consume_num
再来看下一个例子: 当前在天梯竞技场或者跨服竞技场排名1000以内
数据 | 说明 |
---|---|
id | 1002 |
model_name | rank_cover |
desc | 当前在天梯竞技场或者跨服竞技场排名1000以内 |
progress_type | cover |
condition | {"rank" , "<=", 1000} |
default | 100000 |
filter | {{{"rank_type", "=", "天梯"},{"rank_type", "=", "跨服"}}} |
进度类型为覆盖性,如果排名由 1500 上升到 1300,则进度值直接覆盖为1300.
过滤条件为 天梯竞技场或者跨服竞技场
,可以分解为 在天梯竞技场
or 在跨服竞技场
,这两个条件的关系为 or, 只需满足一个, 在filter的数据格式中表现为{{条件1, 条件2}}
。如果filter中既有and又有or的关系,则表现为{条件1, {条件2, 条件3}}
, 即 需满足条件1, 而且 条件2和条件3至少一个满足。
完成条件为 进度值 小于等于 1000,也就是排名1000以内,进度值属性名称为rank
接下来是针对进度类型
的说明,上面两个例子已经包含了"add"和"cover"两种,分别为累计型和覆盖型,这也是最基本的两种。为了表述方便,我们以x表示进度值,delta表示进度触发值。累计型
,是进度值一直累加,表达式为 x += delta
。覆盖型
是直接赋值,表达式为x = delta
。还有一些扩展:
- 单次覆盖(
single
),表现为首次充值,首次得分等等,表达式为
if delta ~= default then
x = delta
end
- 计数覆盖(
count
),这里的delta不是直接给出,而是通过筛选条件计算获得。例子: 当前有10个3星角色,表达式为
local delta = 0
for _, model in pairs(models) do
if check_filter(model_name, model) then
delta = delta + 1
end
end
x = delta
请警惕这种进度类型,它的算法复杂度为O(n),所以一般要少用。对于当前有10个3星角色,这个例子,如果角色不能被降星,也不能被删除,可以转换为累计型 add。
4. 连续累计(continue
),一般表现形式为连续登陆,连续充值等等,如果中途中断,则重置为默认值。表达式为
if check_filter(model_name, model) then
x += delta
else
x = default
end
然后看单个条件,单个条件的数据格式为 {属性名, 比较方法, 属性值}
,属性名固定为字符串格式,属性值可以是单个数值,字符串,也可以是一个条件(和比较方法有关),比较方法如下:
比较方法 | 说明 |
---|---|
= | 等于 |
>= | 大于等于 |
<= | 小于等于 |
< | 小于 |
> | 大于 |
include | 包含,此比较方法对应的属性值是一个条件(也可以是复合条件) |
ninclude | 不包含,属性值与包含类似 |
对于include与ninclude,条件的数据格式为 {属性名, include, 复合条件, n} 这里的n表示,数据中包含大于等于n个满足复合条件的元素。 |
复杂任务
场景1: 复杂主线任务,有多个分支,每个分支有一系列任务,每个任务有多个复合完成条件,每完成一个条件会触发相应事件(剧情,更新任务描述等)。解决方案:配置前置任务,将任务串成任务链。
场景2: 复杂的剧情任务,通过一些隐藏条件来触发,触发后和正常任务一样。解决方案: 配置隐藏任务,记录隐藏条件的进度。