using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using Assets.PixelFantasy.Common.Scripts.CharacterScripts; using Assets.PixelFantasy.Common.Scripts.CollectionScripts; using UnityEditor; using UnityEngine; using UnityEngine.UI; namespace Assets.PixelFantasy.Common.Scripts.EditorScripts { public class CharacterEditor : MonoBehaviour { public SpriteCollection SpriteCollection; public List Layers; public CharacterBuilderBase CharacterBuilder; public Sprite EmptyIcon; public AudioSource AudioSource; public AudioClip EquipSound; public static event Action SliceTextureRequest = _ => {}; public static event Action CreateSpriteLibraryRequest = _ => { }; public void Start() { foreach (var layer in Layers) { if (layer.Controls) { if (layer.Default != "") { layer.Index = SpriteCollection.Layers.Single(i => i.Name == layer.Name).Textures.FindIndex(i => i.name == layer.Default); } else { layer.Index = -1; } layer.Content = SpriteCollection.Layers.Single(i => i.Name == layer.Name); layer.Controls.Dropdown.options = new List(); if (layer.CanBeEmpty) layer.Controls.Dropdown.options.Add(new Dropdown.OptionData("Empty", EmptyIcon)); layer.Controls.Dropdown.options.AddRange(layer.Content.Textures.Select(i => new Dropdown.OptionData(GetDisplayName(i.name), layer.Content.GetIcon(i)))); layer.Controls.Dropdown.value = -1; layer.Controls.Dropdown.value = layer.Index + (layer.CanBeEmpty ? 1 : 0); layer.Controls.Dropdown.onValueChanged.AddListener(value => SetIndex(layer, value)); layer.Controls.Prev.onClick.AddListener(() => Switch(layer, -1)); layer.Controls.Next.onClick.AddListener(() => Switch(layer, +1)); layer.Controls.Hide.onClick.AddListener(() => Hide(layer)); layer.Controls.Paint.onClick.AddListener(() => Paint(layer)); layer.Controls.Hue.onValueChanged.AddListener(value => Rebuild()); layer.Controls.Saturation.onValueChanged.AddListener(value => Rebuild()); layer.Controls.Brightness.onValueChanged.AddListener(value => Rebuild()); layer.Controls.OnSelectFixedColor = color => Repaint(layer, color); } } Rebuild(); } private void Rebuild() { var layers = Layers.ToDictionary(i => i.Name, i => i.SpriteData); CharacterBuilder.Head = layers["Head"]; CharacterBuilder.Ears = layers["Ears"]; CharacterBuilder.Eyes = layers["Eyes"]; CharacterBuilder.Body = layers["Body"]; CharacterBuilder.Hair = layers["Hair"]; CharacterBuilder.Armor = layers["Armor"]; CharacterBuilder.Helmet = layers["Helmet"]; CharacterBuilder.Weapon = layers["Weapon"]; CharacterBuilder.Firearm = layers["Firearm"]; CharacterBuilder.Shield = layers["Shield"]; CharacterBuilder.Cape = layers["Cape"]; CharacterBuilder.Back = layers["Back"]; CharacterBuilder.Mask = layers["Mask"]; CharacterBuilder.Horns = layers["Horns"]; CharacterBuilder.Rebuild(); if (AudioSource && EquipSound) { AudioSource.PlayOneShot(EquipSound, 0.5f); } } public void Hide(LayerEditor layer) { layer.Hidden = !layer.Hidden; Rebuild(); } public void Paint(LayerEditor layer) { #if UNITY_EDITOR ColorPicker.Open(layer.Color); ColorPicker.OnColorPicked = color => { layer.Color = color; Rebuild(); }; #endif } public void Repaint(LayerEditor layer, Color color) { layer.Color = color; if (layer.Name == "Body") { Layers.Single(i => i.Name == "Head").Color = color; Layers.Single(i => i.Name == "Ears").Color = color; } if (layer.Name == "Head") { Layers.Single(i => i.Name == "Ears").Color = color; } Rebuild(); } public void Preset(string preset) { var body = Layers.Single(i => i.Name == "Body"); var dropdown = body.Controls.Dropdown; var index = dropdown.options.FindIndex(i => i.text == GetDisplayName(preset)); body.Color = Color.white; if (index == -1) { dropdown.value = 0; } else if (index == dropdown.value) { dropdown.onValueChanged.Invoke(index); } else { dropdown.value = index; } Layers.Single(i => i.Name == "Body").Color = Color.white; Layers.Single(i => i.Name == "Head").Color = Color.white; Layers.Single(i => i.Name == "Ears").Color = Color.white; Layers.Single(i => i.Name == "Eyes").Color = Color.white; Layers.Single(i => i.Name == "Horns").Color = Color.white; } private void Switch(LayerEditor layer, int direction) { layer.Switch(direction); Rebuild(); } private LayerEditor _layer; private int _index; private void SetIndex(LayerEditor layer, int index) { if (layer == _layer && index == _index) return; _layer = layer; _index = index; if (layer.CanBeEmpty) index--; layer.SetIndex(index); var caption = layer.Controls.Dropdown.options[layer.Controls.Dropdown.value].text; if (layer.Name == "Body") { var head = Layers.Single(i => i.Name == "Head"); var ears = Layers.Single(i => i.Name == "Ears"); var eyes = Layers.Single(i => i.Name == "Eyes"); var hair = Layers.Single(i => i.Name == "Hair"); var horns = Layers.Single(i => i.Name == "Horns"); var headIndex = head.Controls.Dropdown.options.FindIndex(i => i.text == caption); var earsIndex = ears.Controls.Dropdown.options.FindIndex(i => i.text == caption); var eyesIndex = eyes.Controls.Dropdown.options.FindIndex(i => i.text == caption); var hornsIndex = horns.Controls.Dropdown.options.FindIndex(i => i.text == caption); if (headIndex == -1) headIndex = 0; if (earsIndex == -1) earsIndex = 0; if (eyesIndex == -1) eyesIndex = 0; if (hornsIndex == -1) hornsIndex = 0; head.Controls.Dropdown.value = headIndex; ears.Controls.Dropdown.value = earsIndex; eyes.Controls.Dropdown.value = eyesIndex; horns.Controls.Dropdown.value = hornsIndex; head.Color = layer.Color; ears.Color = layer.Color; if (caption != "Human") { hair.Controls.Dropdown.value = 0; } } else if (layer.Name == "Weapon" && index != -1) { Layers.Single(i => i.Name == "Firearm").Controls.Dropdown.value = -1; } else if (layer.Name == "Firearm" && index != -1) { Layers.Single(i => i.Name == "Weapon").Controls.Dropdown.value = -1; } Rebuild(); } private static string GetDisplayName(string fileName) { var displayName = Regex.Replace(fileName, @"\[\w+\]", ""); displayName = Regex.Replace(displayName, "([a-z])([A-Z])", "$1 $2"); return displayName.Trim(); } public void Reset() { CharacterBuilder.Reset(); } public void Randomize() { CharacterBuilder.Randomize(); } public void Save() { CharacterBuilder.Rebuild(forceMerge: true); var bytes = CharacterBuilder.Texture.EncodeToPNG(); CharacterBuilder.Rebuild(forceMerge: false); SaveFileDialog("Save as PNG", "SpriteSheet", "Image", ".png", bytes); } private void SaveFileDialog(string title, string fileName, string fileType, string extension, byte[] bytes) { #if UNITY_EDITOR var path = EditorUtility.SaveFilePanel(title, null, fileName + extension, extension.Replace(".", "")); if (path == "") return; File.WriteAllBytes(path, bytes); if (path.StartsWith(Application.dataPath)) { path = "Assets" + path.Substring(Application.dataPath.Length); AssetDatabase.Refresh(); var importer = (TextureImporter) AssetImporter.GetAtPath(path); importer.textureType = TextureImporterType.Sprite; importer.maxTextureSize = 2048; importer.SaveAndReimport(); AssetDatabase.Refresh(); SliceTextureRequest(path); if (EditorUtility.DisplayDialog("Success", $"Texture saved and sliced:\n{path}\n\nDo you want to create Sprite Library Asset for it?", "Yes", "No")) { CreateSpriteLibraryRequest(path); } } else { EditorUtility.DisplayDialog("Success", $"Texture saved:\n{path}\n\nTip: textures are automatically sliced when saving to Assets.", "OK"); } #elif UNITY_STANDALONE #if FILE_BROWSER StartCoroutine(SimpleFileBrowserForWindows.WindowsFileBrowser.SaveFile(title, "", fileName, fileType, extension, bytes, (success, p) => { })); #else Debug.LogWarning("Please import this asset: http://u3d.as/2QLg"); #endif #elif UNITY_WEBGL #if FILE_BROWSER SimpleFileBrowserForWebGL.WebFileBrowser.Download(fileName + extension, bytes); #else Debug.LogWarning("Please import this asset: http://u3d.as/2W52"); #endif #endif } } }