代码已上传至:https://github.com/pinzeweifen/demo/tree/master/Unity/Frame
作为一个Unity 的用户,接触这编辑器已经很久了,写的代码一般都是拖拖拖。
也萌生过写个架构,但是都失败了。至于原因可能是我知识量不足?
作为只萌新,今日来写写任务系统。
首先我想知道的是任务到底有哪些类型,然后我找到了这边文章,我觉得他归类得很好,所以直接用他的了
https://necromanov.wordpress.com/2010/11/23/quest_design_2/
先把底层写了,我应该有一个抽象的任务类,它将会记录任务的状态
public abstract partial class Task
{
public enum State
{
/// <summary>
/// 不可接取
/// </summary>
CannotAccept,
/// <summary>
/// 可接取
/// </summary>
CanAccept,
/// <summary>
/// 任务进行中
/// </summary>
DoTasking,
/// <summary>
/// 完成未领奖
/// </summary>
CompleteTask,
/// <summary>
/// 完成已领取奖励
/// </summary>
FinishTask
}
}
在我的设计中,所有任务都会在游戏开始的时候就创建完毕,将会有一个管理类来管理到底哪个任务接受哪个任务完成和放弃。所以我用了一个词典来保存所有的任务。
/// <summary>
/// 任务管理
/// </summary>
public class TaskManager
{
private Dictionary<int, Task> dic = new Dictionary<int, Task>();
public Task this[int key]
{
get { return dic[key]; }
}
public bool Add(Task task)
{
if (dic.ContainsKey(task.GetID))
return true;
dic[task.GetID] = task;
return false;
}
public void Remove(int task)
{
if (dic.ContainsKey(task))
dic.Remove(task);
}
}
任务管理器全局当然只会有一个,你可以添加单例模式。如果添加的任务ID 重复了就返回 true。如果要在返回true后执行代码,只需要这样
TaskManager taskManager = new TaskManager();
if (taskManager.Add(new StrikeKillTask(0,new Award(),
new EqOperation(1,1),new EqOperation(1,1),new EqOperation(1,1))))
{
}
假设返回检测的是 false ,你将会多执行一次取反操作。
我应该可以查询到某个任务是否可接
public bool IsAccept()
{
return acceptOperation.IsTrue();
}
由于我想使用类代替运算符操作方便数据转换为对应代码。所以封装了四个运算符
/// <summary>
/// 运算符运算
/// </summary>
public abstract class OperatorOperation
{
protected object obj, obj2;
public OperatorOperation(object o)
{
obj = o;
}
public OperatorOperation(object o,object o2)
{
obj = o;
obj2 = o2;
}
public abstract bool IsTrue();
public abstract bool IsTrue(object obj);
}
/// <summary>
/// 相等
/// </summary>
public class EqOperation : OperatorOperation
{
public EqOperation(object o) : base(o) { }
public EqOperation(object o,object o2) : base(o,o2) { }
public override bool IsTrue()
{
return obj.Equals(obj2);
}
public override bool IsTrue(object obj)
{
return this.obj.Equals(obj);
}
}
/// <summary>
/// 不相等
/// </summary>
public class NotEqOperation : OperatorOperation
{
public NotEqOperation(object o) : base(o) { }
public NotEqOperation(object o, object o2) : base(o, o2) { }
public override bool IsTrue()
{
return !obj.Equals(obj2);
}
public override bool IsTrue(object obj)
{
return !this.obj.Equals(obj);
}
}
/// <summary>
/// 并且
/// </summary>
public class AndOperation : OperatorOperation
{
public AndOperation(OperatorOperation o) : base(o) { }
public AndOperation(OperatorOperation o, OperatorOperation o2) : base(o, o2) { }
public override bool IsTrue()
{
return (obj as OperatorOperation).IsTrue() && (obj2 as OperatorOperation).IsTrue();
}
public override bool IsTrue(object obj)
{
if (obj is OperatorOperation)
return (this.obj as OperatorOperation).IsTrue() && (obj as OperatorOperation).IsTrue();
return false;
}
}
/// <summary>
/// 或
/// </summary>
public class OrOperation : OperatorOperation
{
public OrOperation(OperatorOperation o) : base(o) { }
public OrOperation(OperatorOperation o, OperatorOperation o2) : base(o, o2) { }
public override bool IsTrue()
{
return (obj as OperatorOperation).IsTrue() || (obj2 as OperatorOperation).IsTrue();
}
public override bool IsTrue(object obj)
{
if (obj is OperatorOperation)
return (this.obj as OperatorOperation).IsTrue() || (obj as OperatorOperation).IsTrue();
return false;
}
}
不相等就只是取反而已,它使用起来就像下面这样
if(new EqOperation(
1,new NotEqOperation(
2,new OrOperation(
new EqOperation(3,4), new EqOperation(5, 6)))).IsTrue())
{
//code
}
调用管理器接受任务之后,将会调用 Task的Start
/// <summary>
/// 接受任务
/// </summary>
/// <param name="task"></param>
public bool Accept(int task)
{
if (dic.ContainsKey(task))
return dic[task].Start();
return false;
}
它首先检查的是否可接受任务,如果可以就改变为正在进行任务的状态,并且通知开始任务,为啥要通知呢,毕竟我不可能在这里写上调用UI 的代码(#^.^#)
public bool Start()
{
if (state == State.CanAccept)
return true;
OnStart();
state = State.DoTasking;
if (GameEvents.OnTaskStart != null)
GameEvents.OnTaskStart(id);
return false;
}
如果任务已经完成那么就需要提交任务
/// <summary>
/// 完成任务
/// </summary>
/// <param name="task"></param>
public bool Submit(int task)
{
if (dic.ContainsKey(task))
return dic[task].Submit();
return false;
}
检查完状态后,判断是否可以领取奖励,领取完成更改状态并通知任务结束
public bool Submit()
{
if(state != State.CompleteTask)
return true;
if (OnSubmit())
{
ward.Provide();
state = State.FinishTask;
if (GameEvents.OnTaskEnd != null)
GameEvents.OnTaskEnd(id);
}
return false;
}
还有放弃任务,没什么好说了,自己领会
public bool Renounce()
{
if (state != State.DoTasking)
return true;
OnRenounce();
state = State.CanAccept;
if (GameEvents.OnTaskRenounce != null)
GameEvents.OnTaskRenounce(id);
return false;
}
当然啦还有就是任务更新
protected void Update()
{
if (OnUpdate())
{
if (GameEvents.OnTaskUpdate != null)
GameEvents.OnTaskUpdate(id);
}
}
至此抽象的任务类就完成了?,不!你可以添加一些字段令子类不那么苦逼
实现一个具体的任务类型,击杀任务类型
击杀嘛当然是杀死某单位的时候更新任务状态,在开始任务的时候监听死亡事件
/// <summary>
/// 击杀任务
/// </summary>
public class StrikeKillTask : Task
{
private int count;
private int maxCount;
public StrikeKillTask(int id, Award ward, OperatorOperation accept, OperatorOperation update, OperatorOperation complete, State state = State.CannotAccept) : base(id, ward, accept, update, complete, state)
{
}
protected override void OnStart()
{
count = 0;
GameEvents.OnDeath += OnDeath;
}
在更新前判断一下条件是否为真
private void OnDeath(Unit unit)
{
//是否可以更新
if (updateOperation.IsTrue(unit))
{
Update();
}
}
更新一下杀怪的数量,如果已经杀够就改变状态
protected override bool OnUpdate()
{
if (count < maxCount)
{
count++;
if(count == maxCount)
{
state = State.CompleteTask;
}
return true;
}
return false;
}
在领取奖励或放弃任务时,删除事件监听
protected override bool OnSubmit()
{
//是否可以获得物品
if (completeOperation.IsTrue(count))
{
GameEvents.OnDeath -= OnDeath;
return true;
}
return false;
}
protected override void OnRenounce()
{
GameEvents.OnDeath -= OnDeath;
}
当然这个类其实还没写完,需要你自己补充完整。其他类型任务应该很好写,就讲到这里啦