Cozy Wather + buld systeme
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Ashwild.Building;
|
||||
|
||||
namespace Ashwild.EditorTools
|
||||
{
|
||||
/// <summary>
|
||||
/// The custom editor for a BuildableData shown in the right pane of the Ashwild Database. Replaces
|
||||
/// the default ScriptableObject inspector with a hero header (large clickable icon, editable name,
|
||||
/// "Buildable" badge) and cards for the identity (description) and the ghost/built prefabs the
|
||||
/// construction menu and placement ghost consume. All fields bind live to the asset; changing the
|
||||
/// name or icon notifies the list so the row updates without a full rebuild.
|
||||
/// </summary>
|
||||
public class BuildableEditorView
|
||||
{
|
||||
#region State
|
||||
|
||||
public VisualElement Root { get; }
|
||||
|
||||
private const int IconPickerControlId = 0x41534842;
|
||||
|
||||
private readonly BuildableData buildable;
|
||||
private readonly SerializedObject so;
|
||||
private readonly Action onMetaChanged;
|
||||
|
||||
private VisualElement iconPreview;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Builds the full editor tree for a buildable. <paramref name="onMetaChanged"/> is raised when
|
||||
/// the display name or icon changes so the list can refresh that row.
|
||||
/// </summary>
|
||||
public BuildableEditorView(BuildableData buildable, Action onMetaChanged)
|
||||
{
|
||||
this.buildable = buildable;
|
||||
this.onMetaChanged = onMetaChanged;
|
||||
so = new SerializedObject(buildable);
|
||||
|
||||
Root = new VisualElement();
|
||||
Root.Add(BuildHero());
|
||||
Root.Add(BuildIdentityCard());
|
||||
Root.Add(BuildPrefabsCard());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hero
|
||||
|
||||
/// <summary>
|
||||
/// Builds the hero header: a large clickable icon preview, the editable display name and the
|
||||
/// "Buildable" badge. Name/icon changes notify the list so its row follows immediately.
|
||||
/// </summary>
|
||||
private VisualElement BuildHero()
|
||||
{
|
||||
VisualElement hero = new VisualElement();
|
||||
hero.AddToClassList("ash-hero");
|
||||
|
||||
iconPreview = new VisualElement();
|
||||
iconPreview.AddToClassList("ash-hero__icon");
|
||||
iconPreview.AddToClassList("ash-hero__icon--clickable");
|
||||
iconPreview.tooltip = "Click to change the buildable icon";
|
||||
iconPreview.RegisterCallback<ClickEvent>(_ => OpenIconPicker());
|
||||
UpdateIconPreview(buildable.Icon);
|
||||
hero.Add(iconPreview);
|
||||
|
||||
IMGUIContainer iconPickerProxy = new IMGUIContainer(HandleIconPickerCommands);
|
||||
iconPickerProxy.style.position = Position.Absolute;
|
||||
iconPickerProxy.style.width = 1;
|
||||
iconPickerProxy.style.height = 1;
|
||||
hero.Add(iconPickerProxy);
|
||||
|
||||
VisualElement info = new VisualElement();
|
||||
info.AddToClassList("ash-hero__info");
|
||||
|
||||
TextField nameField = new TextField { value = buildable.DisplayName };
|
||||
nameField.AddToClassList("ash-hero__name");
|
||||
nameField.BindProperty(so.FindProperty("displayName"));
|
||||
nameField.RegisterValueChangedCallback(_ => onMetaChanged?.Invoke());
|
||||
info.Add(AshwildUI.EditableNameRow(nameField));
|
||||
|
||||
VisualElement typeRow = new VisualElement();
|
||||
typeRow.AddToClassList("ash-hero__typerow");
|
||||
typeRow.Add(AshwildUI.Badge("Buildable", AshwildUI.BuildableColor));
|
||||
info.Add(typeRow);
|
||||
|
||||
hero.Add(info);
|
||||
return hero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the buildable's icon in the hero preview, or a neutral placeholder when none is set.
|
||||
/// </summary>
|
||||
private void UpdateIconPreview(Sprite sprite)
|
||||
{
|
||||
iconPreview.style.backgroundImage = sprite != null ? new StyleBackground(sprite) : new StyleBackground();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens Unity's sprite object picker, seeded with the current icon, so the designer can change
|
||||
/// the buildable icon by clicking the hero preview directly.
|
||||
/// </summary>
|
||||
private void OpenIconPicker()
|
||||
{
|
||||
EditorGUIUtility.ShowObjectPicker<Sprite>(buildable.Icon, false, string.Empty, IconPickerControlId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listens (through the hidden IMGUI proxy) for the picker selecting/closing on our control id
|
||||
/// and applies the chosen sprite live, so the hero preview and the list row update immediately.
|
||||
/// </summary>
|
||||
private void HandleIconPickerCommands()
|
||||
{
|
||||
Event evt = Event.current;
|
||||
if (evt == null || evt.type != EventType.ExecuteCommand) return;
|
||||
if (EditorGUIUtility.GetObjectPickerControlID() != IconPickerControlId) return;
|
||||
if (evt.commandName != "ObjectSelectorUpdated" && evt.commandName != "ObjectSelectorClosed") return;
|
||||
|
||||
AssignIcon(EditorGUIUtility.GetObjectPickerObject() as Sprite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the picked icon onto the asset (no-op when unchanged) and refreshes the hero preview
|
||||
/// and the list row.
|
||||
/// </summary>
|
||||
private void AssignIcon(Sprite sprite)
|
||||
{
|
||||
SerializedProperty iconProp = so.FindProperty("icon");
|
||||
if (iconProp.objectReferenceValue == sprite) return;
|
||||
|
||||
iconProp.objectReferenceValue = sprite;
|
||||
so.ApplyModifiedProperties();
|
||||
UpdateIconPreview(sprite);
|
||||
onMetaChanged?.Invoke();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cards
|
||||
|
||||
/// <summary>
|
||||
/// Identity card: the description shown on the menu card, plus the icon field (kept in sync
|
||||
/// with the hero preview and the list row when edited here).
|
||||
/// </summary>
|
||||
private VisualElement BuildIdentityCard()
|
||||
{
|
||||
VisualElement card = AshwildUI.Card("Identity");
|
||||
|
||||
TextField description = new TextField("Description") { multiline = true };
|
||||
description.AddToClassList("ash-description");
|
||||
description.BindProperty(so.FindProperty("description"));
|
||||
card.Add(description);
|
||||
|
||||
ObjectField icon = new ObjectField("Icon") { objectType = typeof(Sprite), allowSceneObjects = false };
|
||||
icon.BindProperty(so.FindProperty("icon"));
|
||||
icon.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
UpdateIconPreview(evt.newValue as Sprite);
|
||||
onMetaChanged?.Invoke();
|
||||
});
|
||||
card.Add(icon);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefabs card: the semi-transparent ghost spawned while positioning and the real structure
|
||||
/// spawned once placement is confirmed.
|
||||
/// </summary>
|
||||
private VisualElement BuildPrefabsCard()
|
||||
{
|
||||
VisualElement card = AshwildUI.Card("Prefabs");
|
||||
|
||||
ObjectField ghost = new ObjectField("Ghost Prefab") { objectType = typeof(GameObject), allowSceneObjects = false };
|
||||
ghost.BindProperty(so.FindProperty("ghostPrefab"));
|
||||
card.Add(ghost);
|
||||
|
||||
ObjectField built = new ObjectField("Built Prefab") { objectType = typeof(GameObject), allowSceneObjects = false };
|
||||
built.BindProperty(so.FindProperty("builtPrefab"));
|
||||
card.Add(built);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user