精华内容
下载资源
问答
  • 游戏任务系统太复杂,带你一步一步实现

    万次阅读 多人点赞 2020-09-26 22:43:40
    任务系统是每个游戏的标配,但是任务系统又是很复杂的,怎么实现一个任务系统呐。?

     

    目录

            1、任务的分类.

    2、基础数据的定义

    3、系统的设计

    4、show me the fuck code !

    1.任务进度定义:

    2.定义任务类型枚举

    3.定义任务模块枚举

    4.定义任务处理器的抽象类

    5.实现主线任务处理类

    6.在服务器启动的时候将所有的处理器加入到map

    7.服务器启动后加载基础数据,将对应的任务注册到对应的处理器

    8.通知任务系统做检测

    5、总结


    前言:一直在写Java 方面的,今天写一写游戏设计方面的 一任务系统。任务系统是每个任务的标配,不管是普通的小游戏,还是大型的端游,手游,没了任务系统的游戏是不完整的。任务系统是游戏的驱动,是玩家的目标,有了目标才会有追求,正常完成任务都会获得奖励,有糖吃,开心。

      任务其实本身就是一种“激励制度”,接受任务-进行挑战-完成奖励,这个过程中的每一个环节,都是对玩家游戏的激励,所以任务在其中就起着这样的这样的作用。对于玩家自身来说,从心理学上,完成任务是对自己挑战的肯定,会大大增加玩家游戏的满足感,即使没有顺利完成某一项任务,玩家感受到到了任务的难度,也会激起自己的挑战欲望和探索心理,进一步提升了游戏性。

    1、任务的分类.

    任务的需求就不多说了,先说下之前的SLG 游戏的任务类型。

    根据任务类型分为 主线任务,支线任务,公会任务,势力任务,每日任务,还有各种不同的功能根据需求的任务类型

    根据进度类型分为 累计型进度,递减型进度,达到型进度,激活型任务进度,自定义类型进度等等。

    任务是游戏里比较复杂的系统,所以设计的时候应该尽可能的方便扩展,在增加任务的时候能简单的配置出来。

    总结下设计原则:尽可能的解决问题,如果特殊需求可以有接口简单可以实现。

    让我们操练起来吧!

    2、基础数据的定义

    配置是基础数据,是策划配置的,因此最简单的配置就是

    任务id 一 任务达成条件一奖励

    任务id 是测试自己创建唯一的id,任务达成条件是在游戏内任务的判断条件,当达到条件的时候发给玩家奖励。

    3、系统的设计

    根据任务的需求,我们对任务进行拆分。

    根据进度类型进行拆分:

    4、show me the fuck code !

    对任务拆分之后,现在得想办法实现我们的任务系统了。

    首先先解决任务进度定义的问题:

    1.任务进度定义:

    
     
    package org.pdool.task;
    
    import com.google.common.base.Joiner;
    
    public enum TaskProgress {
      /**
        * 格式:x_n
        * 专指完成某一任务几次(完成一次扣一次)
        * eq:送花{n}次
        */
      PROGRESS_TYPE1 {
          @Override
          public String checkProgress(int roleId, String config, String current, Object paramArr) {
              String configId = config.split("_")[0];
              Object[] ext = (Object[]) paramArr;
              String param = ext[0].toString();
              long var = Long.parseLong(param);
              int needNum = Integer.parseInt(current.split("_")[1]);
              if (needNum > var) {
                  return "";
              }
              return Joiner.on("_").join(configId, needNum - var);
          }
      },
      ;
    
      /**
        * 检测任务进度
        * @param roleId 玩家id
        * @param config 配置的任务条件
        * @param current 当前的任务进度
        * @param param 传进的参数
        * @return 当前的任务进度
        */
      public abstract String checkProgress(int roleId, String config, String current, Object param);
    }

    2.定义任务类型枚举

    
     
    /**
    * @author 香菜
    */
    public enum TaskTypeEnum {
      // 1:送花 eg:1_100
      SEND_FLOWER_1(TaskProgressEnum.PROGRESS_TYPE1, "1"),
      ;
    
      // 任务进度处理类型
      private TaskProgressEnum progressType;
      // 任务事件激活类型
      private String taskType;
    
      TaskTypeEnum(TaskProgressEnum taskType, String actType) {
          this.progressType = taskType;
          this.taskType = actType;
      }
    
      public TaskProgressEnum getProgressType() {
          return progressType;
      }
    
      public String getTaskType() {
          return taskType;
      }
    }

    策划可以配置的任务就是 1_100  表示 送花100 次则完成任务。

    3.定义任务模块枚举

    举个例子,我们的创角七日任务,在服务器启动的时候加载就加载基础数据,并且注册到每日任务的处理器上,这样在有任务过来的,就不会分配到其他的任务上,因此我们实现一个处理器的抽象类,一个任务类型枚举。

    
    /**
    * @author 香菜
    */
    public enum TaskHandlerEnum {
      // 主线任务
      MAIN_TASK(1),
      // 日常任务
      DAILY_TASK(2),
      ;
      private int type;
      public int getType() {
          return type;
      }
      private TaskHandlerEnum(int type) {
          this.type = (byte) type;
      }
    }

    4.定义任务处理器的抽象类

    至少得三个方法,一个构造函数,一个handle方法,一个注册方法。

    
    /**
    * @author 香菜
    */
    public abstract class AbsTaskHandler {
      public TaskHandlerEnum handlerEnum;
      private Map<TaskTypeEnum, Set<Integer>> canHandMap = Maps.newHashMap();
      public AbsTaskHandler(TaskHandlerEnum handlerEnum) {
          this.handlerEnum = handlerEnum;
      }
      /**
        * 注册任务到处理器
        * @param taskType
        * @param taskId
        */
      protected void registerTask(TaskTypeEnum taskType, int taskId) {
          Set<Integer> taskIdSet = canHandMap.computeIfAbsent(taskType, k -> Sets.newHashSet());
          taskIdSet.add(taskId);
      }
    
      /**
        * 每种任务类型单独实现
        * @param roleId
        * @param paramMap
        */
      protected abstract void handle(int roleId, Map<TaskTypeEnum, Object> paramMap);
    }

    5.实现主线任务处理类

    
    import java.util.Map;
    
    public class MainTaskHandler extends AbsTaskHandler {
      public MainTaskHandler(TaskHandlerEnum handlerEnum) {
          super(handlerEnum);
      }
    
      @Override
      protected void handle(int roleId, Map<TaskTypeEnum, Object> paramMap) {
          // do what you want
      }
    }

    6.在服务器启动的时候将所有的处理器加入到map

    Map<TaskHandlerEnum ,AbsTaskHandler>  handlerMap

    7.服务器启动后加载基础数据,将对应的任务注册到对应的处理器

    registTaskToHanlder(TaskHandlerEnum,TaskType,TaskId)

    8.通知任务系统做检测

    sendMsgToTask(TaskType,param)

    遍历所有的处理器,能处理这个这个任务,则处理,不能处理则过

    5、总结

     由于任务系统的复杂性,设计上必然有一些挑战,但是这种系统如果理解了,也都是套路的问题,做的久了自然而然就会了,并且可以根据需求自由的调整,理解最重要。

     基本的介绍了任务系统的设计实现,后面一些没有做具体的展示,大家可以自己发挥,如果觉得有困难,并且又感兴趣的小伙伴可以联系我。或者你有其他的更好的设计我们可以一起交流。坚持写不容易,希望能获得大家的支持,点赞,转发 三连,谢谢。

    展开全文
  • 分布式任务系统cronsun

    千次阅读 2017-12-20 00:00:00
    一、任务系统图 1图 2说任务系统的话大家想起的就是要执行任务了,什么时间什么地点做什么事情。图 1 是简单的任务,在每天 8 点输出 Hello Gophers!,大家用的比较多的任务系统就是 crond,其实这个系统(图 2)也...
        

    一、任务系统


    640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

    图 1

    640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

    图 2

    说任务系统的话大家想起的就是要执行任务了,什么时间什么地点做什么事情。图 1 是简单的任务,在每天 8 点输出 Hello Gophers!,大家用的比较多的任务系统就是 crond,其实这个系统(图 2)也很简单,就是守护进程加一个任务列表。


    |早期的 cron

    说一下早期的 cron,早期的时候(大概在80 年代在 Unix 系统里面 cron 运行逻辑

    1. /usr/lib/crontab 文件

    2.如果有命令要在当前时间执行,就用 root 用去执行命令

    3.每秒钟去运行一次,有就执行,没有就重复,比较简单


    |支持多用户的 cron

    -Unix System V,1983

    1. 启动的时候读取所有用户下的 .crontab 文件

    2. 计算出每个 crontab 文件里需要执行的命令的下一次执行时间

    3. 把这些命令按下一次执行时间排序后放入队列里

    4. 进入主循环

    • 计算队列里第一个任务的执行时间与当前的时间差 

    • Sleep 直到第一个任务执行时间

    • 后台执行任务

    • 计算这个任务的下一次执行时间,放回队列,排序

    后面发展成支持多用户的,这时候的执行算法改了。这相当于按照时间顺序排列,谁先执行的就放在那里,计算现在的时间与下个时间间隔,再让程序暂停,需要时唤醒程序执行,然后重复。


    |近代的 cron

    Linux,1991

    1. Vixiecron(PaulVixie1987)

    2. Version3Vixiecron(1993) 

    3. Version4.1ISCCron(2004) 

    4. anacron,dcron,fcron


    现在的话 90 年代,大多数的都是用 4.0 的版本。大家用了这么久,基本都是在一些单机上跑一些任务,也是这样的操作。功能很简单,一个时间的规则,一个命令,如果公司有很多服务器的话,维护起来就不方便了,必须得一台一台去管理的或者是用脚本管理,多机器的情况下任务维护成本较高。

    而且如果单机的话,如果失败了之后怎么办?就无法继续了,如果能做成分布式的就好了。


    二、分布式任务系统


    |分布式任务系统特点

    • 分布性

    • 对等性

    • 并发性

    • 缺乏全局时钟 

    • 故障总是会发生

    分布式系统有什么特点呢?大概的特点就不延伸了,大家可以理解为把一个简单的软件放在多台机器上,然后多台机器是都可以完成这个任务的。那么分布式的 crond 的问题,怎么解决呢?

    0?wx_fmt=jpeg

    图 3

    第一个就是把守护进程做成多个分布式的进程(图 3),把命令分布在数据库里面,这是最简单的实践方式。


    |市面上的一些任务系统

    • Azkaban 

    • Chronos 

    • Airflow 

    • dkron

    • swoole-crontab 

    • Saturn

    现在我们也想用一个这样的东西,一开始的时候找了市面上的方案,如上述现在市面上有很多方案,国内国外都有,最后一个是唯品会弄的,我挑几个讲一下。

    1.Azkaban 是一个 Hadoop 上的任务管理,提供功能清晰,简单易用的 Web UI 界面,也提供 job 配置文件快速建立任务和任务之间的依赖关系等等好处,但只能对 Hadoop 做任务管理,符合我们的要求,我们的要求是替换单机版的 crond

    2.Chronos 适合在容器编排管理工具上的调动,里面全部是替代了 crond,里面有 UI,也有灵活的调度,但是要依赖于容器,对于我们来说应该还有更好的方案。

    3.Dkron 这个就比较接近我想要的东西,比较简单高可用,也可控。但是不好的就是对任务的支持比较简单,而且都跑在容器上,相当于替换成容器。因为我们的机器很多都是本地任务需要无缝替换 crond,因此也不考虑。


    |需求

    对很多任务系统进行考察之后,我们有一下需求:

    • 可替换 crond

    • 分布式、高可用

    • 支持多种任务属性

    • 易用

    • 易部署

    因此,我们开发了 cronsun。


    三、cronsun


    0?wx_fmt=jpeg

    图 4

    图 4 是 cronsun 的系统架构,简单来说就是把任务存储在一个分布式 etcd 里,单个 crond 部署成一个服务,也就是node.1\2\3等等部署下去,再由 web 界面去管理。


    |cronsun 特性

    • 部署简单

    • Web界面统一管理任务

    • 任务失败重试

    • 任务失败邮件提醒

    • 多机单任务(防止单机挂掉任务不按时执行)

    • 单机任务并行数限制

    • 执行单次任务

    • 多机器严格的时间间隔任务

    • 支持安全性配置,可以限制任务脚本的后缀和执行用户

    • ....

    现在看一下 cronsun 的特性。首先第一点就是部署简单,只需要在每个机器上部署 crond 节点再部署一个界面管理就可以了。如果 cronweb 挂掉了,只是这个界面不能对任务进行更新,但是不影响任务节点运行,也就不影响任务的执行。其他的任务属性也讲了,最主要的是对任务有几种任务类型,就是可以在单台机器替换 crond ,也解决单点的问题。比如说某个机器死了另外一台机器就会执行这个任务,保证任务执行。


    |cronsun 主要组件

    0?wx_fmt=jpeg

    图 5

    cronsun 主要有 3 个主件,都是通过 etcd 通讯的。cronnode 负责节点的分组及节点的状态,croeweb 是管理任务的、执行结果都可以在上面看。


    |任务类型

    • 普通任务,和 crontab 中的任务一样

    • 单机单进程任务,普通的 crontab 任务是单机的,如果执行任务的机器出现问题,任务可能执行失败。 cronsun 提供此任务类型是保证有多台机器可以执行一个任务,但在执行任务被执行时,只有一台机器在执行任务

    • 一个任务执行间隔内允许执行一次,这个类型的任务和单机单进程任务类似,但限制更严格。因为多台机器间,时间可能会不一致,而某些任务要求执行的时间间隔要严格一致时,可以考虑采取这种类型

    刚才说的任务就是这 3 种类型,单机单进程是只想在一台机器上执行,有 n 个节点,但是只会在一台机器上执行结果。此外还有一种情况,假如有3台机器,每台机器的时间不一致的话,这种任务保证在一个时间间隔内,不管机器时间差怎样,保证只执行一次,不重复执行,解决机器时间不同步的情况。


    |任务属性

    • 失败重试

    • 超时设置

    • 安全设置

    • 同时执行任务数设置 

    • 分组设置

    任务的属性也大概说一下,如果随便填任务的话,web 任务界面暴露出去人家随便填几个任务就可以攻击你,安全设置只要加了脚本的后缀(就是本机器有的脚本),假如你的机器是安全的,那么整个系统就是安全的。还有同时执行任务数量设置,还有分组设置便于方便管理的。


    |任务定时器

    0?wx_fmt=jpeg

    图 6

    定时器,跟 crontab 是一样的,只是多了一个秒级。crontab 便于集中管理,多台服务器的时候就比较方便,保证了不会单点失败。还有就是简单的任务调度,web 是通过 API 来调度的,如果想使用的话稍微看一下 API 就可以调用了,整个系统大概就是这样。


    四、心得体会

    说一个开发过程中的体会。

    第一个是方案的选择,方案选择一开始的时候基本都有这样的问题,你到底要做什么东西,系统要搞很多东西,我想调度,我想备份,能达成多种任务的系统里面。另外一种就是我把我想要的东西某个点做的很好,基于我们的人力物力,而且我们做的足够好,至于后面想扩展的时候能够扩展就可以了。


    |timer 的使用


    0?wx_fmt=jpeg

    图 7

    如图 7 是一个典型的运用场景,我先跑一个任务,假如这个任务超时了就设置超时。在监听的过程中,有任务就执行,没任务就执行超时处理。


    0?wx_fmt=jpeg

    图 8

    刚才的使用只是单次的话是没有问题的,但是在 for 循环里面会每次循环的话都会新建一个timer,这样的情况在要求性能比较高的场合,这是不可行的。有什么替代的方法呢?


    0?wx_fmt=jpeg

    图 9

    0?wx_fmt=jpeg

    图 10

    熟悉的小伙伴应该就会想到直接做一个 tick(图 9 ),自动给出消息,但是这个代码有一些问题,例如上面的代码,这个代码假如 1 秒之后没有了就超时。有个执行(图 10),如果你在这里可以直接刷新的话,这个超时的时候不会刷新的。

    0?wx_fmt=jpeg

    图 11

    如果想超时也能刷新的话就需要做一些改造(图 11)。改造后就会刷新它,来的时候就会刷新超时,处理完了第一个,再处理完第二个,这样就可以解决 timer up 的问题。


    |goroutine 退出

    0?wx_fmt=jpeg

    图 12

    第二个是 goroutine 的退出,大家可能有这种习惯就是每当起任务的时候都会起 goroutine ,这是不好的习惯。解决的办法是就是限定一定的 goroutine,限定 goroutine 的数量而防止流量暴涨的后续问题(图 12),这是比较好的方案。

    大家可以看一下 goroutine 退出的机制,每起一个 goroutine ,就起一个监听,退出的时候就等待 goroutine 退出,再结束。

    0?wx_fmt=jpeg

    图 13

    这里有个问题,这种方式只适合 goroutine 一跑就结束的形式,并不能通过信号去让 goroutine 的退出。如果要通过信号控制 goroutine 的退出怎么办呢?需要有一个等待的函数(图 13),就是退出接受信号的函数。


    0?wx_fmt=jpeg

    图 14

    具体是怎么实现的呢?如图 14 函数监听退出的信号,goroutine 接到信号就直接退出,在外面的时候就等待,整个退出机制就很完善了。

    0?wx_fmt=jpeg

    图 15

    0?wx_fmt=jpeg

    图 16

    但是以上情况是如果有一个信号退出的时候所有 goroutine 就会退出了,如果想实现链式的退出怎么办呢?就需要使用到信号传递了(图15)。可以这么做(图16),如图信号传递在第一个结束后再做传递,第二个监听完退出再传递,如此类推到所有退出完毕,就可以实现链式的有秩序退出。


    |语言的选择

    最后再来说一下为什么选择 Go 语言来做开发语言,总的来说可以总结为以下几点:

    • 简单、开发效率高

    • 部署简单,只需一个二进制文件,无依赖

    • 适合自己的才是最好的

    一是我们看中它容易学习,开发效率高,运营也不错。两个人在工作之余,相当于工作的 20% 的时间,团队一个月就弄了一个版本出来,我们觉得还不错。

    二是部署很简单,部署的时候就是二进制,很小没有依赖,服务器只要太老的系统部署十分简单轻便。

    最后一个就是适合自己的才是最好的, Go 语言对我们公司来讲实现的成本是最低的,是最适合我们的,在我们的眼里是最好的


    展开全文
  • Unity3d 任务系统实现

    千次阅读 2019-11-15 18:45:29
    分享下我rpg游戏的第二部分,任务系统 任务UI 这里没有我背包系统比较繁杂的UI操作,所以大部分时间花在了任务系统控制方面的设计上。 任务系统 说到任务系统,想到,领任务,以及是否完成对应任务,以及任务的各种...

    前言

    分享下我rpg游戏的第二部分,任务系统

    任务UI

    在这里插入图片描述
    这里没有我背包系统比较繁杂的UI操作,所以大部分时间花在了任务系统控制方面的设计上。

    任务系统

    说到任务系统,想到,领任务,以及是否完成对应任务,以及任务的各种状态等等
    秉持着MVC的思想,大致分为以下设计:

    1. Mission类
      在这里插入图片描述
      这里我把任务简单分为两类:寻人以及击杀特定数目的怪
    2. MissionModel类
      在这里插入图片描述
      这个类里存放了各种对数据的操作
    3. MissionCtrl类
      在这里插入图片描述

    心得

    其实以上内容都是很简单的操作,任务系统的主要问题是比如,我要杀多少只特定的怪,我该怎么去判断任务什么时候完成,我的做法是:
    在这里插入图片描述
    这是CTRL类里面的方法,这里注册上给怪死亡之后执行的事件,然后枚举所有已经领过但是没有完成且是杀人类型的任务,如果找不到,说明不在任务列表里,找到了,那就更新一下状态,同理,寻人我也是这样做的。

    结语

    希望可以学到更多东西,努力成为主程,嘿嘿,欢迎有问题私信我

    展开全文
  • Unity 实现任务系统 TaskSystem

    千次阅读 2018-05-09 11:08:22
    本帖最后由 martin4500 于 2018-5-9 09:57 编辑这段时间比较闲,所以抽时间写了游戏中常见的系统,任务系统,可以接受任务啊,然后通过刷怪等条件去触发任务条件,直到完成任务。这个系统相对来说比较的简单,可以...
    本帖最后由 martin4500 于 2018-5-9 09:57 编辑

    这段时间比较闲,所以抽时间写了游戏中常见的系统,任务系统,可以接受任务啊,然后通过刷怪等条件去触发任务条件,直到完成任务。
    这个系统相对来说比较的简单,可以满足小型的游戏任务系统的基本要求吧!这里面的任务的描述是通过读取Json数据来获取的,当然你也可以去写Excel和XML格式的。序列化Json数据不是用的Unity自带的 JsonUtility.FromJson函数,因为有个更强大的Json解析插件Json .Net for Unity2.0,直接支持对Dictionary类型的支持,这样省事多了,可以在AssetStore直接下载。下面是效果展示: 废话不多说了上代码:
    using System.Collections;

    using System.Collections.Generic;

    using UnityEngine;

    using Newtonsoft.Json;

        public class DataManager : MonoSingletions<DataManager>
        {
            private Dictionary<string, Task> taskAllDic = new Dictionary<string, Task>();

            private TextAsset mTextAsset;

            private void Awake()

            {

                if (mTextAsset == null)
                {
                    mTextAsset = Resources.Load("Txt/Task", typeof(TextAsset)) as TextAsset;
                }
                 taskAllDic = JsonConvert.DeserializeObject<Dictionary<string, Task>>(mTextAsset.text);

               // taskAllDic = UnityEngine.JsonUtility.FromJson <Dictionary<string, Task>> (mTextAsset.text);
                foreach (var item in taskAllDic)
                {
                    string tempName=item.Value.taskName;
                    Debug.Log(tempName);
                }
            }

            public Task GetTaskByID(string Id)

            {
                Task value;
                if (taskAllDic.TryGetValue(Id, out value)) return value;

                else Debug.LogError("不存在这个字典");
                return null;
        }
    }

    这个类主要是来读取Json文本解析数据,也不需要多去解释了MonoSingletions是Mono的单例

    public class Task
        {
            public string taskID;
            public string taskName;
            public string description;
            public List<TaskConditions> taskConditions = new List<TaskConditions>();
            public TaskRewards[] taskRewards = new TaskRewards[2];//最好是用数组比链表要节省空间
            public Task(string _taskId,string _taskName,string _description, TaskRewards[] _taskRewards,List<TaskConditions> _taskConditions)
            {
                taskID = _taskId;
                taskName=_taskName;
                description = _description;
                taskRewards = _taskRewards;
                taskConditions=_taskConditions;

            }
        }
    Task类就是一个JSon数据实例化的载体类,就是根据你的Json文本来写的,记住一点的就是:属性名称一定要和json的属性名称一致。
    public class TaskManager :MonoSingletions<TaskManager>
        {
            TransferEvent transfer = new TransferEvent();
            private Dictionary<string, Task> currentTaskDic = new Dictionary<string, Task>();
            public void AcceptTask(string taskID)
            {
                if (currentTaskDic.ContainsKey(taskID))
                {
                    print(string.Format("{0},任务已经接受过",taskID));
                    return;
                }
                else
                {
                    Task t = DataManager.Instance.GetTaskByID(taskID);
                    if (t == null) return;
                    currentTaskDic.Add(taskID, t);
                    TaskArgs args = new TaskArgs();
                    args.taskId = taskID;
                    TransferEvent.Instance.InvokeEventListen((System.Int16)EventType.OnGetEvent, args);
                }
            }
            /// <summary>
            /// 更新任务进度
            /// </summary>
            /// <param name="args"></param>
            public void CheackTask(TaskArgs args)
            {
                foreach (var item in currentTaskDic)
                {
                    UdateUIData(item, args);
                    CheackFinishTask(item, args);
                }
            }
            //更新数据
            private void UdateUIData(KeyValuePair<string,Task> item,TaskArgs args)
            {
                TaskConditions tc;
                for (int i = 0; i < item.Value.taskConditions.Count; i++)
                {
                    tc = item.Value.taskConditions;
                    if (tc.id == args.id)
                    {
                        if (tc.nowAmount >= tc.targetAmount) return;
                        tc.nowAmount += args.amount;
                        args.taskId = item.Value.taskID;
                        args.amount = tc.nowAmount;
                        if (tc.nowAmount < 0) tc.nowAmount = 0;
                        if (tc.nowAmount >= tc.targetAmount)
                        {
                            tc.nowAmount = tc.targetAmount;
                            tc.isFinish = true;
                        }
                        else tc.isFinish = false;
                        //更新UI数据
                        TransferEvent.Instance.InvokeEventListen((System.Int16)EventType.OnCheackEvent, args);
                    }
                }
            }
            private void CheackFinishTask(KeyValuePair<string, Task> item,TaskArgs args)
            {
                TaskConditions tc;
                for (int i = 0; i < item.Value.taskConditions.Count; i++)
                {
                    tc = item.Value.taskConditions;
                    if (!tc.isFinish) return;//只要是没有完成就返回
                }
                FinishTask(args);

            }
            private void FinishTask(TaskArgs args)
            {
                //调用任务完成事件
                TransferEvent.Instance.InvokeEventListen((System.Int16)EventType.OnFinishEvent, args);
            }
            /// <summary>
            /// 获取任务奖励
            /// </summary>
            /// <param name="args"></param>
            public void GetReward(TaskArgs args)
            {
                if (currentTaskDic.ContainsKey(args.taskId))//当任务存在
                {
                    Task t = currentTaskDic[args.taskId];
                    for (int i = 0; i < t.taskRewards.Length; i++)
                    {
                        TaskArgs a = new TaskArgs();
                        a.id=t.taskRewards.id;
                        a.amount = t.taskRewards.amount;
                        a.taskId = args.taskId;
                        TransferEvent.Instance.InvokeEventListen((System.Int16)EventType.OnRewardEvent, args);
                        currentTaskDic.Remove(args.taskId);
                    }
                }
            }
            public void CancelTask(TaskArgs args)
            {
                if (currentTaskDic.ContainsKey(args.taskId))
                {
                    TransferEvent.Instance.InvokeEventListen((System.Int16)EventType.OnCancelEvent, args);
                    currentTaskDic.Remove(args.taskId);
                }
            }
        }
    TaskManager是管理类,简单的说就是连接任务数据和相关任务操作(UI文本提示,事件的触发等)这里的CheackTask(TaskArgs args是检查任务是否完成和更新UI提示,主要通过对当前任务字典的中的任务内容进行相关赋值实现。其它函数都是比较简单看几眼就知道了就不多说了。
       public enum EventType
        {
            OnGetEvent=0,
            OnCheackEvent=1,
            OnFinishEvent=2,
            OnRewardEvent=3,
            OnCancelEvent=4
        }
        public class TransferEvent
        {
            private List<MesTransfer> mListTransfer ;
            private List<MesTransfer> mAddListener;
            private event MesTransfer OnGetEvent;//接受任务时,更新任务到任务面板等操作
            private event MesTransfer OnCheackEvent;//更新任务信息
            private event MesTransfer OnFinishEvent;//完成任务时,提示完成任务等操作
            private event MesTransfer OnRewardEvent;//得到奖励时,显示获取的物品等操作
            private event MesTransfer OnCancelEvent;//取消任务时,显示提示信息等操作
            private static TransferEvent mInstance;
            public TransferEvent()
            {
                mListTransfer = new List<MesTransfer>();
                mListTransfer.Add(OnGetEvent);
                mListTransfer.Add(OnCheackEvent);
                mListTransfer.Add(OnFinishEvent);
                mListTransfer.Add(OnRewardEvent);
                mListTransfer.Add(OnCancelEvent);

            }
            public static TransferEvent Instance
            {
                get
                {
                    if (mInstance == null)
                        mInstance = new TransferEvent();
                    return mInstance;
                }
            }
            public bool isCheackNull(System.Int16 index)
            {
                return mListTransfer[index] == null ? true:false ;
            }
            //添加事件
            public void AddEventListen(MesTransfer temp,System.Int16 index)
            {
                if (mListTransfer[index]!=null) return;
                mListTransfer[index] += temp;
            }
            //回调事件
            public void InvokeEventListen(System.Int16 index,TaskArgs args)
            {
                if (index > mListTransfer.Count - 1)
                {
                    Debug.Log("链表索引越界");
                    return;
                }
                MesTransfer mes = mListTransfer[index];
                if (mListTransfer[index]!=null)
                {
                    if (!isCheackNull(index)) mes(args);
                }
            }
            //清空所有的监听事件
            public void ClearListTransfer()
            {
                int i = 0;
                IEnumerator listEnumerartor=mListTransfer.GetEnumerator();
                while(listEnumerartor.MoveNext())
                {
                    MesTransfer mes = (MesTransfer)listEnumerartor.Current ;
                    mes -= mAddListener;
                    i++;
                }
                mListTransfer.Clear();
            }
               }

    这是一个事件委托的管理类网上的模板很多,大概都是这个样子了,只要是对事件的增加监听,或者事件回调,和观察者模式很像,主要是为了降低代码之间的耦合性的,如果对委托不是很了解建议自己网上去查,或者照着我这个敲一遍练练手还是可以的。
      public class SMSNotifiler :MonoSingletions<SMSNotifiler>
        {
            private void Start()
            {
                TransferEvent.Instance.AddEventListen(GetPrintInfo, (System.Int16)EventType.OnGetEvent);
                TransferEvent.Instance.AddEventListen(finishPrintInfo, (System.Int16)EventType.OnFinishEvent);
                TransferEvent.Instance.AddEventListen(rewardPrintInfo, (System.Int16)EventType.OnRewardEvent);
                TransferEvent.Instance.AddEventListen(cancelPrintInfo, (System.Int16)EventType.OnCancelEvent);
                TransferEvent.Instance.AddEventListen(cheackPrintInfo, (System.Int16)EventType.OnCheackEvent);
            }
            public void GetPrintInfo(TaskArgs e)
            {
                print("接受任务" + e.taskId);
            }

            public void finishPrintInfo(TaskArgs e)
            {
                print("完成任务" + e.taskId);
            }

            public void rewardPrintInfo(TaskArgs e)
            {
                print("奖励物品" + e.id + "数量" + e.amount);
            }

            public void cancelPrintInfo(TaskArgs e)
            {
                print("取消任务" + e.taskId);
            }
            public void cheackPrintInfo(TaskArgs e)
            {
                print(string.Format("任务是{0},{1}完成了{2}",e.taskId,e.id,e.amount));
            }
    就像类名一样这个就是相关提示信息,由TaskManager中的去发布信息,然后Notifiler去执行相关细节而已,也是非常简单的脚本。

        public class ControllerTest : MonoBehaviour
        {
            private SMSNotifiler mSMSNotifiler;
            private TaskManager mTaskManager;
            void Start()
            {
                if(mSMSNotifiler==null)
                mSMSNotifiler = SMSNotifiler.Instance;

                if (mTaskManager == null)
                    mTaskManager = TaskManager.Instance;
            }
            private void OnGUI()
            {
                if (GUILayout.Button("接受任务Task1"))
                {
                    mTaskManager.AcceptTask("T001");
                }
                if (GUILayout.Button("接受任务Task2"))
                {
                    mTaskManager.AcceptTask("T002");
                }
                if (GUILayout.Button("接受任务T003"))
                {
                    mTaskManager.AcceptTask("T003");
                }
                if (GUILayout.Button("打怪Enemy1"))
                {
                    TaskArgs e = new TaskArgs();
                    e.id = "Enemy1";
                    e.amount = 1;
                    mTaskManager.CheackTask(e);

                }
                if (GUILayout.Button("打怪Enemy2"))
                {
                    TaskArgs e = new TaskArgs();
                    e.id = "Enemy2";
                    e.amount = 1;
                    mTaskManager.CheackTask(e);
                }
            }
        }
    这个ControllerTest挂在unity的主场景中会自动添加相关的调用代码比如:TaskManager,主要是一个你游戏任务的相关操作都可以写这里,这个类只是一个简单的示例,比如添加不同的任务参数种类等等。
    好了这个任务相对比较简单,不过我自己觉得也算是五脏俱全了吧,欢迎给我大佬指正不足的地方。最后是项目的工程文件下载地址https://download.csdn.net/download/martins1994/10402293


    展开全文
  • Linux定时任务系统 Cron

    万次阅读 2016-12-28 20:03:26
    Linux定时任务系统 Cron运行计划任务时: service crond restart 提示: crond: unrecognized service 安装计划任务: yum -y install vixie-cron另外附计划任务的一些使用方法 ...
  • Unity中任务系统书写

    千次阅读 2015-02-14 10:27:25
    任务系统一直是游戏中非常重要的系统,它一直伴随在游戏左右,玩家通过完任务去赚取装备,去升级,所以说任务系统是非常重要的,值得我们好好去架构。在手机中的任务系统没有PC端那么复杂,在Unity中由于有委托以及...
  • 游戏任务系统设计思路

    千次阅读 2016-11-09 15:59:00
    为什么要设计任务系统 1. 体现世界观世界观 指主线剧情,历史背景,塑造主角的成长历程。 WOW中的任务虽然不是必须完成的,但是顺着部落主线的剧情延伸至南海镇的任务却是很明显的主线剧情,从亡灵新手村...
  • 游戏任务系统的设计要素

    千次阅读 2016-11-16 16:32:10
    任务系统的基本流程包括:触发任务、接受任务、进行任务、完成任务,共四个阶段组成。  任务的事件结构就如同记叙文一般,包含其中各方面的要素,即时间、地点、人物、事件、结果等。  时间:何时发生、何时...
  • unity3d 任务系统设计 mmo

    千次阅读 2014-11-13 23:46:08
    unity3d 任务系统设计 mmo  2013-08-23 13:09:12| 分类: unity3d | 标签:unity3d |举报|字号 订阅 最近一直在思考MMORPG的任务系统的设计。以下是需要达到的几个设计目标: 1. 任务逻辑...
  • 竞速游戏任务系统设计

    千次阅读 2013-10-20 00:03:40
    将MMOPRG的任务系统融入竞速游戏中,可以在竞速和道具模式外,创造出一个新的游戏模式,即任务模式,同样任务模式也可以分为个人和组队完成。 这样,既能增强游戏的趣味性,又能给玩家带来强烈的
  • 游戏中任务系统设计

    千次阅读 2019-10-31 21:27:46
    游戏中任务可以分为主线任务、支线任务、日常任务、周任务、节日活动任务,其中周任务和节日任务可以根据设定的日期进行开启关闭,属于重复性任务。 2、游戏条件 各类任务开启条件:1、玩家等级 2、玩家攻击力3...
  • 网游任务系统设计

    千次阅读 2010-12-02 16:36:00
    站在大世界 原文地址:http://blog.donews.com/xzwenlan/archive/2005/01/20/249444.aspx<br />首先,网络游戏是一个大的概念,本文所述网络游戏的类型为MMORPG,我们在此基础上进行讨论网络游戏任务系统该去...
  • 基于STM32的多任务系统内核--FSC_STOS代码解析

    千次阅读 多人点赞 2019-03-06 17:59:40
    FSC_STOS(点击下载@px86)是专为STM32芯片编写的多任务系统内核。 *任务之间相互独立,互不干扰。 *提供三种运行模式:时间轮询模式、纯优先级模式、时间片+优先级混合模式。 *采用时间切片轮询方式,每个任务运行...
  • 游戏中的任务系统的简单架构!

    万次阅读 2015-11-18 10:54:02
    之所以 想到先写这个“任务系统”是被面试到了!  废话不多少,上传不要代码! “任务”的五种状态 /** * 任务状态 * @author kevin chen * @Description: TODO * @date 2015年10月21日 下午8:20:39 */ ...
  • Lua程序设计任务系统和NPC

    千次阅读 2013-11-20 23:04:00
    最近自己的新任务是涉及游戏中的任务系统。设计的过程中,遇到第一个问题是下拉列表的设计。第二个是对服务端数据的处理。第三个是通过链接切换到另一个版面。  对于下拉列表的设计,刚开始进行了网上搜索,大部分...
  • 受够了一个单片机傻乎乎的一路执行着代码的时代,决定自己实现一个多任务系统,虽然有现成开源的,但是借这个机会用自己的想法去设计系统毕竟是个不错的事情。 一个多任务系统的重点是实现任务的上下文切换,在多个...
  • 利用Protothread实现实时多任务系统

    千次阅读 2008-10-18 21:00:00
    摘要在许多系统资源非常紧张的单片机应用中,使用实时操作系统进行任务调度来实现实时多任务系统时,由操作系统带来的系统开销往往是不可接受的。通过升级硬件来改善系统资源紧张,意味着成本的增加,降低产品的竞争...
  • 第四章:任务系统这部分主要对任务系统进行设计,游戏的关键因素之一就是任务系统与玩家的交互,但在代码实现中并不算复杂。本篇博客主要通过一下几个方面实现任务系统。任务模型的导入与任务UI界面的创建任务的接受...
  • go语言实现分布式crontab任务系统

    千次阅读 2019-04-08 11:56:29
    最近离职交接空档期,在慕课网上学习了下go语言实现分布式crontab任务调度系统。自己也跟随视频实现了一把(跟原版略有不同)。现把成果记录一下。 最终代码: https://github.com/funkol2007/distributed_crontab ...
  • 轮询系统:即在裸机编程时,先初始化相关硬件,让主程序在一个死循环里面不断循环,顺序地处理各种事件。不能说轮询是低端的,轮询系统是一种非常简单的软件结构,但适用于仅需要顺序执行代码且不需要外部事件来驱动...
  • unity3d 网络游戏任务系统设计考良  2013-08-23 10:18:49| 分类: unity3d | 标签:unity3d |举报|字号 订阅 2013-08-23 10:18:49| 分类: unity3d | 标签:unity3d |...
  • 网络游戏的任务系统

    千次阅读 2011-06-15 12:21:00
    声望系统、经验系统、金钱系统,技能系统,用来累计升级的小任务。应该都可以尝试让系统去管理。从“玩”的角度讲,游戏是休闲、娱乐、放松,游戏最主要的作用就是打发时间,而且是比较愉悦的打发,
  • 如何设计一个分布式定时任务系统

    千次阅读 2019-06-04 14:34:00
    1、定时任务指定集群中的一台机器执行 2、如何修改cron参数,且修改永久有效 当然直接用quartz来实现肯定最棒,但设计的配置太多,小公司没那个需求; 关于第1个,我开始选择得做法是: 读取zk固定节点path的值...
  • 任务系统中两个程序A和B,其中 A程序:CPU:10s ->  设备1:5s -> CPU: 5s -> 设备2:10s -> CPU:10s;  B程序:设备1:10s -> CPU:10s -> 设备2:5s -> CPU: 5S -> 设备2: 10s; 执行顺序为A ->B,...
  • MMORPG开发杂谈(一):任务系统设计

    万次阅读 2006-07-11 11:27:00
    最近一直在思考MMORPG的任务系统的设计。以下是需要达到的几个设计目标:1. 任务逻辑与程序逻辑完全脱离;2. 服务器端程序和客户端程序提供有限的功能之后,可以由脚本程序员完成任务编写;3. 必须方便任务的更新...
  • [Unity实战]一个简单的任务系统

    千次阅读 2018-05-30 16:49:54
    1.任务管理类与任务类是一对一的关系,而任务管理类与其他类是一对多的关系。对于一对多,比较容易想到的就是观察者模式了。在观察者模式中,是观察者决定要监视的东西,而不是事件的发生者决定谁观察它。2.对于任务...
  • 来看这样一个问题: 某账号系统的账号都在unsigned int... 现在要设计一个定时赠言系统, 比如: 今天是2017年3月25日, 那么用户A可以给他的好友B送定时赠言(精确到未来某天, 不包括今天), 预期未来这天到达。而

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 160,698
精华内容 64,279
关键字:

任务系统