游戏任务系统的设计(上
Contents
前言
忙忙碌碌地又一周过去了,又到了每周博客的时间了,这一周疲惫地推各种功能,没带脑子思考,又没心思用半天时间做一个新的功能探讨,终了翻了翻以前设计的功能,接下来就拿自己设计的任务系统做讲解了。
需求
任务系统需求有三种:
- 每日任务:每个任务有独立的奖励,每日还有活跃度,活跃度可以兑换奖励,任务有次数限制,每日凌晨3点刷新,并清除活跃度。
- 周任务:周任务没有活跃度,除了个人奖励外,会增加公会积分,不可重复完成,每周一凌晨3点刷新。
- 成就:主要奖励成就点(用于显示玩家水平的一种方式),成就不可刷新。
任务类型分类:
- 聊天:世界频道发送**条信息 (日常)
- 战斗:扫荡**关卡次 (日常)
- 好友:添加**个好友 (日常)
- 战斗:进行世界Boss达到**名 (周常、成就)
- 登录:玩家累计登录**次数可完成 (日常、成就、周常)
- 卡牌:玩家培养**次卡牌 (日常)
- 卡牌:玩家拥有**张卡牌 (成就)
- 卡牌:玩家拥有**张X星卡牌 (成就)
…我又不是策划就不一一枚举了
功能提取
- 刷新处理
- 任务类型分类
- 任务分发
- 任务记录
- 任务触发
- 奖励发送
- 任务动态增加
…仔细想想提取的又不是那个的有条理
设计实现
终于可以晒代码,水篇幅了,作为一个服务器端程序员,讲故事的确不是我所长。
刷新
1、玩家每次登录时,上次刷新时间戳和当前时间做比较
function isEnableRefresh(lastTime) {
let hour5Time = Math.floor(new Date().setHours(3, 0, 0, 0) / 1000);
return ((lastTime < hour5Time) && ((lastTime < hour5Time - 86400) || (utils.timestamp() >= hour5Time)));
};
2、系统每日3天发送刷新事件,每个在线玩家的任务刷新
function sysDailyRefresh() {
let nextTime = Math.floor(new Date().setHours(3, 0, 0, 0) / 1000) + 86400;
let seconds = nextTime - utils.timestamp();
setTimeout(() => {
userDailyRefresh();
sysDailyRefresh();
}, seconds * 1000);
};
3.周任务,需要判断判断再添加今日是否是周一即可
任务类型分类
仔细分各种任务类型,再一一枚举
const TASK_MODE = {
FINISH_TASK: {
ALL: 11, //所有
},
RANDOM_CARD: {
NUM: 21, //召唤-累计召唤
},
BATTLE: {
MAIN: 31, //战斗-主线剧情
UNLIMITED: 32, //战斗-无限模式
WORLD_BOSS: 33, //战斗-世界Boss
},
FRIEND: {
HAVE: 41, //好友-拥有好友
},
CARD: {
LEVEL_DEV: 51, //卡牌-培养
LEVEL: 52, //卡牌-等级
STAR: 53, //卡牌-星级拥有
},
}
再具体细分抽象可以为三类
- 累计型:需要玩家手动触发的,每次响应累计+1,比如累计登陆、聊天次数
- 拥有型:总共拥有多少,比如拥有卡牌数量
- 排名型:达到多少名,因为和累计判断相反,故单独抽出来
- ALL型:完成所有任务,这种一般针对日常任务
任务分发
简单的采用玩家上线自动领取,毕竟是个坑钱的手游,那么任务触发的设计情怀。
任务记录
因为都是一些简单的任务,可以抽象成下面几个属性记录即可
{
"type" : 0 //日常、周常、成就
"mode" : 0 //任务具体枚举类型
"cfgId" : 0 //对应静态配置ID,用于查询具体
"num" : 0 //任务需求数量、名次、等级
}
刷新、完成领取奖励后,直接删除即可。 任务完成的状态只有玩家领取任务奖励成功才出发。
任务触发
分为条件触发和登录触发两种方式
登录触发
顾名思义,玩家登录后,需要遍历玩家数据,后直接触发任务,主要应对拥有型任务。 eg:每次玩家上线,都要计算玩家卡组数量,并触发任务发送任务类型、以及卡牌数量。
条件触发
直接举例说明,每次玩家获得卡牌都要计算玩家卡组数量,并触发任务发送任务类型、以及卡牌数量。
其实条件触发基本上所有任务类型都可以截获,但登录触发如果没有的话手动修改数据、新增成就任务等都无法兼容,所以登录触发是有必要的,尤其是针对一次性的成就。
下面是具体针四种抽象的任务类型的响应
/**
* @description 常规通用任务触发
* 累计型
* @param {Object} objTask 任务Obj
* @param {Number} num 数量
* @return {Boolean} 是否移除任务监听
*/
function commonTrigger (objTask, num) {
let isRemoveListener;
do {
isRemoveListener = false;
let tbObjTask = Config.getTbObjTask(objTask.getAttrInt('type'), objTask.getAttrInt('cfgId'));
if(!tbObjTask) {
break;
}
let oldNum = objTask.getAttrInt('num');
let maxNum = tbObjTask["num"];
let isMax = (oldNum + num) >= maxNum;
let newNum = isMax ? maxNum : (oldNum + num);
objTask.setAttrInt('num', newNum);
isRemoveListener = isMax;
} while(false);
return isRemoveListener;
}
/**
* @description 常规通用任务触发
* 拥有型
* @param {Object} objTask 任务Obj
* @param {Number} num 数量
* @return {Boolean} 是否移除任务监听
*/
function commonHaveTrigger (objTask, num) {
let isRemoveListener;
do {
let tbObjTask = Config.getTbObjTask(objTask.getAttrInt('type'), objTask.getAttrInt('cfgId'));
if(!tbObjTask) {
break;
}
let maxNum = tbObjTask["num"];
let isMax = num >= maxNum;
let newNum = isMax ? maxNum : num;
objTask.setAttrInt('num', newNum);
isRemoveListener = isMax;
} while(false);
return isRemoveListener;
}
/**
* @description 常规通用任务触发
* 排名型
* @param {Object} objTask 任务Obj
* @param {Number} num 名次
* @return {Boolean} 是否移除任务监听
*/
function commonRankTrigger (objTask, num) {
let isRemoveListener;
do {
let tbObjTask = Config.getTbObjTask(objTask.getAttrInt('type'), objTask.getAttrInt('cfgId'));
if(!tbObjTask) {
break;
}
let maxNum = tbObjTask["num"];
let isMax = num <= maxNum;
let newNum = isMax ? maxNum : num;
objTask.setAttrInt('num', newNum);
isRemoveListener = isMax;
} while(false);
return isRemoveListener;
}
/**
* @description 常规通用任务触发
* ALL型
* !此类型有外部任务种类统计任务剩余数量为0时会出发一次
*/
function commonAll(objTask, type) {
let isRemoveListener;
do {
isRemoveListener = false;
if(objTask.getAttrInt('type') !== type) { //类型相同则完成
break;
}
let tbObjTask = Config.getTbObjTask(objTask.getAttrInt('type'), objTask.getAttrInt('cfgId'));
if(!tbObjTask) {
break;
}
let maxNum = tbObjTask["num"];
objTask.setAttrInt(maxNum);
isRemoveListener = true;
} while(false);
return isRemoveListener;
};
小结
时间准备的不够充足,先写到这里吧,下篇再具体讲解。
Author wangkm
LastMod 2018/07/16