返回

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器

发布时间:2022-12-17 01:22:58 407
# 编辑器# 数据# 脚本

更新日期:2020年2月14日。
Github源码:​​​[点我获取源码]​​​ Gitee源码:​​[点我获取源码]​​

索引

  • ​​TaskEditor简介​​
  • ​​使用TaskEditor​​
  • ​​创建Task Content Asset​​
  • ​​打开TaskEditor窗口​​
  • ​​TaskEditor窗口详解​​
  • ​​任务内容​​
  • ​​任务内容属性详解​​
  • ​​新建任务内容类型​​
  • ​​新建任务内容​​
  • ​​任务点​​
  • ​​任务点属性详解​​
  • ​​新建任务点类型​​
  • ​​新建任务点​​
  • ​​任务点完成​​
  • ​​任务点依赖​​
  • ​​在代码中总控​​
  • ​​运行时检视面板​​

TaskEditor简介

任务编辑器,可以自定义任务点,设置任务达成条件,多个任务点组成一个任务内容,使用一系列任务内容完成角色扮演的设计。

使用TaskEditor

创建Task Content Asset

Task Content Asset(任务内容资源)为TaskEditor使用的标准资源,创建方法:
Project界面右键 -> Create -> HTFramework -> TaskContentAsset

如下,新创建的Task001,点击Open按钮(或双击资源)便可以打开TaskEditor窗口编辑此资源:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_ide

打开TaskEditor窗口

打开任意一个TaskContentAsset资源后,TaskEditor初始窗口如下图:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_#if_02

TaskEditor窗口详解

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_#if_03

 

①.Task Content List(任务内容列表)

1.这里显示所有的任务内容,点击右上角的+按钮可以新增任务内容,或者创建新的任务内容类型。

2.选中任意一个任务内容后,点击右端的铅笔按钮可以打开并编辑此任务内容的脚本,点击垃圾桶按钮可以删除此任务内容。

②.Task Property(任务内容属性)
1.选中任意一个任务内容后,这里显示该任务内容的属性。

③.Task Point Area(任务点显示区域)
1.选中任意一个任务内容后,这里显示该任务内容的所有任务点。
2.右键点击可以新增任务点,或者创建新的任务点类型。

任务内容

任务内容属性详解

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_ide_04

当在①面板中选中一个任务内容时,②面板则显示此任务内容的属性:

1.ID:任务内容唯一标识符,不能重复(默认会自动累加,永不重复,前提是你不手动修改)。

2.Name:任务内容名称简述。

3.Details:任务内容详述。

4.Target:任务内容默认自带的一个GameObject属性,可以通过拖拽关联至场景、预制体中的任意对象,拖拽后通过ID关联,在任何时候都能找到该目标。

不过,上述为TaskContentDefault默认任务内容,我们点击编辑脚本,可以看到里面什么也没有:

///
/// 默认的任务内容
///
[TaskContent("默认")]
public sealed class TaskContentDefault : TaskContentBase
{

}

新建任务内容类型

框架会自带TaskContentDefault这个默认任务内容类型,通过选择New Task Content Script选项启动创建向导来快捷创建新的任务内容类。

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_ide_05

如下,我们新建一个任务内容类型TaskKill

[TaskContent("击杀任务")]
public class TaskKill : TaskContentBase
{
protected override void OnStart()
{
base.OnStart();
}
protected override void OnUpdate()
{
base.OnUpdate();
}
protected override void OnComplete()
{
base.OnComplete();
}

#if UNITY_EDITOR
protected override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

GUILayout.BeginHorizontal();
GUILayout.Label("[新建任务内容]");
GUILayout.EndHorizontal();

height += 20;

return height;
}
#endif
}

然后我们就可以直接在编辑面板创建该类型的任务内容:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_任务流程_06

新建任务内容

新建如下这样一个常见的击杀任务:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_unity_07

 

通过重写OnPropertyGUI方法可以扩展任务内容属性面板UI:

#if UNITY_EDITOR
protected override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

return height;
}
#endif

height为延续属性面板高度的参数,每添加一行UI,理论上将height+=20最合适,如下,我们在TaskKill添加一个属性:

[TaskContent("击杀任务")]
public class TaskKill : TaskContentBase
{
//怪物地图标记
public int Sign;

#if UNITY_EDITOR
protected override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

GUILayout.BeginHorizontal();
GUILayout.Label("怪物地图标记:");
Sign = EditorGUILayout.IntField(Sign);
GUILayout.EndHorizontal();

height += 20;

return height;
}
#endif
}

查看属性面板的变化:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_任务流程_08

任务点

一个任务内容包含多个任务点,任务内容和任务点都有一个完成标记,默认情况下,任务内容的完成标记会在其所有任务点的完成标记均为true时为true

任务点属性详解

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_框架_09

1.ID:任务点唯一标识符,不能重复(默认会自动累加,永不重复,前提是你不手动修改)。

2.Name:任务点名称简述。

3.Details:任务点详述。

4.Target:任务点目标。

5.触发方式:此为默认任务点携带的属性。

6.指引时高亮目标:此为默认任务点携带的属性。

7.持续时间:此为默认任务点携带的属性。

如下,我们点击【铅笔】按钮,打开TaskPointDefault默认任务点:

[TaskPoint("默认")]
public sealed class TaskPointDefault : TaskPointBase
{
[SerializeField] private TaskTrigger _trigger = TaskTrigger.MouseClick;
[SerializeField] private bool _highlighting = true;
[SerializeField] private float _duration = 0;
private TaskTarget _target;

protected override void OnStart()
{
base.OnStart();

if (GetTarget == null)
{
Log.Error("任务点 " + GetName + " 的目标为空,这是不被允许的!");
}
else
{
_target = GetTarget.GetComponent();
}
}
protected override void OnUpdate()
{
base.OnUpdate();

switch (_trigger)
{
case TaskTrigger.MouseClick:
if (Main.m_Input.GetButtonDown(InputButtonType.MouseLeft))
{
if (Main.m_Controller.RayTargetObj && Main.m_Controller.RayTargetObj == GetTarget)
{
Complete();
}
}
break;
case TaskTrigger.StateChange:
if (_target != null && _target.State == TaskTargetState.Done)
{
Complete();
}
break;
}
}
protected override void OnGuide()
{
base.OnGuide();

if (_highlighting && GetTarget)
{
Collider collider = GetTarget.GetComponent();
if (collider && collider.enabled)
{
switch (Main.m_TaskMaster.GuideHighlighting)
{
case MouseRay.HighlightingType.Normal:
GetTarget.OpenHighLight();
break;
case MouseRay.HighlightingType.Flash:
GetTarget.OpenFlashHighLight();
break;
case MouseRay.HighlightingType.Outline:
GetTarget.OpenMeshOutline();
break;
}
}
}
}
protected override IEnumerator OnComplete()
{
yield return base.OnComplete();

if (!_duration.Approximately(0))
{
yield return YieldInstructioner.GetWaitForSeconds(_duration);
}
}

///
/// 默认的任务点触发类型
///
public enum TaskTrigger
{
///
/// 鼠标点击目标触发
///
MouseClick,
///
/// 目标状态变为Done时触发
///
StateChange
}

#if UNITY_EDITOR
protected override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

GUILayout.BeginHorizontal();
GUILayout.Label("触发方式:", GUILayout.Width(90));
_trigger = (TaskTrigger)EditorGUILayout.EnumPopup(_trigger);
GUILayout.EndHorizontal();

height += 20;

GUILayout.BeginHorizontal();
GUILayout.Label("指引时高亮目标:", GUILayout.Width(90));
_highlighting = EditorGUILayout.Toggle(_highlighting);
GUILayout.EndHorizontal();

height += 20;

GUILayout.BeginHorizontal();
GUILayout.Label("持续时间:", GUILayout.Width(90));
_duration = EditorGUILayout.FloatField(_duration);
GUILayout.EndHorizontal();

height += 20;

return height;
}
#endif
}

新建任务点类型

框架会自带TaskPointDefault这个默认任务点类型,通过空白处点击右键,选择New Task Point Script选项启动创建向导来快捷创建新的任务点类。

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_框架_10

 

如下,我们新建一个任务点类型TaskPointKill

[TaskPoint("TaskPointKill")]
public class TaskPointKill : TaskPointBase
{
protected override void OnStart()
{
base.OnStart();
}
protected override void OnUpdate()
{
base.OnUpdate();
}
protected override void OnGuide()
{
base.OnGuide();
}
protected override IEnumerator OnComplete()
{
yield return base.OnComplete();
}
protected override void OnAutoComplete()
{
base.OnAutoComplete();
}
protected override void OnEnd()
{
base.OnEnd();
}

#if UNITY_EDITOR
protected override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

GUILayout.BeginHorizontal();
GUILayout.Label("[新建任务点]");
GUILayout.EndHorizontal();

height += 20;

return height;
}
#endif
}

然后我们就可以直接在编辑面板创建该类型的任务点:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_框架_11

新建任务点

我们新建如下两个任务点,用来细分任务内容:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_ide_12

 

不过,我们的任务点目前并不知道如何才算杀了黄蜂,所以我们要在TaskPointKill中写一些东西:

[TaskPoint("击杀任务点")]
public class TaskPointKill : TaskPointBase
{
//任务的击杀目标
public string KillTarget;
//任务的击杀数量
public int KillNumber;

protected override void OnUpdate()
{
base.OnUpdate();

if (KillPool.Target[KillTarget].KillNumber >= KillNumber)
{
Complete();
}
}

protected override IEnumerator OnComplete()
{
yield return base.OnComplete();

//等待1秒后再改变自身完成状态
yield return YieldInstructioner.GetWaitForSeconds(1);
}

#if UNITY_EDITOR
public override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

GUILayout.BeginHorizontal();
GUILayout.Label("任务击杀目标:");
KillTarget = EditorGUILayout.TextField(KillTarget);
GUILayout.EndHorizontal();

height += 20;

GUILayout.BeginHorizontal();
GUILayout.Label("任务击杀数量:");
KillNumber = EditorGUILayout.IntField(KillNumber);
GUILayout.EndHorizontal();

height += 20;

return height;
}
#endif
}

查看属性面板的变化:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_框架_13

任务点完成

任务点的OnUpdate会每帧执行,当此任务内容激活,且此任务点激活时:

public override void OnUpdate()
{
base.OnUpdate();

if (KillPool.Target[KillTarget].KillNumber >= KillNumber)
{
Complete();
}
}

所以,在OnUpdate中判断合适的时机,调用Complete(),便是标记此任务点完成。

任务点依赖

对于如上的两个简单的任务点,不存在任何的依赖(连线),也就不存在任何的先后关系,先杀大黄蜂或是先杀小黄蜂都可以,只要两个任务点完成,整个任务内容就算完成。

但是,如果我们的要求是先杀3只小黄蜂,然后再杀2只大黄蜂,那么就要用到接下来的任务点依赖了。

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_ide_14

 

注意:任务点杀死2只大黄蜂的左侧连接至任务点杀死3只小黄蜂的右侧,表示任务点杀死2只大黄蜂依赖于杀死3只小黄蜂,如果A依赖于B,则必须B任务点完成以后,A任务点才会激活。

注意:请不要在任务内容和任务点中定义不可序列化类型的字段,对于GameObject这个常用的类型,理论上他是可以序列化的,但我们的TaskContentAsset资源是全局的,并不针对某一个Prefab,所以GameObject在这里也是不可序列化类型。

注意:在这里可以使用TaskGameObject代替GameObject。

如下,定义一个TaskGameObject字段,在OnPropertyGUI中必须使用TaskGameObjectField才能画出该字段:

public TaskGameObject Target;

#if UNITY_EDITOR
public override int OnPropertyGUI()
{
int height = base.OnPropertyGUI();

GUILayout.BeginHorizontal();
GUILayout.Label("任务击杀目标:");
KillTarget = EditorGUILayout.TextField(KillTarget);
GUILayout.EndHorizontal();

height += 20;

GUILayout.BeginHorizontal();
GUILayout.Label("任务击杀数量:");
KillNumber = EditorGUILayout.IntField(KillNumber);
GUILayout.EndHorizontal();

height += 20;

TaskGameObject.DrawField(Target, "Target:", 50, Anchor.width);

height += 20;

return height;
}
#endif

查看属性面板变化:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_#if_15

 

我们可以拖拽Scene中的任意GameObject到属性面板:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_任务流程_16

 

我们把鼠标放在TaskGameObject字段的名称(比如这里的Target)上,会显示该对象的GUID,任何时候,当对象丢失时,任务执行器会通过GUID找到他,只要场景中存在这个对象,不管他是名字改变了,还是层级改变了!只有点击后面的垃圾桶按钮才能彻底删除这个对象。

在代码中总控

1、首先,需要将TaskContentAsset资源指定给TaskMaster(静态指定和动态指定均可):

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_#if_17

 

2、然后,开始整个Task流程:

//重新编译所有任务内容
Main.m_TaskMaster.RecompileTaskContent();
//任务流程开始
Main.m_TaskMaster.Begin();

3、终止整个Task流程:

//任务流程终止
Main.m_TaskMaster.End();

4、监听全局事件:

//任务流程开始事件
EventTaskBegin
//任务流程结束事件
EventTaskEnd
//任意任务内容激活事件
EventTaskContentStart
//任意任务内容完成事件
EventTaskContentComplete
//任意任务点激活事件
EventTaskPointStart
//任意任务点完成事件
EventTaskPointComplete

运行时检视面板

在编辑器中运行时将会出现运行时检视面板(Runtime Data),主要用以调试或数据监测,目前面板如下:

【Unity】 HTFramework框架(三十)TaskEditor任务编辑器_#if_18

 

1.No Runtime Data!

 

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
UE4 动画系统 2022-12-17 00:43:43