using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using UnityEditor; //继承编辑器 空间要放到 Editor文件夹
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
public class SkillEditor : EditorWindow
{
static AddTyped addTyped; //添加类型
static Texture texture;//技能图片
static Vector2 vector2;
static string path;//技能
static List<SkillData> skillDatas = new List<SkillData>();//存放技能
static string[] SkillName; //技能名字
static int skillid;// 技能Id
static AnimationClip animation;//动画
static AudioClip audioClip;//动画
static GameObject effect;//动画
Vector3 v3=new Vector3(0,0,5); //敌人位置
GameObject player,target;
//折叠
bool isAni;
bool isAud;
bool isEff;
[MenuItem("Tool/我的编辑器")]
public static void SetEditor()
{
GetWindow<SkillEditor>(false, "技能编辑器");
path = Application.dataPath + "/Resources/Data.json";
//读取边缘的技能
if (File.Exists(path))
{
string a = File.ReadAllText(path);
skillDatas = JsonConvert.DeserializeObject<List<SkillData>>(a);
}
else
{
skillDatas = new List<SkillData>();//没有就重新实例
}
GetNameList();
}
//获取名字集合
static void GetNameList()
{
SkillName = new string[skillDatas.Count + 1];
for (int i = 0; i < skillDatas.Count; i++)
{
SkillName[i] = skillDatas[i].name;
}
SkillName[skillDatas.Count] = "创建新的技能";
}
private void OnGUI()
{
if (skillDatas.Count <= skillid) //当前选择大于等于技能数量代表我们要创建新的技能
{
skillDatas.Add(new SkillData());//开辟空间
//初始化
skillDatas[skillid].id = skillid;//选择的技能id
skillDatas[skillid].name = "新技能" + skillid;
skillDatas[skillid].imgicon = "icon/女性 靴子 (2)";
}
GetNameList();//实时刷新技能名字
vector2 = GUILayout.BeginScrollView(vector2); //滑动框
GUILayout.BeginVertical();
//技能选择
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.BeginHorizontal();
GUILayout.Label("请选择你的技能");
skillid = EditorGUILayout.Popup(skillid, SkillName); //下拉框不能重名要不会隐藏
GUILayout.EndHorizontal();
GUILayout.EndVertical();
//优化
if (skillDatas.Count <= skillid)
{
//记得结束
GUILayout.EndVertical();
GUILayout.EndHorizontal();
//开辟了新的技能 要进行编译
return;
}
//编辑名字
GUILayout.Space(20);
GUILayout.BeginHorizontal();
GUILayout.Label("更改技能名字");
skillDatas[skillid].name = EditorGUILayout.TextField(skillDatas[skillid].name);
GUILayout.EndHorizontal();
//技能图标
GUILayout.Space(20);
GUILayout.BeginHorizontal();
GUILayout.Label("更改技能图标");
texture = Resources.Load<Texture>(skillDatas[skillid].imgicon);
if (GUILayout.Button(texture, GUILayout.Width(50), GUILayout.Height(50)))
{
string imgicon = EditorUtility.OpenFilePanel("选择技能", Application.dataPath + "/Resources/icon", "png");
imgicon = imgicon.Replace(Application.dataPath + "/Resources/", ""); //替换路径
skillDatas[skillid].imgicon = imgicon.Replace(".png", "");
}
GUILayout.EndHorizontal();
//技能描述
GUILayout.Space(20);
GUILayout.BeginHorizontal();
GUILayout.Label("技能描述");
skillDatas[skillid].des = EditorGUILayout.TextField(skillDatas[skillid].des);
GUILayout.EndHorizontal();
//技能范围
GUILayout.Space(20);
GUILayout.BeginHorizontal();
GUILayout.Label("技能攻击范围");
skillDatas[skillid].range = EditorGUILayout.FloatField(skillDatas[skillid].range);
GUILayout.Label("技能攻击距离");
skillDatas[skillid].distance = EditorGUILayout.FloatField(skillDatas[skillid].distance);
GUILayout.EndHorizontal();
//攻击类型
GUILayout.Space(20);
GUILayout.BeginHorizontal();
addTyped = (AddTyped)EditorGUILayout.EnumPopup(addTyped);
if (GUILayout.Button("添加"))
{
switch (addTyped)
{
case AddTyped.动画:
skillDatas[skillid].animtonDatas.Add(new AnimtonData());
break;
case AddTyped.音效:
skillDatas[skillid].audioDatas.Add(new AudioData());
break;
case AddTyped.效果:
skillDatas[skillid].effectDatas.Add(new EffectData());
break;
}
}
GUILayout.EndHorizontal();
//折叠窗口
isAni = EditorGUILayout.Foldout(isAni, "动画");
if (isAni)
{
for (int i = 0; i < skillDatas[skillid].animtonDatas.Count; i++)
{
//动画
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.BeginHorizontal();
GUILayout.Label("设置动画");
animation = Resources.Load<AnimationClip>(skillDatas[skillid].animtonDatas[i].anipath);
animation = EditorGUILayout.ObjectField(animation, typeof(AnimationClip), false) as AnimationClip;
if (GUILayout.Button("删除"))
{
skillDatas[skillid].animtonDatas.RemoveAt(i);
animation = null;
}
GUILayout.EndHorizontal();
if (animation != null)
{
string path = AssetDatabase.GetAssetPath(animation);
path = path.Replace("Assets/Resources/", ""); //替换路径
skillDatas[skillid].animtonDatas[i].anipath = path.Replace(".anim", "");
skillDatas[skillid].animtonDatas[i].aniduration = animation.length;
GUILayout.BeginHorizontal();
GUILayout.Label("动画持续时间");
skillDatas[skillid].animtonDatas[i].aniduration = EditorGUILayout.FloatField(skillDatas[skillid].animtonDatas[i].aniduration);
GUILayout.Label("动画开始时间");
skillDatas[skillid].animtonDatas[i].anistart = EditorGUILayout.FloatField(skillDatas[skillid].animtonDatas[i].anistart);
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
}
//折叠窗口
isAud = EditorGUILayout.Foldout(isAud, "音频");
if (isAud)
{
for (int i = 0; i < skillDatas[skillid].audioDatas.Count; i++)
{
//动画
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.BeginHorizontal();
GUILayout.Label("设置音频");
audioClip = Resources.Load<AudioClip>(skillDatas[skillid].audioDatas[i].audpath);
audioClip = EditorGUILayout.ObjectField(audioClip, typeof(AudioClip), false) as AudioClip;
if (GUILayout.Button("删除"))
{
skillDatas[skillid].audioDatas.RemoveAt(i);
audioClip = null;
}
GUILayout.EndHorizontal();
if (audioClip != null)
{
string path = AssetDatabase.GetAssetPath(audioClip);
path = path.Replace("Assets/Resources/", ""); //替换路径
skillDatas[skillid].audioDatas[i].audpath = path.Replace(".mp3", "");
skillDatas[skillid].audioDatas[i].audduration = audioClip.length;
GUILayout.BeginHorizontal();
GUILayout.Label("声音持续时间");
skillDatas[skillid].audioDatas[i].audduration = EditorGUILayout.FloatField(skillDatas[skillid].audioDatas[i].audduration);
GUILayout.Label("声音开始时间");
skillDatas[skillid].audioDatas[i].audstart = EditorGUILayout.FloatField(skillDatas[skillid].audioDatas[i].audstart);
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
}
//折叠窗口
isEff = EditorGUILayout.Foldout(isEff, "效果");
if (isEff)
{
for (int i = 0; i < skillDatas[skillid].effectDatas.Count; i++)
{
//动画
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.BeginHorizontal();
GUILayout.Label("设置效果");
effect = Resources.Load<GameObject>(skillDatas[skillid].effectDatas[i].effectpath);
effect = EditorGUILayout.ObjectField(effect, typeof(GameObject), false) as GameObject;
if (GUILayout.Button("删除"))
{
skillDatas[skillid].effectDatas.RemoveAt(i);
effect = null;
}
GUILayout.EndHorizontal();
if (effect != null)
{
string path = AssetDatabase.GetAssetPath(effect);
path = path.Replace("Assets/Resources/", ""); //替换路径
skillDatas[skillid].effectDatas[i].effectpath = path.Replace(".prefab", "");
GUILayout.BeginHorizontal();
GUILayout.Label("特效持续时间");
skillDatas[skillid].effectDatas[i].effectduration = EditorGUILayout.FloatField(skillDatas[skillid].effectDatas[i].effectduration);
GUILayout.Label("特效开始时间");
skillDatas[skillid].effectDatas[i].effectstart = EditorGUILayout.FloatField(skillDatas[skillid].effectDatas[i].effectstart);
GUILayout.Label("特效数量");
skillDatas[skillid].effectDatas[i].num = EditorGUILayout.IntField(skillDatas[skillid].effectDatas[i].num);
GUILayout.Label("特效间隔时间");
skillDatas[skillid].effectDatas[i].invetime = EditorGUILayout.FloatField(skillDatas[skillid].effectDatas[i].invetime);
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
}
GUILayout.Space(10);
v3 = EditorGUILayout.Vector3Field("敌人坐标", v3);
GUILayout.Space(10);
if (GUILayout.Button("预览"))
{
//创建敌人和主角 主角挂载导演类型
if (player!=null)
{
DestroyImmediate(target);
DestroyImmediate(player);
}
target = Instantiate(Resources.Load<GameObject>("Model/Enemy/TeddyBear"));
target.transform.position = v3;
player = Instantiate(Resources.Load<GameObject>("Model/Player/Teddy"));
//导演类
PlayableDirector director = player.AddComponent<PlayableDirector>();
//添加 asset
TimelineAsset asset = TimelineAsset.CreateInstance<TimelineAsset>();
director.playableAsset = asset;
director.playOnAwake = false;
//动画轨道
AnimationTrack animationTrack = asset.CreateTrack<AnimationTrack>();
animationTrack.trackOffset = TrackOffset.ApplySceneOffsets;
director.SetGenericBinding(animationTrack, player);
for (int i = 0; i < skillDatas[skillid].animtonDatas.Count; i++)
{
TimelineClip timelineClip = animationTrack.CreateClip<AnimationPlayableAsset>();
AnimationPlayableAsset animationPlayableAsset = timelineClip.asset as AnimationPlayableAsset;
animationPlayableAsset.clip = Resources.Load<AnimationClip>(skillDatas[skillid].animtonDatas[i].anipath);
animationPlayableAsset.position = player.transform.position;
timelineClip.start = skillDatas[skillid].animtonDatas[i].anistart;
timelineClip.duration = skillDatas[skillid].animtonDatas[i].aniduration;
}
//音频轨道
for (int i = 0; i < skillDatas[skillid].audioDatas.Count; i++)
{
AudioTrack audioTrack = asset.CreateTrack<AudioTrack>();
GameObject audioMgr = new GameObject("audioMgr");
audioMgr.AddComponent<AudioSource>();
director.SetGenericBinding(audioTrack, audioMgr);
TimelineClip timelineClip = audioTrack.CreateClip<AudioPlayableAsset>();
AudioPlayableAsset audioPlayableAsset = timelineClip.asset as AudioPlayableAsset;
audioPlayableAsset.clip = Resources.Load<AudioClip>(skillDatas[skillid].audioDatas[i].audpath);
timelineClip.start = skillDatas[skillid].audioDatas[i].audstart;
timelineClip.duration = skillDatas[skillid].audioDatas[i].audduration;
}
//特效
for (int i = 0; i < skillDatas[skillid].effectDatas.Count; i++)
{
EffectData effectData = skillDatas[skillid].effectDatas[i];
for (int j = 0; j < effectData.num; j++)
{
GameObject effectMgr = new GameObject("effectMgr");
Trajectory trajectory = effectMgr.AddComponent<Trajectory>();
trajectory.begin = player.transform;
trajectory.traget = target.transform;
trajectory.effectprefab = Resources.Load<GameObject>(effectData.effectpath);
trajectory.effectduration = effectData.effectduration;
trajectory.effectstart = effectData.effectstart;
ControlTrack controlTrack = asset.CreateTrack<ControlTrack>();
TimelineClip timelineClip = controlTrack.CreateClip<ControlPlayableAsset>();
ControlPlayableAsset controlPlayableAsset = timelineClip.asset as ControlPlayableAsset;
controlPlayableAsset.sourceGameObject.defaultValue = effectMgr;
timelineClip.start = effectData.effectstart + j * effectData.invetime;
timelineClip.duration = effectData.effectduration;
}
}
if (director!=null)
{
director.Play();
}
}
if (GUILayout.Button("保存"))
{
string info = JsonConvert.SerializeObject(skillDatas);
File.WriteAllText(path, info);
}
GUILayout.EndVertical();
GUILayout.EndScrollView();
}
private void OnDestroy()
{
if (player!=null)
{
DestroyImmediate(player);
DestroyImmediate(target);
}
}
}
技能编辑器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Timeline;
public class Trajectory : MonoBehaviour, ITimeControl //特效
{
public Transform begin,traget;
public GameObject effectprefab;
GameObject effect;
public float effectduration, effectstart;
public void OnControlTimeStart()
{
if (effect==null)
{
effect = Instantiate(effectprefab);
effect.transform.position = begin.position;
}
}
public void OnControlTimeStop()
{
if (effect!=null)
{
DestroyImmediate(effect);
}
}
public void SetTime(double time)
{
if (effect!=null)
{
Vector3 zhong = Vector3.Lerp(begin.position, traget.position, 0.5f);
List<Vector3> list = new List<Vector3>();
Vector3 yuan = Random.insideUnitCircle;
Vector3 pos = begin.rotation * yuan + zhong;
list.Add(begin.position);
list.Add(pos);
list.Add(traget.position);
effect.transform.position = RBS(list,((float)time)/effectduration) ;
}
}
Vector3 RBS(List<Vector3> list,float a)//贝塞尔曲线
{
List<Vector3> vector3s = new List<Vector3>();
for (int i = 0; i < list.Count-1; i++)
{
vector3s.Add(Vector3.Lerp(list[i], list[i + 1], a));
}
if (vector3s.Count==1)
{
return vector3s[0];
}
else
{
return RBS(vector3s, a);
}
}
}
弹道
using System.Collections.Generic;
public enum AddTyped
{
动画,
音效,
效果
}
public class SkillData
{
public int id; //id
public string name; //名字
public string imgicon;//图片
public string des;//描述
public float range;//攻击范围
public float distance;//攻击距离
public List<AnimtonData> animtonDatas = new List<AnimtonData>();
public List<AudioData> audioDatas = new List<AudioData>();
public List<EffectData> effectDatas = new List<EffectData>();
}
/// <summary>
/// 动画
/// </summary>
public class AnimtonData
{
public string anipath;
public float aniduration;
public float anistart;
}
/// <summary>
/// 音频
/// </summary>
public class AudioData
{
public string audpath;
public float audduration;
public float audstart;
}
/// <summary>
/// 特效
/// </summary>
public class EffectData
{
public string effectpath;
public float effectduration;
public float effectstart;
public int num;
public float invetime;
}
数据