shapes
This commit is contained in:
145
Assets/ThemeBundles/Basic/Prefabs/Custom2DShape.prefab
Normal file
145
Assets/ThemeBundles/Basic/Prefabs/Custom2DShape.prefab
Normal file
@@ -0,0 +1,145 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &5088079323518852183
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5538993855018306935}
|
||||
- component: {fileID: 5809771010128262868}
|
||||
- component: {fileID: 8026468966593356782}
|
||||
m_Layer: 0
|
||||
m_Name: Custom2DShape
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5538993855018306935
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5088079323518852183}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!212 &5809771010128262868
|
||||
SpriteRenderer:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5088079323518852183}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 0
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_FlipX: 0
|
||||
m_FlipY: 0
|
||||
m_DrawMode: 0
|
||||
m_Size: {x: 1, y: 1}
|
||||
m_AdaptiveModeThreshold: 0.5
|
||||
m_SpriteTileMode: 0
|
||||
m_WasSpriteAssigned: 0
|
||||
m_SpriteSortPoint: 0
|
||||
--- !u!114 &8026468966593356782
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5088079323518852183}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1950337aa8bc8c04f9e99db80a4a9aac, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.RhythmGame.ThemeBundles.Basic.Custom2DShape
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: enableTypes
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: elementGuid
|
||||
Entry: 2
|
||||
Data: 00000000000000000000000000000000
|
||||
- Name: submoduleList
|
||||
Entry: 7
|
||||
Data: 0|System.Collections.Generic.List`1[[Ichni.RhythmGame.SubmoduleBase,
|
||||
Assembly-CSharp]], mscorlib
|
||||
- Name:
|
||||
Entry: 12
|
||||
Data: 0
|
||||
- Name:
|
||||
Entry: 13
|
||||
Data:
|
||||
- Name:
|
||||
Entry: 8
|
||||
Data:
|
||||
connectedTab: {fileID: 0}
|
||||
elementName:
|
||||
tags: []
|
||||
parentElement: {fileID: 0}
|
||||
childElementList: []
|
||||
themeBundleName:
|
||||
objectName:
|
||||
isStatic: 0
|
||||
spriteThemeBundleName:
|
||||
spriteName: None
|
||||
spriteRenderer: {fileID: 5809771010128262868}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00643927510b85b41a9db40917709fe6
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName: basic
|
||||
assetBundleVariant:
|
||||
8
Assets/ThemeBundles/Basic/Scripts/EditorCore.meta
Normal file
8
Assets/ThemeBundles/Basic/Scripts/EditorCore.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9064f7ed277cabe4fbfa2f982dcf3ee4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51a0372bcf911564081d22e0d89b61f1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Ichni.RhythmGame.ThemeBundles.Basic.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame.ThemeBundles.Basic
|
||||
{
|
||||
public partial class Custom2DShape
|
||||
{
|
||||
#region [保存与序列化] Save & Serialize
|
||||
public override void SaveBM()
|
||||
{
|
||||
matchedBM = new Custom2DShape_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
|
||||
themeBundleName, objectName, isStatic, spriteThemeBundleName, spriteName);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region [绘制编辑器面板] Inspector Setup
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
base.SetUpInspector();
|
||||
|
||||
var container = inspector.GenerateContainer("Custom 2D Shape");
|
||||
|
||||
// 获取可选的主题包列表
|
||||
themeBundleList = ThemeBundleManager.instance.loadedThemeBundleList.ConvertAll(x => x.themeBundleName);
|
||||
|
||||
// 排版布置
|
||||
var selectionGroup = container.GenerateSubcontainer(3);
|
||||
|
||||
// 选择主题包列表
|
||||
inspector.GenerateDropdown(this, selectionGroup, "Sprite Theme", themeBundleList, nameof(spriteThemeBundleName))
|
||||
.AddListenerFunction(() => {
|
||||
// 当切换主题包时,强制重置下面的物体名称列表,并刷新面板以装填新列表
|
||||
spriteName = string.Empty;
|
||||
inspectorMain.SetInspector(this);
|
||||
});
|
||||
|
||||
// 如果选择了主题包,则填充其 图片资源 列表
|
||||
if (!string.IsNullOrEmpty(spriteThemeBundleName) && ThemeBundleManager.instance.TryGetThemeBundle(spriteThemeBundleName, out ThemeBundle themeBundle))
|
||||
{
|
||||
// 注意:由于资源加载规则,一些图片可能存在于 assetList_Other (Sprite 类型),另一些在 assetList_Texture (Texture2D 类型)
|
||||
spriteNameList = new List<string>();
|
||||
|
||||
// 收集两个列表中的所有资源名称进行合并
|
||||
var spriteNames = themeBundle.assetList_Other.FindAll(x => x is Sprite).ConvertAll(x => x.name);
|
||||
var textureNames = themeBundle.assetList_Texture.ConvertAll(x => x.name);
|
||||
|
||||
spriteNameList.AddRange(spriteNames);
|
||||
spriteNameList.AddRange(textureNames);
|
||||
|
||||
// 去重以防万一(有些包里同名资源可能存在多态)
|
||||
spriteNameList = new List<string>(new HashSet<string>(spriteNameList));
|
||||
|
||||
inspector.GenerateDropdown(this, selectionGroup, "Sprite Name", spriteNameList, nameof(spriteName))
|
||||
.AddListenerFunction(() => inspectorMain.SetInspector(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 未选择或选择无效时,禁用下一级列表
|
||||
var spriteDropdown = inspector.GenerateDropdown(this, selectionGroup, "Sprite Name", new List<string>(), nameof(spriteName));
|
||||
spriteDropdown.dropdown.interactable = false;
|
||||
}
|
||||
|
||||
// 确认并应用按钮
|
||||
var applyButton = inspector.GenerateButton(this, selectionGroup, "Apply Sprite", () =>
|
||||
{
|
||||
UpdateSprite();
|
||||
Refresh();
|
||||
});
|
||||
|
||||
// 如果没有选好,则不给确认
|
||||
if (string.IsNullOrEmpty(spriteThemeBundleName) || string.IsNullOrEmpty(spriteName))
|
||||
{
|
||||
applyButton.button.interactable = false;
|
||||
}
|
||||
|
||||
// 最后把通用的 Transform 和 颜色面板附加上去
|
||||
var settings = container.GenerateSubcontainer(3);
|
||||
StandardInspectionElement.GenerateForTransform(this, container);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aed80aa0a39f68f4ab45db9b7882eb89
|
||||
@@ -0,0 +1,97 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame.ThemeBundles.Basic
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义 2D 形状环境物体,支持从 AssetBundle 动态加载 Sprite,
|
||||
/// 并通过 ColorSubmodule 同步颜色。接入了 DirtyMark 集中刷新机制。
|
||||
/// </summary>
|
||||
public partial class Custom2DShape : EnvironmentObject
|
||||
{
|
||||
#region [暴露属性字段] Exposed Fields
|
||||
public List<string> themeBundleList = new List<string>();
|
||||
public List<string> spriteNameList = new List<string>();
|
||||
public string spriteThemeBundleName;
|
||||
public string spriteName = "None";
|
||||
public SpriteRenderer spriteRenderer;
|
||||
#endregion
|
||||
|
||||
#region [生命周期与工厂] Lifecycle & Factory
|
||||
public static Custom2DShape GenerateElement(string elementName, Guid id, List<string> tags,
|
||||
bool isFirstGenerated, string themeBundleName, string objectName, GameElement parentElement,
|
||||
bool isStatic, string spriteThemeBundleName, string spriteName)
|
||||
{
|
||||
// 通过 EnvironmentObject.GenerateElement 创建 GameObject 并获取组件
|
||||
Custom2DShape obj = EnvironmentObject.GenerateElement(elementName, id, tags,
|
||||
isFirstGenerated, themeBundleName, objectName, parentElement, isStatic).GetComponent<Custom2DShape>();
|
||||
obj.spriteThemeBundleName = spriteThemeBundleName;
|
||||
obj.spriteName = spriteName;
|
||||
return obj;
|
||||
}
|
||||
public override void FirstSetUpObject(bool isFirstGenerated)
|
||||
{
|
||||
spriteRenderer ??= GetComponentInChildren<SpriteRenderer>();
|
||||
}
|
||||
|
||||
public override void AfterInitialize()
|
||||
{
|
||||
UpdateSprite();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
// 响应由 PropertyAnimation 触发的延迟刷新
|
||||
public override void OnDirtyRefresh(Dictionary<string, bool> flags)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
#endregion
|
||||
#region [效果核心逻辑] Core Effect Logic
|
||||
/// <summary>
|
||||
/// 从当前 ThemeBundle 获取 Sprite 资源
|
||||
/// </summary>
|
||||
public void UpdateSprite()
|
||||
{
|
||||
if (spriteRenderer != null && !string.IsNullOrEmpty(spriteName) && spriteName != "None")
|
||||
{
|
||||
// 优先尝试直接获取 Sprite 资源(兼容老版或特殊包)
|
||||
Sprite sp = ThemeBundleManager.instance.GetObject<Sprite>(spriteThemeBundleName, spriteName);
|
||||
if (sp == null)
|
||||
{
|
||||
// 如果没有找到 Sprite,则从 Texture2D 列表中获取并动态创建 Sprite
|
||||
Texture2D tex = ThemeBundleManager.instance.GetObject<Texture2D>(spriteThemeBundleName, spriteName);
|
||||
if (tex != null)
|
||||
{
|
||||
sp = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
if (sp != null)
|
||||
{
|
||||
spriteRenderer.sprite = sp;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[Custom2DShape] 无法在包 '{spriteThemeBundleName}' 中找到 Sprite/Texture: {spriteName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void Refresh()
|
||||
{
|
||||
// 同步 ColorSubmodule 的颜色状态
|
||||
base.Refresh();
|
||||
if (spriteRenderer != null)
|
||||
{
|
||||
spriteRenderer.color = colorSubmodule.currentBaseColor;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region [继承接口实现] Inherited Logic overrides
|
||||
// 如果有特定的子物体需要刷新逻辑,可在此重载
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1950337aa8bc8c04f9e99db80a4a9aac
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a189c011db566c745993601ee16e08cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame.ThemeBundles.Basic.Beatmap
|
||||
{
|
||||
[System.Serializable]
|
||||
public class Custom2DShape_BM : EnvironmentObject_BM
|
||||
{
|
||||
public string spriteThemeBundleName;
|
||||
public string spriteName = "None";
|
||||
public Custom2DShape_BM() { }
|
||||
public Custom2DShape_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM parentElement,
|
||||
string themeBundleName, string objectName, bool isStatic, string spriteThemeBundleName, string spriteName)
|
||||
: base(elementName, elementGuid, tags, parentElement, themeBundleName, objectName, isStatic)
|
||||
{
|
||||
this.spriteThemeBundleName = spriteThemeBundleName;
|
||||
this.spriteName = spriteName;
|
||||
}
|
||||
public override void ExecuteBM()
|
||||
{
|
||||
matchedElement = Custom2DShape.GenerateElement(elementName, elementGuid, tags, false,
|
||||
themeBundleName, objectName, GetElement(attachedElementGuid), isStatic, spriteThemeBundleName, spriteName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b853ccb87309754c8965b43c38db8a8
|
||||
Reference in New Issue
Block a user