添加包
This commit is contained in:
parent
1dd7770195
commit
4e1ccd0c02
98
EintooAR/.gitignore
vendored
Normal file
98
EintooAR/.gitignore
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
# UnityProject
|
||||
|
||||
/[Ll]ibrary/
|
||||
/[Tt]emp/
|
||||
/[Oo]bj/
|
||||
/[Bb]uild/
|
||||
/[Bb]uilds/
|
||||
/[Ll]ogs/
|
||||
/[Mm]emoryCaptures/
|
||||
/EditorBuild/
|
||||
/[Aa]ssets/StreamingAssets
|
||||
/[Aa]ssets/StreamingAssets.meta
|
||||
/BuildBundleInfo/
|
||||
/[AR]FoundationRemoteCompanionApp
|
||||
|
||||
# Asset meta data should only be ignored when the corresponding asset is also ignored
|
||||
!/[Aa]ssets/**/*.meta
|
||||
|
||||
# Uncomment this line if you wish to ignore the asset store tools plugin
|
||||
# /[Aa]ssets/AssetStoreTools*
|
||||
|
||||
# Autogenerated Jetbrains Rider plugin
|
||||
[Aa]ssets/Plugins/Editor/JetBrains*
|
||||
|
||||
# Visual Studio cache directory
|
||||
.vs/
|
||||
|
||||
# Gradle cache directory
|
||||
.gradle/
|
||||
|
||||
# Autogenerated VS/MD/Consulo solution and project files
|
||||
ExportedObj/
|
||||
.consulo/
|
||||
*.csproj
|
||||
*.unityproj
|
||||
*.sln
|
||||
*.suo
|
||||
*.tmp
|
||||
*.user
|
||||
*.userprefs
|
||||
*.pidb
|
||||
*.booproj
|
||||
*.svd
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.opendb
|
||||
*.VC.db
|
||||
|
||||
# Unity3D generated meta files
|
||||
*.pidb.meta
|
||||
*.pdb.meta
|
||||
*.mdb.meta
|
||||
|
||||
# Unity3D generated file on crash reports
|
||||
sysinfo.txt
|
||||
|
||||
# Builds
|
||||
*.apk
|
||||
|
||||
# Crashlytics generated file
|
||||
crashlytics-build.properties
|
||||
|
||||
#HybirdCLR(HuaTuo)
|
||||
/HybirdCLRData/
|
||||
[Hh]ybridCLRData/
|
||||
[Aa]ssets/HybridCLRGenerate/
|
||||
[Aa]ssets/HybridCLRGenerate.meta
|
||||
|
||||
#AATemp
|
||||
[Aa]ssets/AATemp/
|
||||
[Aa]ssets/AATemp.meta
|
||||
|
||||
# Custom AATest
|
||||
[Aa]ssets/AATest/
|
||||
[Aa]ssets/AATest.meta
|
||||
|
||||
#Bundles
|
||||
Bundles/
|
||||
|
||||
#Sandbox
|
||||
Sandbox/
|
||||
|
||||
#MAC
|
||||
.DS_Store
|
||||
|
||||
#Rider
|
||||
.idea/
|
||||
|
||||
#Odin Inspector
|
||||
# [Aa]ssets/Plugins/Sirenix/
|
||||
# [Aa]ssets/Plugins/Sirenix.meta
|
||||
|
||||
#YooAssets
|
||||
package/
|
||||
yoo/
|
||||
[Aa]ssets/TEngine/AssetSetting/Resources/BuiltinFileManifest.asset
|
||||
[Aa]ssets/TEngine/AssetSetting/Resources/BuiltinFileManifest.asset.meta
|
||||
ARFoundationRemoteInstaller
|
6
EintooAR/.vsconfig
Normal file
6
EintooAR/.vsconfig
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"components": [
|
||||
"Microsoft.VisualStudio.Workload.ManagedGame"
|
||||
]
|
||||
}
|
239
EintooAR/Packages/GAS/CHANGELOG.md
Normal file
239
EintooAR/Packages/GAS/CHANGELOG.md
Normal file
@ -0,0 +1,239 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.8] - 2024-07-30
|
||||
|
||||
进行了一系列的优化。(From: BCC @kenkinky)
|
||||
|
||||
### Changed
|
||||
|
||||
- 进行了一系列的优化
|
||||
|
||||
## [1.1.6] - 2024-06-26
|
||||
|
||||
修复了AbilitySpec中CheckCost时,modifier为减法时的计算错误;追加了Attribute的钳制功能。
|
||||
|
||||
### Changed
|
||||
|
||||
- 追加了Attribute的钳制功能(From: BCC @kenkinky)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了AbilitySpec中CheckCost时,modifier为减法时的计算错误。
|
||||
|
||||
|
||||
## [1.1.6] - 2024-06-26
|
||||
|
||||
修复了由于优化GE创建流程时导致的Granted Ability生成错误;优化了period的边界问题
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化了period的边界问题(From: BCC @kenkinky)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了由于优化GE创建流程时导致的Granted Ability生成错误。
|
||||
|
||||
|
||||
## [1.1.5] - 2024-06-19
|
||||
|
||||
修复了AttrBasedMMC的快照读取错误;Modifier新增了减法,除法操作类型。
|
||||
|
||||
### Changed
|
||||
|
||||
- Modifier新增了减法,除法操作类型。(From: BCC @kenkinky)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了AttrBasedMMC的快照读取错误。
|
||||
|
||||
|
||||
## [1.1.4] - 2024-06-14
|
||||
|
||||
重新整理了ASC的ApplyGameplayEffect方法的逻辑,现在GE的Tag相关判断是在实例化之后。允许用户在GameplayEffectSpec生效前对GE进行修改和操作。
|
||||
|
||||
### Changed
|
||||
|
||||
- 重新整理了ASC的ApplyGameplayEffectTo(GameplayEffect gameplayEffect, AbilitySystemComponent target)方法的逻辑
|
||||
- ASC新增:ApplyGameplayEffectTo(GameplayEffectSpec gameplayEffectSpec, AbilitySystemComponent target) 和
|
||||
ApplyGameplayEffectToSelf(GameplayEffectSpec gameplayEffectSpec)
|
||||
|
||||
## [1.1.3] - 2024-06-13
|
||||
|
||||
添加了带level形参的ApplyGE方法。
|
||||
|
||||
### Changed
|
||||
|
||||
- 添加了带level形参的ApplyGE方法。
|
||||
|
||||
|
||||
## [1.1.2] - 2024-06-12
|
||||
|
||||
修复了部分bug。编辑器界面部分优化
|
||||
|
||||
### Changed
|
||||
|
||||
- 编辑器界面部分优化(From: BCC @kenkinky)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了时间轴能力的durational cue重复调用OnRemove()的错误
|
||||
- 修复了时间轴编辑器的TargetCatcher的Inspector不更新的错误
|
||||
|
||||
|
||||
## [1.1.1] - 2024-05-31
|
||||
|
||||
补充了Stacking相关功能。
|
||||
|
||||
### Changed
|
||||
|
||||
- 添加Stack相关MMC
|
||||
- 补充stack刷新计算current value逻辑
|
||||
- 添加stack count变化监听事件
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了Attribute Aggregator的事件注册逻辑错误。
|
||||
|
||||
## [1.1.0] - 2024-05-30
|
||||
|
||||
补充了Granted Ability和GameplayEffect Stacking两个功能;优化了部分GC;优化了编辑器界面操作等;修复了部分bug。
|
||||
|
||||
### Changed
|
||||
|
||||
- 补充了Granted Ability,详情可见README文档的2.8.c
|
||||
- 补充了GameplayEffect Stacking,详情可见README文档的2.7中Stacking部分
|
||||
- 优化了部分GC。(From: BCC @kenkinky)
|
||||
- 优化了部分执行逻辑,增强了代码可读性。
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了部分逻辑bug。(From: BCC @kenkinky)
|
||||
|
||||
## [1.0.9] - 2024-04-25
|
||||
|
||||
优化type查找,优化GAS的项目级配置文件管理。
|
||||
|
||||
### Changed
|
||||
|
||||
- 新增TimelineAbilityT, 方便继承和扩展TimelineAbility.(From: BCC @kenkinky)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修正TryAddDynamicAddedTag添加不同类型Source时类型转换失败异常(From: BCC @kenkinky)
|
||||
- 修复了Setting中生成配置目录后,未调用AssetDatabase.Refresh()导致配置文件目录未及时更新的问题。
|
||||
## [1.0.8] - 2024-04-23
|
||||
|
||||
优化了部分GC。
|
||||
|
||||
### Fixed
|
||||
|
||||
- AttributeSetContainer的TryGetAttributeSet方法中,Type.Name存在GC。
|
||||
- 新增了预缓存接口:GasCache.CacheAttributeSetName。
|
||||
- 使用方法:在GAS初始化时,调用GasCache.CacheAttributeSetName(GAttrSetLib.TypeToName);
|
||||
- GameplayTagAggregator的Tag判断相关方法存在GC。GC来源是LINQ表达式的过程匿名方法产生的GC。已经把LINQ表达式改成了普通循环做法。
|
||||
- 新增了Pool工具类,优化了部分GC。(From: BCC @kenkinky)
|
||||
|
||||
## [1.0.7] - 2024-04-17
|
||||
|
||||
修复全局配置保存失败问题;修复Editor代码不该编译问题
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复全局配置保存失败问题,Tag,Attribute,AttributeSet,Setting的配置文件保存不该使用AssetDataBase。
|
||||
- 修正无法打包编译异常 #11 (From: BCC @kenkinky)
|
||||
|
||||
## [1.0.6] - 2024-04-16
|
||||
|
||||
优化type查找,优化GAS的项目级配置文件管理。
|
||||
|
||||
### Changed
|
||||
|
||||
- 修改了Tag,Attribute,AttributeSet,Setting的配置文件路径,调整至ProjectSettings,并且为单例配置文件。
|
||||
- 优化了TypeUtil,Editor环境下类型查找范围改为全程序集。
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复一个严重bug: 修复AttributeBasedModCalculation不能正确保存的问题, 还有一些小优化.(From: BCC @kenkinky)
|
||||
|
||||
## [1.0.5] - 2024-04-12
|
||||
|
||||
修复了部分bug;优化编辑器操作。
|
||||
|
||||
### Added
|
||||
|
||||
- 优化编辑器操作。(From: BCC @kenkinky)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了TryActivateAbility的返回值逻辑错误。
|
||||
|
||||
|
||||
## [1.0.4] - 2024-04-11
|
||||
|
||||
修复了部分bug;测试通过了推导属性设计;优化了GE容器的管理,增强代码可读性。
|
||||
|
||||
### Added
|
||||
|
||||
- 添加了GAS内部的子Event系统,为方便之后用上事件系统做准备。
|
||||
|
||||
### Fixed
|
||||
|
||||
- 推导属性的实时更新错误。补上了AttributeBasedMMC的Track类修改器属性变化监听。
|
||||
- 修复GASHost销毁时的错误逻辑,Host的静态单例改为饿汉式,同步GAS的初始化只会执行一次。
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化GameplayEffectContainer结构,现在只维护一个GameplayEffect列表
|
||||
|
||||
### Removed
|
||||
|
||||
- 移除DerivedAttribute和MetaAttribute脚本,弃用。这两个属性式设计方式,而不是实际存在的类。
|
||||
|
||||
## [1.0.3] - 2024-04-09
|
||||
|
||||
删除SetByCallerModCalculation,弃用。
|
||||
|
||||
### Removed
|
||||
|
||||
- 删除SetByCallerModCalculation,弃用。
|
||||
|
||||
## [1.0.2] - 2024-04-08
|
||||
|
||||
优化Editor使用体验(From: BCC @kenkinky)
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化Editor使用体验(From: BCC @kenkinky)
|
||||
|
||||
|
||||
## [1.0.1] - 2024-03-29
|
||||
|
||||
删除Instant类型GameplayCue的Apply Target参数。
|
||||
|
||||
### Removed
|
||||
|
||||
- Instant类型GameplayCue的Apply Target弃用。
|
||||
|
||||
## [1.0.0] - 2024-03-13
|
||||
|
||||
EX-GAS 1.0.0 发布
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- none
|
||||
|
||||
### Changed
|
||||
|
||||
- none
|
||||
|
||||
### Removed
|
||||
|
||||
- none
|
7
EintooAR/Packages/GAS/CHANGELOG.md.meta
Normal file
7
EintooAR/Packages/GAS/CHANGELOG.md.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34ae97a0d741c5844a4fac12ff8e1c45
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
3
EintooAR/Packages/GAS/Editor.meta
Normal file
3
EintooAR/Packages/GAS/Editor.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceb70b71a95f4810bb22c72560de1755
|
||||
timeCreated: 1701928918
|
3
EintooAR/Packages/GAS/Editor/Ability.meta
Normal file
3
EintooAR/Packages/GAS/Editor/Ability.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 916ae4e58ce74ba2b0686ddc372419d9
|
||||
timeCreated: 1703772158
|
@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GAS.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class AbilityCollectionGenerator
|
||||
{
|
||||
public static void Gen()
|
||||
{
|
||||
string pathWithoutAssets = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
|
||||
var filePath =
|
||||
$"{pathWithoutAssets}/{GASSettingAsset.CodeGenPath}/{GasDefine.GAS_ABILITY_LIB_CSHARP_SCRIPT_NAME}";
|
||||
GenerateAbilityCollection(filePath);
|
||||
}
|
||||
|
||||
private static void GenerateAbilityCollection(string filePath)
|
||||
{
|
||||
using var writer = new IndentedWriter(new StreamWriter(filePath));
|
||||
writer.WriteLine("///////////////////////////////////");
|
||||
writer.WriteLine("//// This is a generated file. ////");
|
||||
writer.WriteLine("//// Do not modify it. ////");
|
||||
writer.WriteLine("///////////////////////////////////");
|
||||
|
||||
writer.WriteLine("");
|
||||
|
||||
writer.WriteLine("using System;");
|
||||
writer.WriteLine("using System.Collections.Generic;");
|
||||
|
||||
writer.WriteLine("");
|
||||
|
||||
writer.WriteLine("namespace GAS.Runtime");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
writer.WriteLine("public static class GAbilityLib");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
writer.WriteLine("public struct AbilityInfo");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
writer.WriteLine("public string Name;");
|
||||
writer.WriteLine("public string AssetPath;");
|
||||
writer.WriteLine("public Type AbilityClassType;");
|
||||
//writer.WriteLine("public AbilityAsset Asset()");
|
||||
// writer.WriteLine("{");
|
||||
// writer.Indent++;
|
||||
// {
|
||||
// string loadAbilityAssetCode = string.Format(loadMethodCodeString, "AssetPath");
|
||||
// writer.WriteLine($"return {loadAbilityAssetCode};");
|
||||
// }
|
||||
// writer.Indent--;
|
||||
// writer.WriteLine("}");
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.WriteLine("}");
|
||||
|
||||
writer.WriteLine("");
|
||||
|
||||
var abilityAssets = EditorUtil
|
||||
.FindAssetsByType<AbilityAsset>(GASSettingAsset.GameplayAbilityLibPath)
|
||||
.OrderBy(x => x.UniqueName)
|
||||
.ThenBy(x => x.name)
|
||||
.ToArray();
|
||||
|
||||
foreach (var ability in abilityAssets)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(ability);
|
||||
#if true
|
||||
writer.WriteLine(
|
||||
$"public static AbilityInfo {ability.UniqueName} = " +
|
||||
$"new AbilityInfo {{ " +
|
||||
$"Name = \"{ability.UniqueName}\", " +
|
||||
$"AssetPath = \"{path}\"," +
|
||||
$"AbilityClassType = typeof({ability.InstanceAbilityClassFullName}) }};");
|
||||
#else
|
||||
writer.WriteLine($"public static AbilityInfo {ability.UniqueName} = new AbilityInfo");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
writer.WriteLine($"Name = \"{ability.UniqueName}\",");
|
||||
writer.WriteLine($"AssetPath = \"{path}\",");
|
||||
writer.WriteLine($"AbilityClassType = typeof({ability.InstanceAbilityClassFullName})");
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.WriteLine("};");
|
||||
#endif
|
||||
// writer.WriteLine($"private static {ability.InstanceAbilityClassFullName} _{validName};");
|
||||
// writer.WriteLine($"public static {ability.InstanceAbilityClassFullName} {validName}()");
|
||||
// writer.WriteLine("{");
|
||||
// writer.Indent++;
|
||||
// {
|
||||
// writer.WriteLine($"if (_{validName} == null) _{validName} = new {ability.InstanceAbilityClassFullName}({validName}_Info.Asset());");
|
||||
// writer.Indent++;
|
||||
// {
|
||||
// writer.WriteLine($"return _{validName};");
|
||||
// }
|
||||
// writer.Indent--;
|
||||
// }
|
||||
// writer.Indent--;
|
||||
// writer.WriteLine("}");
|
||||
|
||||
writer.WriteLine("");
|
||||
}
|
||||
|
||||
writer.WriteLine("");
|
||||
|
||||
writer.WriteLine(
|
||||
"public static Dictionary<string, AbilityInfo> AbilityMap = new Dictionary<string, AbilityInfo>");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
foreach (var ability in abilityAssets)
|
||||
{
|
||||
writer.WriteLine($"[\"{ability.UniqueName}\"] = {ability.UniqueName},");
|
||||
}
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.WriteLine("};");
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.Write("}");
|
||||
|
||||
Console.WriteLine($"Generated GTagLib at path: {filePath}");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 499ab276139746f595dbcfc5fc935f68
|
||||
timeCreated: 1705071386
|
37
EintooAR/Packages/GAS/Editor/Ability/AbilityEditorUtil.cs
Normal file
37
EintooAR/Packages/GAS/Editor/Ability/AbilityEditorUtil.cs
Normal file
@ -0,0 +1,37 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Runtime;
|
||||
|
||||
public static class AbilityEditorUtil
|
||||
{
|
||||
public static List<string> GetAbilityClassNames()
|
||||
{
|
||||
var classNames = new List<string>();
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
var types = assembly.GetTypes();
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (type.IsSubclassOf(typeof(AbstractAbility)))
|
||||
{
|
||||
classNames.Add(type.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ReflectionTypeLoadException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return classNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f6afbd9c3ac4e958729c82c6ef46146
|
||||
timeCreated: 1704263269
|
141
EintooAR/Packages/GAS/Editor/Ability/AbilityOverview.cs
Normal file
141
EintooAR/Packages/GAS/Editor/Ability/AbilityOverview.cs
Normal file
@ -0,0 +1,141 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GAS.General.Validation;
|
||||
using GAS.Runtime;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class AbilityOverview
|
||||
{
|
||||
[BoxGroup("Warning", order: -1)]
|
||||
[HideLabel]
|
||||
[ShowIf("ExistAbilityWithEmptyUniqueName")]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string Warning_AbilityUniqueNameIsNull =
|
||||
"<size=13><color=yellow>The <color=orange>Unique Name</color> of the ability must not be <color=red><b>EMPTY</b></color>! " +
|
||||
"Please check!</color></size>";
|
||||
|
||||
[BoxGroup("Warning", order: -1)]
|
||||
[HideLabel]
|
||||
[ShowIf("ExistAbilityWithDuplicatedUniqueName")]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string Warning_AbilityUniqueNameRepeat =
|
||||
"<size=13><color=yellow>The <color=orange>Unique Name</color> of the ability must not be <color=red><b>DUPLICATED</b></color>! " +
|
||||
"The duplicated abilities are as follows:<color=white> Move,Attack </color>.</color></size>";
|
||||
|
||||
[VerticalGroup("Abilities", order: 1)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowIndexLabels = false, ShowItemCount = true, IsReadOnly = true)]
|
||||
[DisplayAsString]
|
||||
public List<string> Abilities = new List<string>();
|
||||
|
||||
public AbilityOverview()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
[HorizontalGroup("Buttons", order: 0, MarginRight = 0.2f)]
|
||||
[GUIColor(0, 0.9f, 0.1f, 1)]
|
||||
[Button("Generate Ability Collection", ButtonSizes.Large, ButtonStyle.Box, Expanded = true)]
|
||||
void GenerateAbilityCollection()
|
||||
{
|
||||
if (ExistAbilityWithEmptyUniqueName() || ExistAbilityWithDuplicatedUniqueName())
|
||||
{
|
||||
EditorUtility.DisplayDialog("Warning", "Please check the warning message!\n" +
|
||||
"Fix the Unique Name Error!\n" +
|
||||
"(If you have fixed all and the warning still exist," +
|
||||
" try to refresh the abilities with the REFRESH button.)", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
AbilityCollectionGenerator.Gen();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private bool _orderByUniqueName = true;
|
||||
|
||||
[HorizontalGroup("Buttons", width: 180)]
|
||||
[Button(SdfIconType.SortAlphaDown, "@_orderByUniqueName?\"Sort By AssetName\":\"Sort By UniqueName\"",
|
||||
ButtonHeight = 30)]
|
||||
public void ToggleOrderByUniqueName()
|
||||
{
|
||||
_orderByUniqueName = !_orderByUniqueName;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private bool _showDetail = false;
|
||||
|
||||
[HorizontalGroup("Buttons", width: 120)]
|
||||
[Button(SdfIconType.TicketDetailed, "@_showDetail?\"Hide Detail\":\"Show Detail\"", ButtonHeight = 30)]
|
||||
public void ToggleShowDetail()
|
||||
{
|
||||
_showDetail = !_showDetail;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
[HorizontalGroup("Buttons", width: 50)]
|
||||
[GUIColor(1, 1f, 0)]
|
||||
[Button(SdfIconType.ArrowRepeat, "", ButtonHeight = 30)]
|
||||
[HideLabel]
|
||||
public void Refresh()
|
||||
{
|
||||
Abilities.Clear();
|
||||
var abilityAssets = EditorUtil.FindAssetsByType<AbilityAsset>(GASSettingAsset.GameplayAbilityLibPath);
|
||||
var orderedAbilityAssets = _orderByUniqueName
|
||||
? abilityAssets
|
||||
.OrderBy(x => x.UniqueName)
|
||||
.ThenBy(x => x.name)
|
||||
: abilityAssets.OrderBy(x => x.name);
|
||||
|
||||
Abilities = orderedAbilityAssets.Select(ability =>
|
||||
{
|
||||
var text = Validations.ValidateVariableName(ability.UniqueName).IsValid
|
||||
? ability.UniqueName
|
||||
: $"{ability.UniqueName}(非法UniqueName)";
|
||||
|
||||
if (_showDetail)
|
||||
{
|
||||
text += $" - asset: {ability.name}, type: {ability.GetType().FullName}";
|
||||
}
|
||||
|
||||
return text;
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
bool ExistAbilityWithEmptyUniqueName()
|
||||
{
|
||||
bool existEmpty = Abilities.Exists(string.IsNullOrEmpty);
|
||||
return existEmpty;
|
||||
}
|
||||
|
||||
bool ExistAbilityWithDuplicatedUniqueName()
|
||||
{
|
||||
var duplicateStrings = FindDuplicateStrings(Abilities);
|
||||
bool existDuplicated = duplicateStrings.Length > 0;
|
||||
if (existDuplicated)
|
||||
{
|
||||
string duplicatedUniqueName = duplicateStrings.Aggregate("", (current, d) => current + (d + ","));
|
||||
duplicatedUniqueName = duplicatedUniqueName.Remove(duplicatedUniqueName.Length - 1, 1);
|
||||
Warning_AbilityUniqueNameRepeat =
|
||||
"<size=13><color=yellow>The <color=orange>Unique Name</color> of the ability must not be <color=red><b>DUPLICATED</b></color>! " +
|
||||
$"The duplicated abilities are as follows: \n <size=15><b><color=white> {duplicatedUniqueName} </color></b></size>.</color></size>";
|
||||
}
|
||||
|
||||
return existDuplicated;
|
||||
}
|
||||
|
||||
static string[] FindDuplicateStrings(IEnumerable<string> names)
|
||||
{
|
||||
var duplicates = names
|
||||
.Where(name => !string.IsNullOrEmpty(name))
|
||||
.GroupBy(name => name)
|
||||
.Where(group => group.Count() > 1)
|
||||
.Select(group => group.Key)
|
||||
.ToArray();
|
||||
|
||||
return duplicates;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3209fb75be944c36b4f2b9d347aee120
|
||||
timeCreated: 1705290851
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f637cff7efc48542be2b4138fe99108
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55f35a69d4a54054d96e7cc375d25246
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,17 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement name="RightContent" style="flex-grow: 1; height: 100%; max-height: 100%; min-height: 100%; flex-shrink: 0;">
|
||||
<GAS.Editor.General.VisualElement.SplitView orientation="Horizontal" usage-hints="None" fixed-pane-initial-dimension="200" fixed-pane-index="1" style="position: relative; left: 0; top: 0; flex-direction: column; width: 100%; max-width: 100%; min-width: 100%; height: 100%; max-height: 100%; min-height: 100%;">
|
||||
<ui:VisualElement name="RightTimeline" style="flex-grow: 1; padding-right: 0; width: 500px; flex-shrink: 0; height: 100%; max-height: 100%; min-height: 100%; min-width: auto;">
|
||||
<ui:IMGUIContainer name="TimerShaft" style="height: 30px; min-height: 30px; border-left-color: rgb(43, 43, 43); border-right-color: rgb(43, 43, 43); border-top-color: rgb(43, 43, 43); border-bottom-color: rgb(43, 43, 43); border-bottom-width: 1px; margin-right: 13px; max-height: 30px;" />
|
||||
<ui:ScrollView name="MainContent" mode="VerticalAndHorizontal" vertical-scroller-visibility="AlwaysVisible" style="flex-grow: 1;">
|
||||
<ui:VisualElement name="ContentTrackList" style="flex-grow: 1; height: 1000px; flex-shrink: 1; width: auto;" />
|
||||
</ui:ScrollView>
|
||||
<ui:IMGUIContainer name="SelectLine" style="position: absolute; left: 0;" />
|
||||
<ui:IMGUIContainer name="FinishLine" style="position: absolute; left: 0;" />
|
||||
<ui:IMGUIContainer name="DottedLine" style="position: absolute; left: 0;" />
|
||||
<ui:IMGUIContainer name="DragItemPreview" style="position: absolute; left: 0; top: 0;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="ClipInspector" style="flex-grow: 0; width: 300px; min-width: 100px; border-left-color: rgb(120, 120, 120); border-right-color: rgb(120, 120, 120); border-top-color: rgb(120, 120, 120); border-bottom-color: rgb(120, 120, 120); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; max-width: none; align-self: auto; align-items: flex-start; flex-shrink: 1; height: 100%; max-height: 100%; min-height: 100%;" />
|
||||
</GAS.Editor.General.VisualElement.SplitView>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f6767c7cb94e1940bb9595b5fba5d45
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
@ -0,0 +1,15 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using GAS.General;
|
||||
|
||||
public class AbilityTimelineEditorConfig
|
||||
{
|
||||
public int FrameUnitWidth = 10;
|
||||
public const int StandardFrameUnitWidth = 1;
|
||||
public const int MaxFrameUnitLevel= 20;
|
||||
public const float MinTimerShaftFrameDrawStep = 5;
|
||||
public int DefaultFrameRate => GASTimer.FrameRate;
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51b96cc42da3453c9db1934582d0a8c2
|
||||
timeCreated: 1708482904
|
@ -0,0 +1,397 @@
|
||||
using System;
|
||||
using GAS.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UIElements;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 这个类被反射引用到, 重构请小心!!
|
||||
/// </summary>
|
||||
public class AbilityTimelineEditorWindow : EditorWindow
|
||||
{
|
||||
[SerializeField]
|
||||
private VisualTreeAsset m_VisualTreeAsset;
|
||||
|
||||
private VisualElement _root;
|
||||
|
||||
|
||||
public static AbilityTimelineEditorWindow Instance { get; private set; }
|
||||
public TimelineTrackView TrackView { get; private set; }
|
||||
|
||||
public TimelineInspector TimelineInspector { get; private set; }
|
||||
|
||||
private static EditorWindow _childInspector;
|
||||
|
||||
public void CreateGUI()
|
||||
{
|
||||
Instance = this;
|
||||
_root = rootVisualElement;
|
||||
|
||||
// Instantiate UXML
|
||||
VisualElement labelFromUxml = m_VisualTreeAsset.Instantiate();
|
||||
_root.Add(labelFromUxml);
|
||||
|
||||
InitAbilityAssetBar();
|
||||
InitTopBar();
|
||||
InitController();
|
||||
TimerShaftView = new TimerShaftView(_root);
|
||||
TrackView = new TimelineTrackView(_root);
|
||||
TimelineInspector = new TimelineInspector(_root);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 这个方法被反射引用到, 重构请小心!!
|
||||
/// </summary>
|
||||
public static void ShowWindow(TimelineAbilityAssetBase asset)
|
||||
{
|
||||
var wnd = GetWindow<AbilityTimelineEditorWindow>();
|
||||
wnd.titleContent = new GUIContent("AbilityTimelineEditorWindow");
|
||||
wnd.InitAbility(asset);
|
||||
|
||||
// 打开子Inspector
|
||||
EditorApplication.delayCall += () => wnd.ShowChildInspector();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
AbilityAsset.Save();
|
||||
}
|
||||
|
||||
private void InitAbility(TimelineAbilityAssetBase asset)
|
||||
{
|
||||
_abilityAsset.value = asset;
|
||||
MaxFrame.value = AbilityAsset.FrameCount;
|
||||
CurrentSelectFrameIndex = 0;
|
||||
TimerShaftView.RefreshTimerDraw();
|
||||
TrackView.RefreshTrackDraw();
|
||||
}
|
||||
|
||||
private void SaveAsset()
|
||||
{
|
||||
EditorUtility.SetDirty(AbilityAsset);
|
||||
AssetDatabase.SaveAssetIfDirty(AbilityAsset);
|
||||
}
|
||||
|
||||
#region Config
|
||||
|
||||
public AbilityTimelineEditorConfig Config { get; } = new();
|
||||
|
||||
private ObjectField _abilityAsset;
|
||||
private Button _btnShowAbilityAssetDetail;
|
||||
public TimelineAbilityAssetBase AbilityAsset => _abilityAsset.value as TimelineAbilityAssetBase;
|
||||
|
||||
// private TimelineAbilityEditorWindow AbilityAssetEditor => AbilityAsset != null
|
||||
// ? UnityEditor.Editor.CreateEditor(AbilityAsset) as TimelineAbilityEditorWindow
|
||||
// : null;
|
||||
|
||||
private void InitAbilityAssetBar()
|
||||
{
|
||||
_abilityAsset = _root.Q<ObjectField>("SequentialAbilityAsset");
|
||||
_abilityAsset.RegisterValueChangedCallback(OnSequentialAbilityAssetChanged);
|
||||
|
||||
_btnShowAbilityAssetDetail = _root.Q<Button>("BtnShowAbilityAssetDetail");
|
||||
_btnShowAbilityAssetDetail.clickable.clicked += ShowAbilityAssetDetail;
|
||||
}
|
||||
|
||||
private void OnSequentialAbilityAssetChanged(ChangeEvent<Object> evt)
|
||||
{
|
||||
if (AbilityAsset != null)
|
||||
{
|
||||
MaxFrame.value = AbilityAsset.FrameCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
Selection.activeObject = null;
|
||||
}
|
||||
|
||||
CurrentSelectFrameIndex = 0;
|
||||
TimerShaftView.RefreshTimerDraw();
|
||||
TrackView.RefreshTrackDraw();
|
||||
}
|
||||
|
||||
private void ShowAbilityAssetDetail()
|
||||
{
|
||||
if (AbilityAsset == null) return;
|
||||
Selection.activeObject = AbilityAsset;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TopBar
|
||||
|
||||
private string _previousScenePath;
|
||||
private Button BtnLoadPreviewScene;
|
||||
private Button BtnBackToScene;
|
||||
private Button BtnChildInspector;
|
||||
private ObjectField _previewObjectField;
|
||||
public GameObject PreviewObject => _previewObjectField.value as GameObject;
|
||||
|
||||
private void InitTopBar()
|
||||
{
|
||||
BtnLoadPreviewScene = _root.Q<Button>(nameof(BtnLoadPreviewScene));
|
||||
BtnLoadPreviewScene.clickable.clicked += LoadPreviewScene;
|
||||
BtnBackToScene = _root.Q<Button>(nameof(BtnBackToScene));
|
||||
BtnBackToScene.clickable.clicked += BackToScene;
|
||||
|
||||
BtnChildInspector = _root.Q<Button>(nameof(BtnChildInspector));
|
||||
BtnChildInspector.clickable.clicked += ShowChildInspector;
|
||||
|
||||
_previewObjectField = _root.Q<ObjectField>("PreviewInstance");
|
||||
_previewObjectField.RegisterValueChangedCallback(OnPreviewObjectChanged);
|
||||
}
|
||||
|
||||
private void ShowChildInspector()
|
||||
{
|
||||
if (_childInspector == null)
|
||||
{
|
||||
_childInspector = GetInspectTarget();
|
||||
_childInspector.Show();
|
||||
}
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
DockUtilities.DockWindow(this, _childInspector, DockUtilities.DockPosition.Right);
|
||||
}
|
||||
|
||||
private void OnPreviewObjectChanged(ChangeEvent<Object> evt)
|
||||
{
|
||||
// TODO : 在这里处理预览对象的变化
|
||||
}
|
||||
|
||||
private void BackToScene()
|
||||
{
|
||||
// 判断是否有记录前一个Scene
|
||||
if (!string.IsNullOrEmpty(_previousScenePath))
|
||||
// 激活前一个Scene
|
||||
EditorSceneManager.OpenScene(_previousScenePath);
|
||||
else
|
||||
Debug.LogWarning("No previous scene available.");
|
||||
}
|
||||
|
||||
private void LoadPreviewScene()
|
||||
{
|
||||
// 记录当前Scene
|
||||
_previousScenePath = SceneManager.GetActiveScene().path;
|
||||
// 创建一个新的Scene
|
||||
var newScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
// 在这里添加临时预览的内容,例如放置一些对象
|
||||
// 这里只是演示,具体可以根据需求添加你的内容
|
||||
// GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
// SceneManager.MoveGameObjectToScene(cube, newScene);
|
||||
// 激活新创建的Scene
|
||||
SceneManager.SetActiveScene(newScene);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TimerShaft
|
||||
|
||||
public TimerShaftView TimerShaftView { get; private set; }
|
||||
|
||||
private int _currentMaxFrame;
|
||||
|
||||
public int CurrentMaxFrame
|
||||
{
|
||||
get => _currentMaxFrame;
|
||||
private set
|
||||
{
|
||||
if (AbilityAsset == null)
|
||||
{
|
||||
_currentMaxFrame = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentMaxFrame == value) return;
|
||||
_currentMaxFrame = value;
|
||||
AbilityAsset.FrameCount = _currentMaxFrame;
|
||||
SaveAsset();
|
||||
MaxFrame.value = _currentMaxFrame;
|
||||
TrackView.UpdateContentSize();
|
||||
TimerShaftView.RefreshTimerDraw();
|
||||
}
|
||||
}
|
||||
|
||||
private int _currentSelectFrameIndex;
|
||||
|
||||
public int CurrentSelectFrameIndex
|
||||
{
|
||||
get => _currentSelectFrameIndex;
|
||||
set
|
||||
{
|
||||
if (_currentSelectFrameIndex == value) return;
|
||||
_currentSelectFrameIndex = Mathf.Clamp(value, 0, MaxFrame.value);
|
||||
CurrentFrame.value = _currentSelectFrameIndex;
|
||||
TimerShaftView.RefreshTimerDraw();
|
||||
|
||||
EvaluateFrame(_currentSelectFrameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public float CurrentFramePos => Mathf.Abs(TimerShaftView.TimeLineContainer.transform.position.x);
|
||||
public float CurrentSelectFramePos => _currentSelectFrameIndex * Config.FrameUnitWidth;
|
||||
public float CurrentEndFramePos => CurrentMaxFrame * Config.FrameUnitWidth;
|
||||
|
||||
public int GetFrameIndexByPosition(float x)
|
||||
{
|
||||
return TimerShaftView.GetFrameIndexByPosition(x);
|
||||
}
|
||||
|
||||
public int GetFrameIndexByMouse(float x)
|
||||
{
|
||||
return TimerShaftView.GetFrameIndexByMouse(x);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Controller
|
||||
|
||||
private Button BtnPlay;
|
||||
private Button BtnLeftFrame;
|
||||
private Button BtnRightFrame;
|
||||
private IntegerField CurrentFrame;
|
||||
private IntegerField MaxFrame;
|
||||
|
||||
private void InitController()
|
||||
{
|
||||
BtnPlay = _root.Q<Button>(nameof(BtnPlay));
|
||||
BtnPlay.clickable.clicked += OnPlay;
|
||||
|
||||
BtnLeftFrame = _root.Q<Button>(nameof(BtnLeftFrame));
|
||||
BtnLeftFrame.clickable.clicked += OnLeftFrame;
|
||||
|
||||
BtnRightFrame = _root.Q<Button>(nameof(BtnRightFrame));
|
||||
BtnRightFrame.clickable.clicked += OnRightFrame;
|
||||
|
||||
CurrentFrame = _root.Q<IntegerField>(nameof(CurrentFrame));
|
||||
CurrentFrame.RegisterValueChangedCallback(OnCurrentFrameChanged);
|
||||
MaxFrame = _root.Q<IntegerField>(nameof(MaxFrame));
|
||||
MaxFrame.RegisterValueChangedCallback(OnMaxFrameChanged);
|
||||
}
|
||||
|
||||
private void OnMaxFrameChanged(ChangeEvent<int> evt)
|
||||
{
|
||||
CurrentMaxFrame = evt.newValue;
|
||||
MaxFrame.value = CurrentMaxFrame;
|
||||
}
|
||||
|
||||
private void OnCurrentFrameChanged(ChangeEvent<int> evt)
|
||||
{
|
||||
CurrentSelectFrameIndex = evt.newValue;
|
||||
CurrentFrame.value = CurrentSelectFrameIndex;
|
||||
}
|
||||
|
||||
private void RefreshPlayButton()
|
||||
{
|
||||
BtnPlay.text = !IsPlaying ? "▶" : "⏹";
|
||||
BtnPlay.style.backgroundColor =
|
||||
!IsPlaying ? new Color(0.5f, 0.5f, 0.5f, 0.5f) : new Color(0.1f, 0.8f, 0.1f, 0.5f);
|
||||
}
|
||||
|
||||
private void OnPlay()
|
||||
{
|
||||
if (AbilityAsset == null) return;
|
||||
IsPlaying = !IsPlaying;
|
||||
}
|
||||
|
||||
private void OnLeftFrame()
|
||||
{
|
||||
if (AbilityAsset == null) return;
|
||||
IsPlaying = false;
|
||||
CurrentSelectFrameIndex -= 1;
|
||||
}
|
||||
|
||||
private void OnRightFrame()
|
||||
{
|
||||
if (AbilityAsset == null) return;
|
||||
IsPlaying = false;
|
||||
CurrentSelectFrameIndex += 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Clip Inspector
|
||||
|
||||
public object CurrentInspectorObject => TimelineInspector.CurrentInspectorObject;
|
||||
|
||||
public void SetInspector(object target = null)
|
||||
{
|
||||
if (AbilityAsset == null) return;
|
||||
TimelineInspector.SetInspector(target);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TimelinePreview
|
||||
|
||||
private DateTime _startTime;
|
||||
private int _startPlayFrameIndex;
|
||||
private bool _isPlaying;
|
||||
|
||||
public bool IsPlaying
|
||||
{
|
||||
get => _isPlaying;
|
||||
private set
|
||||
{
|
||||
_isPlaying = CanPlay() && value;
|
||||
|
||||
if (_isPlaying)
|
||||
{
|
||||
_startTime = DateTime.Now;
|
||||
_startPlayFrameIndex = CurrentSelectFrameIndex;
|
||||
}
|
||||
|
||||
RefreshPlayButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (IsPlaying)
|
||||
{
|
||||
var deltaTime = (DateTime.Now - _startTime).TotalSeconds;
|
||||
var frameIndex = (int)(deltaTime * Config.DefaultFrameRate) + _startPlayFrameIndex;
|
||||
if (frameIndex >= CurrentMaxFrame)
|
||||
{
|
||||
frameIndex = CurrentMaxFrame;
|
||||
IsPlaying = false;
|
||||
}
|
||||
|
||||
CurrentSelectFrameIndex = frameIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void EvaluateFrame(int frameIndex)
|
||||
{
|
||||
if (AbilityAsset == null || _previewObjectField.value == null) return;
|
||||
|
||||
foreach (var track in TrackView.TrackList)
|
||||
track.TickView(frameIndex);
|
||||
}
|
||||
|
||||
private bool CanPlay()
|
||||
{
|
||||
var canPlay = AbilityAsset != null && _previewObjectField.value != null;
|
||||
return canPlay;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Another Inspector
|
||||
|
||||
private static EditorWindow GetInspectTarget(Object targetGO = null)
|
||||
{
|
||||
Type inspectorType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.InspectorWindow");
|
||||
EditorWindow inspectorInstance = CreateInstance(inspectorType) as EditorWindow;
|
||||
if (targetGO) Selection.activeObject = targetGO;
|
||||
return inspectorInstance;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d389b67c6c74be4d9e22a30e4527d0f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_VisualTreeAsset: {fileID: 9197481963319205126, guid: 0ad52cc89065e3e4f9fef4bc5674a5f5, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,9 @@
|
||||
.custom-label {
|
||||
font-size: 20px;
|
||||
-unity-font-style: bold;
|
||||
color: rgb(68, 138, 255);
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
flex-direction: column;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28fcc296ac2d3554db81c84901f63835
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
@ -0,0 +1,46 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<Style src="project://database/Assets/GAS/Editor/Ability/AbilityTimelineEditor/EditorWindow/AbilityTimelineEditorWindow.uss?fileID=7433441132597879392&guid=28fcc296ac2d3554db81c84901f63835&type=3#AbilityTimelineEditorWindow" />
|
||||
<ui:VisualElement name="Root" style="flex-grow: 1; flex-direction: column; height: 100%; min-height: 100%; max-height: 100%; flex-shrink: 0;">
|
||||
<ui:VisualElement name="AbilityAsset" style="flex-grow: 1; min-width: auto; min-height: auto; max-height: 40px; flex-direction: row; border-left-color: rgba(34, 34, 34, 0.84); border-right-color: rgba(34, 34, 34, 0.84); border-top-color: rgba(34, 34, 34, 0.84); border-bottom-color: rgba(34, 34, 34, 0.84); border-top-width: 0; border-right-width: 0; border-bottom-width: 2px; border-left-width: 0; height: 40px; align-self: auto; align-items: center;">
|
||||
<uie:ObjectField label="Ability配置 " name="SequentialAbilityAsset" type="GAS.Runtime.TimelineAbilityAsset, com.exhard.exgas.runtime" style="-unity-font-style: bold; font-size: 13px; -unity-text-align: middle-left; align-items: center; width: auto; align-self: stretch; flex-direction: row; min-width: auto; max-height: none; max-width: 300px;" />
|
||||
<ui:Button text="查看能力基本信息" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnShowAbilityAssetDetail" style="justify-content: center; height: 20px;" />
|
||||
<ui:VisualElement name="Right" style="flex-grow: 1; flex-direction: row; align-items: center; align-self: flex-start; -unity-text-align: upper-left; justify-content: flex-start; padding-left: 30px; border-left-color: rgba(0, 0, 0, 0.53); border-right-color: rgba(0, 0, 0, 0.53); border-top-color: rgba(0, 0, 0, 0.53); border-bottom-color: rgba(0, 0, 0, 0.53); border-right-width: 0; border-left-width: 2px;">
|
||||
<uie:ObjectField label="预览实例" name="PreviewInstance" type="UnityEngine.GameObject, UnityEngine.CoreModule" allow-scene-objects="true" style="align-items: center; align-self: center; flex-direction: row; height: 20px; -unity-font-style: bold; font-size: 15px; -unity-text-align: middle-center; width: 300px; border-left-color: rgb(255, 255, 255); border-right-color: rgb(255, 255, 255); border-top-color: rgb(255, 255, 255); border-bottom-color: rgb(255, 255, 255); border-top-width: 0; border-right-width: 0; border-bottom-width: 0; border-left-width: 0; border-top-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; border-bottom-left-radius: 0;" />
|
||||
<ui:VisualElement name="Buttons" style="flex-grow: 1; flex-direction: row;">
|
||||
<ui:Button text="预览场景" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnLoadPreviewScene" style="-unity-font-style: bold; width: 120px; height: 25px; align-self: auto; justify-content: flex-start; align-items: auto;" />
|
||||
<ui:Button text="返回原场景" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnBackToScene" style="width: 120px; -unity-font-style: bold; height: 25px;" />
|
||||
<ui:Button text="显示子Inspector" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnChildInspector" enable-rich-text="true" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="Content" style="flex-grow: 1; flex-direction: row; flex-shrink: 1; height: auto;">
|
||||
<ui:VisualElement name="LeftConsole" style="flex-grow: 1; width: 200px; min-width: 200px; border-left-color: rgb(41, 41, 41); border-right-color: rgb(41, 41, 41); border-top-color: rgb(41, 41, 41); border-bottom-color: rgb(41, 41, 41); border-left-width: 0; border-right-width: 2px; margin-right: 5px; max-width: 200px; height: 100%; max-height: 100%; min-height: auto; flex-shrink: 0;">
|
||||
<ui:VisualElement name="Controller" style="flex-grow: 1; flex-direction: row; height: 30px; max-height: 30px; min-width: 200px; width: 200px; max-width: 200px; border-left-color: rgba(24, 24, 24, 0.5); border-right-color: rgba(24, 24, 24, 0.5); border-top-color: rgba(24, 24, 24, 0.5); border-bottom-color: rgba(24, 24, 24, 0.5); border-right-width: 0; align-items: auto; align-self: flex-start; justify-content: space-around; position: relative; left: auto; border-bottom-width: 2px;">
|
||||
<ui:VisualElement name="ButtonGroup" style="flex-grow: 1; flex-direction: row; justify-content: flex-start; align-self: center;">
|
||||
<ui:Button text="<" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnLeftFrame" style="font-size: 13px; -unity-font-style: bold; align-self: center;" />
|
||||
<ui:Button text="▶" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnPlay" style="-unity-font-style: bold; font-size: 13px; align-self: center;" />
|
||||
<ui:Button text=">" parse-escape-sequences="true" display-tooltip-when-elided="true" name="BtnRightFrame" style="-unity-font-style: bold; font-size: 13px; align-self: center;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="FrameCount" style="flex-grow: 1; flex-direction: row-reverse; justify-content: flex-end; align-items: center; align-self: center; flex-wrap: nowrap; flex-shrink: 1;">
|
||||
<ui:IntegerField value="0" name="MaxFrame" is-delayed="true" style="width: 40px;" />
|
||||
<ui:Label tabindex="-1" text="/" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Label" />
|
||||
<ui:IntegerField value="0" name="CurrentFrame" readonly="false" style="width: 40px;" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="TrackMenu" style="flex-grow: 1; height: 100%; max-height: 100%; min-height: auto; padding-left: 3px; padding-right: 3px;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="RightContent" style="flex-grow: 1; height: 100%; max-height: 100%; min-height: 100%; flex-shrink: 0;">
|
||||
<ui:VisualElement name="RightTimeline" style="flex-grow: 1; padding-right: 0; width: auto; flex-shrink: 0; height: 100%; max-height: 100%; min-height: 100%; min-width: auto; max-width: none;">
|
||||
<ui:IMGUIContainer name="TimerShaft" style="height: 30px; min-height: 30px; border-left-color: rgb(43, 43, 43); border-right-color: rgb(43, 43, 43); border-top-color: rgb(43, 43, 43); border-bottom-color: rgb(43, 43, 43); border-bottom-width: 1px; margin-right: 13px; max-height: 30px;" />
|
||||
<ui:ScrollView name="MainContent" mode="VerticalAndHorizontal" vertical-scroller-visibility="AlwaysVisible" style="flex-grow: 1;">
|
||||
<ui:VisualElement name="ContentTrackList" style="flex-grow: 1; height: 1000px; flex-shrink: 1; width: auto;" />
|
||||
</ui:ScrollView>
|
||||
<ui:IMGUIContainer name="SelectLine" style="position: absolute; left: 0;" />
|
||||
<ui:IMGUIContainer name="FinishLine" style="position: absolute; left: 0;" />
|
||||
<ui:IMGUIContainer name="DottedLine" style="position: absolute; left: 0;" />
|
||||
<ui:IMGUIContainer name="DragItemPreview" style="position: absolute; left: 0; top: 0;" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ad52cc89065e3e4f9fef4bc5674a5f5
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
@ -0,0 +1,55 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEngine.UIElements;
|
||||
public class TimelineInspector
|
||||
{
|
||||
private VisualElement _root;
|
||||
public object CurrentInspectorObject;
|
||||
public TimelineInspector(VisualElement root)
|
||||
{
|
||||
_root = root;
|
||||
SetInspector();
|
||||
}
|
||||
|
||||
public void SetInspector(object target=null)
|
||||
{
|
||||
UpdateInspector(false,target);
|
||||
}
|
||||
|
||||
private void UpdateInspector(bool force = false, object target = null)
|
||||
{
|
||||
if (CurrentInspectorObject == target && !force) return;
|
||||
|
||||
if (CurrentInspectorObject != null && !force)
|
||||
{
|
||||
if (CurrentInspectorObject is TrackClipBase oldTrackItem) oldTrackItem.ClipVe.OnUnSelect();
|
||||
if (CurrentInspectorObject is TrackBase oldTrack) oldTrack.OnUnSelect();
|
||||
if (CurrentInspectorObject is TrackMarkBase oldMark) oldMark.OnUnSelect();
|
||||
}
|
||||
|
||||
CurrentInspectorObject = target;
|
||||
switch (CurrentInspectorObject)
|
||||
{
|
||||
case null:
|
||||
UnityEditor.Selection.activeObject = null;
|
||||
return;
|
||||
case TrackClipBase trackClip:
|
||||
UnityEditor.Selection.activeObject = trackClip.DataInspector;
|
||||
break;
|
||||
case TrackBase track:
|
||||
UnityEditor.Selection.activeObject = track.DataInspector;
|
||||
break;
|
||||
case TrackMarkBase mark:
|
||||
UnityEditor.Selection.activeObject = mark.DataInspector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshInspector()
|
||||
{
|
||||
UpdateInspector(true,CurrentInspectorObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de22069e09424610a3b23bf48b2c2523
|
||||
timeCreated: 1709101722
|
@ -0,0 +1,144 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class TimelineTrackView
|
||||
{
|
||||
private static List<Type> _trackTypeList;
|
||||
private static readonly Dictionary<string, Type> _trackTypeMap = new();
|
||||
private readonly VisualElement _root;
|
||||
private Button _btnAddTrack;
|
||||
private VisualElement _contentTrackListParent;
|
||||
private MenuTrack _menuBuffGameplayEffect;
|
||||
private MenuTrack _menuDurationalCue;
|
||||
private MenuTrack _menuInstantCue;
|
||||
private MenuTrack _menuInstantTask;
|
||||
private MenuTrack _menuOngoingTask;
|
||||
private MenuTrack _menuReleaseGameplayEffect;
|
||||
private VisualElement _trackMenuParent;
|
||||
|
||||
public TimelineTrackView(VisualElement root)
|
||||
{
|
||||
_root = root;
|
||||
InitTracks();
|
||||
}
|
||||
|
||||
public List<TrackBase> TrackList { get; } = new();
|
||||
|
||||
private static AbilityTimelineEditorConfig Config => AbilityTimelineEditorWindow.Instance.Config;
|
||||
private static TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
private void InitTracks()
|
||||
{
|
||||
_contentTrackListParent = _root.Q<VisualElement>("ContentTrackList");
|
||||
_trackMenuParent = _root.Q<VisualElement>("TrackMenu");
|
||||
|
||||
RefreshTrackDraw();
|
||||
UpdateContentSize();
|
||||
}
|
||||
|
||||
public void RefreshTrackDraw()
|
||||
{
|
||||
TrackList.Clear();
|
||||
_contentTrackListParent.Clear();
|
||||
_trackMenuParent.Clear();
|
||||
if (AbilityAsset == null) return;
|
||||
|
||||
// Instant Cue
|
||||
_menuInstantCue = new MenuTrack();
|
||||
_menuInstantCue.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
typeof(InstantCueTrack), typeof(InstantCueTrackData), "Instant Cue",
|
||||
new Color(0.1f, 0.2f, 0.6f, 0.2f), new Color(0.1f, 0.6f, 0.9f, 0.9f));
|
||||
foreach (var durationalCueTrackData in AbilityAsset.InstantCues)
|
||||
{
|
||||
var instantCueTrack = new InstantCueTrack();
|
||||
instantCueTrack.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
durationalCueTrackData);
|
||||
TrackList.Add(instantCueTrack);
|
||||
}
|
||||
|
||||
|
||||
// Release GameplayEffect
|
||||
_menuReleaseGameplayEffect = new MenuTrack();
|
||||
_menuReleaseGameplayEffect.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
typeof(ReleaseGameplayEffectTrack), typeof(ReleaseGameplayEffectTrackData), "Release Effect",
|
||||
new Color(0.9f, 0.3f, 0.35f, 0.2f), new Color(0.9f, 0.3f, 0.35f, 0.9f));
|
||||
foreach (var releaseGameplayEffectTrackData in AbilityAsset.ReleaseGameplayEffect)
|
||||
{
|
||||
var releaseGameplayEffectTrack = new ReleaseGameplayEffectTrack();
|
||||
releaseGameplayEffectTrack.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
releaseGameplayEffectTrackData);
|
||||
TrackList.Add(releaseGameplayEffectTrack);
|
||||
}
|
||||
|
||||
|
||||
// Instant Task
|
||||
_menuInstantTask = new MenuTrack();
|
||||
_menuInstantTask.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
typeof(TaskMarkEventTrack), typeof(TaskMarkEventTrackData), "Instant Task",
|
||||
new Color(0.1f, 0.6f, 0.6f, 0.2f), new Color(0.1f, 0.6f, 0.6f, 0.9f));
|
||||
foreach (var instantTaskEventTrackData in AbilityAsset.InstantTasks)
|
||||
{
|
||||
var instantTaskEventTrack = new TaskMarkEventTrack();
|
||||
instantTaskEventTrack.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
instantTaskEventTrackData);
|
||||
TrackList.Add(instantTaskEventTrack);
|
||||
}
|
||||
|
||||
|
||||
// Durational Cue
|
||||
_menuDurationalCue = new MenuTrack();
|
||||
_menuDurationalCue.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
typeof(DurationalCueTrack), typeof(DurationalCueTrackData), "Durational Cue",
|
||||
new Color(0.1f, 0.6f, 0.1f, 0.2f), new Color(0.1f, 0.6f, 0.1f, 1));
|
||||
foreach (var durationalCueTrackData in AbilityAsset.DurationalCues)
|
||||
{
|
||||
var cueTrack = new DurationalCueTrack();
|
||||
cueTrack.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth, durationalCueTrackData);
|
||||
TrackList.Add(cueTrack);
|
||||
}
|
||||
|
||||
// Buff GameplayEffect
|
||||
_menuBuffGameplayEffect = new MenuTrack();
|
||||
_menuBuffGameplayEffect.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
typeof(BuffGameplayEffectTrack), typeof(BuffGameplayEffectTrackData), "Buff",
|
||||
new Color(0.9f, 0.6f, 0.6f, 0.2f), new Color(0.9f, 0.6f, 0.6f, 1));
|
||||
foreach (var buffGameplayEffectTrackData in AbilityAsset.BuffGameplayEffects)
|
||||
{
|
||||
var buffTrack = new BuffGameplayEffectTrack();
|
||||
buffTrack.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
buffGameplayEffectTrackData);
|
||||
TrackList.Add(buffTrack);
|
||||
}
|
||||
|
||||
// Ongoing Task
|
||||
_menuOngoingTask = new MenuTrack();
|
||||
_menuOngoingTask.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
typeof(TaskClipEventTrack), typeof(TaskClipEventTrackData), "Ongoing Task",
|
||||
new Color(0.7f, 0.3f, 0.7f, 0.2f), new Color(0.5f, 0.3f, 0.5f, 1));
|
||||
foreach (var customClipEventTrackData in AbilityAsset.OngoingTasks)
|
||||
{
|
||||
var customClipTrack = new TaskClipEventTrack();
|
||||
customClipTrack.Init(_contentTrackListParent, _trackMenuParent, Config.FrameUnitWidth,
|
||||
customClipEventTrackData);
|
||||
TrackList.Add(customClipTrack);
|
||||
}
|
||||
|
||||
UpdateContentSize();
|
||||
}
|
||||
|
||||
public void UpdateContentSize()
|
||||
{
|
||||
_contentTrackListParent.style.width =
|
||||
AbilityTimelineEditorWindow.Instance.CurrentMaxFrame * Config.FrameUnitWidth;
|
||||
foreach (var track in TrackList) track.RefreshShow(Config.FrameUnitWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fd4dc4ec6be4b149e428db5c2ca0fb0
|
||||
timeCreated: 1709022190
|
@ -0,0 +1,272 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
public class TimerShaftView
|
||||
{
|
||||
private readonly VisualElement _root;
|
||||
|
||||
private int _dottedLineFrameIndex = -1;
|
||||
|
||||
private Rect _dragItemPreviewRect;
|
||||
|
||||
private bool _showDragItemPreview;
|
||||
private VisualElement contentViewPort;
|
||||
private IMGUIContainer DottedLine;
|
||||
private IMGUIContainer DragItemPreview;
|
||||
private IMGUIContainer FinishLine;
|
||||
private IMGUIContainer SelectLine;
|
||||
|
||||
private bool timerShaftMouseIn;
|
||||
|
||||
public TimerShaftView(VisualElement root)
|
||||
{
|
||||
_root = root;
|
||||
InitTimerShaft();
|
||||
}
|
||||
|
||||
private static AbilityTimelineEditorWindow EditorInst => AbilityTimelineEditorWindow.Instance;
|
||||
private static AbilityTimelineEditorConfig Config => AbilityTimelineEditorWindow.Instance.Config;
|
||||
|
||||
public IMGUIContainer TimerShaft { get; private set; }
|
||||
public VisualElement TimeLineContainer { get; private set; }
|
||||
public ScrollView MainContent { get; private set; }
|
||||
|
||||
public int DottedLineFrameIndex
|
||||
{
|
||||
get => _dottedLineFrameIndex;
|
||||
set
|
||||
{
|
||||
if (_dottedLineFrameIndex == value) return;
|
||||
_dottedLineFrameIndex = value;
|
||||
var showDottedLine = _dottedLineFrameIndex * Config.FrameUnitWidth >= EditorInst.CurrentFramePos &&
|
||||
_dottedLineFrameIndex * Config.FrameUnitWidth <
|
||||
EditorInst.CurrentFramePos + TimerShaft.contentRect.width;
|
||||
DottedLine.style.display = showDottedLine ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
DottedLine.MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowDragItemPreview
|
||||
{
|
||||
get => _showDragItemPreview;
|
||||
set
|
||||
{
|
||||
if (_showDragItemPreview == value) return;
|
||||
_showDragItemPreview = value;
|
||||
DragItemPreview.MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
public Rect DragItemPreviewRect
|
||||
{
|
||||
get => _dragItemPreviewRect;
|
||||
set
|
||||
{
|
||||
_dragItemPreviewRect = value;
|
||||
DragItemPreview.MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitTimerShaft()
|
||||
{
|
||||
var mainContainer = _root.Q<ScrollView>("MainContent");
|
||||
MainContent = mainContainer;
|
||||
TimeLineContainer = mainContainer.Q<VisualElement>("unity-content-container");
|
||||
contentViewPort = mainContainer.Q<VisualElement>("unity-content-viewport");
|
||||
|
||||
TimerShaft = _root.Q<IMGUIContainer>(nameof(TimerShaft));
|
||||
TimerShaft.onGUIHandler = OnTimerShaftGUI;
|
||||
TimerShaft.RegisterCallback<WheelEvent>(OnWheelEvent);
|
||||
TimerShaft.RegisterCallback<MouseDownEvent>(OnTimerShaftMouseDown);
|
||||
TimerShaft.RegisterCallback<MouseMoveEvent>(OnTimerShaftMouseMove);
|
||||
TimerShaft.RegisterCallback<MouseUpEvent>(OnTimerShaftMouseUp);
|
||||
TimerShaft.RegisterCallback<MouseOutEvent>(OnTimerShaftMouseOut);
|
||||
|
||||
SelectLine = _root.Q<IMGUIContainer>(nameof(SelectLine));
|
||||
SelectLine.onGUIHandler = OnSelectLineGUI;
|
||||
|
||||
FinishLine = _root.Q<IMGUIContainer>(nameof(FinishLine));
|
||||
FinishLine.onGUIHandler = OnFinishLineGUI;
|
||||
|
||||
DottedLine = _root.Q<IMGUIContainer>(nameof(DottedLine));
|
||||
DottedLine.onGUIHandler = OnDottedLineGUI;
|
||||
|
||||
DragItemPreview = _root.Q<IMGUIContainer>(nameof(DragItemPreview));
|
||||
DragItemPreview.onGUIHandler = OnDragItemPreviewGUI;
|
||||
}
|
||||
|
||||
public void RefreshTimerDraw()
|
||||
{
|
||||
TimerShaft.MarkDirtyRepaint();
|
||||
SelectLine.MarkDirtyRepaint();
|
||||
FinishLine.MarkDirtyRepaint();
|
||||
}
|
||||
|
||||
private void OnTimerShaftMouseDown(MouseDownEvent evt)
|
||||
{
|
||||
timerShaftMouseIn = true;
|
||||
EditorInst.CurrentSelectFrameIndex = GetFrameIndexByMouse(evt.localMousePosition.x);
|
||||
}
|
||||
|
||||
private void OnTimerShaftMouseUp(MouseUpEvent evt)
|
||||
{
|
||||
timerShaftMouseIn = false;
|
||||
}
|
||||
|
||||
private void OnTimerShaftMouseMove(MouseMoveEvent evt)
|
||||
{
|
||||
if (timerShaftMouseIn) EditorInst.CurrentSelectFrameIndex = GetFrameIndexByMouse(evt.localMousePosition.x);
|
||||
}
|
||||
|
||||
private void OnTimerShaftMouseOut(MouseOutEvent evt)
|
||||
{
|
||||
timerShaftMouseIn = false;
|
||||
}
|
||||
|
||||
public int GetFrameIndexByMouse(float x)
|
||||
{
|
||||
return GetFrameIndexByPosition(x + EditorInst.CurrentFramePos);
|
||||
}
|
||||
|
||||
public int GetFrameIndexByPosition(float x)
|
||||
{
|
||||
return Mathf.RoundToInt(x) / Config.FrameUnitWidth;
|
||||
}
|
||||
|
||||
private void OnSelectLineGUI()
|
||||
{
|
||||
if (EditorInst.CurrentSelectFramePos >= EditorInst.CurrentFramePos &&
|
||||
EditorInst.CurrentSelectFramePos < EditorInst.CurrentFramePos + TimerShaft.contentRect.width)
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
Handles.color = Color.green;
|
||||
var length = contentViewPort.contentRect.height + TimerShaft.contentRect.height;
|
||||
var x = EditorInst.CurrentSelectFramePos - EditorInst.CurrentFramePos;
|
||||
x = Mathf.Max(x, 1);
|
||||
Handles.DrawLine(new Vector3(x, 0), new Vector3(x, length));
|
||||
Handles.EndGUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFinishLineGUI()
|
||||
{
|
||||
if (EditorInst.CurrentEndFramePos >= EditorInst.CurrentFramePos &&
|
||||
EditorInst.CurrentEndFramePos < EditorInst.CurrentFramePos + TimerShaft.contentRect.width)
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
Handles.color = Color.red;
|
||||
var length = contentViewPort.contentRect.height + TimerShaft.contentRect.height;
|
||||
var x = EditorInst.CurrentEndFramePos - EditorInst.CurrentFramePos;
|
||||
x = Mathf.Max(x, 1);
|
||||
Handles.DrawLine(new Vector3(x, 0), new Vector3(x, length));
|
||||
Handles.EndGUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDottedLineGUI()
|
||||
{
|
||||
var dottedLinePos = DottedLineFrameIndex * Config.FrameUnitWidth;
|
||||
if (dottedLinePos >= EditorInst.CurrentFramePos &&
|
||||
dottedLinePos < EditorInst.CurrentFramePos + TimerShaft.contentRect.width)
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
Handles.color = new Color(1, 0.5f, 0, 1);
|
||||
var length = contentViewPort.contentRect.height + TimerShaft.contentRect.height;
|
||||
var x = dottedLinePos - EditorInst.CurrentFramePos;
|
||||
x = Mathf.Max(x, 1);
|
||||
|
||||
var lineUnitSize = 10f;
|
||||
var lineUnitsCount = 0;
|
||||
for (float i = 0; i < length; i += lineUnitSize)
|
||||
if (lineUnitsCount++ % 2 == 0)
|
||||
Handles.DrawLine(new Vector3(x, i), new Vector3(x, i + lineUnitSize));
|
||||
|
||||
Handles.EndGUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDragItemPreviewGUI()
|
||||
{
|
||||
if (ShowDragItemPreview)
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
Handles.color = new Color(0.5f, 0.5f, 0.5f, 0.5f);
|
||||
Handles.DrawSolidRectangleWithOutline(DragItemPreviewRect, new Color(0.9f, 0.5f, 0, 0.9f), Color.white);
|
||||
Handles.EndGUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWheelEvent(WheelEvent evt)
|
||||
{
|
||||
var deltaY = (int)evt.delta.y;
|
||||
Config.FrameUnitWidth =
|
||||
Mathf.Clamp(Config.FrameUnitWidth - deltaY,
|
||||
AbilityTimelineEditorConfig.StandardFrameUnitWidth,
|
||||
Mathf.RoundToInt(AbilityTimelineEditorConfig.MaxFrameUnitLevel *
|
||||
AbilityTimelineEditorConfig.StandardFrameUnitWidth));
|
||||
|
||||
// 以鼠标为缩放中心
|
||||
// var mousePos = evt.localMousePosition.x;
|
||||
// var mouseFrame = GetFrameIndexByMouse(mousePos);
|
||||
// var mouseFramePos = mouseFrame * Config.FrameUnitWidth;
|
||||
// var deltaFrame = mouseFramePos - EditorInst.CurrentFramePos;
|
||||
// var contentWidth = contentViewPort.contentRect.width;
|
||||
// var scrollViewWidth = MainContent.worldBound.width;
|
||||
// var scrollOffsetDelta = (EditorInst.CurrentFramePos + deltaFrame * Config.FrameUnitWidth) / contentWidth *
|
||||
// scrollViewWidth;
|
||||
// MainContent.scrollOffset = new Vector2(MainContent.scrollOffset.x - scrollOffsetDelta, 0);
|
||||
|
||||
RefreshTimerDraw();
|
||||
EditorInst.TrackView.UpdateContentSize();
|
||||
}
|
||||
|
||||
private void OnTimerShaftGUI()
|
||||
{
|
||||
Handles.BeginGUI();
|
||||
Handles.color = Color.white;
|
||||
|
||||
var rect = TimerShaft.contentRect;
|
||||
var tickStep = AbilityTimelineEditorConfig.MaxFrameUnitLevel + 1 -
|
||||
Config.FrameUnitWidth / AbilityTimelineEditorConfig.StandardFrameUnitWidth;
|
||||
tickStep /= 2;
|
||||
tickStep = Mathf.Max(tickStep, 2);
|
||||
|
||||
var index = Mathf.CeilToInt(EditorInst.CurrentFramePos / Config.FrameUnitWidth);
|
||||
var startFrameOffset =
|
||||
index > 0 ? Config.FrameUnitWidth - EditorInst.CurrentFramePos % Config.FrameUnitWidth : 0;
|
||||
|
||||
var minDrawStep = AbilityTimelineEditorConfig.MinTimerShaftFrameDrawStep;
|
||||
var tooSmall = Config.FrameUnitWidth < minDrawStep;
|
||||
var drawStepFrame = tooSmall ? Mathf.CeilToInt(minDrawStep / Config.FrameUnitWidth) : 1;
|
||||
tickStep *= drawStepFrame;
|
||||
|
||||
for (var i = startFrameOffset; i <= rect.width; i += Config.FrameUnitWidth)
|
||||
{
|
||||
var isDraw = !tooSmall || index % drawStepFrame == 0;
|
||||
if (isDraw)
|
||||
{
|
||||
var isTick = index % tickStep == 0;
|
||||
var x = i;
|
||||
var startY = isTick ? rect.height * 0.5f : rect.height * 0.85f;
|
||||
var endY = rect.height;
|
||||
Handles.DrawLine(new Vector3(x, startY), new Vector3(x, endY));
|
||||
|
||||
if (isTick)
|
||||
{
|
||||
var frameStr = index.ToString();
|
||||
Handles.Label(new Vector3(x, rect.height * 0.3f), frameStr);
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
Handles.EndGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eef4c200759470f9d78578b25f638ce
|
||||
timeCreated: 1709022708
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9778b39d339623c43b5959266eec599b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
After Width: | Height: | Size: 815 B |
@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57ce001ccda69fb42a45620a155e9f0a
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
After Width: | Height: | Size: 145 B |
@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9779130815dc9124f8b6f8eb91b639ed
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
After Width: | Height: | Size: 251 B |
@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92f1dbb6ded22b743a877eefd625e2e9
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
After Width: | Height: | Size: 223 B |
@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c3a5a8bb9c5ac04cbefb66939648675
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 275b0fae483c03b41bf38af8e22b53cb
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,31 @@
|
||||
//
|
||||
// #if UNITY_EDITOR
|
||||
// namespace GAS.Editor
|
||||
// {
|
||||
// using Runtime;
|
||||
// using Sirenix.OdinInspector.Editor;
|
||||
// using UnityEditor;
|
||||
// using UnityEngine;
|
||||
// using GAS.General;
|
||||
//
|
||||
// [CustomEditor(typeof(TimelineAbilityAsset))]
|
||||
// public class TimelineAbilityEditorWindow : OdinEditor
|
||||
// {
|
||||
// private TimelineAbilityAsset _asset => target as TimelineAbilityAsset;
|
||||
//
|
||||
// public override void OnInspectorGUI()
|
||||
// {
|
||||
// base.OnInspectorGUI();
|
||||
//
|
||||
// EditorGUILayout.BeginVertical(GUI.skin.box);
|
||||
// if (GUILayout.Button(GASTextDefine.BUTTON_CHECK_TIMELINE_ABILITY, GUILayout.Height(30), GUILayout.Width(300))) EditAbilityTimeline();
|
||||
// EditorGUILayout.EndVertical();
|
||||
// }
|
||||
//
|
||||
// private void EditAbilityTimeline()
|
||||
// {
|
||||
// AbilityTimelineEditorWindow.ShowWindow(_asset);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 532c2163527942a1980d38f4f7b939ba
|
||||
timeCreated: 1708439991
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75b92df8baa9d394b8c750f49e1139b5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a14fb0e3c3d64a5ca183c242d3bd07f0
|
||||
timeCreated: 1709188522
|
@ -0,0 +1,70 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System.Linq;
|
||||
using GAS.Runtime;
|
||||
|
||||
|
||||
public class TaskClip : TrackClip<TaskClipEventTrack>
|
||||
{
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
public TaskClipEvent TaskClipData => clipData as TaskClipEvent;
|
||||
|
||||
public TaskClipEvent ClipDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
var cueTrackDataForSave = track.TaskClipTrackDataForSave;
|
||||
for (var i = 0; i < cueTrackDataForSave.clipEvents.Count; i++)
|
||||
if (cueTrackDataForSave.clipEvents[i] == TaskClipData)
|
||||
return track.TaskClipTrackDataForSave.clipEvents[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
var success = track.TaskClipTrackDataForSave.clipEvents.Remove(TaskClipData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
if (!success) return;
|
||||
track.RemoveTrackItem(this);
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector();
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameUnitWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameUnitWidth);
|
||||
var taskType = TaskClipData.ongoingTask.TaskData.Type;
|
||||
var shortName = taskType.Split('.').Last();
|
||||
ItemLabel.text = !string.IsNullOrEmpty(shortName) ? shortName : "Null!";
|
||||
}
|
||||
|
||||
public override void UpdateClipDataStartFrame(int newStartFrame)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.startFrame = newStartFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public override void UpdateClipDataDurationFrame(int newDurationFrame)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.durationFrame = newDurationFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public override void OnTickView(int frameIndex, int startFrame, int endFrame)
|
||||
{
|
||||
if (frameIndex < startFrame || frameIndex > endFrame) return;
|
||||
var ongoingAbilityTask = TaskClipData.Load();
|
||||
ongoingAbilityTask.OnEditorPreview( frameIndex, startFrame, endFrame);
|
||||
}
|
||||
|
||||
public override UnityEngine.Object DataInspector => TaskClipEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa654674f82841b0aca803e511168082
|
||||
timeCreated: 1709188590
|
@ -0,0 +1,145 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using GAS.General;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class TaskClipEditor:OdinEditorWindow
|
||||
{
|
||||
private static IEnumerable OngoingTaskSonTypes = OngoingTaskData.OngoingTaskSonTypeChoices;
|
||||
|
||||
private static Type[] _ongoingTaskInspectorTypes;
|
||||
|
||||
public static Type[] OngoingTaskInspectorTypes =>
|
||||
_ongoingTaskInspectorTypes ??= TypeUtil.GetAllSonTypesOf(typeof(OngoingTaskInspector));
|
||||
|
||||
private static Dictionary<Type, Type> _ongoingTaskInspectorMap;
|
||||
private static Dictionary<Type, Type> OngoingTaskInspectorMap
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_ongoingTaskInspectorMap != null) return _ongoingTaskInspectorMap;
|
||||
_ongoingTaskInspectorMap = new Dictionary<Type, Type>();
|
||||
foreach (var inspectorType in OngoingTaskInspectorTypes)
|
||||
{
|
||||
var taskType = inspectorType.BaseType.GetGenericArguments()[0];
|
||||
_ongoingTaskInspectorMap.Add(taskType, inspectorType);
|
||||
}
|
||||
|
||||
return _ongoingTaskInspectorMap;
|
||||
}
|
||||
}
|
||||
|
||||
private const string GRP_BOX = "GRP_BOX";
|
||||
private const string GRP_BOX_TASK = "GRP_BOX/Task";
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
private TaskClip _clip;
|
||||
|
||||
public static TaskClipEditor Create(TaskClip clip)
|
||||
{
|
||||
var window = new TaskClipEditor();
|
||||
window._clip = clip;
|
||||
window.Refresh();
|
||||
return window;
|
||||
}
|
||||
|
||||
[BoxGroup(GRP_BOX)]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string RunInfo;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup(GRP_BOX)]
|
||||
[LabelText("Duration(f)")]
|
||||
[OnValueChanged("OnDurationFrameChanged")]
|
||||
public int Duration;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup(GRP_BOX_TASK)]
|
||||
[LabelText("OngoingTask")]
|
||||
[ValueDropdown("OngoingTaskSonTypes")]
|
||||
[InfoBox("This Task has no inspector!",InfoMessageType.Warning, "OngoingTaskIsNull")]
|
||||
[OnValueChanged("OnTaskTypeChanged")]
|
||||
public string OngoingTaskType;
|
||||
|
||||
[BoxGroup(GRP_BOX_TASK)]
|
||||
[HideReferenceObjectPicker]
|
||||
[HideIf("OngoingTaskIsNull")]
|
||||
[LabelText("Task Detail")]
|
||||
public OngoingTaskInspector OngoingTask;
|
||||
|
||||
[BoxGroup(GRP_BOX)]
|
||||
[Button]
|
||||
[GUIColor(0.9f,0.2f,0.2f)]
|
||||
void Delete()
|
||||
{
|
||||
_clip.Delete();
|
||||
}
|
||||
|
||||
void Refresh()
|
||||
{
|
||||
RunInfo = $"<b>Run(f):{_clip.TaskClipData.startFrame} -> {_clip.TaskClipData.EndFrame}</b>";
|
||||
Duration = _clip.TaskClipData.durationFrame;
|
||||
OngoingTaskType = _clip.TaskClipData.ongoingTask.TaskData.Type;
|
||||
|
||||
RefreshTaskInspector();
|
||||
}
|
||||
|
||||
void RefreshTaskInspector()
|
||||
{
|
||||
// 根据选择的OngoingAbilityTask子类,显示对应的属性
|
||||
var ongoingAbilityTask = _clip.TaskClipData.Load();
|
||||
if (OngoingTaskInspectorMap.TryGetValue(ongoingAbilityTask.GetType(), out var inspectorType))
|
||||
{
|
||||
var taskInspector = (OngoingTaskInspector)Activator.CreateInstance(inspectorType);
|
||||
taskInspector.Init(ongoingAbilityTask);
|
||||
OngoingTask = taskInspector;
|
||||
}
|
||||
else
|
||||
{
|
||||
OngoingTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDurationFrameChanged()
|
||||
{
|
||||
// 钳制
|
||||
var max = AbilityAsset.FrameCount - _clip.ClipDataForSave.startFrame;
|
||||
Duration = Mathf.Clamp(Duration, 1, max);
|
||||
_clip.UpdateClipDataDurationFrame(Duration);
|
||||
_clip.RefreshShow(_clip.FrameUnitWidth);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnTaskTypeChanged()
|
||||
{
|
||||
_clip.ClipDataForSave.ongoingTask.TaskData.Type = OngoingTaskType;
|
||||
_clip.ClipDataForSave.ongoingTask.TaskData.Data = null;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
AbilityTimelineEditorWindow.Instance.TimelineInspector.RefreshInspector();
|
||||
|
||||
RefreshTaskInspector();
|
||||
}
|
||||
|
||||
bool OngoingTaskIsNull()
|
||||
{
|
||||
return OngoingTask == null;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(TaskClipEditor))]
|
||||
public class TaskClipInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cba12e6f7c134f23bfef110061a95041
|
||||
timeCreated: 1710404613
|
@ -0,0 +1,97 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class TaskClipEventTrack:TrackBase
|
||||
{
|
||||
private TaskClipEventTrackData _taskClipEventTrackData;
|
||||
public override Type TrackDataType => typeof(TaskClipEventTrackData);
|
||||
protected override Color TrackColor => new Color(0.7f, 0.3f, 0.7f, 0.2f);
|
||||
protected override Color MenuColor => new Color(0.5f, 0.3f, 0.5f, 1);
|
||||
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
public TaskClipEventTrackData TaskClipTrackDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < AbilityAsset.OngoingTasks.Count; i++)
|
||||
{
|
||||
if(AbilityAsset.OngoingTasks[i] == _taskClipEventTrackData)
|
||||
return AbilityAsset.OngoingTasks[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
foreach (var item in _trackItems)
|
||||
{
|
||||
var taskClip = item as TaskClip;
|
||||
taskClip.OnTickView(frameIndex, taskClip.StartFrameIndex, taskClip.EndFrameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth, TrackDataBase trackData)
|
||||
{
|
||||
base.Init(trackParent, menuParent, frameWidth, trackData);
|
||||
_taskClipEventTrackData = trackData as TaskClipEventTrackData;
|
||||
MenuText.text = _taskClipEventTrackData.trackName;
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameWidth);
|
||||
foreach (var item in _trackItems) Track.Remove(((TrackClipBase)item).ClipVe);
|
||||
_trackItems.Clear();
|
||||
|
||||
if (AbilityTimelineEditorWindow.Instance.AbilityAsset != null)
|
||||
foreach (var clipEvent in _taskClipEventTrackData.clipEvents)
|
||||
{
|
||||
var item = new TaskClip();
|
||||
item.InitTrackClip(this, Track, _frameWidth, clipEvent);
|
||||
_trackItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
// 添加Clip数据
|
||||
var clipEvent = new TaskClipEvent
|
||||
{
|
||||
startFrame = GetTrackIndexByMouse(action.eventInfo.localMousePosition.x),
|
||||
durationFrame = 5,
|
||||
ongoingTask = new OngoingTaskData()
|
||||
};
|
||||
TaskClipTrackDataForSave.clipEvents.Add(clipEvent);
|
||||
|
||||
// 刷新显示
|
||||
var item = new TaskClip();
|
||||
item.InitTrackClip(this, Track, _frameWidth, clipEvent);
|
||||
_trackItems.Add(item);
|
||||
|
||||
// 选中新Clip
|
||||
item.ClipVe.OnSelect();
|
||||
|
||||
Debug.Log("[EX] Add a new Custom Clip Event");
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
// 删除数据
|
||||
AbilityAsset.OngoingTasks.Remove(_taskClipEventTrackData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
// 删除显示
|
||||
TrackParent.Remove(TrackRoot);
|
||||
MenuParent.Remove(MenuRoot);
|
||||
Debug.Log("[EX] Remove Task Clip Track");
|
||||
}
|
||||
|
||||
public override UnityEngine.Object DataInspector => TaskClipEventTrackEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c984467e4d15458089c9831f5f9a55d7
|
||||
timeCreated: 1709188570
|
@ -0,0 +1,60 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
public class TaskClipEventTrackEditor:OdinEditorWindow
|
||||
{
|
||||
private TaskClipEventTrack _track;
|
||||
|
||||
public static TaskClipEventTrackEditor Create(TaskClipEventTrack track)
|
||||
{
|
||||
var window = new TaskClipEventTrackEditor();
|
||||
window._track = track;
|
||||
window.TrackName = track.TaskClipTrackDataForSave.trackName;
|
||||
window.UpdateTrackInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Name")]
|
||||
[OnValueChanged("OnTrackNameChanged")]
|
||||
public string TrackName;
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string TrackInfo;
|
||||
|
||||
void UpdateTrackInfo()
|
||||
{
|
||||
string info = "";
|
||||
foreach (var clip in _track.TaskClipTrackDataForSave.clipEvents)
|
||||
{
|
||||
var taskName = clip.ongoingTask.TaskData.Type;
|
||||
var shortName = taskName.Substring(taskName.LastIndexOf('.') + 1);
|
||||
info += $"[{shortName}] Run(f):{clip.startFrame} -> {clip.EndFrame} \n";
|
||||
}
|
||||
TrackInfo = $"<b>{info}</b>";
|
||||
}
|
||||
|
||||
|
||||
void OnTrackNameChanged()
|
||||
{
|
||||
_track.TaskClipTrackDataForSave.trackName = TrackName;
|
||||
_track.MenuText.text = TrackName;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(TaskClipEventTrackEditor))]
|
||||
public class TaskClipEventTrackInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6632bf9b61448918503ab3c971fb532
|
||||
timeCreated: 1710402173
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c3476b4812248ed8e94d2e2e48d492a
|
||||
timeCreated: 1709188546
|
@ -0,0 +1,197 @@
|
||||
using GAS.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class TaskMark : TrackMark<TaskMarkEventTrack>
|
||||
{
|
||||
public new TaskMarkEvent MarkData => markData as TaskMarkEvent;
|
||||
|
||||
public TaskMarkEvent MarkDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
var trackDataForSave = track.InstantTaskEventTrackData;
|
||||
for (var i = 0; i < trackDataForSave.markEvents.Count; i++)
|
||||
if (trackDataForSave.markEvents[i] == MarkData)
|
||||
return track.InstantTaskEventTrackData.markEvents[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override Object DataInspector => TaskMarkEditor.Create(this);
|
||||
|
||||
public override void Duplicate()
|
||||
{
|
||||
// 添加Mark数据
|
||||
var startFrame = markData.startFrame < AbilityAsset.FrameCount
|
||||
? markData.startFrame + 1
|
||||
: markData.startFrame - 1;
|
||||
startFrame = Mathf.Clamp(startFrame, 0, AbilityAsset.FrameCount);
|
||||
var markEvent = new TaskMarkEvent
|
||||
{
|
||||
startFrame = startFrame,
|
||||
InstantTasks = (markData as TaskMarkEvent)?.InstantTasks
|
||||
};
|
||||
track.InstantTaskEventTrackData.markEvents.Add(markEvent);
|
||||
|
||||
// 刷新显示
|
||||
var mark = new TaskMark();
|
||||
mark.InitTrackMark(track, track.Track, FrameUnitWidth, markEvent);
|
||||
track.TrackItems.Add(mark);
|
||||
mark.OnSelect();
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameUnitWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameUnitWidth);
|
||||
ItemLabel.text = "";
|
||||
}
|
||||
|
||||
// #region Inspector
|
||||
//
|
||||
// private VisualElement taskSonInspector;
|
||||
// private ListView taskList;
|
||||
//
|
||||
// public override VisualElement Inspector()
|
||||
// {
|
||||
// var inspector = TrackInspectorUtil.CreateTrackInspector();
|
||||
// var markFrame = TrackInspectorUtil.CreateLabel($"Trigger(f):{markData.startFrame}");
|
||||
// inspector.Add(markFrame);
|
||||
//
|
||||
// taskSonInspector = TrackInspectorUtil.CreateSonInspector();
|
||||
// inspector.Add(taskSonInspector);
|
||||
//
|
||||
// // task列表
|
||||
// taskList = TrackInspectorUtil.CreateListView<InstantTaskData>("Task", MarkData.InstantTasks,
|
||||
// MakeInstantTaskData,BindInstantTaskData, OnSelectionChanged,OnItemAdded,OnItemRemoved);
|
||||
// inspector.Add(taskList);
|
||||
// taskList.SetSelection(0);
|
||||
//
|
||||
// // InstantTask面板渲染
|
||||
// DrawTaskSonInspector(taskSonInspector);
|
||||
//
|
||||
// return inspector;
|
||||
// }
|
||||
//
|
||||
// private void OnItemRemoved(IEnumerable<int> obj)
|
||||
// {
|
||||
// if (taskList.childCount == 0)
|
||||
// {
|
||||
// taskSonInspector.Clear();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void OnItemAdded(IEnumerable<int> obj)
|
||||
// {
|
||||
// if (taskList.childCount == 1)
|
||||
// {
|
||||
// taskList.SetSelection(0);
|
||||
// DrawTaskSonInspector(taskSonInspector);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void OnSelectionChanged(IEnumerable<object> obj)
|
||||
// {
|
||||
// DrawTaskSonInspector(taskSonInspector);
|
||||
// }
|
||||
//
|
||||
// private void DrawTaskSonInspector(VisualElement parent)
|
||||
// {
|
||||
// parent.Clear();
|
||||
//
|
||||
// // 选择项:所有InstantAbilityTask子类
|
||||
// if (taskList.selectedIndex < MarkData.InstantTasks.Count && taskList.selectedIndex >= 0)
|
||||
// {
|
||||
// taskList.SetSelection(0);
|
||||
// var taskSonTypes = InstantTaskData.InstantTaskSonTypes;
|
||||
// List<string> taskSons = taskSonTypes.Select(sonType => sonType.FullName).ToList();
|
||||
// var initValue = MarkData.InstantTasks[taskList.selectedIndex].TaskData.Type;
|
||||
// var typeSelector =
|
||||
// TrackInspectorUtil.CreateDropdownField("", taskSons, initValue, (evt) =>
|
||||
// {
|
||||
// MarkDataForSave.InstantTasks[taskList.selectedIndex].TaskData.Type = evt.newValue;
|
||||
// MarkDataForSave.InstantTasks[taskList.selectedIndex].TaskData.Data = null;
|
||||
// AbilityTimelineEditorWindow.Instance.Save();
|
||||
// AbilityTimelineEditorWindow.Instance.TimelineInspector.RefreshInspector();
|
||||
// });
|
||||
// parent.Add(typeSelector);
|
||||
//
|
||||
// // 根据选择的InstantAbilityTask子类,显示对应的属性
|
||||
// var task = MarkDataForSave.InstantTasks[taskList.selectedIndex].Load();
|
||||
// if(InstantTaskInspectorMap.TryGetValue(task.GetType(), out var inspectorType))
|
||||
// {
|
||||
// var taskInspector = (InstantTaskInspector)Activator.CreateInstance(inspectorType, task);
|
||||
// parent.Add(taskInspector.Inspector());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// parent.Add(TrackInspectorUtil.CreateLabel($"{task.GetType()}'s Inspector not found!"));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// parent.MarkDirtyRepaint();
|
||||
// }
|
||||
//
|
||||
// private void BindInstantTaskData(VisualElement root, int i)
|
||||
// {
|
||||
// MarkData.InstantTasks[i] ??= new InstantTaskData();
|
||||
// var taskValue = MarkData.InstantTasks[i];
|
||||
// var label = (Label)root;
|
||||
// var shotName = taskValue.TaskData.Type.Split('.').Last();
|
||||
// label.text = shotName;
|
||||
//
|
||||
// // taskValue.Task.l
|
||||
// //
|
||||
// // var textField = (TextField)e;
|
||||
// // textField.value = list[i];
|
||||
// // textField.RegisterValueChangedCallback(evt =>
|
||||
// // {
|
||||
// // onItemValueChanged(i, evt);
|
||||
// // });
|
||||
// }
|
||||
//
|
||||
// private VisualElement MakeInstantTaskData()
|
||||
// {
|
||||
// return TrackInspectorUtil.CreateLabel("");
|
||||
// }
|
||||
//
|
||||
|
||||
//
|
||||
// #endregion
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
var success = track.InstantTaskEventTrackData.markEvents.Remove(MarkData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
if (!success) return;
|
||||
track.RemoveTrackItem(this);
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector();
|
||||
}
|
||||
|
||||
public override void UpdateMarkDataFrame(int newStartFrame)
|
||||
{
|
||||
var updatedClip = MarkDataForSave;
|
||||
MarkDataForSave.startFrame = newStartFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
markData = updatedClip;
|
||||
}
|
||||
|
||||
public override void OnTickView(int frameIndex)
|
||||
{
|
||||
if (frameIndex == StartFrameIndex)
|
||||
{
|
||||
foreach (var t in MarkData.InstantTasks)
|
||||
{
|
||||
var task = t.Load() as InstantAbilityTask;
|
||||
task?.OnEditorPreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveCurrentTask(InstantAbilityTask task)
|
||||
{
|
||||
//MarkDataForSave.InstantTasks[taskList.selectedIndex].Save(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5fe9e9767964d92b29e5ce9101f9251
|
||||
timeCreated: 1709188609
|
@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using GAS.Runtime;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class TaskMarkEditor : OdinEditorWindow
|
||||
{
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string RunInfo;
|
||||
|
||||
private TaskMark _mark;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[HideReferenceObjectPicker]
|
||||
[ListDrawerSettings(ShowFoldout = true, DraggableItems = true)]
|
||||
[OnValueChanged("OnTaskListChanged", true)]
|
||||
public List<InstantTaskCellInspector> Tasks;
|
||||
|
||||
public static TaskMarkEditor Create(TaskMark mark)
|
||||
{
|
||||
var window = CreateInstance<TaskMarkEditor>();
|
||||
window._mark = mark;
|
||||
|
||||
window.UpdateMarkInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[BoxGroup]
|
||||
[Button]
|
||||
[GUIColor(0.9f, 0.2f, 0.2f)]
|
||||
private void Delete()
|
||||
{
|
||||
_mark.Delete();
|
||||
}
|
||||
|
||||
private void UpdateMarkInfo()
|
||||
{
|
||||
RunInfo = $"<b>Trigger(f):{_mark.MarkData.startFrame}</b>";
|
||||
Tasks = new List<InstantTaskCellInspector>();
|
||||
foreach (var taskData in _mark.MarkData.InstantTasks) Tasks.Add(new InstantTaskCellInspector(taskData));
|
||||
}
|
||||
|
||||
private void OnTaskListChanged()
|
||||
{
|
||||
var tasks = new List<InstantTaskData>();
|
||||
foreach (var t in Tasks)
|
||||
tasks.Add(new InstantTaskData
|
||||
{
|
||||
TaskData = new JsonData
|
||||
{
|
||||
Type = t.InstantTaskType,
|
||||
Data = t.Data()
|
||||
}
|
||||
});
|
||||
|
||||
_mark.MarkDataForSave.InstantTasks = tasks;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(TaskMarkEditor))]
|
||||
public class TaskMarkInspector : OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public class InstantTaskCellInspector
|
||||
{
|
||||
private static IEnumerable InstantTaskSonTypes = InstantTaskData.InstantTaskSonTypeChoices;
|
||||
private static Type[] _instantTaskInspectorTypes;
|
||||
|
||||
private static Dictionary<Type, Type> _instantTaskInspectorMap;
|
||||
|
||||
private readonly InstantTaskData _data;
|
||||
|
||||
private InstantAbilityTask _instantAbilityTask;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Task")]
|
||||
[ValueDropdown("InstantTaskSonTypes")]
|
||||
[InfoBox("This Task has no inspector!", InfoMessageType.Warning, "InstantTaskIsNull")]
|
||||
[OnValueChanged("OnTaskTypeChanged")]
|
||||
public string InstantTaskType;
|
||||
|
||||
[BoxGroup]
|
||||
[HideReferenceObjectPicker]
|
||||
[HideIf("InstantTaskIsNull")]
|
||||
[LabelText("Detail")]
|
||||
public InstantTaskInspector InstantTask;
|
||||
|
||||
public InstantTaskCellInspector(InstantTaskData data)
|
||||
{
|
||||
_data = data;
|
||||
_instantAbilityTask = data.Load() as InstantAbilityTask;
|
||||
InstantTaskType = data.TaskData.Type;
|
||||
RefreshDetailInspector();
|
||||
}
|
||||
|
||||
public InstantTaskCellInspector()
|
||||
{
|
||||
_data = new InstantTaskData();
|
||||
_instantAbilityTask = _data.Load() as InstantAbilityTask;
|
||||
InstantTaskType = _data.TaskData.Type;
|
||||
RefreshDetailInspector();
|
||||
}
|
||||
|
||||
public static Type[] InstantTaskInspectorTypes =>
|
||||
_instantTaskInspectorTypes ??= TypeUtil.GetAllSonTypesOf(typeof(InstantTaskInspector));
|
||||
|
||||
private static Dictionary<Type, Type> InstantTaskInspectorMap
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instantTaskInspectorMap != null) return _instantTaskInspectorMap;
|
||||
_instantTaskInspectorMap = new Dictionary<Type, Type>();
|
||||
foreach (var inspectorType in InstantTaskInspectorTypes)
|
||||
{
|
||||
if (inspectorType.BaseType != null)
|
||||
{
|
||||
var taskType = inspectorType.BaseType.GetGenericArguments()[0];
|
||||
_instantTaskInspectorMap.Add(taskType, inspectorType);
|
||||
}
|
||||
}
|
||||
|
||||
return _instantTaskInspectorMap;
|
||||
}
|
||||
}
|
||||
|
||||
public string Data()
|
||||
{
|
||||
if (_instantAbilityTask == null) return null;
|
||||
|
||||
_data.Save(_instantAbilityTask);
|
||||
return _data.TaskData.Data;
|
||||
}
|
||||
|
||||
private void OnTaskTypeChanged()
|
||||
{
|
||||
_data.TaskData.Type = InstantTaskType;
|
||||
_data.TaskData.Data = null;
|
||||
RefreshDetailInspector();
|
||||
}
|
||||
|
||||
private bool InstantTaskIsNull()
|
||||
{
|
||||
return InstantTask == null;
|
||||
}
|
||||
|
||||
public void RefreshDetailInspector()
|
||||
{
|
||||
_instantAbilityTask = _data.Load() as InstantAbilityTask;
|
||||
if (_instantAbilityTask != null && InstantTaskInspectorMap.TryGetValue(_instantAbilityTask.GetType(), out var inspectorType))
|
||||
{
|
||||
var taskInspector = (InstantTaskInspector)Activator.CreateInstance(inspectorType);
|
||||
taskInspector.Init(_instantAbilityTask);
|
||||
InstantTask = taskInspector;
|
||||
}
|
||||
else
|
||||
{
|
||||
InstantTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24bdabb4d76b46f3a93fd5999a611fe7
|
||||
timeCreated: 1710412687
|
@ -0,0 +1,94 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class TaskMarkEventTrack : TrackBase
|
||||
{
|
||||
private TaskMarkEventTrackData _instantTasksTrackData;
|
||||
private static TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
public TaskMarkEventTrackData InstantTaskEventTrackData
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < AbilityAsset.InstantTasks.Count; i++)
|
||||
if (AbilityAsset.InstantTasks[i] == _instantTasksTrackData)
|
||||
return AbilityAsset.InstantTasks[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override Type TrackDataType => typeof(TaskMarkEventTrackData);
|
||||
protected override Color TrackColor => new(0.1f, 0.6f, 0.6f, 0.2f);
|
||||
protected override Color MenuColor => new(0.1f, 0.6f, 0.6f, 0.9f);
|
||||
|
||||
public override void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth,
|
||||
TrackDataBase trackData)
|
||||
{
|
||||
base.Init(trackParent, menuParent, frameWidth, trackData);
|
||||
_instantTasksTrackData = trackData as TaskMarkEventTrackData;
|
||||
MenuText.text = _instantTasksTrackData.trackName;
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
foreach (var item in _trackItems)
|
||||
((TrackMarkBase)item).OnTickView(frameIndex);
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameWidth);
|
||||
foreach (var item in _trackItems) Track.Remove(((TrackMarkBase)item).Ve);
|
||||
_trackItems.Clear();
|
||||
|
||||
if (AbilityTimelineEditorWindow.Instance.AbilityAsset == null) return;
|
||||
|
||||
foreach (var markEvent in _instantTasksTrackData.markEvents)
|
||||
{
|
||||
var item = new TaskMark();
|
||||
item.InitTrackMark(this, Track, _frameWidth, markEvent);
|
||||
_trackItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public override UnityEngine.Object DataInspector => TaskMarkEventTrackEditor.Create(this);
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
// 添加Mark数据
|
||||
var markEvent = new TaskMarkEvent
|
||||
{
|
||||
startFrame = GetTrackIndexByMouse(action.eventInfo.localMousePosition.x)
|
||||
};
|
||||
InstantTaskEventTrackData.markEvents.Add(markEvent);
|
||||
|
||||
// 刷新显示
|
||||
var mark = new TaskMark();
|
||||
mark.InitTrackMark(this, Track, _frameWidth, markEvent);
|
||||
_trackItems.Add(mark);
|
||||
|
||||
mark.OnSelect();
|
||||
|
||||
Debug.Log("[EX] Add Instant Task Mark");
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
// 删除数据
|
||||
AbilityAsset.InstantTasks.Remove(_instantTasksTrackData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
// 删除显示
|
||||
TrackParent.Remove(TrackRoot);
|
||||
MenuParent.Remove(MenuRoot);
|
||||
Debug.Log("[EX] Remove Instant Task Track");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e77bb736b8f4172b97e0c5cbb29e734
|
||||
timeCreated: 1709188602
|
@ -0,0 +1,65 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
public class TaskMarkEventTrackEditor:OdinEditorWindow
|
||||
{
|
||||
private TaskMarkEventTrack _track;
|
||||
|
||||
public static TaskMarkEventTrackEditor Create(TaskMarkEventTrack track)
|
||||
{
|
||||
var window = new TaskMarkEventTrackEditor();
|
||||
window._track = track;
|
||||
window.TrackName = track.InstantTaskEventTrackData.trackName;
|
||||
window.UpdateTrackInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Name")]
|
||||
[OnValueChanged("OnTrackNameChanged")]
|
||||
public string TrackName;
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string TrackInfo;
|
||||
|
||||
void UpdateTrackInfo()
|
||||
{
|
||||
string info = "";
|
||||
foreach (var mark in _track.InstantTaskEventTrackData.markEvents)
|
||||
{
|
||||
info += $"Trigger(f):{mark.startFrame} \n";
|
||||
foreach (var task in mark.InstantTasks)
|
||||
{
|
||||
var taskName = task.TaskData.Type;
|
||||
var shortName = taskName.Substring(taskName.LastIndexOf('.') + 1);
|
||||
info += $" |-> {shortName}\n";
|
||||
}
|
||||
info += "\n";
|
||||
}
|
||||
TrackInfo = $"<b>{info}</b>";
|
||||
}
|
||||
|
||||
|
||||
void OnTrackNameChanged()
|
||||
{
|
||||
_track.InstantTaskEventTrackData.trackName = TrackName;
|
||||
_track.MenuText.text = TrackName;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(TaskMarkEventTrackEditor))]
|
||||
public class TaskMarkEventTrackInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9b48a0ead1e46fda171f81526de090c
|
||||
timeCreated: 1710401923
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87b8970b4a8f40dc8ceca574d4a7f7f3
|
||||
timeCreated: 1709177306
|
@ -0,0 +1,78 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class BuffGameplayEffectClip : TrackClip<BuffGameplayEffectTrack>
|
||||
{
|
||||
public BuffGameplayEffectClipEvent BuffGameplayEffectClipData => clipData as BuffGameplayEffectClipEvent;
|
||||
|
||||
private BuffGameplayEffectClipEvent ClipDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
var cueTrackDataForSave = track.BuffTrackDataForSave;
|
||||
for (var i = 0; i < cueTrackDataForSave.clipEvents.Count; i++)
|
||||
if (cueTrackDataForSave.clipEvents[i] == BuffGameplayEffectClipData)
|
||||
return track.BuffTrackDataForSave.clipEvents[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
var success = track.BuffTrackDataForSave.clipEvents.Remove(BuffGameplayEffectClipData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
if (!success) return;
|
||||
track.RemoveTrackItem(this);
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector();
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameUnitWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameUnitWidth);
|
||||
// clip 文本
|
||||
ItemLabel.text = BuffGameplayEffectClipData.gameplayEffect
|
||||
? BuffGameplayEffectClipData.gameplayEffect.name
|
||||
: "【NULL】";
|
||||
|
||||
// 刷新面板显示
|
||||
if (AbilityTimelineEditorWindow.Instance.CurrentInspectorObject == this)
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector(this);
|
||||
}
|
||||
|
||||
public override void UpdateClipDataStartFrame(int newStartFrame)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.startFrame = newStartFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public override void UpdateClipDataDurationFrame(int newDurationFrame)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.durationFrame = newDurationFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public void UpdateClipDataBuff(GameplayEffectAsset newBuff)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.gameplayEffect = newBuff;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public override void OnTickView(int frameIndex, int startFrame, int endFrame)
|
||||
{
|
||||
}
|
||||
|
||||
public override Object DataInspector=> BuffGameplayEffectClipEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6dc3231fa98249a9a40eb1239dc40654
|
||||
timeCreated: 1709177333
|
@ -0,0 +1,91 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class BuffGameplayEffectClipEditor : OdinEditorWindow
|
||||
{
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
private BuffGameplayEffectClip _clip;
|
||||
|
||||
public static BuffGameplayEffectClipEditor Create(BuffGameplayEffectClip clip)
|
||||
{
|
||||
var window = new BuffGameplayEffectClipEditor();
|
||||
window._clip = clip;
|
||||
window.Refresh();
|
||||
return window;
|
||||
}
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string RunInfo;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Duration(f)")]
|
||||
[OnValueChanged("OnDurationFrameChanged")]
|
||||
public int Duration;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[AssetSelector]
|
||||
[OnValueChanged("OnBuffChanged")]
|
||||
public GameplayEffectAsset Buff;
|
||||
|
||||
[BoxGroup]
|
||||
[Button]
|
||||
[GUIColor(0.9f, 0.2f, 0.2f)]
|
||||
void Delete()
|
||||
{
|
||||
_clip.Delete();
|
||||
}
|
||||
|
||||
void Refresh()
|
||||
{
|
||||
Buff = _clip.BuffGameplayEffectClipData.gameplayEffect;
|
||||
RunInfo = $"<b>Run(f):{_clip.BuffGameplayEffectClipData.startFrame} -> {_clip.BuffGameplayEffectClipData.EndFrame}</b>";
|
||||
Duration = _clip.BuffGameplayEffectClipData.durationFrame;
|
||||
}
|
||||
|
||||
private void OnDurationFrameChanged()
|
||||
{
|
||||
// 钳制
|
||||
var max = AbilityAsset.FrameCount - _clip.BuffGameplayEffectClipData.startFrame;
|
||||
var newValue = Mathf.Clamp(Duration, 1, max);
|
||||
// 保存数据
|
||||
_clip.UpdateClipDataDurationFrame(newValue);
|
||||
|
||||
_clip.RefreshShow(_clip.FrameUnitWidth);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnBuffChanged()
|
||||
{
|
||||
_clip.UpdateClipDataBuff(Buff);
|
||||
_clip.RefreshShow(_clip.FrameUnitWidth);
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[CustomEditor(typeof(BuffGameplayEffectClipEditor))]
|
||||
public class BuffGameplayEffectClipInspector : OdinEditorWithoutHeader
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("【注意!!】请确保设置的GameplayEffect类型为Durational或Infinite。 非持续类型的GameplayEffect不会生效。且GameplayEffect执行时会设置为Infinite执行策略, 生命周期由Clip长度(Duration)决定。", MessageType.Info);
|
||||
|
||||
GUILayout.Space(20);
|
||||
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 893063b1dce94875864d8b866874c352
|
||||
timeCreated: 1710403004
|
@ -0,0 +1,92 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class BuffGameplayEffectTrack : TrackBase
|
||||
{
|
||||
private BuffGameplayEffectTrackData _buffGameplayEffectTrackData;
|
||||
public override Type TrackDataType => typeof(BuffGameplayEffectTrackData);
|
||||
protected override Color TrackColor => new(0.9f, 0.6f, 0.6f, 0.2f);
|
||||
protected override Color MenuColor => new(0.9f, 0.6f, 0.6f, 1);
|
||||
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
public BuffGameplayEffectTrackData BuffTrackDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < AbilityAsset.BuffGameplayEffects.Count; i++)
|
||||
if (AbilityAsset.BuffGameplayEffects[i] == _buffGameplayEffectTrackData)
|
||||
return AbilityAsset.BuffGameplayEffects[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth,
|
||||
TrackDataBase trackData)
|
||||
{
|
||||
base.Init(trackParent, menuParent, frameWidth, trackData);
|
||||
_buffGameplayEffectTrackData = trackData as BuffGameplayEffectTrackData;
|
||||
MenuText.text = _buffGameplayEffectTrackData.trackName;
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameWidth);
|
||||
foreach (var item in _trackItems) Track.Remove(((TrackClipBase)item).ClipVe);
|
||||
_trackItems.Clear();
|
||||
|
||||
if (AbilityTimelineEditorWindow.Instance.AbilityAsset != null)
|
||||
foreach (var clipEvent in _buffGameplayEffectTrackData.clipEvents)
|
||||
{
|
||||
var item = new BuffGameplayEffectClip();
|
||||
item.InitTrackClip(this, Track, _frameWidth, clipEvent);
|
||||
_trackItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
// 添加Clip数据
|
||||
var clipEvent = new BuffGameplayEffectClipEvent
|
||||
{
|
||||
startFrame = GetTrackIndexByMouse(action.eventInfo.localMousePosition.x),
|
||||
durationFrame = 5
|
||||
};
|
||||
BuffTrackDataForSave.clipEvents.Add(clipEvent);
|
||||
|
||||
// 刷新显示
|
||||
var item = new BuffGameplayEffectClip();
|
||||
item.InitTrackClip(this, Track, _frameWidth, clipEvent);
|
||||
_trackItems.Add(item);
|
||||
|
||||
// 选中新Clip
|
||||
item.ClipVe.OnSelect();
|
||||
|
||||
Debug.Log("[EX] Add a new Buff GameplayEffect Clip");
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
// 删除数据
|
||||
AbilityAsset.BuffGameplayEffects.Remove(_buffGameplayEffectTrackData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
// 删除显示
|
||||
TrackParent.Remove(TrackRoot);
|
||||
MenuParent.Remove(MenuRoot);
|
||||
Debug.Log("[EX] Remove Durational Cue Track");
|
||||
}
|
||||
|
||||
|
||||
public override UnityEngine.Object DataInspector => BuffGameplayEffectTrackEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 228f546dcb634e75af2ff3d991d753bf
|
||||
timeCreated: 1709177320
|
@ -0,0 +1,59 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
public class BuffGameplayEffectTrackEditor:OdinEditorWindow
|
||||
{
|
||||
private BuffGameplayEffectTrack _track;
|
||||
|
||||
public static BuffGameplayEffectTrackEditor Create(BuffGameplayEffectTrack track)
|
||||
{
|
||||
var window = new BuffGameplayEffectTrackEditor();
|
||||
window._track = track;
|
||||
window.TrackName = track.BuffTrackDataForSave.trackName;
|
||||
window.UpdateTrackInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Name")]
|
||||
[OnValueChanged("OnTrackNameChanged")]
|
||||
public string TrackName;
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string TrackInfo;
|
||||
|
||||
void UpdateTrackInfo()
|
||||
{
|
||||
string info = "";
|
||||
foreach (var clip in _track.BuffTrackDataForSave.clipEvents)
|
||||
{
|
||||
var clipName = clip.gameplayEffect != null ? clip.gameplayEffect.name : "NULL";
|
||||
info += $"[{clipName}] Run(f):{clip.startFrame} -> {clip.EndFrame} \n";
|
||||
}
|
||||
TrackInfo = $"<b>{info}</b>";
|
||||
}
|
||||
|
||||
|
||||
void OnTrackNameChanged()
|
||||
{
|
||||
_track.BuffTrackDataForSave.trackName = TrackName;
|
||||
_track.MenuText.text = TrackName;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(BuffGameplayEffectTrackEditor))]
|
||||
public class BuffGameplayEffectTrackInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f8eef4e32cd448da39b120ab098b342
|
||||
timeCreated: 1710401707
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 780123e8286b4fe1be3f0ad55c4375fb
|
||||
timeCreated: 1709030487
|
@ -0,0 +1,113 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class DurationalCueClip : TrackClip<DurationalCueTrack>
|
||||
{
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
public DurationalCueClipEvent DurationalCueClipData => clipData as DurationalCueClipEvent;
|
||||
|
||||
private DurationalCueClipEvent ClipDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
var cueTrackDataForSave = track.CueTrackDataForSave;
|
||||
for (var i = 0; i < cueTrackDataForSave.clipEvents.Count; i++)
|
||||
if (cueTrackDataForSave.clipEvents[i] == DurationalCueClipData)
|
||||
return track.CueTrackDataForSave.clipEvents[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitTrackClip(TrackBase track, VisualElement parent, float frameUnitWidth,
|
||||
ClipEventBase clipData)
|
||||
{
|
||||
base.InitTrackClip(track, parent, frameUnitWidth, clipData);
|
||||
|
||||
//ve.RegisterFuncGetMinStartFrameIndex(MinStartFrameIndex);
|
||||
//ve.RegisterFuncGetMaxEndFrameIndex(MaxEndFrameIndex);
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
var success = track.CueTrackDataForSave.clipEvents.Remove(DurationalCueClipData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
if (!success) return;
|
||||
track.RemoveTrackItem(this);
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector();
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameUnitWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameUnitWidth);
|
||||
// clip 文本
|
||||
ItemLabel.text = DurationalCueClipData.cue ? DurationalCueClipData.cue.name : "NULL!";
|
||||
|
||||
// 刷新面板显示
|
||||
if (AbilityTimelineEditorWindow.Instance.CurrentInspectorObject == this)
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector(this);
|
||||
}
|
||||
|
||||
public override void UpdateClipDataStartFrame(int newStartFrame)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.startFrame = newStartFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public override void UpdateClipDataDurationFrame(int newDurationFrame)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.durationFrame = newDurationFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
}
|
||||
|
||||
public void UpdateClipDataCue(GameplayCueDurational newCue)
|
||||
{
|
||||
var updatedClip = ClipDataForSave;
|
||||
ClipDataForSave.cue = newCue;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
clipData = updatedClip;
|
||||
RefreshShow(FrameUnitWidth);
|
||||
}
|
||||
|
||||
public override void OnTickView(int frameIndex, int startFrame, int endFrame)
|
||||
{
|
||||
DurationalCueClipData.cue.OnEditorPreview(AbilityTimelineEditorWindow.Instance.PreviewObject, frameIndex,
|
||||
startFrame, endFrame);
|
||||
}
|
||||
|
||||
#region Clip Visual Element Event
|
||||
|
||||
// private int MinStartFrameIndex(float lastMainDragStartPos)
|
||||
// {
|
||||
// var minFrame = 0;
|
||||
// foreach (var clipEvent in AbilityTimelineEditorWindow.Instance.AbilityAsset.AnimationData.animationClipData)
|
||||
// if (clipEvent != ClipData && clipEvent.EndFrame <= lastMainDragStartPos)
|
||||
// minFrame = Mathf.Max(minFrame, clipEvent.EndFrame);
|
||||
//
|
||||
// return minFrame;
|
||||
// }
|
||||
//
|
||||
// private int MaxEndFrameIndex(float lastMainDragStartPos)
|
||||
// {
|
||||
// var maxFrame = AbilityTimelineEditorWindow.Instance.AbilityAsset.FrameCount;
|
||||
// foreach (var clipEvent in AbilityTimelineEditorWindow.Instance.AbilityAsset.AnimationData.animationClipData)
|
||||
// if (clipEvent != ClipData && clipEvent.startFrame >= lastMainDragStartPos + DurationFrame)
|
||||
// maxFrame = Mathf.Min(maxFrame, clipEvent.startFrame);
|
||||
//
|
||||
// return maxFrame;
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
public override Object DataInspector => DurationalCueClipEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34e96f7eaaca42f5b4252685084ad440
|
||||
timeCreated: 1709030571
|
@ -0,0 +1,86 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class DurationalCueClipEditor : OdinEditorWindow
|
||||
{
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
private DurationalCueClip _clip;
|
||||
|
||||
public static DurationalCueClipEditor Create(DurationalCueClip clip)
|
||||
{
|
||||
var window = new DurationalCueClipEditor();
|
||||
window._clip = clip;
|
||||
window.Refresh();
|
||||
return window;
|
||||
}
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string RunInfo;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Duration(f)")]
|
||||
[OnValueChanged("OnDurationFrameChanged")]
|
||||
public int Duration;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[AssetSelector]
|
||||
[OnValueChanged("OnCueChanged")]
|
||||
public GameplayCueDurational Cue;
|
||||
|
||||
[BoxGroup]
|
||||
[Button]
|
||||
[GUIColor(0.9f, 0.2f, 0.2f)]
|
||||
void Delete()
|
||||
{
|
||||
_clip.Delete();
|
||||
}
|
||||
|
||||
void Refresh()
|
||||
{
|
||||
RunInfo = $"<b>Run(f):{_clip.DurationalCueClipData.startFrame} -> {_clip.DurationalCueClipData.EndFrame}</b>";
|
||||
Duration = _clip.DurationalCueClipData.durationFrame;
|
||||
Cue = _clip.DurationalCueClipData.cue;
|
||||
}
|
||||
|
||||
private void OnDurationFrameChanged()
|
||||
{
|
||||
// 钳制
|
||||
var max = AbilityAsset.FrameCount - _clip.DurationalCueClipData.startFrame;
|
||||
Duration = Mathf.Clamp(Duration, 1, max);
|
||||
_clip.UpdateClipDataDurationFrame(Duration);
|
||||
_clip.RefreshShow(_clip.FrameUnitWidth);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnCueChanged()
|
||||
{
|
||||
_clip.UpdateClipDataCue(Cue);
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(DurationalCueClipEditor))]
|
||||
public class DurationalCueClipInspector : OdinEditorWithoutHeader
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("注意!! TimelineAbility下的持续性Cue, 只会执行OnAdd(Cue播放的第一帧),OnRemove(Cue播放的最后一帧)及OnTick, 和GameplayEffect相关的方法不会被执行", MessageType.Info);
|
||||
|
||||
GUILayout.Space(20);
|
||||
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 555dbb9258c24339b1246835568b4c94
|
||||
timeCreated: 1710404017
|
@ -0,0 +1,97 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class DurationalCueTrack : TrackBase
|
||||
{
|
||||
private DurationalCueTrackData _durationalCueTrackData;
|
||||
public override Type TrackDataType => typeof(DurationalCueTrackData);
|
||||
protected override Color TrackColor => new(0.1f, 0.6f, 0.1f, 0.2f);
|
||||
protected override Color MenuColor => new(0.1f, 0.6f, 0.1f, 1);
|
||||
|
||||
private TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
public DurationalCueTrackData CueTrackDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < AbilityAsset.DurationalCues.Count; i++)
|
||||
if (AbilityAsset.DurationalCues[i] == _durationalCueTrackData)
|
||||
return AbilityAsset.DurationalCues[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
foreach (var item in _trackItems)
|
||||
{
|
||||
var durationalCueClip = item as DurationalCueClip;
|
||||
durationalCueClip?.OnTickView(frameIndex, durationalCueClip.StartFrameIndex,
|
||||
durationalCueClip.EndFrameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth,
|
||||
TrackDataBase trackData)
|
||||
{
|
||||
base.Init(trackParent, menuParent, frameWidth, trackData);
|
||||
_durationalCueTrackData = trackData as DurationalCueTrackData;
|
||||
MenuText.text = _durationalCueTrackData.trackName;
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameWidth);
|
||||
foreach (var item in _trackItems) Track.Remove(((TrackClipBase)item).ClipVe);
|
||||
_trackItems.Clear();
|
||||
|
||||
if (AbilityTimelineEditorWindow.Instance.AbilityAsset != null)
|
||||
foreach (var clipEvent in _durationalCueTrackData.clipEvents)
|
||||
{
|
||||
var item = new DurationalCueClip();
|
||||
item.InitTrackClip(this, Track, _frameWidth, clipEvent);
|
||||
_trackItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
// 添加Clip数据
|
||||
var clipEvent = new DurationalCueClipEvent
|
||||
{
|
||||
startFrame = GetTrackIndexByMouse(action.eventInfo.localMousePosition.x),
|
||||
durationFrame = 5
|
||||
};
|
||||
CueTrackDataForSave.clipEvents.Add(clipEvent);
|
||||
|
||||
// 刷新显示
|
||||
var item = new DurationalCueClip();
|
||||
item.InitTrackClip(this, Track, _frameWidth, clipEvent);
|
||||
_trackItems.Add(item);
|
||||
|
||||
// 选中新Clip
|
||||
item.ClipVe.OnSelect();
|
||||
|
||||
Debug.Log("[EX] Add a new Durational Cue Clip");
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
// 删除数据
|
||||
AbilityAsset.DurationalCues.Remove(_durationalCueTrackData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
// 删除显示
|
||||
TrackParent.Remove(TrackRoot);
|
||||
MenuParent.Remove(MenuRoot);
|
||||
Debug.Log("[EX] Remove Durational Cue Track");
|
||||
}
|
||||
|
||||
public override UnityEngine.Object DataInspector => DurationalCueTrackEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 899a06ffd86a4b6e832ce82f279207bb
|
||||
timeCreated: 1709030523
|
@ -0,0 +1,59 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
public class DurationalCueTrackEditor:OdinEditorWindow
|
||||
{
|
||||
private DurationalCueTrack _track;
|
||||
|
||||
public static DurationalCueTrackEditor Create(DurationalCueTrack track)
|
||||
{
|
||||
var window = new DurationalCueTrackEditor();
|
||||
window._track = track;
|
||||
window.TrackName = track.CueTrackDataForSave.trackName;
|
||||
window.UpdateTrackInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Name")]
|
||||
[OnValueChanged("OnTrackNameChanged")]
|
||||
public string TrackName;
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string TrackInfo;
|
||||
|
||||
void UpdateTrackInfo()
|
||||
{
|
||||
string info = "";
|
||||
foreach (var clip in _track.CueTrackDataForSave.clipEvents)
|
||||
{
|
||||
var clipName = clip.cue != null ? clip.cue.name : "NULL";
|
||||
info += $"[{clipName}] Run(f):{clip.startFrame} -> {clip.EndFrame} \n";
|
||||
}
|
||||
TrackInfo = $"<b>{info}</b>";
|
||||
}
|
||||
|
||||
|
||||
void OnTrackNameChanged()
|
||||
{
|
||||
_track.CueTrackDataForSave.trackName = TrackName;
|
||||
_track.MenuText.text = TrackName;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(DurationalCueTrackEditor))]
|
||||
public class DurationalCueTrackInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd1f531896fc433285c1c6c53cda8f89
|
||||
timeCreated: 1710401400
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdd0f3a0481a4cc686203d7b0d8e0cd4
|
||||
timeCreated: 1709105891
|
@ -0,0 +1,79 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class InstantCueMark : TrackMark<InstantCueTrack>
|
||||
{
|
||||
public InstantCueMarkEvent InstantCueMarkData => markData as InstantCueMarkEvent;
|
||||
|
||||
public InstantCueMarkEvent MarkDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
var cueTrackDataForSave = track.InstantCueTrackData;
|
||||
for (var i = 0; i < cueTrackDataForSave.markEvents.Count; i++)
|
||||
if (cueTrackDataForSave.markEvents[i] == InstantCueMarkData)
|
||||
return track.InstantCueTrackData.markEvents[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Duplicate()
|
||||
{
|
||||
// 添加Mark数据
|
||||
var startFrame = markData.startFrame < AbilityAsset.FrameCount
|
||||
? markData.startFrame + 1
|
||||
: markData.startFrame - 1;
|
||||
startFrame = Mathf.Clamp(startFrame, 0, AbilityAsset.FrameCount);
|
||||
var markEvent = new InstantCueMarkEvent
|
||||
{
|
||||
startFrame = startFrame,
|
||||
cues = (markData as InstantCueMarkEvent)?.cues
|
||||
};
|
||||
track.InstantCueTrackData.markEvents.Add(markEvent);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
|
||||
var mark = new InstantCueMark();
|
||||
mark.InitTrackMark(track, track.Track, FrameUnitWidth, markEvent);
|
||||
track.TrackItems.Add(mark);
|
||||
mark.OnSelect();
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameUnitWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameUnitWidth);
|
||||
ItemLabel.text = InstantCueMarkData.cues.Count.ToString();
|
||||
}
|
||||
|
||||
public override Object DataInspector => InstantCueMarkEditor.Create(this);
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
var success = track.InstantCueTrackData.markEvents.Remove(InstantCueMarkData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
if (!success) return;
|
||||
track.RemoveTrackItem(this);
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector();
|
||||
}
|
||||
|
||||
public override void UpdateMarkDataFrame(int newStartFrame)
|
||||
{
|
||||
var updatedClip = MarkDataForSave;
|
||||
MarkDataForSave.startFrame = newStartFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
markData = updatedClip;
|
||||
}
|
||||
|
||||
public override void OnTickView(int frameIndex)
|
||||
{
|
||||
foreach (var cue in InstantCueMarkData.cues)
|
||||
cue.OnEditorPreview(AbilityTimelineEditorWindow.Instance.PreviewObject, frameIndex,
|
||||
InstantCueMarkData.startFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 006183b1e1fa46918aa44a1c0cda7a2c
|
||||
timeCreated: 1709105913
|
@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
using GAS.Runtime;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class InstantCueMarkEditor : OdinEditorWindow
|
||||
{
|
||||
private InstantCueMark _mark;
|
||||
|
||||
public static InstantCueMarkEditor Create(InstantCueMark mark)
|
||||
{
|
||||
var window = CreateInstance<InstantCueMarkEditor>();
|
||||
window._mark = mark;
|
||||
|
||||
window.UpdateMarkInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string RunInfo;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[AssetSelector]
|
||||
[ListDrawerSettings(ShowFoldout = true, DraggableItems = true)]
|
||||
[OnValueChanged("OnCueListChanged")]
|
||||
public List<GameplayCueInstant> Cues;
|
||||
|
||||
[BoxGroup]
|
||||
[Button]
|
||||
[GUIColor(0.9f, 0.2f, 0.2f)]
|
||||
void Delete()
|
||||
{
|
||||
_mark.Delete();
|
||||
}
|
||||
|
||||
void UpdateMarkInfo()
|
||||
{
|
||||
RunInfo = $"<b>Trigger(f):{_mark.InstantCueMarkData.startFrame}</b>";
|
||||
Cues = _mark.InstantCueMarkData.cues;
|
||||
}
|
||||
|
||||
void OnCueListChanged()
|
||||
{
|
||||
_mark.MarkDataForSave.cues = Cues;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(InstantCueMarkEditor))]
|
||||
public class InstantCueMarkInspector : OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d3b0634bef24b3fb624c6a2184b99e9
|
||||
timeCreated: 1710411938
|
@ -0,0 +1,124 @@
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using GAS.Runtime;
|
||||
|
||||
public class InstantCueTrack : TrackBase
|
||||
{
|
||||
private InstantCueTrackData _instantCuesTrackData;
|
||||
private static TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
|
||||
public InstantCueTrackData InstantCueTrackData
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < AbilityAsset.InstantCues.Count; i++)
|
||||
if (AbilityAsset.InstantCues[i] == _instantCuesTrackData)
|
||||
return AbilityAsset.InstantCues[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override Type TrackDataType => typeof(InstantCueTrackData);
|
||||
protected override Color TrackColor => new(0.1f, 0.2f, 0.6f, 0.2f);
|
||||
protected override Color MenuColor => new(0.1f, 0.6f, 0.9f, 0.9f);
|
||||
|
||||
public override void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth,
|
||||
TrackDataBase trackData)
|
||||
{
|
||||
base.Init(trackParent, menuParent, frameWidth, trackData);
|
||||
_instantCuesTrackData = trackData as InstantCueTrackData;
|
||||
MenuText.text = _instantCuesTrackData.trackName;
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
foreach (var item in _trackItems)
|
||||
((TrackMarkBase)item).OnTickView(frameIndex);
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameWidth);
|
||||
foreach (var item in _trackItems) Track.Remove(((TrackMarkBase)item).Ve);
|
||||
_trackItems.Clear();
|
||||
|
||||
if (AbilityTimelineEditorWindow.Instance.AbilityAsset == null) return;
|
||||
|
||||
foreach (var markEvent in _instantCuesTrackData.markEvents)
|
||||
{
|
||||
var item = new InstantCueMark();
|
||||
item.InitTrackMark(this, Track, _frameWidth, markEvent);
|
||||
_trackItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// public override VisualElement Inspector()
|
||||
// {
|
||||
// var inspector = TrackInspectorUtil.CreateTrackInspector();
|
||||
//
|
||||
// var trackName =
|
||||
// TrackInspectorUtil.CreateTextField("Name", _instantCuesTrackData.trackName,
|
||||
// e =>
|
||||
// {
|
||||
// _instantCuesTrackData.trackName = e.newValue;
|
||||
// MenuText.text = _instantCuesTrackData.trackName;
|
||||
// AbilityTimelineEditorWindow.Instance.Save();
|
||||
// });
|
||||
// inspector.Add(trackName);
|
||||
//
|
||||
// foreach (var mark in _instantCuesTrackData.markEvents)
|
||||
// {
|
||||
// var markFrame = TrackInspectorUtil.CreateLabel($"Trigger(f):{mark.startFrame}");
|
||||
// inspector.Add(markFrame);
|
||||
// foreach (var c in mark.cues)
|
||||
// {
|
||||
// var cueName = c != null ? c.name : "NULL";
|
||||
// var cueCount = TrackInspectorUtil.CreateLabel($" |-> Cue:{cueName}");
|
||||
// inspector.Add(cueCount);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return inspector;
|
||||
// }
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
// 添加Mark数据
|
||||
var markEvent = new InstantCueMarkEvent
|
||||
{
|
||||
startFrame = GetTrackIndexByMouse(action.eventInfo.localMousePosition.x),
|
||||
cues = new List<GameplayCueInstant>()
|
||||
};
|
||||
InstantCueTrackData.markEvents.Add(markEvent);
|
||||
|
||||
// 刷新显示
|
||||
var mark = new InstantCueMark();
|
||||
mark.InitTrackMark(this, Track, _frameWidth, markEvent);
|
||||
_trackItems.Add(mark);
|
||||
|
||||
mark.OnSelect();
|
||||
Debug.Log("[EX] Add Instant Cue Mark");
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
// 删除数据
|
||||
AbilityAsset.InstantCues.Remove(_instantCuesTrackData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
// 删除显示
|
||||
TrackParent.Remove(TrackRoot);
|
||||
MenuParent.Remove(MenuRoot);
|
||||
Debug.Log("[EX] Remove Instant Cue Track");
|
||||
}
|
||||
|
||||
public override UnityEngine.Object DataInspector => InstantCueTrackEditor.Create(this);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f519c65b0761462ebb77625d5081eddf
|
||||
timeCreated: 1709105875
|
@ -0,0 +1,65 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
public class InstantCueTrackEditor:OdinEditorWindow
|
||||
{
|
||||
private InstantCueTrack _track;
|
||||
public static InstantCueTrackEditor Create(InstantCueTrack track)
|
||||
{
|
||||
var window = new InstantCueTrackEditor();
|
||||
window._track = track;
|
||||
window.TrackName = track.InstantCueTrackData.trackName;
|
||||
window.UpdateTrackInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Name")]
|
||||
[OnValueChanged("OnTrackNameChanged")]
|
||||
public string TrackName;
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string TrackInfo;
|
||||
|
||||
void UpdateTrackInfo()
|
||||
{
|
||||
string info = "";
|
||||
foreach (var mark in _track.InstantCueTrackData.markEvents)
|
||||
{
|
||||
info += $"Trigger(f):{mark.startFrame} \n";
|
||||
foreach (var c in mark.cues)
|
||||
{
|
||||
var cueName = c != null ? c.name : "NULL";
|
||||
info += $" |-> {cueName}\n";
|
||||
}
|
||||
info += "\n";
|
||||
}
|
||||
|
||||
TrackInfo = $"<b>{info}</b>";
|
||||
}
|
||||
|
||||
|
||||
void OnTrackNameChanged()
|
||||
{
|
||||
Debug.Log("TrackName Changed");
|
||||
_track.InstantCueTrackData.trackName = TrackName;
|
||||
_track.MenuText.text = TrackName;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(InstantCueTrackEditor))]
|
||||
public class InstantCueTrackInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5865319f3db4441b7c249a5ed3127b2
|
||||
timeCreated: 1710387029
|
@ -0,0 +1,118 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class MenuTrack : TrackBase
|
||||
{
|
||||
private Color _menuColor;
|
||||
|
||||
private Color _trackColor;
|
||||
private Type _trackDataType;
|
||||
private Type _trackType;
|
||||
private static TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
private static AbilityTimelineEditorConfig Config => AbilityTimelineEditorWindow.Instance.Config;
|
||||
private static TimelineTrackView TrackView => AbilityTimelineEditorWindow.Instance.TrackView;
|
||||
public override Type TrackDataType { get; }
|
||||
protected override Color TrackColor => _trackColor;
|
||||
protected override Color MenuColor => _menuColor;
|
||||
protected override string MenuAssetGuid => "944173d62639bb04b8b64be960c8ef29";
|
||||
|
||||
public Button AddButton { get; private set; }
|
||||
|
||||
public void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth, Type trackType,
|
||||
Type trackDataType,
|
||||
string label, Color trackColor, Color menuColor)
|
||||
{
|
||||
_trackType = trackType;
|
||||
_trackDataType = trackDataType;
|
||||
_trackColor = trackColor;
|
||||
_menuColor = menuColor;
|
||||
|
||||
base.Init(trackParent, menuParent, frameWidth, null);
|
||||
AddButton = MenuRoot.Q<Button>("BtnAdd");
|
||||
AddButton.style.display = DisplayStyle.Flex;
|
||||
AddButton.clickable.clicked += OnClickAddTrack;
|
||||
MenuBox.style.left = 0;
|
||||
MenuBox.style.right = new StyleLength(StyleKeyword.Auto);
|
||||
MenuText.text = label;
|
||||
|
||||
Track.style.backgroundColor = new Color(0, 0, 0, 0);
|
||||
BoundingBox.style.backgroundColor = MenuColor;
|
||||
const int height = 20;
|
||||
MenuRoot.style.height = height;
|
||||
MenuRoot.style.minHeight = height;
|
||||
MenuRoot.style.maxHeight = height;
|
||||
|
||||
TrackRoot.style.height = height;
|
||||
TrackRoot.style.minHeight = height;
|
||||
TrackRoot.style.maxHeight = height;
|
||||
}
|
||||
|
||||
private void OnClickAddTrack()
|
||||
{
|
||||
// 创建View
|
||||
var track = (TrackBase)Activator.CreateInstance(_trackType);
|
||||
if (track.IsFixedTrack()) return;
|
||||
|
||||
// 创建Data
|
||||
var data = (TrackDataBase)Activator.CreateInstance(_trackDataType);
|
||||
data.DefaultInit();
|
||||
data.AddToAbilityAsset(AbilityAsset);
|
||||
|
||||
// 初始化View
|
||||
track.Init(TrackParent, MenuParent, Config.FrameUnitWidth, data);
|
||||
TrackParent.Remove(track.TrackRoot);
|
||||
MenuParent.Remove(track.MenuRoot);
|
||||
var index = CurrentAddIndex();
|
||||
TrackParent.Insert(index, track.TrackRoot);
|
||||
MenuParent.Insert(index, track.MenuRoot);
|
||||
|
||||
TrackView.TrackList.Add(track);
|
||||
|
||||
Debug.Log("[EX] Add a new track:" + _trackType.Name);
|
||||
|
||||
AbilityAsset.Save();
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
}
|
||||
|
||||
private int CurrentAddIndex()
|
||||
{
|
||||
var baseIndex = TrackParent.IndexOf(TrackRoot);
|
||||
if (_trackType == typeof(InstantCueTrack))
|
||||
return baseIndex + (AbilityAsset.InstantCues?.Count ?? 0);
|
||||
|
||||
if (_trackType == typeof(TaskMarkEventTrack))
|
||||
return baseIndex + (AbilityAsset.InstantTasks?.Count ?? 0);
|
||||
|
||||
if (_trackType == typeof(ReleaseGameplayEffectTrack))
|
||||
return baseIndex + (AbilityAsset.ReleaseGameplayEffect?.Count ?? 0);
|
||||
|
||||
if (_trackType == typeof(BuffGameplayEffectTrack))
|
||||
return baseIndex + (AbilityAsset.BuffGameplayEffects?.Count ?? 0);
|
||||
|
||||
if (_trackType == typeof(TaskClipEventTrack))
|
||||
return baseIndex + (AbilityAsset.OngoingTasks?.Count ?? 0);
|
||||
|
||||
if (_trackType == typeof(DurationalCueTrack))
|
||||
return baseIndex + (AbilityAsset.DurationalCues?.Count ?? 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccfa764d58764d56b5b0ecd3cb16e064
|
||||
timeCreated: 1709798443
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf6fdec790cf4bfe9e0c9df3e0534071
|
||||
timeCreated: 1709133883
|
@ -0,0 +1,130 @@
|
||||
using GAS.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class ReleaseGameplayEffectMark : TrackMark<ReleaseGameplayEffectTrack>
|
||||
{
|
||||
private new ReleaseGameplayEffectMarkEvent MarkData => markData as ReleaseGameplayEffectMarkEvent;
|
||||
|
||||
public ReleaseGameplayEffectMarkEvent MarkDataForSave
|
||||
{
|
||||
get
|
||||
{
|
||||
var trackDataForSave = track.ReleaseGameplayEffectTrackData;
|
||||
for (var i = 0; i < trackDataForSave.markEvents.Count; i++)
|
||||
if (trackDataForSave.markEvents[i] == MarkData)
|
||||
return track.ReleaseGameplayEffectTrackData.markEvents[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Duplicate()
|
||||
{
|
||||
var startFrame = markData.startFrame < AbilityAsset.FrameCount
|
||||
? markData.startFrame + 1
|
||||
: markData.startFrame - 1;
|
||||
startFrame = Mathf.Clamp(startFrame, 0, AbilityAsset.FrameCount);
|
||||
var markEvent = new ReleaseGameplayEffectMarkEvent
|
||||
{
|
||||
startFrame = startFrame,
|
||||
jsonTargetCatcher = (markData as ReleaseGameplayEffectMarkEvent)?.jsonTargetCatcher,
|
||||
gameplayEffectAssets = (markData as ReleaseGameplayEffectMarkEvent)?.gameplayEffectAssets
|
||||
};
|
||||
track.ReleaseGameplayEffectTrackData.markEvents.Add(markEvent);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
|
||||
var mark = new ReleaseGameplayEffectMark();
|
||||
mark.InitTrackMark(track, track.Track, FrameUnitWidth, markEvent);
|
||||
track.TrackItems.Add(mark);
|
||||
mark.OnSelect();
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameUnitWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameUnitWidth);
|
||||
ItemLabel.text = MarkData.gameplayEffectAssets.Count.ToString();
|
||||
}
|
||||
|
||||
public override Object DataInspector => ReleaseGameplayEffectMarkEditor.Create(this);
|
||||
// public override VisualElement Inspector()
|
||||
// {
|
||||
// var inspector = TrackInspectorUtil.CreateTrackInspector();
|
||||
// var markFrame = TrackInspectorUtil.CreateLabel($"Trigger(f):{markData.startFrame}");
|
||||
// inspector.Add(markFrame);
|
||||
//
|
||||
// // 目标捕捉器
|
||||
// // 选择项:所有TargetCatcher子类
|
||||
// var targetCatcherSonTypes = ReleaseGameplayEffectMarkEvent.TargetCatcherSonTypes;
|
||||
// var targetCatcherSons = targetCatcherSonTypes.Select(sonType => sonType.FullName).ToList();
|
||||
// var catcherTypeSelector =
|
||||
// TrackInspectorUtil.CreateDropdownField("TargetCatcher", targetCatcherSons,
|
||||
// MarkData.jsonTargetCatcher.Type, OnTargetCatcherChanged);
|
||||
// inspector.Add(catcherTypeSelector);
|
||||
//
|
||||
// // 根据选择的TargetCatcher子类,显示对应的属性
|
||||
// var targetCatcher = MarkData.LoadTargetCatcher();
|
||||
// if (TargetCatcherInspectorMap.TryGetValue(targetCatcher.GetType(), out var inspectorType))
|
||||
// {
|
||||
// var targetCatcherInspector =
|
||||
// (TargetCatcherInspector)Activator.CreateInstance(inspectorType, targetCatcher);
|
||||
// inspector.Add(targetCatcherInspector.Inspector());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Debug.LogError($"[EX] TargetCatcherInspector not found: {targetCatcher.GetType()}");
|
||||
// }
|
||||
//
|
||||
// // GameplayEffects
|
||||
// var list = TrackInspectorUtil.CreateObjectListView("GameplayEffects", MarkData.gameplayEffectAssets,
|
||||
// OnGameplayEffectAssetChanged);
|
||||
// inspector.Add(list);
|
||||
//
|
||||
// return inspector;
|
||||
// }
|
||||
|
||||
// private void OnTargetCatcherChanged(ChangeEvent<string> evt)
|
||||
// {
|
||||
// MarkDataForSave.jsonTargetCatcher.Type = evt.newValue;
|
||||
// MarkDataForSave.jsonTargetCatcher.Data = null;
|
||||
// AbilityTimelineEditorWindow.Instance.Save();
|
||||
//
|
||||
// AbilityTimelineEditorWindow.Instance.TimelineInspector.RefreshInspector();
|
||||
// }
|
||||
//
|
||||
// private void OnGameplayEffectAssetChanged(int index, ChangeEvent<Object> evt)
|
||||
// {
|
||||
// var gameplayEffectAsset = evt.newValue as GameplayEffectAsset;
|
||||
// MarkDataForSave.gameplayEffectAssets[index] = gameplayEffectAsset;
|
||||
// AbilityTimelineEditorWindow.Instance.Save();
|
||||
//
|
||||
// RefreshShow(FrameUnitWidth);
|
||||
// }
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
var success = track.ReleaseGameplayEffectTrackData.markEvents.Remove(MarkData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
if (!success) return;
|
||||
track.RemoveTrackItem(this);
|
||||
AbilityTimelineEditorWindow.Instance.SetInspector();
|
||||
}
|
||||
|
||||
public override void UpdateMarkDataFrame(int newStartFrame)
|
||||
{
|
||||
var updatedClip = MarkDataForSave;
|
||||
MarkDataForSave.startFrame = newStartFrame;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
markData = updatedClip;
|
||||
}
|
||||
|
||||
public override void OnTickView(int frameIndex)
|
||||
{
|
||||
if (frameIndex == StartFrameIndex)
|
||||
{
|
||||
var targetCatcher = MarkData.TargetCatcher;
|
||||
targetCatcher.OnEditorPreview(AbilityTimelineEditorWindow.Instance.PreviewObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2b29a1caa5a405f90c2ae1252fd2170
|
||||
timeCreated: 1709133936
|
@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GAS.General;
|
||||
using GAS.Runtime;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public class ReleaseGameplayEffectMarkEditor : OdinEditorWindow
|
||||
{
|
||||
private const string GRP_BOX = "GRP_BOX";
|
||||
private const string GRP_BOX_CATCHER = "GRP_BOX/Catcher";
|
||||
|
||||
private ReleaseGameplayEffectMark _mark;
|
||||
|
||||
public static ReleaseGameplayEffectMarkEditor Create(ReleaseGameplayEffectMark mark)
|
||||
{
|
||||
var window = CreateInstance<ReleaseGameplayEffectMarkEditor>();
|
||||
window._mark = mark;
|
||||
window.UpdateMarkInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[BoxGroup(GRP_BOX)]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string RunInfo;
|
||||
|
||||
// TODO TargetCatcher
|
||||
[Delayed]
|
||||
[BoxGroup(GRP_BOX_CATCHER)]
|
||||
[LabelText("Target Catcher")]
|
||||
[ValueDropdown("TargetCatcherSonTypeChoices")]
|
||||
[InfoBox("This Catcher has no inspector!", InfoMessageType.Warning, "CatcherIsNull")]
|
||||
[OnValueChanged("OnCatcherTypeChanged")]
|
||||
public string CatcherType;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup(GRP_BOX_CATCHER)]
|
||||
[HideReferenceObjectPicker]
|
||||
[HideIf("CatcherIsNull")]
|
||||
[LabelText("Detail")]
|
||||
[OnValueChanged("OnCatcherChanged", true)]
|
||||
public TargetCatcherInspector Catcher;
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup(GRP_BOX)]
|
||||
[AssetSelector]
|
||||
[ListDrawerSettings(ShowFoldout = true, DraggableItems = true)]
|
||||
[OnValueChanged("OnGameplayEffectListChanged")]
|
||||
public List<GameplayEffectAsset> gameplayEffects;
|
||||
|
||||
[BoxGroup(GRP_BOX)]
|
||||
[Button]
|
||||
[GUIColor(0.9f, 0.2f, 0.2f)]
|
||||
void Delete()
|
||||
{
|
||||
_mark.Delete();
|
||||
}
|
||||
|
||||
void UpdateMarkInfo()
|
||||
{
|
||||
RunInfo = $"<b>Trigger(f):{_mark.MarkData.startFrame}</b>";
|
||||
gameplayEffects = _mark.MarkDataForSave.gameplayEffectAssets;
|
||||
|
||||
CatcherType = _mark.MarkDataForSave.jsonTargetCatcher.Type;
|
||||
RefreshCatcherInspector();
|
||||
}
|
||||
|
||||
void RefreshCatcherInspector()
|
||||
{
|
||||
// 根据选择的OngoingAbilityTask子类,显示对应的属性
|
||||
var catcher = _mark.MarkDataForSave.LoadTargetCatcher();
|
||||
if (TargetCatcherInspectorMap.TryGetValue(catcher.GetType(), out var inspectorType))
|
||||
{
|
||||
var targetCatcherInspector =
|
||||
(TargetCatcherInspector)Activator.CreateInstance(inspectorType, catcher);
|
||||
Catcher = targetCatcherInspector;
|
||||
}
|
||||
else
|
||||
{
|
||||
Catcher = null;
|
||||
Debug.LogWarning($"[EX] TargetCatcherInspector not found: {catcher.GetType()}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameplayEffectListChanged()
|
||||
{
|
||||
_mark.MarkDataForSave.gameplayEffectAssets = gameplayEffects;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
|
||||
void OnCatcherTypeChanged()
|
||||
{
|
||||
_mark.MarkDataForSave.jsonTargetCatcher.Type = CatcherType;
|
||||
_mark.MarkDataForSave.jsonTargetCatcher.Data = null;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
AbilityTimelineEditorWindow.Instance.TimelineInspector.RefreshInspector();
|
||||
}
|
||||
|
||||
void OnCatcherChanged()
|
||||
{
|
||||
// _mark.MarkDataForSave.jsonTargetCatcher.Data = Catcher.ToJson();
|
||||
// AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
|
||||
private bool CatcherIsNull => Catcher == null;
|
||||
|
||||
|
||||
private static Type[] _targetCatcherInspectorTypes;
|
||||
private static List<string> TargetCatcherSonTypeChoices;
|
||||
private static Dictionary<Type, Type> _targetCatcherInspectorMap;
|
||||
|
||||
public static Type[] TargetCatcherInspectorTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_targetCatcherInspectorTypes != null) return _targetCatcherInspectorTypes;
|
||||
_targetCatcherInspectorTypes = TypeUtil.GetAllSonTypesOf(typeof(TargetCatcherInspector));
|
||||
TargetCatcherSonTypeChoices = ReleaseGameplayEffectMarkEvent.TargetCatcherSonTypes.Select(type => type.FullName).ToList();
|
||||
return _targetCatcherInspectorTypes;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<Type, Type> TargetCatcherInspectorMap
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_targetCatcherInspectorMap != null) return _targetCatcherInspectorMap;
|
||||
_targetCatcherInspectorMap = new Dictionary<Type, Type>();
|
||||
foreach (var catcherInspectorType in TargetCatcherInspectorTypes)
|
||||
{
|
||||
if (catcherInspectorType.BaseType != null)
|
||||
{
|
||||
var targetCatcherType = catcherInspectorType.BaseType.GetGenericArguments()[0];
|
||||
_targetCatcherInspectorMap.Add(targetCatcherType, catcherInspectorType);
|
||||
}
|
||||
}
|
||||
|
||||
return _targetCatcherInspectorMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ReleaseGameplayEffectMarkEditor))]
|
||||
public class ReleaseGameplayEffectMarkInspector : OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94946599b70e4166903f7df94af3e3e5
|
||||
timeCreated: 1710418194
|
@ -0,0 +1,94 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class ReleaseGameplayEffectTrack : TrackBase
|
||||
{
|
||||
private static TimelineAbilityAssetBase AbilityAsset => AbilityTimelineEditorWindow.Instance.AbilityAsset;
|
||||
public ReleaseGameplayEffectTrackData ReleaseGameplayEffectTrackData {
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < AbilityAsset.ReleaseGameplayEffect.Count; i++)
|
||||
{
|
||||
if(AbilityAsset.ReleaseGameplayEffect[i] == _releaseGameplayEffectTrackData)
|
||||
return AbilityAsset.ReleaseGameplayEffect[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ReleaseGameplayEffectTrackData _releaseGameplayEffectTrackData;
|
||||
public override Type TrackDataType => typeof(ReleaseGameplayEffectTrackData);
|
||||
protected override Color TrackColor => new(0.9f, 0.3f, 0.35f, 0.2f);
|
||||
protected override Color MenuColor => new(0.9f, 0.3f, 0.35f, 0.9f);
|
||||
|
||||
public override void Init(VisualElement trackParent, VisualElement menuParent, float frameWidth,
|
||||
TrackDataBase trackData)
|
||||
{
|
||||
base.Init(trackParent, menuParent, frameWidth, trackData);
|
||||
_releaseGameplayEffectTrackData = trackData as ReleaseGameplayEffectTrackData;
|
||||
MenuText.text = _releaseGameplayEffectTrackData.trackName;
|
||||
}
|
||||
|
||||
public override void TickView(int frameIndex, params object[] param)
|
||||
{
|
||||
foreach (var item in _trackItems)
|
||||
((TrackMarkBase)item).OnTickView(frameIndex);
|
||||
}
|
||||
|
||||
public override void RefreshShow(float newFrameWidth)
|
||||
{
|
||||
base.RefreshShow(newFrameWidth);
|
||||
foreach (var item in _trackItems) Track.Remove(item.Ve);
|
||||
_trackItems.Clear();
|
||||
|
||||
if (AbilityTimelineEditorWindow.Instance.AbilityAsset == null) return;
|
||||
|
||||
foreach (var markEvent in _releaseGameplayEffectTrackData.markEvents)
|
||||
{
|
||||
var item = new ReleaseGameplayEffectMark();
|
||||
item.InitTrackMark(this, Track, _frameWidth, markEvent);
|
||||
_trackItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public override UnityEngine.Object DataInspector => ReleaseGameplayEffectTrackEditor.Create(this);
|
||||
|
||||
protected override void OnAddTrackItem(DropdownMenuAction action)
|
||||
{
|
||||
// 添加Mark数据
|
||||
var markEvent = new ReleaseGameplayEffectMarkEvent
|
||||
{
|
||||
startFrame = GetTrackIndexByMouse(action.eventInfo.localMousePosition.x),
|
||||
gameplayEffectAssets = new List<GameplayEffectAsset>()
|
||||
};
|
||||
ReleaseGameplayEffectTrackData.markEvents.Add(markEvent);
|
||||
|
||||
// 刷新显示
|
||||
var mark = new ReleaseGameplayEffectMark();
|
||||
mark.InitTrackMark(this, Track, _frameWidth, markEvent);
|
||||
_trackItems.Add(mark);
|
||||
|
||||
mark.OnSelect();
|
||||
|
||||
Debug.Log("[EX] Add ReleaseGameplayEffect Mark");
|
||||
}
|
||||
|
||||
protected override void OnRemoveTrack(DropdownMenuAction action)
|
||||
{
|
||||
// 删除数据
|
||||
AbilityAsset.ReleaseGameplayEffect.Remove(_releaseGameplayEffectTrackData);
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
// 删除显示
|
||||
TrackParent.Remove(TrackRoot);
|
||||
MenuParent.Remove(MenuRoot);
|
||||
Debug.Log("[EX] Remove Release GameplayEffect Track");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ad9df1318a54f8dad8cc6117a2377c1
|
||||
timeCreated: 1709133898
|
@ -0,0 +1,65 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using Editor;
|
||||
using UnityEngine;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
public class ReleaseGameplayEffectTrackEditor:OdinEditorWindow
|
||||
{
|
||||
private ReleaseGameplayEffectTrack _track;
|
||||
|
||||
public static ReleaseGameplayEffectTrackEditor Create(ReleaseGameplayEffectTrack track)
|
||||
{
|
||||
var window = new ReleaseGameplayEffectTrackEditor();
|
||||
window._track = track;
|
||||
window.TrackName = track.ReleaseGameplayEffectTrackData.trackName;
|
||||
window.UpdateTrackInfo();
|
||||
return window;
|
||||
}
|
||||
|
||||
[Delayed]
|
||||
[BoxGroup]
|
||||
[LabelText("Name")]
|
||||
[OnValueChanged("OnTrackNameChanged")]
|
||||
public string TrackName;
|
||||
|
||||
[BoxGroup]
|
||||
[HideLabel]
|
||||
[DisplayAsString(TextAlignment.Left,true)]
|
||||
public string TrackInfo;
|
||||
|
||||
void UpdateTrackInfo()
|
||||
{
|
||||
string info = "";
|
||||
foreach (var mark in _track.ReleaseGameplayEffectTrackData.markEvents)
|
||||
{
|
||||
info += $"Trigger(f):{mark.startFrame} \n";
|
||||
foreach (var ge in mark.gameplayEffectAssets)
|
||||
{
|
||||
var geName = ge != null ? ge.name : "NULL";
|
||||
info += $" |-> {geName}\n";
|
||||
}
|
||||
|
||||
info += "\n";
|
||||
}
|
||||
TrackInfo = $"<b>{info}</b>";
|
||||
}
|
||||
|
||||
|
||||
void OnTrackNameChanged()
|
||||
{
|
||||
_track.ReleaseGameplayEffectTrackData.trackName = TrackName;
|
||||
_track.MenuText.text = TrackName;
|
||||
AbilityTimelineEditorWindow.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ReleaseGameplayEffectTrackEditor))]
|
||||
public class ReleaseGameplayEffectTrackInspector:OdinEditorWithoutHeader
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee4c649971894b9696c0076c18bf3b40
|
||||
timeCreated: 1710400873
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user