This commit is contained in:
陈思海 2026-04-15 19:47:09 +08:00
commit a2808b627d
206 changed files with 24165 additions and 0 deletions

83
.gitignore vendored Normal file
View File

@ -0,0 +1,83 @@
# UnityProject
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Mm]emoryCaptures/
/EditorBuild/
/[Aa]ssets/StreamingAssets
/[Aa]ssets/StreamingAssets.meta
/BuildBundleInfo/
# 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/
#AATemp
[Aa]ssets/AATemp/
[Aa]ssets/AATemp.meta
# Custom AATest
[Aa]ssets/AATest/
[Aa]ssets/AATest.meta
#Sandbox
Sandbox/
#MAC
.DS_Store
#Rider
.idea/

View File

@ -0,0 +1,22 @@
{
"permissions": {
"allow": [
"Bash(where pdftotext:*)",
"Bash(pdftotext \"G:\\\\\\\\UnityProject\\\\\\\\CapabilitySystem\\\\\\\\Assets\\\\\\\\技术文档.pdf\" \"G:\\\\\\\\UnityProject\\\\\\\\CapabilitySystem\\\\\\\\Assets\\\\\\\\技术文档.txt\")",
"Bash(ls -1 CapabilitySystem/Core/*.cs)",
"Bash(pdftotext \"技术文档.pdf\" - | head -n 500)",
"Bash(pdftotext \"技术文档.pdf\" - | tail -n +500 | head -n 500)",
"Bash(pdftotext \"技术文档.pdf\" /tmp/tech_doc.txt)",
"Read(//tmp/**)",
"Bash(pdftotext \"技术文档.pdf\" - 2>/dev/null)",
"Bash(grep '\"role\":\"user\"' \"C:\\\\Users\\\\admin\\\\.claude\\\\projects\\\\G--UnityProject-CapabilitySystem-Assets\\\\8203d8cd-1a37-42bd-8ba3-21ec01f49b28.jsonl\" | tail -1 | python -c \"import sys, json; data = json.load\\(sys.stdin\\); print\\(data['message']['content'][0]['text']\\)\")",
"Bash(grep '\"role\":\"user\"' \"C:\\\\Users\\\\admin\\\\.claude\\\\projects\\\\G--UnityProject-CapabilitySystem-Assets\\\\8203d8cd-1a37-42bd-8ba3-21ec01f49b28.jsonl\" | tail -1 | python -c \"import sys, json; data = json.load\\(sys.stdin\\); content = data['message']['content']; print\\(content if isinstance\\(content, str\\) else content[0] if isinstance\\(content, list\\) else content\\)\")",
"Bash(python3 -c \"import PyPDF2; pdf = PyPDF2.PdfReader\\('/g/UnityProject/CapabilitySystem/Assets/技术文档.pdf'\\); print\\(f'页数: {len\\(pdf.pages\\)}'\\); [print\\(f'--- 第{i+1}页 ---\\\\n{pdf.pages[i].extract_text\\(\\)}'\\) for i in range\\(min\\(5, len\\(pdf.pages\\)\\)\\)]\" 2>/dev/null || python3 -c \"import pdfplumber; pdf = pdfplumber.open\\('/g/UnityProject/CapabilitySystem/Assets/技术文档.pdf'\\); print\\(f'页数: {len\\(pdf.pages\\)}'\\); [print\\(f'--- 第{i+1}页 ---\\\\n{pdf.pages[i].extract_text\\(\\)}'\\) for i in range\\(min\\(5, len\\(pdf.pages\\)\\)\\)]\" 2>/dev/null || echo \"需要安装PDF解析库\")",
"Bash(pip install:*)",
"Bash(python3 -c \"\nimport pdfplumber\npdf = pdfplumber.open\\('/g/UnityProject/CapabilitySystem/Assets/技术文档.pdf'\\)\ntotal = len\\(pdf.pages\\)\nprint\\(f'总页数: {total}'\\)\nfor i in range\\(min\\(10, total\\)\\):\n text = pdf.pages[i].extract_text\\(\\)\n if text:\n print\\(f'\\\\n===== 第{i+1}页 ====='\\)\n print\\(text[:2000]\\)\n\" 2>&1)",
"Bash(python --version 2>&1; where python 2>&1; ls /g/UnityProject/CapabilitySystem/Assets/技术文档.pdf)",
"Bash(python -c \"import pdfplumber; print\\('pdfplumber ok'\\)\" 2>&1)",
"Bash(python -c \"\nimport pdfplumber\npdf = pdfplumber.open\\('G:/UnityProject/CapabilitySystem/Assets/技术文档.pdf'\\)\ntotal = len\\(pdf.pages\\)\nprint\\(f'总页数: {total}'\\)\nfor i in range\\(min\\(8, total\\)\\):\n text = pdf.pages[i].extract_text\\(\\)\n if text:\n print\\(f'\\\\n===== 第{i+1}页 ====='\\)\n print\\(text[:3000]\\)\npdf.close\\(\\)\n\" 2>&1)"
]
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bbdaf55c33b53e34b81f7e2588d66cf7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5ea2f924fbe109c44be5ebb61f540d30
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
using System;
namespace CapabilitySystem
{
/// <summary>
/// 标记Capability的Tick执行顺序
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class TickOrderAttribute : Attribute
{
public TickGroup TickGroup { get; }
public int Order { get; }
/// <summary>
/// 定义Capability的执行顺序
/// </summary>
/// <param name="tickGroup">Tick组</param>
/// <param name="order">组内顺序默认0数值越小越先执行</param>
public TickOrderAttribute(TickGroup tickGroup, int order = 0)
{
TickGroup = tickGroup;
Order = order;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08c8672f9dd000447aef58db8940efd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e49e089b37c87894696d6f3b49563abf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,73 @@
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Action Capability基类
/// 配合ActionQueue使用用于队列化的行为
/// </summary>
public abstract class ActionCapability : Capability
{
protected ActionQueue actionQueue;
protected bool isActionComplete;
protected override void Setup()
{
base.Setup();
actionQueue = new ActionQueue();
}
protected override bool ShouldActivate()
{
// 由外部控制激活通过ActionQueue
return false;
}
protected override void OnActivated()
{
base.OnActivated();
isActionComplete = false;
SetupActions();
actionQueue.Start();
}
protected override void TickActive(float deltaTime)
{
base.TickActive(deltaTime);
actionQueue.Update(deltaTime);
// 检查队列是否完成
if (!actionQueue.IsRunning)
{
isActionComplete = true;
}
}
protected override bool ShouldDeactivate()
{
return isActionComplete;
}
protected override void OnDeactivated()
{
actionQueue.Clear();
base.OnDeactivated();
}
/// <summary>
/// 子类实现设置Action队列
/// </summary>
protected abstract void SetupActions();
/// <summary>
/// 手动激活此ActionCapability
/// </summary>
public void Execute()
{
if (!IsActive)
{
Activate();
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2c5f43ff96d913240bd0d7d270a05814

View File

@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Action队列系统
/// 用于管理顺序执行的Action适用于Boss战斗和Puzzle系统
/// </summary>
public class ActionQueue
{
/// <summary>Action定义</summary>
public class ActionDefinition
{
public string Name;
public Action OnStart;
public Action<float> OnUpdate;
public Func<bool> IsComplete;
public Action OnEnd;
public float Duration;
public bool UsesDuration;
public ActionDefinition(string name)
{
Name = name;
Duration = 0f;
UsesDuration = false;
}
}
private Queue<ActionDefinition> actionQueue = new Queue<ActionDefinition>();
private ActionDefinition currentAction;
private float currentActionTime;
private bool isRunning;
#region Properties
public bool IsRunning => isRunning;
public int QueueCount => actionQueue.Count;
public ActionDefinition CurrentAction => currentAction;
#endregion
#region Queue Management
/// <summary>
/// 添加Action到队列
/// </summary>
public void Enqueue(ActionDefinition action)
{
if (action == null)
{
Debug.LogWarning("[ActionQueue] Cannot enqueue null action");
return;
}
actionQueue.Enqueue(action);
}
/// <summary>
/// 添加基于时长的Action
/// </summary>
public void EnqueueDuration(string name, float duration, Action onStart = null, Action<float> onUpdate = null, Action onEnd = null)
{
var action = new ActionDefinition(name)
{
Duration = duration,
UsesDuration = true,
OnStart = onStart,
OnUpdate = onUpdate,
OnEnd = onEnd
};
Enqueue(action);
}
/// <summary>
/// 添加基于条件的Action
/// </summary>
public void EnqueueCondition(string name, Func<bool> isComplete, Action onStart = null, Action<float> onUpdate = null, Action onEnd = null)
{
var action = new ActionDefinition(name)
{
IsComplete = isComplete,
UsesDuration = false,
OnStart = onStart,
OnUpdate = onUpdate,
OnEnd = onEnd
};
Enqueue(action);
}
/// <summary>
/// 清空队列
/// </summary>
public void Clear()
{
actionQueue.Clear();
if (currentAction != null)
{
currentAction.OnEnd?.Invoke();
currentAction = null;
}
currentActionTime = 0f;
isRunning = false;
}
#endregion
#region Execution
/// <summary>
/// 开始执行队列
/// </summary>
public void Start()
{
if (isRunning)
{
Debug.LogWarning("[ActionQueue] Already running");
return;
}
isRunning = true;
StartNextAction();
}
/// <summary>
/// 停止执行
/// </summary>
public void Stop()
{
if (currentAction != null)
{
currentAction.OnEnd?.Invoke();
currentAction = null;
}
isRunning = false;
currentActionTime = 0f;
}
/// <summary>
/// 更新队列(需要在外部每帧调用)
/// </summary>
public void Update(float deltaTime)
{
if (!isRunning || currentAction == null)
return;
currentActionTime += deltaTime;
// 调用更新回调
currentAction.OnUpdate?.Invoke(deltaTime);
// 检查是否完成
bool isComplete = false;
if (currentAction.UsesDuration)
{
isComplete = currentActionTime >= currentAction.Duration;
}
else if (currentAction.IsComplete != null)
{
isComplete = currentAction.IsComplete();
}
if (isComplete)
{
// 当前Action完成
currentAction.OnEnd?.Invoke();
currentAction = null;
currentActionTime = 0f;
// 开始下一个Action
StartNextAction();
}
}
private void StartNextAction()
{
if (actionQueue.Count == 0)
{
// 队列为空,停止
isRunning = false;
return;
}
currentAction = actionQueue.Dequeue();
currentActionTime = 0f;
currentAction.OnStart?.Invoke();
}
#endregion
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 590dcae1712665a49ae5ffced1edce04

View File

@ -0,0 +1,314 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability基类
/// Capability是一个单一的功能单元包含自身所有的状态和决策逻辑
/// </summary>
public abstract class Capability
{
#region Properties
/// <summary>是否激活</summary>
public bool IsActive { get; private set; }
/// <summary>拥有者GameObject</summary>
public GameObject Owner { get; private set; }
/// <summary>Tick组</summary>
public TickGroup TickGroup { get; private set; }
/// <summary>Tick顺序</summary>
public int TickOrder { get; private set; }
/// <summary>标签列表</summary>
public List<CapabilityTag> Tags { get; private set; }
/// <summary>配置数据</summary>
public CapabilityData Data { get; private set; }
/// <summary>关联的CapabilityComponent</summary>
protected CapabilityComponent CapabilityComponent { get; private set; }
/// <summary>黑板系统(快捷访问)</summary>
protected CapabilityBlackboard Blackboard => CapabilityComponent?.Blackboard;
/// <summary>时间记录器(快捷访问)</summary>
protected TemporalLogger TemporalLogger => CapabilityComponent?.TemporalLogger;
/// <summary>激活历史记录(用于调试)</summary>
public List<CapabilityActivationRecord> ActivationHistory { get; private set; }
/// <summary>最大历史记录数量</summary>
private const int MaxHistoryCount = 500; // 增加到500条,支持更长时间的调试
/// <summary>IsBlocked缓存</summary>
private bool cachedIsBlocked;
private int lastBlockCheckFrame = -1;
#endregion
#region Lifecycle
/// <summary>
/// 初始化Capability
/// </summary>
internal void Initialize(GameObject owner, CapabilityComponent component, CapabilityData data = null)
{
Owner = owner;
CapabilityComponent = component;
Data = data;
Tags = new List<CapabilityTag>();
IsActive = false;
ActivationHistory = new List<CapabilityActivationRecord>();
// 读取TickOrder特性
var attribute = GetType().GetCustomAttributes(typeof(TickOrderAttribute), true);
if (attribute.Length > 0)
{
var tickOrderAttr = (TickOrderAttribute)attribute[0];
TickGroup = tickOrderAttr.TickGroup;
TickOrder = tickOrderAttr.Order;
}
else
{
// 默认值
TickGroup = TickGroup.Gameplay;
TickOrder = 0;
}
// 注册到系统
CapabilitySystem.Instance.RegisterCapability(this);
// 调用子类Setup
Setup();
}
/// <summary>
/// 销毁Capability
/// </summary>
internal void Destroy()
{
if (IsActive)
{
Deactivate();
}
CapabilitySystem.Instance.UnregisterCapability(this);
}
/// <summary>
/// 激活Capability
/// </summary>
internal void Activate()
{
if (IsActive) return;
IsActive = true;
// 记录激活时间
var record = new CapabilityActivationRecord
{
ActivateTime = Time.time,
ActivateFrame = Time.frameCount,
Position = Owner.transform.position
};
ActivationHistory.Add(record);
// 限制历史记录数量
if (ActivationHistory.Count > MaxHistoryCount)
{
ActivationHistory.RemoveAt(0);
}
// 记录到TemporalLogger
if (TemporalLogger != null)
{
string key = $"{Owner.name}.{GetType().Name}";
TemporalLogger.Log($"{key}.Active", true);
TemporalLogger.LogPosition(key, Owner.transform.position);
TemporalLogger.LogRotation(key, Owner.transform.rotation);
}
OnActivated();
}
/// <summary>
/// 失活Capability
/// </summary>
internal void Deactivate()
{
if (!IsActive) return;
IsActive = false;
// 记录失活时间
if (ActivationHistory.Count > 0)
{
var lastRecord = ActivationHistory[ActivationHistory.Count - 1];
lastRecord.DeactivateTime = Time.time;
lastRecord.DeactivateFrame = Time.frameCount;
lastRecord.Duration = lastRecord.DeactivateTime - lastRecord.ActivateTime;
}
// 记录到TemporalLogger
if (TemporalLogger != null)
{
string key = $"{Owner.name}.{GetType().Name}";
TemporalLogger.Log($"{key}.Active", false);
}
OnDeactivated();
}
/// <summary>
/// 每帧更新(仅在激活时调用)
/// </summary>
internal void Tick(float deltaTime)
{
TickActive(deltaTime);
}
#endregion
#region Virtual Methods ()
/// <summary>
/// 初始化时调用,用于获取组件引用等
/// </summary>
protected virtual void Setup() { }
/// <summary>
/// 检查是否应该激活(未激活时每帧调用)
/// </summary>
protected virtual bool ShouldActivate() { return false; }
/// <summary>
/// 检查是否应该失活(激活时每帧调用)
/// </summary>
protected virtual bool ShouldDeactivate() { return false; }
/// <summary>
/// 激活时调用
/// </summary>
protected virtual void OnActivated() { }
/// <summary>
/// 失活时调用
/// </summary>
protected virtual void OnDeactivated() { }
/// <summary>
/// 激活状态下每帧调用
/// </summary>
protected virtual void TickActive(float deltaTime) { }
#endregion
#region Tag Blocking
/// <summary>
/// 阻塞带有指定Tag的所有Capability
/// </summary>
protected void BlockCapabilitiesWithTag(CapabilityTag tag, Instigator instigator)
{
CapabilityComponent.BlockTag(tag, instigator);
}
/// <summary>
/// 解除阻塞带有指定Tag的Capability
/// </summary>
protected void UnblockCapabilitiesWithTag(CapabilityTag tag, Instigator instigator)
{
CapabilityComponent.UnblockTag(tag, instigator);
}
/// <summary>
/// 检查是否被阻塞(带缓存优化)
/// </summary>
public bool IsBlocked()
{
// 同一帧内使用缓存结果
if (lastBlockCheckFrame == Time.frameCount)
{
return cachedIsBlocked;
}
cachedIsBlocked = false;
foreach (var tag in Tags)
{
if (CapabilityComponent.IsTagBlocked(tag))
{
cachedIsBlocked = true;
break;
}
}
lastBlockCheckFrame = Time.frameCount;
return cachedIsBlocked;
}
#endregion
#region Dynamic Priority
/// <summary>
/// 运行时设置Tick顺序
/// </summary>
public void SetTickOrder(TickGroup group, int order)
{
if (TickGroup != group || TickOrder != order)
{
TickGroup = group;
TickOrder = order;
CapabilitySystem.Instance.MarkNeedsSort();
}
}
#endregion
#region Helper Methods
/// <summary>
/// 获取组件(泛型方法)
/// </summary>
protected T GetComponent<T>() where T : Component
{
return Owner.GetComponent<T>();
}
/// <summary>
/// 尝试获取组件
/// </summary>
protected bool TryGetComponent<T>(out T component) where T : Component
{
return Owner.TryGetComponent(out component);
}
#endregion
#region Internal Update Methods
/// <summary>
/// 内部更新方法由CapabilitySystem调用
/// </summary>
internal bool InternalShouldActivate()
{
if (IsBlocked()) return false;
return ShouldActivate();
}
/// <summary>
/// 内部失活检查由CapabilitySystem调用
/// </summary>
internal bool InternalShouldDeactivate()
{
return ShouldDeactivate();
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dbadc84377efab488b761cd541fc9b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
namespace CapabilitySystem
{
/// <summary>
/// Capability激活记录
/// 用于调试和时间轴显示
/// </summary>
public class CapabilityActivationRecord
{
/// <summary>激活时间</summary>
public float ActivateTime { get; set; }
/// <summary>失活时间</summary>
public float DeactivateTime { get; set; }
/// <summary>激活帧</summary>
public int ActivateFrame { get; set; }
/// <summary>失活帧</summary>
public int DeactivateFrame { get; set; }
/// <summary>持续时间</summary>
public float Duration { get; set; }
/// <summary>是否仍在激活中</summary>
public bool IsStillActive => DeactivateTime == 0;
/// <summary>阻塞原因(如果有)</summary>
public string BlockReason { get; set; }
/// <summary>激活时的位置(可选)</summary>
public UnityEngine.Vector3? Position { get; set; }
/// <summary>自定义数据(用于扩展)</summary>
public System.Collections.Generic.Dictionary<string, object> CustomData { get; set; }
public CapabilityActivationRecord()
{
CustomData = new System.Collections.Generic.Dictionary<string, object>();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 504183dddb5845f4fb0aa0beedf7302a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability黑板系统
/// 用于Capability之间共享数据和通信
/// </summary>
public class CapabilityBlackboard
{
private Dictionary<string, object> data = new Dictionary<string, object>();
private Dictionary<string, List<Action<object>>> listeners = new Dictionary<string, List<Action<object>>>();
#region Data Access
/// <summary>
/// 设置数据
/// </summary>
public void Set<T>(string key, T value)
{
if (string.IsNullOrEmpty(key))
{
Debug.LogWarning("[CapabilityBlackboard] Key cannot be null or empty");
return;
}
data[key] = value;
// 通知监听者
if (listeners.ContainsKey(key))
{
foreach (var listener in listeners[key])
{
listener?.Invoke(value);
}
}
}
/// <summary>
/// 获取数据
/// </summary>
public T Get<T>(string key, T defaultValue = default)
{
if (string.IsNullOrEmpty(key))
{
Debug.LogWarning("[CapabilityBlackboard] Key cannot be null or empty");
return defaultValue;
}
if (data.TryGetValue(key, out object value))
{
if (value is T typedValue)
{
return typedValue;
}
else
{
Debug.LogWarning($"[CapabilityBlackboard] Type mismatch for key '{key}'. Expected {typeof(T)}, got {value.GetType()}");
return defaultValue;
}
}
return defaultValue;
}
/// <summary>
/// 尝试获取数据
/// </summary>
public bool TryGet<T>(string key, out T value)
{
value = default;
if (string.IsNullOrEmpty(key))
return false;
if (data.TryGetValue(key, out object objValue) && objValue is T typedValue)
{
value = typedValue;
return true;
}
return false;
}
/// <summary>
/// 检查是否包含指定键
/// </summary>
public bool Contains(string key)
{
return !string.IsNullOrEmpty(key) && data.ContainsKey(key);
}
/// <summary>
/// 移除数据
/// </summary>
public bool Remove(string key)
{
if (string.IsNullOrEmpty(key))
return false;
return data.Remove(key);
}
/// <summary>
/// 清空所有数据
/// </summary>
public void Clear()
{
data.Clear();
}
#endregion
#region Event System
/// <summary>
/// 监听数据变化
/// </summary>
public void AddListener(string key, Action<object> callback)
{
if (string.IsNullOrEmpty(key) || callback == null)
return;
if (!listeners.ContainsKey(key))
{
listeners[key] = new List<Action<object>>();
}
if (!listeners[key].Contains(callback))
{
listeners[key].Add(callback);
}
}
/// <summary>
/// 移除监听
/// </summary>
public void RemoveListener(string key, Action<object> callback)
{
if (string.IsNullOrEmpty(key) || callback == null)
return;
if (listeners.ContainsKey(key))
{
listeners[key].Remove(callback);
if (listeners[key].Count == 0)
{
listeners.Remove(key);
}
}
}
/// <summary>
/// 移除指定键的所有监听
/// </summary>
public void RemoveAllListeners(string key)
{
if (!string.IsNullOrEmpty(key))
{
listeners.Remove(key);
}
}
#endregion
#region Debug
/// <summary>
/// 获取所有键
/// </summary>
public IEnumerable<string> GetAllKeys()
{
return data.Keys;
}
/// <summary>
/// 获取数据数量
/// </summary>
public int Count => data.Count;
#endregion
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: baf276d6a762e61489825601a75f1562

View File

@ -0,0 +1,343 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability组件挂载到GameObject上管理Capability
/// </summary>
public class CapabilityComponent : MonoBehaviour
{
[SerializeField]
[Tooltip("默认应用的Sheet列表")]
private List<CapabilitySheet> defaultSheets = new List<CapabilitySheet>();
// 所有Capability实例
private List<Capability> capabilities = new List<Capability>();
// Capability引用计数Type -> (Capability, RefCount)
private Dictionary<Type, (Capability capability, int refCount)> capabilityRegistry = new Dictionary<Type, (Capability, int)>();
// 标签阻塞器Tag -> Instigator列表
private Dictionary<CapabilityTag, List<Instigator>> tagBlockers = new Dictionary<CapabilityTag, List<Instigator>>();
// 已应用的Sheet用于运行时管理
private HashSet<CapabilitySheet> appliedSheets = new HashSet<CapabilitySheet>();
// 黑板系统用于Capability间通信
private CapabilityBlackboard blackboard = new CapabilityBlackboard();
// 时间记录器(用于调试和回放)
private TemporalLogger temporalLogger;
#region Unity Lifecycle
private void Awake()
{
// 初始化 TemporalLogger不能在字段初始化器中创建因为会调用 Time.time
temporalLogger = new TemporalLogger();
// 应用默认Sheet
foreach (var sheet in defaultSheets)
{
if (sheet != null)
{
AddSheet(sheet);
}
}
}
private void OnDestroy()
{
// 销毁所有Capability
foreach (var capability in capabilities.ToList())
{
capability.Destroy();
}
capabilities.Clear();
}
#endregion
#region Sheet Management
/// <summary>
/// 添加Sheet
/// </summary>
public void AddSheet(CapabilitySheet sheet)
{
if (sheet == null || appliedSheets.Contains(sheet))
return;
appliedSheets.Add(sheet);
sheet.ApplyToGameObject(gameObject, this);
}
/// <summary>
/// 移除Sheet
/// </summary>
public void RemoveSheet(CapabilitySheet sheet)
{
if (sheet == null || !appliedSheets.Contains(sheet))
return;
appliedSheets.Remove(sheet);
// 移除Sheet创建的Capability通过引用计数
sheet.RemoveFromGameObject(this);
}
#endregion
#region Capability Management
/// <summary>
/// 添加Capability实例内部使用支持引用计数
/// </summary>
internal void AddCapability(Capability capability, bool incrementRefCount = true)
{
if (capability == null)
return;
Type capabilityType = capability.GetType();
// 检查是否已存在
if (capabilityRegistry.ContainsKey(capabilityType))
{
if (incrementRefCount)
{
// 增加引用计数
var entry = capabilityRegistry[capabilityType];
capabilityRegistry[capabilityType] = (entry.capability, entry.refCount + 1);
}
return;
}
// 添加新Capability
capabilities.Add(capability);
capabilityRegistry[capabilityType] = (capability, 1);
}
/// <summary>
/// 移除Capability实例内部使用支持引用计数
/// </summary>
internal void RemoveCapability(Capability capability, bool decrementRefCount = true)
{
if (capability == null)
return;
Type capabilityType = capability.GetType();
if (!capabilityRegistry.ContainsKey(capabilityType))
return;
if (decrementRefCount)
{
var entry = capabilityRegistry[capabilityType];
int newRefCount = entry.refCount - 1;
if (newRefCount > 0)
{
// 还有其他引用,只减少计数
capabilityRegistry[capabilityType] = (entry.capability, newRefCount);
return;
}
}
// 引用计数为0真正移除
capabilities.Remove(capability);
capabilityRegistry.Remove(capabilityType);
capability.Destroy();
}
/// <summary>
/// 运行时添加Capability泛型方法
/// </summary>
public T AddCapability<T>() where T : Capability, new()
{
return AddCapability<T>(null);
}
/// <summary>
/// 运行时添加Capability泛型方法带配置数据
/// </summary>
public T AddCapability<T>(CapabilityData data) where T : Capability, new()
{
Type capabilityType = typeof(T);
// 检查是否已存在
if (capabilityRegistry.ContainsKey(capabilityType))
{
Debug.LogWarning($"[CapabilityComponent] Capability of type {capabilityType.Name} already exists on {gameObject.name}");
return capabilityRegistry[capabilityType].capability as T;
}
// 创建新实例
T capability = new T();
capability.Initialize(gameObject, this, data);
AddCapability(capability, false);
return capability;
}
/// <summary>
/// 运行时移除Capability泛型方法
/// </summary>
public void RemoveCapability<T>() where T : Capability
{
Type capabilityType = typeof(T);
if (capabilityRegistry.TryGetValue(capabilityType, out var entry))
{
RemoveCapability(entry.capability, false);
}
}
/// <summary>
/// 获取Capability泛型方法
/// </summary>
public T GetCapability<T>() where T : Capability
{
Type capabilityType = typeof(T);
if (capabilityRegistry.TryGetValue(capabilityType, out var entry))
{
return entry.capability as T;
}
return null;
}
/// <summary>
/// 检查是否有指定类型的Capability
/// </summary>
public bool HasCapability<T>() where T : Capability
{
return capabilityRegistry.ContainsKey(typeof(T));
}
/// <summary>
/// 检查是否有指定类型的Capability非泛型版本
/// </summary>
public bool HasCapabilityOfType(Type capabilityType)
{
return capabilityRegistry.ContainsKey(capabilityType);
}
/// <summary>
/// 获取所有Capability
/// </summary>
public IReadOnlyList<Capability> GetAllCapabilities()
{
return capabilities.AsReadOnly();
}
/// <summary>
/// 获取黑板系统
/// </summary>
public CapabilityBlackboard Blackboard => blackboard;
/// <summary>
/// 获取时间记录器
/// </summary>
public TemporalLogger TemporalLogger => temporalLogger;
/// <summary>
/// 获取所有Capability的激活历史记录用于调试器
/// </summary>
public List<(Capability capability, CapabilityActivationRecord record)> GetActivationHistory()
{
var allRecords = new List<(Capability capability, CapabilityActivationRecord record)>();
foreach (var capability in capabilities)
{
foreach (var record in capability.ActivationHistory)
{
allRecords.Add((capability: capability, record: record));
}
}
// 按激活时间排序
allRecords.Sort((a, b) => a.record.ActivateTime.CompareTo(b.record.ActivateTime));
return allRecords;
}
#endregion
#region Tag Blocking
/// <summary>
/// 阻塞指定Tag
/// </summary>
public void BlockTag(CapabilityTag tag, Instigator instigator)
{
if (tag == null || instigator == null)
return;
if (!tagBlockers.ContainsKey(tag))
{
tagBlockers[tag] = new List<Instigator>();
}
if (!tagBlockers[tag].Contains(instigator))
{
tagBlockers[tag].Add(instigator);
}
}
/// <summary>
/// 解除阻塞指定Tag
/// </summary>
public void UnblockTag(CapabilityTag tag, Instigator instigator)
{
if (tag == null || instigator == null)
return;
if (tagBlockers.ContainsKey(tag))
{
tagBlockers[tag].Remove(instigator);
// 如果没有阻塞者了,移除字典项
if (tagBlockers[tag].Count == 0)
{
tagBlockers.Remove(tag);
}
}
}
/// <summary>
/// 检查Tag是否被阻塞
/// </summary>
public bool IsTagBlocked(CapabilityTag tag)
{
if (tag == null)
return false;
return tagBlockers.ContainsKey(tag) && tagBlockers[tag].Count > 0;
}
/// <summary>
/// 获取阻塞指定Tag的所有Instigator
/// </summary>
public IReadOnlyList<Instigator> GetTagBlockers(CapabilityTag tag)
{
if (tag == null || !tagBlockers.ContainsKey(tag))
return new List<Instigator>().AsReadOnly();
return tagBlockers[tag].AsReadOnly();
}
/// <summary>
/// 获取所有被阻塞的Tag
/// </summary>
public IEnumerable<CapabilityTag> GetBlockedTags()
{
return tagBlockers.Keys;
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d38e65e95dde13e42af0ad02fe3af814
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability配置数据基类
/// 用于存储Capability的参数配置实现数据与逻辑分离
/// </summary>
public abstract class CapabilityData : ScriptableObject
{
[Header("Basic Settings")]
[SerializeField]
[Tooltip("Capability的显示名称")]
private string displayName;
[SerializeField]
[Tooltip("Capability的描述")]
[TextArea(3, 5)]
private string description;
public string DisplayName => displayName;
public string Description => description;
/// <summary>
/// 验证配置数据的有效性
/// </summary>
public virtual bool Validate()
{
return true;
}
private void OnValidate()
{
if (string.IsNullOrEmpty(displayName))
{
displayName = name;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2d12e212f8a01fd4f992c5f66087a888

View File

@ -0,0 +1,275 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability Sheet资源
/// 用于组织和管理一组相关的Capability和Component
/// </summary>
[CreateAssetMenu(fileName = "NewCapabilitySheet", menuName = "Capability/Sheet")]
public class CapabilitySheet : ScriptableObject
{
[Header("Capabilities")]
[SerializeField]
[Tooltip("Capability类的完整名称列表包含命名空间")]
private List<string> capabilityClassNames = new List<string>();
[SerializeField]
[Tooltip("Capability配置数据列表与capabilityClassNames对应")]
private List<CapabilityData> capabilityDatas = new List<CapabilityData>();
[Header("Components")]
[SerializeField]
[Tooltip("需要添加的Component类型列表")]
private List<string> componentTypeNames = new List<string>();
[Header("Sub Sheets")]
[SerializeField]
[Tooltip("子Sheet列表")]
private List<CapabilitySheet> subSheets = new List<CapabilitySheet>();
// 记录Sheet创建的Capability类型用于移除时的引用计数
private List<Type> createdCapabilityTypes = new List<Type>();
#region Public Properties
public IReadOnlyList<string> CapabilityClassNames => capabilityClassNames.AsReadOnly();
public IReadOnlyList<CapabilityData> CapabilityDatas => capabilityDatas.AsReadOnly();
public IReadOnlyList<string> ComponentTypeNames => componentTypeNames.AsReadOnly();
public IReadOnlyList<CapabilitySheet> SubSheets => subSheets.AsReadOnly();
#endregion
#region Apply to GameObject
/// <summary>
/// 应用Sheet到GameObject
/// </summary>
public void ApplyToGameObject(GameObject target, CapabilityComponent capabilityComponent)
{
if (target == null || capabilityComponent == null)
{
Debug.LogError($"[CapabilitySheet] Cannot apply sheet '{name}': target or component is null");
return;
}
// 1. 递归应用子Sheet
foreach (var subSheet in subSheets)
{
if (subSheet != null)
{
subSheet.ApplyToGameObject(target, capabilityComponent);
}
}
// 2. 添加Component
foreach (var componentTypeName in componentTypeNames)
{
if (string.IsNullOrEmpty(componentTypeName))
continue;
try
{
Type componentType = Type.GetType(componentTypeName);
if (componentType == null)
{
Debug.LogWarning($"[CapabilitySheet] Component type not found: {componentTypeName}");
continue;
}
if (!typeof(Component).IsAssignableFrom(componentType))
{
Debug.LogWarning($"[CapabilitySheet] Type is not a Component: {componentTypeName}");
continue;
}
// 检查是否已存在
if (target.GetComponent(componentType) == null)
{
target.AddComponent(componentType);
}
}
catch (Exception e)
{
Debug.LogError($"[CapabilitySheet] Failed to add component '{componentTypeName}': {e.Message}");
}
}
// 3. 创建Capability实例
createdCapabilityTypes.Clear();
for (int i = 0; i < capabilityClassNames.Count; i++)
{
string capabilityClassName = capabilityClassNames[i];
if (string.IsNullOrEmpty(capabilityClassName))
continue;
try
{
Type capabilityType = Type.GetType(capabilityClassName);
if (capabilityType == null)
{
Debug.LogWarning($"[CapabilitySheet] Capability type not found: {capabilityClassName}");
continue;
}
if (!typeof(Capability).IsAssignableFrom(capabilityType))
{
Debug.LogWarning($"[CapabilitySheet] Type is not a Capability: {capabilityClassName}");
continue;
}
// 检查是否已存在(去重)
if (capabilityComponent.HasCapabilityOfType(capabilityType))
{
// 已存在,增加引用计数
var existingCapability = capabilityComponent.GetAllCapabilities()
.FirstOrDefault(c => c.GetType() == capabilityType);
if (existingCapability != null)
{
capabilityComponent.AddCapability(existingCapability, true);
createdCapabilityTypes.Add(capabilityType);
}
continue;
}
// 获取对应的配置数据
CapabilityData data = null;
if (i < capabilityDatas.Count)
{
data = capabilityDatas[i];
}
// 创建实例
Capability capability = (Capability)Activator.CreateInstance(capabilityType);
// 初始化
capability.Initialize(target, capabilityComponent, data);
// 添加到Component
capabilityComponent.AddCapability(capability, true);
createdCapabilityTypes.Add(capabilityType);
}
catch (Exception e)
{
Debug.LogError($"[CapabilitySheet] Failed to create capability '{capabilityClassName}': {e.Message}");
}
}
}
#endregion
#region Remove from GameObject
/// <summary>
/// 从GameObject移除Sheet创建的Capability通过引用计数
/// </summary>
internal void RemoveFromGameObject(CapabilityComponent capabilityComponent)
{
if (capabilityComponent == null)
return;
// 递归移除子Sheet
foreach (var subSheet in subSheets)
{
if (subSheet != null)
{
subSheet.RemoveFromGameObject(capabilityComponent);
}
}
// 移除此Sheet创建的Capability
foreach (var capabilityType in createdCapabilityTypes)
{
var capability = capabilityComponent.GetAllCapabilities()
.FirstOrDefault(c => c.GetType() == capabilityType);
if (capability != null)
{
capabilityComponent.RemoveCapability(capability, true);
}
}
createdCapabilityTypes.Clear();
}
#endregion
#region Editor Helper Methods
#if UNITY_EDITOR
/// <summary>
/// 添加Capability类名
/// </summary>
public void AddCapabilityClassName(string className)
{
if (!string.IsNullOrEmpty(className) && !capabilityClassNames.Contains(className))
{
capabilityClassNames.Add(className);
UnityEditor.EditorUtility.SetDirty(this);
}
}
/// <summary>
/// 移除Capability类名
/// </summary>
public void RemoveCapabilityClassName(string className)
{
if (capabilityClassNames.Remove(className))
{
UnityEditor.EditorUtility.SetDirty(this);
}
}
/// <summary>
/// 添加Component类型名
/// </summary>
public void AddComponentTypeName(string typeName)
{
if (!string.IsNullOrEmpty(typeName) && !componentTypeNames.Contains(typeName))
{
componentTypeNames.Add(typeName);
UnityEditor.EditorUtility.SetDirty(this);
}
}
/// <summary>
/// 移除Component类型名
/// </summary>
public void RemoveComponentTypeName(string typeName)
{
if (componentTypeNames.Remove(typeName))
{
UnityEditor.EditorUtility.SetDirty(this);
}
}
/// <summary>
/// 添加子Sheet
/// </summary>
public void AddSubSheet(CapabilitySheet sheet)
{
if (sheet != null && !subSheets.Contains(sheet) && sheet != this)
{
subSheets.Add(sheet);
UnityEditor.EditorUtility.SetDirty(this);
}
}
/// <summary>
/// 移除子Sheet
/// </summary>
public void RemoveSubSheet(CapabilitySheet sheet)
{
if (subSheets.Remove(sheet))
{
UnityEditor.EditorUtility.SetDirty(this);
}
}
#endif
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffab8a3c2ebe1c442b4912eefbab7a54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,202 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability全局管理系统单例
/// 负责所有Capability的注册、注销和更新
/// </summary>
public class CapabilitySystem : MonoBehaviour
{
private static CapabilitySystem instance;
public static CapabilitySystem Instance
{
get
{
if (instance == null)
{
// 查找场景中的实例
instance = FindObjectOfType<CapabilitySystem>();
// 如果没有,自动创建
if (instance == null)
{
var go = new GameObject("[CapabilitySystem]");
instance = go.AddComponent<CapabilitySystem>();
DontDestroyOnLoad(go);
}
}
return instance;
}
}
// 所有Capability实例按TickOrder排序
private List<Capability> allCapabilities = new List<Capability>();
// 按TickGroup分组的Capability性能优化
private Dictionary<TickGroup, List<Capability>> capabilitiesByGroup = new Dictionary<TickGroup, List<Capability>>();
// 是否需要重新排序
private bool needsSort = false;
#region Unity Lifecycle
private void Awake()
{
if (instance != null && instance != this)
{
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(gameObject);
}
private void Update()
{
// 如果需要排序,先排序
if (needsSort)
{
SortCapabilities();
needsSort = false;
}
float deltaTime = Time.deltaTime;
// 遍历所有Capability
for (int i = 0; i < allCapabilities.Count; i++)
{
var capability = allCapabilities[i];
if (!capability.IsActive)
{
// 未激活:检查是否应该激活
if (capability.InternalShouldActivate())
{
capability.Activate();
}
}
else
{
// 已激活:先检查是否应该失活
if (capability.InternalShouldDeactivate())
{
capability.Deactivate();
}
else
{
// 执行Tick
capability.Tick(deltaTime);
}
}
}
}
#endregion
#region Capability Registration
/// <summary>
/// 注册Capability
/// </summary>
public void RegisterCapability(Capability capability)
{
if (capability == null || allCapabilities.Contains(capability))
return;
allCapabilities.Add(capability);
needsSort = true;
}
/// <summary>
/// 注销Capability
/// </summary>
public void UnregisterCapability(Capability capability)
{
if (capability == null)
return;
allCapabilities.Remove(capability);
}
/// <summary>
/// 按TickOrder排序Capability
/// </summary>
private void SortCapabilities()
{
allCapabilities = allCapabilities
.OrderBy(c => (int)c.TickGroup)
.ThenBy(c => c.TickOrder)
.ToList();
// 重建分组字典
capabilitiesByGroup.Clear();
foreach (var capability in allCapabilities)
{
if (!capabilitiesByGroup.ContainsKey(capability.TickGroup))
{
capabilitiesByGroup[capability.TickGroup] = new List<Capability>();
}
capabilitiesByGroup[capability.TickGroup].Add(capability);
}
}
/// <summary>
/// 标记需要重新排序公开给Capability使用
/// </summary>
public void MarkNeedsSort()
{
needsSort = true;
}
#endregion
#region Query Methods
/// <summary>
/// 获取所有Capability只读
/// </summary>
public IReadOnlyList<Capability> GetAllCapabilities()
{
return allCapabilities.AsReadOnly();
}
/// <summary>
/// 获取指定GameObject的所有Capability
/// </summary>
public List<Capability> GetCapabilitiesForGameObject(GameObject gameObject)
{
return allCapabilities.Where(c => c.Owner == gameObject).ToList();
}
/// <summary>
/// 获取所有激活的Capability
/// </summary>
public List<Capability> GetActiveCapabilities()
{
return allCapabilities.Where(c => c.IsActive).ToList();
}
#endregion
#region Debug Info
/// <summary>
/// 获取统计信息
/// </summary>
public (int total, int active, int blocked) GetStatistics()
{
int total = allCapabilities.Count;
int active = allCapabilities.Count(c => c.IsActive);
int blocked = allCapabilities.Count(c => c.IsBlocked());
return (total, active, blocked);
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 84c9abe5e6bf1244d8842b430e369f78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// Capability标签用于标识和阻塞Capability
/// </summary>
[CreateAssetMenu(fileName = "NewCapabilityTag", menuName = "Capability/Tag")]
public class CapabilityTag : ScriptableObject
{
[SerializeField]
private string tagName;
public string TagName => tagName;
private void OnValidate()
{
if (string.IsNullOrEmpty(tagName))
{
tagName = name;
}
}
public override string ToString()
{
return tagName;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec7408feedfe9234b9e54ea5fedfd004
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,177 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// 复合Capability基类
/// 用于管理多个子Capability适用于AI系统和复杂行为
/// </summary>
public abstract class CompoundCapability : Capability
{
/// <summary>子Capability列表</summary>
protected List<Capability> childCapabilities = new List<Capability>();
/// <summary>当前激活的子Capability</summary>
protected Capability activeChild;
#region Child Management
/// <summary>
/// 添加子Capability
/// </summary>
protected void AddChild(Capability child)
{
if (child == null || childCapabilities.Contains(child))
return;
childCapabilities.Add(child);
}
/// <summary>
/// 移除子Capability
/// </summary>
protected void RemoveChild(Capability child)
{
if (child == null)
return;
if (activeChild == child)
{
DeactivateChild(child);
}
childCapabilities.Remove(child);
}
/// <summary>
/// 激活子Capability
/// </summary>
protected void ActivateChild(Capability child)
{
if (child == null || !childCapabilities.Contains(child))
{
Debug.LogWarning($"[CompoundCapability] Cannot activate child: not in child list");
return;
}
// 如果有其他子Capability激活先停用
if (activeChild != null && activeChild != child)
{
DeactivateChild(activeChild);
}
if (!child.IsActive)
{
child.Activate();
activeChild = child;
OnChildActivated(child);
}
}
/// <summary>
/// 停用子Capability
/// </summary>
protected void DeactivateChild(Capability child)
{
if (child == null)
return;
if (child.IsActive)
{
child.Deactivate();
if (activeChild == child)
{
activeChild = null;
}
OnChildDeactivated(child);
}
}
/// <summary>
/// 停用所有子Capability
/// </summary>
protected void DeactivateAllChildren()
{
foreach (var child in childCapabilities.ToList())
{
if (child.IsActive)
{
DeactivateChild(child);
}
}
}
/// <summary>
/// 获取所有子Capability
/// </summary>
public IReadOnlyList<Capability> GetChildren()
{
return childCapabilities.AsReadOnly();
}
#endregion
#region Lifecycle Overrides
protected override void OnActivated()
{
base.OnActivated();
OnCompoundActivated();
}
protected override void OnDeactivated()
{
// 停用所有子Capability
DeactivateAllChildren();
OnCompoundDeactivated();
base.OnDeactivated();
}
protected override void TickActive(float deltaTime)
{
base.TickActive(deltaTime);
// 更新激活的子Capability
if (activeChild != null && activeChild.IsActive)
{
activeChild.Tick(deltaTime);
}
TickCompound(deltaTime);
}
#endregion
#region Virtual Methods for Subclasses
/// <summary>
/// 复合Capability激活时调用
/// </summary>
protected virtual void OnCompoundActivated() { }
/// <summary>
/// 复合Capability停用时调用
/// </summary>
protected virtual void OnCompoundDeactivated() { }
/// <summary>
/// 复合Capability每帧更新
/// </summary>
protected virtual void TickCompound(float deltaTime) { }
/// <summary>
/// 子Capability激活时调用
/// </summary>
protected virtual void OnChildActivated(Capability child) { }
/// <summary>
/// 子Capability停用时调用
/// </summary>
protected virtual void OnChildDeactivated(Capability child) { }
#endregion
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ad7a50e648a6a2f4081d5496a96d1704

View File

@ -0,0 +1,70 @@
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// 发起者用于追踪谁发起了某个操作如阻塞Tag
/// </summary>
public class Instigator
{
public enum InstigatorType
{
GameObject,
Capability,
String
}
public InstigatorType Type { get; private set; }
public object Source { get; private set; }
private Instigator(InstigatorType type, object source)
{
Type = type;
Source = source;
}
public static Instigator FromGameObject(GameObject obj)
{
return new Instigator(InstigatorType.GameObject, obj);
}
public static Instigator FromCapability(Capability capability)
{
return new Instigator(InstigatorType.Capability, capability);
}
public static Instigator FromString(string name)
{
return new Instigator(InstigatorType.String, name);
}
public override string ToString()
{
switch (Type)
{
case InstigatorType.GameObject:
return $"GameObject: {(Source as GameObject)?.name ?? "null"}";
case InstigatorType.Capability:
return $"Capability: {Source?.GetType().Name ?? "null"}";
case InstigatorType.String:
return $"String: {Source as string ?? "null"}";
default:
return "Unknown";
}
}
public override bool Equals(object obj)
{
if (obj is Instigator other)
{
return Type == other.Type && Equals(Source, other.Source);
}
return false;
}
public override int GetHashCode()
{
return (Type, Source).GetHashCode();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 522dd182cb6f1f644a756270b7ac0111
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,280 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace CapabilitySystem
{
/// <summary>
/// 时间数据记录器
/// 用于记录任意类型的数据到时间轴,支持回放
/// </summary>
public class TemporalLogger
{
/// <summary>
/// 数据记录项
/// </summary>
[Serializable]
public class DataRecord
{
public float Time;
public int Frame;
public string Key;
public object Value;
public Type ValueType;
public DataRecord(string key, object value)
{
Time = UnityEngine.Time.time;
Frame = UnityEngine.Time.frameCount;
Key = key;
Value = value;
ValueType = value?.GetType();
}
}
/// <summary>
/// 数据通道每个Key一个通道
/// </summary>
public class DataChannel
{
public string Key;
public Type DataType;
public List<DataRecord> Records = new List<DataRecord>();
public int MaxRecords = 1000;
public void AddRecord(DataRecord record)
{
Records.Add(record);
// 限制记录数量
if (Records.Count > MaxRecords)
{
Records.RemoveAt(0);
}
}
/// <summary>
/// 获取指定时间的数据(插值)
/// </summary>
public object GetValueAtTime(float time)
{
if (Records.Count == 0)
return null;
// 找到时间前后的记录
DataRecord before = null;
DataRecord after = null;
for (int i = 0; i < Records.Count; i++)
{
if (Records[i].Time <= time)
{
before = Records[i];
}
else
{
after = Records[i];
break;
}
}
// 如果只有一个记录或时间在范围外
if (before == null)
return after?.Value;
if (after == null)
return before.Value;
// 尝试插值(仅支持特定类型)
return InterpolateValue(before, after, time);
}
private object InterpolateValue(DataRecord before, DataRecord after, float time)
{
float t = Mathf.InverseLerp(before.Time, after.Time, time);
// 根据类型进行插值
if (DataType == typeof(Vector3))
{
return Vector3.Lerp((Vector3)before.Value, (Vector3)after.Value, t);
}
else if (DataType == typeof(Quaternion))
{
return Quaternion.Slerp((Quaternion)before.Value, (Quaternion)after.Value, t);
}
else if (DataType == typeof(float))
{
return Mathf.Lerp((float)before.Value, (float)after.Value, t);
}
else if (DataType == typeof(Color))
{
return Color.Lerp((Color)before.Value, (Color)after.Value, t);
}
// 不支持插值的类型,返回最近的值
return t < 0.5f ? before.Value : after.Value;
}
}
private Dictionary<string, DataChannel> channels = new Dictionary<string, DataChannel>();
private float startTime;
private bool isRecording = true;
private bool isInitialized = false;
public IReadOnlyDictionary<string, DataChannel> Channels => channels;
public float StartTime => startTime;
public bool IsRecording => isRecording;
public TemporalLogger()
{
// 不在构造函数中调用 Time.time延迟到第一次使用时初始化
}
/// <summary>
/// 确保已初始化
/// </summary>
private void EnsureInitialized()
{
if (!isInitialized)
{
startTime = Time.time;
isInitialized = true;
}
}
#region Recording
/// <summary>
/// 记录数据
/// </summary>
public void Log(string key, object value)
{
if (!isRecording || value == null)
return;
EnsureInitialized();
if (!channels.ContainsKey(key))
{
channels[key] = new DataChannel
{
Key = key,
DataType = value.GetType()
};
}
var record = new DataRecord(key, value);
channels[key].AddRecord(record);
}
/// <summary>
/// 记录位置
/// </summary>
public void LogPosition(string key, Vector3 position)
{
Log($"{key}.Position", position);
}
/// <summary>
/// 记录旋转
/// </summary>
public void LogRotation(string key, Quaternion rotation)
{
Log($"{key}.Rotation", rotation);
}
/// <summary>
/// 记录Transform
/// </summary>
public void LogTransform(string key, Transform transform)
{
LogPosition(key, transform.position);
LogRotation(key, transform.rotation);
}
/// <summary>
/// 记录动画状态
/// </summary>
public void LogAnimation(string key, Animator animator, string stateName)
{
if (animator == null)
return;
var stateInfo = animator.GetCurrentAnimatorStateInfo(0);
Log($"{key}.AnimState", stateName);
Log($"{key}.AnimTime", stateInfo.normalizedTime);
}
/// <summary>
/// 暂停记录
/// </summary>
public void PauseRecording()
{
isRecording = false;
}
/// <summary>
/// 恢复记录
/// </summary>
public void ResumeRecording()
{
isRecording = true;
}
/// <summary>
/// 清空所有记录
/// </summary>
public void Clear()
{
channels.Clear();
startTime = Time.time;
isInitialized = true;
}
#endregion
#region Playback
/// <summary>
/// 获取指定时间的数据
/// </summary>
public object GetValueAtTime(string key, float time)
{
if (!channels.ContainsKey(key))
return null;
return channels[key].GetValueAtTime(time);
}
/// <summary>
/// 获取时间范围
/// </summary>
public (float min, float max) GetTimeRange()
{
EnsureInitialized();
float min = float.MaxValue;
float max = float.MinValue;
foreach (var channel in channels.Values)
{
if (channel.Records.Count > 0)
{
min = Mathf.Min(min, channel.Records[0].Time);
max = Mathf.Max(max, channel.Records[channel.Records.Count - 1].Time);
}
}
return min == float.MaxValue ? (0, 0) : (min, max);
}
/// <summary>
/// 获取所有数据通道的Key
/// </summary>
public List<string> GetAllKeys()
{
return new List<string>(channels.Keys);
}
#endregion
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: de209aa30b789fa44bfd9c23e7de4fe0

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 474d0f25701409945a5dd85127ce7be4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,223 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace CapabilitySystem.Editor
{
/// <summary>
/// CapabilitySheet自定义编辑器
/// </summary>
[CustomEditor(typeof(CapabilitySheet))]
public class CapabilitySheetEditor : UnityEditor.Editor
{
private CapabilitySheet sheet;
private List<Type> availableCapabilityTypes;
private List<Type> availableComponentTypes;
private int selectedCapabilityIndex = 0;
private int selectedComponentIndex = 0;
private void OnEnable()
{
sheet = (CapabilitySheet)target;
RefreshAvailableTypes();
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Capability Sheet", EditorStyles.boldLabel);
EditorGUILayout.Space();
// Capabilities部分
DrawCapabilitiesSection();
EditorGUILayout.Space();
// Components部分
DrawComponentsSection();
EditorGUILayout.Space();
// Sub Sheets部分
DrawSubSheetsSection();
serializedObject.ApplyModifiedProperties();
if (GUI.changed)
{
EditorUtility.SetDirty(sheet);
}
}
private void DrawCapabilitiesSection()
{
EditorGUILayout.LabelField("Capabilities", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// 显示现有Capability
var capabilityNames = sheet.CapabilityClassNames.ToList();
for (int i = 0; i < capabilityNames.Count; i++)
{
EditorGUILayout.BeginHorizontal();
string className = capabilityNames[i];
string displayName = GetShortTypeName(className);
EditorGUILayout.LabelField($"{i + 1}. {displayName}");
if (GUILayout.Button("X", GUILayout.Width(25)))
{
sheet.RemoveCapabilityClassName(className);
break;
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space();
// 添加新Capability
EditorGUILayout.BeginHorizontal();
selectedCapabilityIndex = EditorGUILayout.Popup("添加Capability", selectedCapabilityIndex,
availableCapabilityTypes.Select(t => t.Name).ToArray());
if (GUILayout.Button("添加", GUILayout.Width(50)))
{
if (selectedCapabilityIndex >= 0 && selectedCapabilityIndex < availableCapabilityTypes.Count)
{
var selectedType = availableCapabilityTypes[selectedCapabilityIndex];
sheet.AddCapabilityClassName(selectedType.AssemblyQualifiedName);
}
}
EditorGUILayout.EndHorizontal();
if (GUILayout.Button("刷新类型列表"))
{
RefreshAvailableTypes();
}
EditorGUILayout.EndVertical();
}
private void DrawComponentsSection()
{
EditorGUILayout.LabelField("Components", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// 显示现有Component
var componentNames = sheet.ComponentTypeNames.ToList();
for (int i = 0; i < componentNames.Count; i++)
{
EditorGUILayout.BeginHorizontal();
string typeName = componentNames[i];
string displayName = GetShortTypeName(typeName);
EditorGUILayout.LabelField($"{i + 1}. {displayName}");
if (GUILayout.Button("X", GUILayout.Width(25)))
{
sheet.RemoveComponentTypeName(typeName);
break;
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space();
// 添加新Component
EditorGUILayout.BeginHorizontal();
selectedComponentIndex = EditorGUILayout.Popup("添加Component", selectedComponentIndex,
availableComponentTypes.Select(t => t.Name).ToArray());
if (GUILayout.Button("添加", GUILayout.Width(50)))
{
if (selectedComponentIndex >= 0 && selectedComponentIndex < availableComponentTypes.Count)
{
var selectedType = availableComponentTypes[selectedComponentIndex];
sheet.AddComponentTypeName(selectedType.AssemblyQualifiedName);
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
private void DrawSubSheetsSection()
{
EditorGUILayout.LabelField("Sub Sheets", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
var subSheets = sheet.SubSheets.ToList();
for (int i = 0; i < subSheets.Count; i++)
{
EditorGUILayout.BeginHorizontal();
var subSheet = subSheets[i];
EditorGUILayout.ObjectField($"{i + 1}.", subSheet, typeof(CapabilitySheet), false);
if (GUILayout.Button("X", GUILayout.Width(25)))
{
sheet.RemoveSubSheet(subSheet);
break;
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space();
// 添加新Sub Sheet
EditorGUILayout.BeginHorizontal();
var newSubSheet = (CapabilitySheet)EditorGUILayout.ObjectField("添加Sub Sheet", null, typeof(CapabilitySheet), false);
if (newSubSheet != null)
{
sheet.AddSubSheet(newSubSheet);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
private void RefreshAvailableTypes()
{
// 查找所有Capability子类
availableCapabilityTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => type.IsClass && !type.IsAbstract && typeof(Capability).IsAssignableFrom(type))
.OrderBy(type => type.Name)
.ToList();
// 查找所有Component类型排除Unity内置的
availableComponentTypes = AppDomain.CurrentDomain.GetAssemblies()
.Where(assembly => !assembly.FullName.StartsWith("Unity") && !assembly.FullName.StartsWith("System"))
.SelectMany(assembly => assembly.GetTypes())
.Where(type => type.IsClass && !type.IsAbstract && typeof(Component).IsAssignableFrom(type) && type != typeof(Transform))
.OrderBy(type => type.Name)
.ToList();
}
private string GetShortTypeName(string assemblyQualifiedName)
{
if (string.IsNullOrEmpty(assemblyQualifiedName))
return "Unknown";
var parts = assemblyQualifiedName.Split(',');
if (parts.Length > 0)
{
var fullName = parts[0].Trim();
var lastDot = fullName.LastIndexOf('.');
return lastDot >= 0 ? fullName.Substring(lastDot + 1) : fullName;
}
return assemblyQualifiedName;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 209106279e66f3349b8b1d62cb9285be
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 836d4cfce7d4ec543baa74d91d396954
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,197 @@
/* Capability Debugger Styles */
.toolbar {
flex-direction: row;
background-color: rgb(56, 56, 56);
border-bottom-width: 1px;
border-bottom-color: rgb(26, 26, 26);
padding: 5px;
}
.control-button {
width: 40px;
height: 30px;
margin-left: 2px;
margin-right: 2px;
font-size: 16px;
}
.time-label {
-unity-text-align: middle-left;
font-size: 12px;
color: rgb(200, 200, 200);
}
.section-header {
font-size: 13px;
-unity-font-style: bold;
background-color: rgb(64, 64, 64);
padding: 8px;
border-bottom-width: 1px;
border-bottom-color: rgb(40, 40, 40);
}
.capability-row {
flex-direction: row;
height: 50px;
border-bottom-width: 1px;
border-bottom-color: rgb(76, 76, 76);
}
.capability-row:hover {
background-color: rgb(80, 80, 80);
}
.capability-name {
width: 200px;
padding-left: 10px;
-unity-text-align: middle-left;
background-color: rgb(70, 70, 70);
font-size: 12px;
}
.channel-row {
padding: 8px;
margin-bottom: 4px;
background-color: rgb(60, 60, 60);
border-radius: 4px;
}
.channel-row:hover {
background-color: rgb(70, 70, 70);
}
/* Timeline specific */
.timeline-track {
height: 40px;
margin-bottom: 2px;
flex-direction: row;
}
.timeline-label {
width: 200px;
background-color: rgb(70, 70, 70);
padding-left: 10px;
-unity-text-align: middle-left;
}
.timeline-area {
flex-grow: 1;
position: relative;
background-color: rgb(56, 56, 56);
}
.activation-bar {
position: absolute;
height: 70%;
top: 15%;
background-color: rgba(76, 204, 76, 0.8);
border-radius: 4px;
}
.activation-bar-blocked {
background-color: rgba(204, 76, 76, 0.8);
}
/* Performance panel */
.performance-stat {
padding: 5px;
margin-bottom: 3px;
background-color: rgb(60, 60, 60);
border-left-width: 3px;
border-left-color: rgb(76, 204, 76);
}
.performance-stat-warning {
border-left-color: rgb(255, 165, 0);
}
.performance-stat-critical {
border-left-color: rgb(204, 76, 76);
}
/* Tag blocker panel */
.tag-blocker-item {
padding: 10px;
margin-bottom: 8px;
background-color: rgb(64, 64, 64);
border-radius: 4px;
border-left-width: 4px;
border-left-color: rgb(255, 128, 64);
}
.tag-blocker-header {
font-size: 13px;
-unity-font-style: bold;
color: rgb(255, 200, 150);
margin-bottom: 5px;
}
.instigator-item {
margin-left: 15px;
font-size: 11px;
color: rgb(180, 180, 180);
}
/* Inspector panel */
.inspector-foldout {
margin-bottom: 10px;
}
.inspector-property {
flex-direction: row;
padding: 3px;
margin-left: 10px;
}
.inspector-property-label {
width: 120px;
color: rgb(180, 180, 180);
}
.inspector-property-value {
flex-grow: 1;
color: rgb(220, 220, 220);
}
/* Status indicators */
.status-active {
color: rgb(76, 204, 76);
}
.status-inactive {
color: rgb(128, 128, 128);
}
.status-blocked {
color: rgb(204, 76, 76);
}
/* Utility classes */
.flex-row {
flex-direction: row;
}
.flex-column {
flex-direction: column;
}
.flex-grow {
flex-grow: 1;
}
.text-center {
-unity-text-align: middle-center;
}
.text-bold {
-unity-font-style: bold;
}
.margin-small {
margin: 5px;
}
.padding-small {
padding: 5px;
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf93baf8c45a5a54a84abff32e2433ac
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0

View File

@ -0,0 +1,185 @@
using UnityEngine;
using UnityEditor;
using System.Linq;
namespace CapabilitySystem.Editor
{
/// <summary>
/// Scene视图中的Capability可视化工具
/// 显示激活状态、Tag阻塞、时间轴等信息
/// </summary>
[InitializeOnLoad]
public static class CapabilitySceneGizmos
{
private static bool showGizmos = true;
private static bool showActivationState = true;
private static bool showTagBlockers = true;
private static bool showActivationHistory = false;
private static float gizmoSize = 0.5f;
static CapabilitySceneGizmos()
{
SceneView.duringSceneGui += OnSceneGUI;
}
[MenuItem("Window/Capability System/Toggle Scene Gizmos")]
private static void ToggleGizmos()
{
showGizmos = !showGizmos;
SceneView.RepaintAll();
}
private static void OnSceneGUI(SceneView sceneView)
{
if (!showGizmos) return;
var allComponents = Object.FindObjectsOfType<CapabilityComponent>();
foreach (var component in allComponents)
{
DrawComponentGizmos(component);
}
// 绘制控制面板
Handles.BeginGUI();
DrawControlPanel();
Handles.EndGUI();
}
private static void DrawComponentGizmos(CapabilityComponent component)
{
if (component == null || component.gameObject == null) return;
Vector3 position = component.transform.position;
var capabilities = component.GetAllCapabilities();
// 绘制激活状态
if (showActivationState)
{
DrawActivationState(position, capabilities);
}
// 绘制Tag阻塞信息
if (showTagBlockers)
{
DrawTagBlockers(position, component);
}
// 绘制激活历史
if (showActivationHistory)
{
DrawActivationHistory(position, capabilities);
}
}
private static void DrawActivationState(Vector3 position, System.Collections.Generic.IReadOnlyList<Capability> capabilities)
{
int activeCount = capabilities.Count(c => c.IsActive);
int totalCount = capabilities.Count;
if (totalCount == 0) return;
// 绘制圆环表示激活比例
float radius = gizmoSize;
Vector3 offset = Vector3.up * 2f;
Vector3 center = position + offset;
// 背景圆
Handles.color = new Color(0.3f, 0.3f, 0.3f, 0.5f);
Handles.DrawSolidDisc(center, Camera.current.transform.forward, radius);
// 激活部分
if (activeCount > 0)
{
float fillAngle = 360f * activeCount / totalCount;
Handles.color = new Color(0.3f, 1f, 0.3f, 0.8f);
Handles.DrawSolidArc(center, Camera.current.transform.forward, Vector3.up, fillAngle, radius);
}
// 文字标签
Handles.Label(center + Vector3.up * (radius + 0.2f),
$"{activeCount}/{totalCount}",
new GUIStyle()
{
normal = { textColor = Color.white },
fontSize = 12,
fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter
});
}
private static void DrawTagBlockers(Vector3 position, CapabilityComponent component)
{
var blockedTags = component.GetBlockedTags().ToList();
if (blockedTags.Count == 0) return;
Vector3 offset = Vector3.up * 2.5f;
Vector3 labelPos = position + offset;
// 绘制阻塞图标
Handles.color = new Color(1f, 0.5f, 0.3f, 0.8f);
float iconSize = gizmoSize * 0.3f;
Handles.DrawSolidDisc(labelPos, Camera.current.transform.forward, iconSize);
// 绘制阻塞信息
string blockerText = $"🚫 {blockedTags.Count} Tags Blocked";
Handles.Label(labelPos + Vector3.right * (iconSize + 0.2f),
blockerText,
new GUIStyle()
{
normal = { textColor = new Color(1f, 0.7f, 0.5f) },
fontSize = 11,
fontStyle = FontStyle.Bold
});
}
private static void DrawActivationHistory(Vector3 position, System.Collections.Generic.IReadOnlyList<Capability> capabilities)
{
foreach (var capability in capabilities)
{
if (capability.ActivationHistory.Count == 0) continue;
// 绘制最近的激活位置
var recentRecords = capability.ActivationHistory
.Where(r => r.Position.HasValue)
.TakeLast(5)
.ToList();
for (int i = 0; i < recentRecords.Count - 1; i++)
{
var from = recentRecords[i].Position.Value;
var to = recentRecords[i + 1].Position.Value;
float alpha = (i + 1) / (float)recentRecords.Count;
Handles.color = new Color(0.5f, 0.5f, 1f, alpha * 0.5f);
Handles.DrawLine(from, to, 2f);
}
}
}
private static void DrawControlPanel()
{
GUILayout.BeginArea(new Rect(10, 10, 250, 200));
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.Label("Capability Gizmos", EditorStyles.boldLabel);
showGizmos = GUILayout.Toggle(showGizmos, "Show Gizmos");
GUI.enabled = showGizmos;
showActivationState = GUILayout.Toggle(showActivationState, "Show Activation State");
showTagBlockers = GUILayout.Toggle(showTagBlockers, "Show Tag Blockers");
showActivationHistory = GUILayout.Toggle(showActivationHistory, "Show Activation History");
GUILayout.Space(5);
GUILayout.Label($"Gizmo Size: {gizmoSize:F2}");
gizmoSize = GUILayout.HorizontalSlider(gizmoSize, 0.1f, 2f);
GUI.enabled = true;
GUILayout.EndVertical();
GUILayout.EndArea();
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5e639ccc748f78a40ac9c54298796d68

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1fb8b4530b387794dacd2bd05922612c

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6f88063fae5e09d44851b6ef79d665f4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,54 @@
namespace CapabilitySystem
{
/// <summary>
/// Tick执行组定义Capability的更新顺序优先级
/// 数值越小越先执行
/// </summary>
public enum TickGroup
{
/// <summary>输入处理</summary>
Input = 0,
/// <summary>移动前处理</summary>
BeforeMovement = 100,
/// <summary>影响移动的逻辑</summary>
InfluenceMovement = 200,
/// <summary>动作移动</summary>
ActionMovement = 300,
/// <summary>主要移动逻辑</summary>
Movement = 400,
/// <summary>移动后处理</summary>
LastMovement = 500,
/// <summary>玩法逻辑前</summary>
BeforeGameplay = 600,
/// <summary>主要玩法逻辑</summary>
Gameplay = 700,
/// <summary>玩法逻辑后</summary>
AfterGameplay = 800,
/// <summary>物理处理前</summary>
BeforePhysics = 850,
/// <summary>物理处理</summary>
Physics = 875,
/// <summary>物理处理后</summary>
AfterPhysics = 900,
/// <summary>音频处理</summary>
Audio = 1000,
/// <summary>后期处理</summary>
PostWork = 1100,
/// <summary>最后的保底处理</summary>
LastDemotable = 1200
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f534b3eed960fac4ea6d8e125578810a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b2cc55c0b6f5ef458d6d490d214f646
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fab2fdefed718f74da1394b711c5d45a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,135 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// AI行为Capability示例
/// 展示CompoundCapability的使用
/// </summary>
[TickOrder(TickGroup.Gameplay, 0)]
public class AIBehaviorCapability : CompoundCapability
{
private enum AIState
{
Idle,
Patrol,
Chase,
Attack
}
private AIState currentState = AIState.Idle;
private Transform aiTransform;
private float stateTimer;
// 子Capability需要在Setup中创建
private Capability idleCapability;
private Capability patrolCapability;
private Capability chaseCapability;
private Capability attackCapability;
protected override void Setup()
{
base.Setup();
aiTransform = Owner.transform;
// 创建子Capability简化示例实际应该是独立的类
// 这里只是演示结构实际使用时应该创建具体的Capability类
}
protected override bool ShouldActivate()
{
// AI系统通常一直激活
return true;
}
protected override void TickCompound(float deltaTime)
{
stateTimer += deltaTime;
// 简单的状态机逻辑
switch (currentState)
{
case AIState.Idle:
if (stateTimer > 2f)
{
TransitionToState(AIState.Patrol);
}
break;
case AIState.Patrol:
// 检测玩家
if (DetectPlayer())
{
TransitionToState(AIState.Chase);
}
else if (stateTimer > 5f)
{
TransitionToState(AIState.Idle);
}
break;
case AIState.Chase:
if (IsPlayerInAttackRange())
{
TransitionToState(AIState.Attack);
}
else if (!DetectPlayer())
{
TransitionToState(AIState.Patrol);
}
break;
case AIState.Attack:
if (!IsPlayerInAttackRange())
{
TransitionToState(AIState.Chase);
}
break;
}
// 使用Blackboard共享AI状态
Blackboard?.Set("AIState", currentState.ToString());
}
private void TransitionToState(AIState newState)
{
if (currentState == newState)
return;
Debug.Log($"[AIBehavior] Transitioning from {currentState} to {newState}");
// 停用当前状态的子Capability
DeactivateAllChildren();
currentState = newState;
stateTimer = 0f;
// 激活新状态的子Capability
// 实际使用时应该激活对应的子Capability
// 例如: ActivateChild(patrolCapability);
}
private bool DetectPlayer()
{
// 简化的玩家检测逻辑
// 实际应该使用Physics.OverlapSphere等
return false;
}
private bool IsPlayerInAttackRange()
{
// 简化的攻击范围检测
return false;
}
protected override void OnChildActivated(Capability child)
{
Debug.Log($"[AIBehavior] Child capability activated: {child.GetType().Name}");
}
protected override void OnChildDeactivated(Capability child)
{
Debug.Log($"[AIBehavior] Child capability deactivated: {child.GetType().Name}");
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 80a23e8468aabfb48ad9ab345ffd66d9

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 462c0459c35398b48b7cbf8fc8ddf631
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,94 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// Boss攻击Capability示例
/// 展示ActionQueue的使用
/// </summary>
[TickOrder(TickGroup.Gameplay, 0)]
public class BossAttackCapability : ActionCapability
{
private Transform bossTransform;
private int attackPhase = 0;
protected override void Setup()
{
base.Setup();
bossTransform = Owner.transform;
}
protected override void SetupActions()
{
// 根据攻击阶段设置不同的Action序列
switch (attackPhase)
{
case 0:
SetupPhase1Actions();
break;
case 1:
SetupPhase2Actions();
break;
default:
SetupPhase1Actions();
break;
}
}
private void SetupPhase1Actions()
{
// Action 1: 准备攻击1秒
actionQueue.EnqueueDuration(
"Prepare",
duration: 1f,
onStart: () => Debug.Log("[BossAttack] Preparing attack..."),
onEnd: () => Debug.Log("[BossAttack] Preparation complete")
);
// Action 2: 执行攻击0.5秒)
actionQueue.EnqueueDuration(
"Attack",
duration: 0.5f,
onStart: () =>
{
Debug.Log("[BossAttack] Attacking!");
// 这里可以触发攻击逻辑
},
onUpdate: (dt) =>
{
// 攻击动画更新
}
);
// Action 3: 恢复1秒
actionQueue.EnqueueDuration(
"Recover",
duration: 1f,
onStart: () => Debug.Log("[BossAttack] Recovering..."),
onEnd: () => Debug.Log("[BossAttack] Attack sequence complete")
);
}
private void SetupPhase2Actions()
{
// 更复杂的攻击序列
actionQueue.EnqueueDuration("Charge", 2f,
onStart: () => Debug.Log("[BossAttack] Phase 2: Charging power..."));
actionQueue.EnqueueDuration("PowerAttack", 1f,
onStart: () => Debug.Log("[BossAttack] Phase 2: POWER ATTACK!"));
actionQueue.EnqueueDuration("Cooldown", 2f,
onStart: () => Debug.Log("[BossAttack] Phase 2: Cooling down..."));
}
/// <summary>
/// 切换攻击阶段
/// </summary>
public void SetAttackPhase(int phase)
{
attackPhase = phase;
Blackboard?.Set("BossAttackPhase", phase);
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b3031893972f3b24a9f6155fff0c96ea

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 877e8c722fc7342418ef7c21230b9b2d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,77 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// 展示如何使用 TemporalLogger 记录调试数据
/// </summary>
[TickOrder(TickGroup.Gameplay, 0)]
public class DebugCapabilityExample : Capability
{
private float chargeAmount = 0f;
private int hitCount = 0;
protected override void Setup()
{
// TemporalLogger 会自动记录激活/停用和位置
// 这里展示如何记录自定义数据
}
protected override bool ShouldActivate()
{
return Input.GetKeyDown(KeyCode.E);
}
protected override void OnActivated()
{
chargeAmount = 0f;
hitCount = 0;
// 记录自定义数据
TemporalLogger?.Log($"{Owner.name}.ChargeAmount", chargeAmount);
TemporalLogger?.Log($"{Owner.name}.HitCount", hitCount);
}
protected override void TickActive(float deltaTime)
{
// 模拟蓄力
chargeAmount += deltaTime;
// 每帧记录蓄力值
TemporalLogger?.Log($"{Owner.name}.ChargeAmount", chargeAmount);
// 记录颜色变化(可视化)
Color chargeColor = Color.Lerp(Color.white, Color.red, chargeAmount / 3f);
TemporalLogger?.Log($"{Owner.name}.ChargeColor", chargeColor);
// 模拟攻击
if (Input.GetKeyDown(KeyCode.Space))
{
hitCount++;
TemporalLogger?.Log($"{Owner.name}.HitCount", hitCount);
TemporalLogger?.Log($"{Owner.name}.LastHitTime", Time.time);
}
// 记录动画状态(如果有 Animator
var animator = GetComponent<Animator>();
if (animator != null)
{
TemporalLogger?.LogAnimation($"{Owner.name}.Anim", animator, "Charge");
}
}
protected override bool ShouldDeactivate()
{
return chargeAmount >= 3f || Input.GetKeyUp(KeyCode.E);
}
protected override void OnDeactivated()
{
Debug.Log($"[DebugCapability] 蓄力完成: {chargeAmount:F2}s, 攻击次数: {hitCount}");
// 记录最终状态
TemporalLogger?.Log($"{Owner.name}.FinalCharge", chargeAmount);
TemporalLogger?.Log($"{Owner.name}.FinalHitCount", hitCount);
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dc9e4e0f0822dea43a9091aebbd7aee6

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eca0bf9b291f0c34a8473da793ef5944
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,46 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// 跳跃Capability配置数据
/// </summary>
[CreateAssetMenu(fileName = "JumpCapabilityData", menuName = "Capability/Data/Jump")]
public class JumpCapabilityData : CapabilityData
{
[Header("Jump Settings")]
[SerializeField]
[Tooltip("跳跃力度")]
private float jumpForce = 10f;
[SerializeField]
[Tooltip("地面检测距离")]
private float groundCheckDistance = 0.1f;
[Header("Tags")]
[SerializeField]
[Tooltip("此Capability的标签")]
private CapabilityTag[] tags;
public float JumpForce => jumpForce;
public float GroundCheckDistance => groundCheckDistance;
public CapabilityTag[] Tags => tags;
public override bool Validate()
{
if (jumpForce <= 0)
{
Debug.LogWarning($"[JumpCapabilityData] Jump force should be positive: {jumpForce}");
return false;
}
if (groundCheckDistance < 0)
{
Debug.LogWarning($"[JumpCapabilityData] Ground check distance should be non-negative: {groundCheckDistance}");
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4856db828fdf6104a8c21c945dee9baa

View File

@ -0,0 +1,46 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// 移动Capability配置数据
/// </summary>
[CreateAssetMenu(fileName = "MoveCapabilityData", menuName = "Capability/Data/Move")]
public class MoveCapabilityData : CapabilityData
{
[Header("Movement Settings")]
[SerializeField]
[Tooltip("移动速度")]
private float moveSpeed = 5f;
[SerializeField]
[Tooltip("旋转速度")]
private float rotationSpeed = 10f;
[Header("Tags")]
[SerializeField]
[Tooltip("此Capability的标签")]
private CapabilityTag[] tags;
public float MoveSpeed => moveSpeed;
public float RotationSpeed => rotationSpeed;
public CapabilityTag[] Tags => tags;
public override bool Validate()
{
if (moveSpeed <= 0)
{
Debug.LogWarning($"[MoveCapabilityData] Move speed should be positive: {moveSpeed}");
return false;
}
if (rotationSpeed <= 0)
{
Debug.LogWarning($"[MoveCapabilityData] Rotation speed should be positive: {rotationSpeed}");
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 055950465cc478b458901297986daaba

View File

@ -0,0 +1,26 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// 玩家输入组件示例
/// </summary>
public class PlayerInputComponent : MonoBehaviour
{
// 输入状态
public bool JumpPressed { get; private set; }
public bool JumpHeld { get; private set; }
public Vector2 MoveInput { get; private set; }
private void Update()
{
// 读取输入
JumpPressed = Input.GetKeyDown(KeyCode.Space);
JumpHeld = Input.GetKey(KeyCode.Space);
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
MoveInput = new Vector2(horizontal, vertical);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4905147a4f4e43843897ced96e2e6b4f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,89 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// 玩家跳跃Capability示例
/// </summary>
[TickOrder(TickGroup.ActionMovement, 10)]
public class PlayerJumpCapability : Capability
{
private PlayerInputComponent inputComp;
private Rigidbody rb;
// 从配置数据读取
private float jumpForce = 10f;
private float groundCheckDistance = 0.1f;
protected override void Setup()
{
// 获取组件引用
inputComp = GetComponent<PlayerInputComponent>();
rb = GetComponent<Rigidbody>();
// 从配置数据读取参数
if (Data is JumpCapabilityData jumpData)
{
jumpForce = jumpData.JumpForce;
groundCheckDistance = jumpData.GroundCheckDistance;
// 添加Tags
if (jumpData.Tags != null)
{
Tags.AddRange(jumpData.Tags);
}
}
if (inputComp == null)
{
Debug.LogError($"[PlayerJumpCapability] PlayerInputComponent not found on {Owner.name}");
}
if (rb == null)
{
Debug.LogError($"[PlayerJumpCapability] Rigidbody not found on {Owner.name}");
}
}
protected override bool ShouldActivate()
{
// 检查输入
if (inputComp == null || !inputComp.JumpPressed)
return false;
// 检查是否在地面
if (!IsGrounded())
return false;
return true;
}
protected override void OnActivated()
{
// 施加跳跃力
if (rb != null)
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
Debug.Log($"[PlayerJumpCapability] Jump! Force: {jumpForce}");
}
}
protected override bool ShouldDeactivate()
{
// 跳跃是瞬时动作,立即失活
return true;
}
/// <summary>
/// 检查是否在地面
/// </summary>
private bool IsGrounded()
{
if (rb == null)
return false;
// 简单的地面检测(向下射线)
return Physics.Raycast(Owner.transform.position, Vector3.down, groundCheckDistance + 0.5f);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21a84a2511ff32f49a24e820a408ab9e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,110 @@
using UnityEngine;
namespace CapabilitySystem.Examples
{
/// <summary>
/// 玩家移动Capability示例
/// </summary>
[TickOrder(TickGroup.Movement, 0)]
public class PlayerMoveCapability : Capability
{
private PlayerInputComponent inputComp;
private Rigidbody rb;
private Transform transform;
// 从配置数据读取
private float moveSpeed = 5f;
private float rotationSpeed = 10f;
protected override void Setup()
{
// 获取组件引用
inputComp = GetComponent<PlayerInputComponent>();
rb = GetComponent<Rigidbody>();
transform = Owner.transform;
// 从配置数据读取参数
if (Data is MoveCapabilityData moveData)
{
moveSpeed = moveData.MoveSpeed;
rotationSpeed = moveData.RotationSpeed;
// 添加Tags
if (moveData.Tags != null)
{
Tags.AddRange(moveData.Tags);
}
}
if (inputComp == null)
{
Debug.LogError($"[PlayerMoveCapability] PlayerInputComponent not found on {Owner.name}");
}
if (rb == null)
{
Debug.LogError($"[PlayerMoveCapability] Rigidbody not found on {Owner.name}");
}
}
protected override bool ShouldActivate()
{
// 有移动输入时激活
if (inputComp == null)
return false;
return inputComp.MoveInput.sqrMagnitude > 0.01f;
}
protected override void OnActivated()
{
Debug.Log("[PlayerMoveCapability] Start moving");
}
protected override void TickActive(float deltaTime)
{
if (inputComp == null || rb == null || transform == null)
return;
Vector2 input = inputComp.MoveInput;
// 计算移动方向(世界空间)
Vector3 moveDirection = new Vector3(input.x, 0, input.y).normalized;
if (moveDirection.sqrMagnitude > 0.01f)
{
// 移动
Vector3 targetVelocity = moveDirection * moveSpeed;
targetVelocity.y = rb.linearVelocity.y; // 保持Y轴速度重力
rb.linearVelocity = targetVelocity;
// 旋转朝向移动方向
Quaternion targetRotation = Quaternion.LookRotation(moveDirection);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * deltaTime);
}
}
protected override bool ShouldDeactivate()
{
// 没有移动输入时失活
if (inputComp == null)
return true;
return inputComp.MoveInput.sqrMagnitude <= 0.01f;
}
protected override void OnDeactivated()
{
Debug.Log("[PlayerMoveCapability] Stop moving");
// 停止水平移动
if (rb != null)
{
Vector3 velocity = rb.linearVelocity;
velocity.x = 0;
velocity.z = 0;
rb.linearVelocity = velocity;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57ae397336fa71c4d88de34353b1258e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b772e4dcc36581d45862cbd85f77e1f4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ec7408feedfe9234b9e54ea5fedfd004, type: 3}
m_Name: JumpTag
m_EditorClassIdentifier:
tagName: Jump

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8ceaf2ec34785d141899ac1637bf90c3
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ffab8a3c2ebe1c442b4912eefbab7a54, type: 3}
m_Name: PlayerMovementSheet
m_EditorClassIdentifier:
capabilityClassNames:
- CapabilitySystem.Examples.PlayerJumpCapability, Assembly-CSharp, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
- CapabilitySystem.Examples.PlayerMoveCapability, Assembly-CSharp, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
- CapabilitySystem.Examples.DebugCapabilityExample, Assembly-CSharp, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
capabilityDatas: []
componentTypeNames:
- CapabilitySystem.Examples.PlayerInputComponent, Assembly-CSharp, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
subSheets: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5aa72f87e4555424986aff238e63db67
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 936e47d12a63a9a448e96b286a9084cb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,158 @@
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace CapabilitySystem
{
/// <summary>
/// 运行时性能监控组件
/// 可以在Game视图中显示Capability系统的性能统计
/// </summary>
public class CapabilityPerformanceMonitor : MonoBehaviour
{
[Header("Display Settings")]
[SerializeField] private bool showMonitor = true;
[SerializeField] private KeyCode toggleKey = KeyCode.F3;
[SerializeField] private int fontSize = 12;
[SerializeField] private Color backgroundColor = new Color(0, 0, 0, 0.7f);
[SerializeField] private Color textColor = Color.white;
[Header("Update Settings")]
[SerializeField] private float updateInterval = 0.5f;
private float lastUpdateTime;
private GUIStyle backgroundStyle;
private GUIStyle textStyle;
private GUIStyle headerStyle;
// 性能数据
private int totalCapabilities;
private int activeCapabilities;
private int blockedCapabilities;
private Dictionary<TickGroup, int> capabilitiesByGroup = new Dictionary<TickGroup, int>();
private List<(string name, int count, bool isActive)> topCapabilities = new List<(string, int, bool)>();
private void Update()
{
// 切换显示
if (Input.GetKeyDown(toggleKey))
{
showMonitor = !showMonitor;
}
// 更新数据
if (Time.time - lastUpdateTime >= updateInterval)
{
UpdatePerformanceData();
lastUpdateTime = Time.time;
}
}
private void UpdatePerformanceData()
{
if (CapabilitySystem.Instance == null) return;
var stats = CapabilitySystem.Instance.GetStatistics();
totalCapabilities = stats.total;
activeCapabilities = stats.active;
blockedCapabilities = stats.blocked;
// 按TickGroup统计
capabilitiesByGroup.Clear();
var allCapabilities = CapabilitySystem.Instance.GetAllCapabilities();
foreach (var cap in allCapabilities)
{
if (!capabilitiesByGroup.ContainsKey(cap.TickGroup))
{
capabilitiesByGroup[cap.TickGroup] = 0;
}
capabilitiesByGroup[cap.TickGroup]++;
}
// Top Capabilities
topCapabilities = allCapabilities
.GroupBy(c => c.GetType().Name)
.Select(g => (name: g.Key, count: g.Count(), isActive: g.Any(c => c.IsActive)))
.OrderByDescending(x => x.count)
.Take(10)
.ToList();
}
private void OnGUI()
{
if (!showMonitor) return;
InitializeStyles();
float width = 400;
float height = 500;
float x = Screen.width - width - 10;
float y = 10;
Rect backgroundRect = new Rect(x, y, width, height);
GUI.Box(backgroundRect, "", backgroundStyle);
GUILayout.BeginArea(new Rect(x + 10, y + 10, width - 20, height - 20));
// 标题
GUILayout.Label("Capability Performance Monitor", headerStyle);
GUILayout.Space(10);
// 总体统计
GUILayout.Label("=== Overall Statistics ===", headerStyle);
GUILayout.Label($"Total Capabilities: {totalCapabilities}", textStyle);
GUILayout.Label($"Active: {activeCapabilities}", textStyle);
GUILayout.Label($"Blocked: {blockedCapabilities}", textStyle);
GUILayout.Label($"FPS: {(1f / Time.deltaTime):F1}", textStyle);
GUILayout.Space(10);
// 按TickGroup统计
GUILayout.Label("=== By Tick Group ===", headerStyle);
foreach (var kvp in capabilitiesByGroup.OrderBy(x => (int)x.Key))
{
GUILayout.Label($"{kvp.Key}: {kvp.Value}", textStyle);
}
GUILayout.Space(10);
// Top Capabilities
GUILayout.Label("=== Top Capabilities ===", headerStyle);
foreach (var cap in topCapabilities)
{
string status = cap.isActive ? "[ACTIVE]" : "[Inactive]";
GUILayout.Label($"{cap.name} x{cap.count} {status}", textStyle);
}
GUILayout.Space(10);
GUILayout.Label($"Press {toggleKey} to toggle", textStyle);
GUILayout.EndArea();
}
private void InitializeStyles()
{
if (backgroundStyle == null)
{
backgroundStyle = new GUIStyle(GUI.skin.box);
Texture2D bgTexture = new Texture2D(1, 1);
bgTexture.SetPixel(0, 0, backgroundColor);
bgTexture.Apply();
backgroundStyle.normal.background = bgTexture;
}
if (textStyle == null)
{
textStyle = new GUIStyle(GUI.skin.label);
textStyle.fontSize = fontSize;
textStyle.normal.textColor = textColor;
textStyle.padding = new RectOffset(5, 5, 2, 2);
}
if (headerStyle == null)
{
headerStyle = new GUIStyle(textStyle);
headerStyle.fontStyle = FontStyle.Bold;
headerStyle.fontSize = fontSize + 2;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c08e24fb61964e8458739f6159b8d62d

8
Assets/Dark.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 88e06d459ce9ed24b883963dd7579809
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Dark/texture_01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: bba49b0ea775f2e4793bcdd72a0ce769
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: ef3376a8e65b5c742ad76a5f79709bbd
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: e8838dbb2b6064c4c9247ef5fdd0bc2d
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_04.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: 02f11dec033794a48a8eab82b5bfaaba
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: d7f06361b0cd9504bb4670f7d9a09abb
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_06.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: 14598b2e5092f22418c5e0cfec26e35f
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_07.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: 57ce36e723f91514991d82ba83a987d9
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_08.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: b387902b682801141bb391cd8140bb70
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: eae11ee3206ad5c428d8308f0abe02bb
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: 9ee08e5229146274195ab21c3cddc573
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: dd7132e791279db4393ced1ed56ddc6b
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

BIN
Assets/Dark/texture_12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: 472cf1f5c316c384fa64c340b51d7089
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
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: 0
spriteTessellationDetail: -1
textureType: 0
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: iPhone
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: Android
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:

Some files were not shown because too many files have changed in this diff Show More