Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cosmetic changes #18

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Unity generated directories
/Library/
/Temp/

# Visual Studio cache directory
/.vs/

# Autogenerated VS/MD/Consulo solution and project files
*.csproj
*.sln
*.userprefs
Temp
Library
205 changes: 131 additions & 74 deletions Assets/Spriter2UnityDX/Editor/AnimationBuilder.cs

Large diffs are not rendered by default.

34 changes: 24 additions & 10 deletions Assets/Spriter2UnityDX/Editor/CustomEditors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,38 @@ private void OnEnable () {
}

// Get the sorting layer names
private string[] GetSortingLayerNames() {
var sortingLayers = typeof(InternalEditorUtility).GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
return (string[])sortingLayers.GetValue(null, new object[0]);
private string[] GetSortingLayerNames () {
var sortingLayers = typeof(InternalEditorUtility).GetProperty ("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
return (string[])sortingLayers.GetValue (null, new object[0]);
}

public override void OnInspectorGUI ()
{
public override void OnInspectorGUI () {
var changed = false;
var color = EditorGUILayout.ColorField ("Color", renderer.Color);
if (color != renderer.Color) {renderer.Color = color; changed = true;}
if (color != renderer.Color) {
renderer.Color = color;
changed = true;
}
var material = (Material)EditorGUILayout.ObjectField ("Material", renderer.Material, typeof(Material), false);
if (material != renderer.Material) {renderer.Material = material; changed = true;}
if (material != renderer.Material) {
renderer.Material = material;
changed = true;
}
var sortIndex = EditorGUILayout.Popup ("Sorting Layer", GetIndex (renderer.SortingLayerName), layerNames, GUILayout.ExpandWidth (true));
if (layerNames [sortIndex] != renderer.SortingLayerName) {renderer.SortingLayerName = layerNames[sortIndex]; changed = true;}
if (layerNames [sortIndex] != renderer.SortingLayerName) {
renderer.SortingLayerName = layerNames[sortIndex];
changed = true;
}
var sortingOrder = EditorGUILayout.IntField ("Order In Layer", renderer.SortingOrder);
if (sortingOrder != renderer.SortingOrder) {renderer.SortingOrder = sortingOrder; changed = true;}
if (sortingOrder != renderer.SortingOrder) {
renderer.SortingOrder = sortingOrder;
changed = true;
}
var applyZ = EditorGUILayout.Toggle ("Apply Spriter Z Order", renderer.ApplySpriterZOrder);
if (applyZ != renderer.ApplySpriterZOrder) {renderer.ApplySpriterZOrder = applyZ; changed = true;}
if (applyZ != renderer.ApplySpriterZOrder) {
renderer.ApplySpriterZOrder = applyZ;
changed = true;
}
if (changed) EditorUtility.SetDirty(renderer);
}

Expand Down
142 changes: 92 additions & 50 deletions Assets/Spriter2UnityDX/Editor/PrefabBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,80 +24,106 @@ public bool Build (ScmlObject obj, string scmlPath) {
//The process begins by loading up all the textures
var success = true;
var directory = Path.GetDirectoryName (scmlPath);
var folders = new Dictionary<int, IDictionary<int, Sprite>> (); //I find these slightly more useful than Lists because
foreach (var folder in obj.folders ) { //you can be 100% sure that the ids match
var files = folders [folder.id] = new Dictionary<int, Sprite> (); //And items can be added in any order
//I find these slightly more useful than Lists because
//you can be 100% sure that the ids match
//And items can be added in any order
var folders = new Dictionary<int, IDictionary<int, Sprite>> ();
foreach (var folder in obj.folders ) {
var files = folders [folder.id] = new Dictionary<int, Sprite> ();
foreach (var file in folder.files) {
var path = string.Format ("{0}/{1}", directory, file.name);
files [file.id] = GetSpriteAtPath (path, file, ref success);
}
} //The process ends here if any of the textures need to have their settings altered
if (!success) return false; //The process will be reattempted after the next import cycle
foreach (var entity in obj.entities) { //Now begins the real prefab build process
}
//The process ends here if any of the textures need to have their settings altered
//The process will be reattempted after the next import cycle
if (!success) return false;
//Now begins the real prefab build process
foreach (var entity in obj.entities) {
var prefabPath = string.Format ("{0}/{1}.prefab", directory, entity.name);
var prefab = (GameObject)AssetDatabase.LoadAssetAtPath (prefabPath, typeof(GameObject));
GameObject instance;
if (prefab == null) { //Creates an empty prefab if one doesn't already exists
//Creates an empty prefab if one doesn't already exists
//instantiates the prefab if it does exist
if (prefab == null) {
instance = new GameObject (entity.name);
prefab = PrefabUtility.CreatePrefab (prefabPath, instance, ReplacePrefabOptions.ConnectToPrefab);
ProcessingInfo.NewPrefabs.Add (prefab);
}
else {
instance = (GameObject)PrefabUtility.InstantiatePrefab (prefab); //instantiates the prefab if it does exist
instance = (GameObject)PrefabUtility.InstantiatePrefab (prefab);
ProcessingInfo.ModifiedPrefabs.Add (prefab);
}
try {
TryBuild (entity, prefab, instance, directory, prefabPath, folders);
}
catch (Exception e) {
DestroyImmediate (instance);
Debug.LogErrorFormat("Unable to build a prefab for '{0}'. Reason: {1}", entity.name, e);
Debug.LogErrorFormat ("Unable to build a prefab for '{0}'. Reason: {1}", entity.name, e);
}
}
return success;
}

private void TryBuild (Entity entity, GameObject prefab, GameObject instance, string directory, string prefabPath, IDictionary<int, IDictionary<int, Sprite>> folders) {
var controllerPath = string.Format ("{0}/{1}.controller", directory, entity.name);
var animator = instance.GetComponent<Animator> (); //Fetches the prefab's Animator
if (animator == null) animator = instance.AddComponent<Animator> (); //Or creates one if it doesn't exist
//Fetches the prefab's Animator
//Or creates one if it doesn't exist
var animator = instance.GetComponent<Animator> ();
if (animator == null) animator = instance.AddComponent<Animator> ();
AnimatorController controller = null;
if (animator.runtimeAnimatorController != null) { //The controller we use is hopefully the controller attached to the animator
controller = animator.runtimeAnimatorController as AnimatorController ?? //Or the one that's referenced by an OverrideController
//The controller we use is hopefully the controller attached to the animator
//Or the one that's referenced by an OverrideController
if (animator.runtimeAnimatorController != null) {
controller = animator.runtimeAnimatorController as AnimatorController ??
(AnimatorController)((AnimatorOverrideController)animator.runtimeAnimatorController).runtimeAnimatorController;
}
if (controller == null) { //Otherwise we have to check the AssetDatabase for our controller
//Otherwise we have to check the AssetDatabase for our controller
if (controller == null) {
controller = (AnimatorController)AssetDatabase.LoadAssetAtPath (controllerPath, typeof(AnimatorController));
//Or create a new one if it doesn't exist.
if (controller == null) {
controller = AnimatorController.CreateAnimatorControllerAtPath (controllerPath); //Or create a new one if it doesn't exist.
controller = AnimatorController.CreateAnimatorControllerAtPath (controllerPath);
ProcessingInfo.NewControllers.Add (controller);
}
animator.runtimeAnimatorController = controller;
}
var transforms = new Dictionary<string, Transform> (); //All of the bones and sprites, identified by TimeLine.name, because those are truly unique
transforms ["rootTransform"] = instance.transform; //The root GameObject needs to be part of this hierarchy as well
var defaultBones = new Dictionary<string, SpatialInfo> (); //These are basically the object states on the first frame of the first animation
var defaultSprites = new Dictionary<string, SpriteInfo> (); //They are used as control values in determining whether something has changed
//All of the bones and sprites, identified by TimeLine.name, because those are truly unique
//The root GameObject needs to be part of this hierarchy as well
//These are basically the object states on the first frame of the first animation
//They are used as control values in determining whether something has changed
var transforms = new Dictionary<string, Transform> ();
transforms ["rootTransform"] = instance.transform;
var defaultBones = new Dictionary<string, SpatialInfo> ();
var defaultSprites = new Dictionary<string, SpriteInfo> ();
var animBuilder = new AnimationBuilder (ProcessingInfo, folders, transforms, defaultBones, defaultSprites, prefabPath, controller);
var firstAnim = true; //The prefab's graphic will be determined by the first frame of the first animation
//The prefab's graphic will be determined by the first frame of the first animation
var firstAnim = true;
foreach (var animation in entity.animations) {
var timeLines = new Dictionary<int, TimeLine> ();
foreach (var timeLine in animation.timelines) //TimeLines hold all the critical data such as positioning and graphics used
//TimeLines hold all the critical data such as positioning and graphics used
foreach (var timeLine in animation.timelines)
timeLines [timeLine.id] = timeLine;
foreach (var key in animation.mainlineKeys) {
var parents = new Dictionary<int, string> (); //Parents are referenced by different IDs V_V
parents [-1] = "rootTransform"; //This is where "-1 == no parent" comes in handy
//Parents are referenced by different IDs V_V
//This is where "-1 == no parent" comes in handy
var parents = new Dictionary<int, string> ();
parents [-1] = "rootTransform";
var boneRefs = new Queue<Ref> (key.boneRefs ?? new Ref[0]);
while (boneRefs.Count > 0) {
var bone = boneRefs.Dequeue ();
var timeLine = timeLines [bone.timeline];
parents [bone.id] = timeLine.name;
if (!transforms.ContainsKey (timeLine.name)) { //We only need to go through this once, so ignore it if it's already in the dict
if (parents.ContainsKey (bone.parent)) { //If the parent cannot be found, it will probably be found later, so save it
//We only need to go through this once, so ignore it if it's already in the dict
if (!transforms.ContainsKey (timeLine.name)) {
//If the parent cannot be found, it will probably be found later, so save it
if (parents.ContainsKey (bone.parent)) {
var parentID = parents [bone.parent];
var parent = transforms [parentID];
var child = parent.Find (timeLine.name); //Try to find the child transform if it exists
if (child == null) { //Or create a new one
//Try to find the child transform if it exists
var child = parent.Find (timeLine.name);
//Or create a new one
if (child == null) {
child = new GameObject (timeLine.name).transform;
child.SetParent (parent);
}
Expand All @@ -117,7 +143,8 @@ private void TryBuild (Entity entity, GameObject prefab, GameObject instance, st
}
foreach (var oref in key.objectRefs) {
var timeLine = timeLines [oref.timeline];
if (!transforms.ContainsKey (timeLine.name)) { //Same as above
//Same as above
if (!transforms.ContainsKey (timeLine.name)) {
var parentID = parents [oref.parent];
var parent = transforms [parentID];
var child = parent.Find (timeLine.name);
Expand All @@ -126,9 +153,11 @@ private void TryBuild (Entity entity, GameObject prefab, GameObject instance, st
child.SetParent (parent);
}
transforms [timeLine.name] = child;
var swapper = child.GetComponent<TextureController> (); //Destroy the Sprite Swapper, we'll make a new one later
//Destroy the Sprite Swapper, we'll make a new one later
var swapper = child.GetComponent<TextureController> ();
if (swapper != null) DestroyImmediate (swapper);
var renderer = child.GetComponent<SpriteRenderer> (); //Get or create a Sprite Renderer
//Get or create a Sprite Renderer
var renderer = child.GetComponent<SpriteRenderer> ();
if (renderer == null) renderer = child.gameObject.AddComponent<SpriteRenderer> ();
var spriteInfo = defaultSprites [timeLine.name] = (SpriteInfo)ArrayUtility.Find (timeLine.keys, x => x.id == 0).info;
renderer.sprite = folders [spriteInfo.folder] [spriteInfo.file];
Expand All @@ -137,45 +166,58 @@ private void TryBuild (Entity entity, GameObject prefab, GameObject instance, st
defaultBones.TryGetValue (parentID, out parentInfo);
spriteInfo.Process (parentInfo);
}
child.localPosition = new Vector3 (spriteInfo.x, spriteInfo.y, oref.z_index); //Z-index helps determine draw order
child.localEulerAngles = new Vector3 (0f, 0f, spriteInfo.angle); //The reason I don't use layers or layer orders is because
child.localScale = new Vector3 (spriteInfo.scale_x, spriteInfo.scale_y, 1f); //There tend to be a LOT of body parts, it's better to treat
var color = renderer.color; //The entity as a single sprite for layer sorting purposes.
//Z-index helps determine draw
//The reason I don't use layers or layer orders is because
//There tend to be a LOT of body parts, it's better to treat
//The entity as a single sprite for layer sorting purposes.
child.localPosition = new Vector3 (spriteInfo.x, spriteInfo.y, oref.z_index);
child.localEulerAngles = new Vector3 (0f, 0f, spriteInfo.angle);
child.localScale = new Vector3 (spriteInfo.scale_x, spriteInfo.scale_y, 1f);
var color = renderer.color;
color.a = spriteInfo.a;
renderer.color = color;
if (!firstAnim) child.gameObject.SetActive (false); //Disable the GameObject if this isn't the first frame of the first animation
//Disable the GameObject if this isn't the first frame of the first animation
if (!firstAnim) child.gameObject.SetActive (false);
}
}
if (firstAnim) firstAnim = false;
}
try {
animBuilder.Build (animation, timeLines); //Builds the currently processed AnimationClip, see AnimationBuilder for more info
//Builds the currently processed AnimationClip, see AnimationBuilder for more info
animBuilder.Build (animation, timeLines);
}
catch (Exception e) {
Debug.LogErrorFormat ("Unable to build animation '{0}' for '{1}', reason: {2}", animation.name, entity.name, e);
}
}
if (instance.GetComponent<EntityRenderer> () == null) instance.AddComponent<EntityRenderer> (); //Adds an EntityRenderer if one is not already present
//Adds an EntityRenderer if one is not already present
if (instance.GetComponent<EntityRenderer> () == null) instance.AddComponent<EntityRenderer> ();
PrefabUtility.ReplacePrefab (instance, prefab, ReplacePrefabOptions.ConnectToPrefab);
DestroyImmediate (instance); //Apply the instance's changes to the prefab, then destroy the instance.
//Apply the instance's changes to the prefab, then destroy the instance.
DestroyImmediate (instance);
}

private IList<TextureImporter> InvalidImporters = new List<TextureImporter> (); //Importers in this list have already been processed and don't need to be processed again
//Importers in this list have already been processed and don't need to be processed again
private IList<TextureImporter> InvalidImporters = new List<TextureImporter> ();
private Sprite GetSpriteAtPath (string path, File file, ref bool success) {
var importer = TextureImporter.GetAtPath (path) as TextureImporter;
if (importer != null) { //If no TextureImporter exists, there's no texture to be found
if ((importer.textureType != TextureImporterType.Sprite || importer.spritePivot.x != file.pivot_x
|| importer.spritePivot.y != file.pivot_y || (ScmlImportOptions.options != null && importer.spritePixelsPerUnit != ScmlImportOptions.options.pixelsPerUnit)) && !InvalidImporters.Contains (importer)) {
if (success) success = false; //If the texture type isn't Sprite, or the pivot isn't set properly,
var settings = new TextureImporterSettings (); //set the texture type and pivot
importer.ReadTextureSettings (settings); //and make success false so the process can abort
settings.ApplyTextureType (TextureImporterType.Sprite, true); //after all the textures have been processed
//If no TextureImporter exists, there's no texture to be found
if (importer != null) {
//If the texture type isn't Sprite, or the pivot isn't set properly,
//set the texture type and pivot
//and make success false so the process can abort
//after all the textures have been processed
if ((importer.textureType != TextureImporterType.Sprite || importer.spritePivot.x != file.pivot_x
|| importer.spritePivot.y != file.pivot_y || (ScmlImportOptions.options != null && importer.spritePixelsPerUnit != ScmlImportOptions.options.pixelsPerUnit)) && !InvalidImporters.Contains (importer)) {
if (success) success = false;
var settings = new TextureImporterSettings ();
importer.ReadTextureSettings (settings);
settings.ApplyTextureType (TextureImporterType.Sprite, true);
settings.spriteAlignment = (int)SpriteAlignment.Custom;
settings.spritePivot = new Vector2 (file.pivot_x, file.pivot_y);
if(ScmlImportOptions.options != null)
{
settings.spritePixelsPerUnit = ScmlImportOptions.options.pixelsPerUnit;
}
if (ScmlImportOptions.options != null) {
settings.spritePixelsPerUnit = ScmlImportOptions.options.pixelsPerUnit;
}
importer.SetTextureSettings (settings);
importer.SaveAndReimport ();
InvalidImporters.Add (importer);
Expand Down
10 changes: 7 additions & 3 deletions Assets/Spriter2UnityDX/Editor/S2USettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ public static void Select () {
}
}

public enum AnimationImportOption : byte { NestedInPrefab, SeparateFolder }
public enum AnimationImportOption : byte {
NestedInPrefab,
SeparateFolder,
}

[CustomEditor (typeof(S2USettings))] public class SettingsEditor: Editor {
[CustomEditor (typeof(S2USettings))]
public class SettingsEditor: Editor {
private AnimationImportOption importStyle;

private void OnEnable () {
Expand All @@ -34,7 +38,7 @@ private void OnDisable () {

public override void OnInspectorGUI () {
EditorGUI.BeginChangeCheck ();
var label = new GUIContent ("Animation Import Style",
var label = new GUIContent ("Animation Import Style",
"By default, animations are nested into the generated prefab. Change this option to instead place animations into a separate folder.");
importStyle = (AnimationImportOption)EditorGUILayout.EnumPopup (label, importStyle);
if (EditorGUI.EndChangeCheck ()) S2USettings.ImportStyle = importStyle;
Expand Down
Loading