1
83
.gitignore
vendored
Normal 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/
|
||||
22
Assets/.claude/settings.local.json
Normal 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)"
|
||||
]
|
||||
}
|
||||
}
|
||||
8
Assets/CapabilitySystem.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbdaf55c33b53e34b81f7e2588d66cf7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Attributes.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ea2f924fbe109c44be5ebb61f540d30
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/CapabilitySystem/Attributes/TickOrderAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08c8672f9dd000447aef58db8940efd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Core.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e49e089b37c87894696d6f3b49563abf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
73
Assets/CapabilitySystem/Core/ActionCapability.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/CapabilitySystem/Core/ActionCapability.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c5f43ff96d913240bd0d7d270a05814
|
||||
194
Assets/CapabilitySystem/Core/ActionQueue.cs
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
2
Assets/CapabilitySystem/Core/ActionQueue.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 590dcae1712665a49ae5ffced1edce04
|
||||
314
Assets/CapabilitySystem/Core/Capability.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Core/Capability.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4dbadc84377efab488b761cd541fc9b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
Assets/CapabilitySystem/Core/CapabilityActivationRecord.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 504183dddb5845f4fb0aa0beedf7302a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
186
Assets/CapabilitySystem/Core/CapabilityBlackboard.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baf276d6a762e61489825601a75f1562
|
||||
343
Assets/CapabilitySystem/Core/CapabilityComponent.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Core/CapabilityComponent.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d38e65e95dde13e42af0ad02fe3af814
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
40
Assets/CapabilitySystem/Core/CapabilityData.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/CapabilitySystem/Core/CapabilityData.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d12e212f8a01fd4f992c5f66087a888
|
||||
275
Assets/CapabilitySystem/Core/CapabilitySheet.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Core/CapabilitySheet.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffab8a3c2ebe1c442b4912eefbab7a54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
202
Assets/CapabilitySystem/Core/CapabilitySystem.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Core/CapabilitySystem.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84c9abe5e6bf1244d8842b430e369f78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Assets/CapabilitySystem/Core/CapabilityTag.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Core/CapabilityTag.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec7408feedfe9234b9e54ea5fedfd004
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
177
Assets/CapabilitySystem/Core/CompoundCapability.cs
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
2
Assets/CapabilitySystem/Core/CompoundCapability.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad7a50e648a6a2f4081d5496a96d1704
|
||||
70
Assets/CapabilitySystem/Core/Instigator.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Core/Instigator.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 522dd182cb6f1f644a756270b7ac0111
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
280
Assets/CapabilitySystem/Core/TemporalLogger.cs
Normal 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
|
||||
}
|
||||
}
|
||||
2
Assets/CapabilitySystem/Core/TemporalLogger.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de209aa30b789fa44bfd9c23e7de4fe0
|
||||
8
Assets/CapabilitySystem/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 474d0f25701409945a5dd85127ce7be4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
223
Assets/CapabilitySystem/Editor/CapabilitySheetEditor.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Editor/CapabilitySheetEditor.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 209106279e66f3349b8b1d62cb9285be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Editor/Debugger.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 836d4cfce7d4ec543baa74d91d396954
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
185
Assets/CapabilitySystem/Editor/Debugger/CapabilitySceneGizmos.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e639ccc748f78a40ac9c54298796d68
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fb8b4530b387794dacd2bd05922612c
|
||||
8
Assets/CapabilitySystem/Enums.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f88063fae5e09d44851b6ef79d665f4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
54
Assets/CapabilitySystem/Enums/TickGroup.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/CapabilitySystem/Enums/TickGroup.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f534b3eed960fac4ea6d8e125578810a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Examples.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b2cc55c0b6f5ef458d6d490d214f646
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Examples/AI.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fab2fdefed718f74da1394b711c5d45a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
135
Assets/CapabilitySystem/Examples/AI/AIBehaviorCapability.cs
Normal 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80a23e8468aabfb48ad9ab345ffd66d9
|
||||
8
Assets/CapabilitySystem/Examples/Boss.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 462c0459c35398b48b7cbf8fc8ddf631
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3031893972f3b24a9f6155fff0c96ea
|
||||
8
Assets/CapabilitySystem/Examples/Debug.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 877e8c722fc7342418ef7c21230b9b2d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc9e4e0f0822dea43a9091aebbd7aee6
|
||||
8
Assets/CapabilitySystem/Examples/Player.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eca0bf9b291f0c34a8473da793ef5944
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4856db828fdf6104a8c21c945dee9baa
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 055950465cc478b458901297986daaba
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4905147a4f4e43843897ced96e2e6b4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21a84a2511ff32f49a24e820a408ab9e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
110
Assets/CapabilitySystem/Examples/Player/PlayerMoveCapability.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57ae397336fa71c4d88de34353b1258e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Examples/Sheets.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b772e4dcc36581d45862cbd85f77e1f4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/CapabilitySystem/Examples/Sheets/JumpTag.asset
Normal 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
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ceaf2ec34785d141899ac1637bf90c3
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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: []
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5aa72f87e4555424986aff238e63db67
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/CapabilitySystem/Runtime.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 936e47d12a63a9a448e96b286a9084cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
158
Assets/CapabilitySystem/Runtime/CapabilityPerformanceMonitor.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c08e24fb61964e8458739f6159b8d62d
|
||||
8
Assets/Dark.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88e06d459ce9ed24b883963dd7579809
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Dark/texture_01.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
140
Assets/Dark/texture_01.png.meta
Normal 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
|
After Width: | Height: | Size: 1.3 KiB |
140
Assets/Dark/texture_02.png.meta
Normal 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
|
After Width: | Height: | Size: 2.7 KiB |
140
Assets/Dark/texture_03.png.meta
Normal 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
|
After Width: | Height: | Size: 13 KiB |
140
Assets/Dark/texture_04.png.meta
Normal 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
|
After Width: | Height: | Size: 19 KiB |
140
Assets/Dark/texture_05.png.meta
Normal 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
|
After Width: | Height: | Size: 2.7 KiB |
140
Assets/Dark/texture_06.png.meta
Normal 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
|
After Width: | Height: | Size: 2.7 KiB |
140
Assets/Dark/texture_07.png.meta
Normal 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
|
After Width: | Height: | Size: 637 B |
140
Assets/Dark/texture_08.png.meta
Normal 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
|
After Width: | Height: | Size: 2.8 KiB |
140
Assets/Dark/texture_09.png.meta
Normal 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
|
After Width: | Height: | Size: 9.0 KiB |
140
Assets/Dark/texture_10.png.meta
Normal 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
|
After Width: | Height: | Size: 8.8 KiB |
140
Assets/Dark/texture_11.png.meta
Normal 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
|
After Width: | Height: | Size: 9.4 KiB |
140
Assets/Dark/texture_12.png.meta
Normal 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:
|
||||