/** * The MIT License (MIT) * * Copyright (c) 2012-2017 DragonBones team and other contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace DragonBones { /// /// The slots sorting mode /// /// DragonBones 4.5 /// en_US /// /// /// 插槽排序模式 /// /// DragonBones 4.5 /// zh_CN public enum SortingMode { /// /// Sort by Z values /// /// DragonBones 4.5 /// en_US /// /// /// 按照插槽显示对象的z值排序 /// /// DragonBones 4.5 /// zh_CN SortByZ, /// /// Renderer's order within a sorting layer. /// /// DragonBones 4.5 /// en_US /// /// /// 在同一层sorting layer中插槽按照sortingOrder排序 /// /// DragonBones 4.5 /// zh_CN SortByOrder } /// [ExecuteInEditMode, DisallowMultipleComponent] public class UnityArmatureComponent : DragonBoneEventDispatcher, IArmatureProxy { public const int ORDER_SPACE = 10; /// public UnityDragonBonesData unityData = null; /// public string armatureName = null; /// /// Is it the UGUI model? /// /// DragonBones 4.5 /// en_US /// /// /// 是否是UGUI模式 /// /// DragonBones 4.5 /// zh_CN public bool isUGUI = false; public bool debugDraw = false; internal readonly ColorTransform _colorTransform = new ColorTransform(); /// public string animationName = null; /// private bool _disposeProxy = true; /// internal Armature _armature = null; [Tooltip("0 : Loop")] [Range(0, 100)] [SerializeField] protected int _playTimes = 0; [Range(-2f, 2f)] [SerializeField] protected float _timeScale = 1.0f; [SerializeField] internal SortingMode _sortingMode = SortingMode.SortByZ; [SerializeField] internal string _sortingLayerName = "Default"; [SerializeField] internal int _sortingOrder = 0; [SerializeField] internal float _zSpace = 0.0f; [SerializeField] protected bool _flipX = false; [SerializeField] protected bool _flipY = false; //default open combineMeshs [SerializeField] protected bool _closeCombineMeshs; private bool _hasSortingGroup = false; private Material _debugDrawer; // internal int _armatureZ; /// public void DBClear() { if (this._armature != null) { this._armature = null; if (this._disposeProxy) { try { var go = gameObject; UnityFactoryHelper.DestroyUnityObject(gameObject); } catch (System.Exception) { } } } this.unityData = null; this.armatureName = null; this.animationName = null; this.isUGUI = false; this.debugDraw = false; this._disposeProxy = true; this._armature = null; this._colorTransform.Identity(); this._sortingMode = SortingMode.SortByZ; this._sortingLayerName = "Default"; this._sortingOrder = 0; this._playTimes = 0; this._timeScale = 1.0f; this._zSpace = 0.0f; this._flipX = false; this._flipY = false; this._hasSortingGroup = false; this._debugDrawer = null; this._armatureZ = 0; this._closeCombineMeshs = false; } /// public void DBInit(Armature armature) { this._armature = armature; } public void DBUpdate() { } void CreateLineMaterial() { if (!_debugDrawer) { // Unity has a built-in shader that is useful for drawing // simple colored things. Shader shader = Shader.Find("Hidden/Internal-Colored"); _debugDrawer = new Material(shader); _debugDrawer.hideFlags = HideFlags.HideAndDontSave; // Turn on alpha blending _debugDrawer.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); _debugDrawer.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); // Turn backface culling off _debugDrawer.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off); // Turn off depth writes _debugDrawer.SetInt("_ZWrite", 0); } } void OnRenderObject() { var drawed = DragonBones.debugDraw || this.debugDraw; if (drawed) { Color boneLineColor = new Color(0.0f, 1.0f, 1.0f, 0.7f); Color boundingBoxLineColor = new Color(1.0f, 0.0f, 1.0f, 1.0f); CreateLineMaterial(); // Apply the line material _debugDrawer.SetPass(0); GL.PushMatrix(); // Set transformation matrix for drawing to // match our transform GL.MultMatrix(transform.localToWorldMatrix); // var bones = this._armature.GetBones(); var offset = 0.02f; // draw bone line for (int i = 0; i < bones.Count; i++) { var bone = bones[i]; var boneLength = System.Math.Max(bone.boneData.length, offset); var startPos = new Vector3(bone.globalTransformMatrix.tx, bone.globalTransformMatrix.ty, 0.0f); var endPos = new Vector3(bone.globalTransformMatrix.a * boneLength, bone.globalTransformMatrix.b * boneLength, 0.0f) + startPos; var torwardDir = (startPos - endPos).normalized; var leftStartPos = Quaternion.AngleAxis(90, Vector3.forward) * torwardDir * offset + startPos; var rightStartPos = Quaternion.AngleAxis(-90, Vector3.forward) * torwardDir * offset + startPos; var newStartPos = startPos + torwardDir * offset; // GL.Begin(GL.LINES); GL.Color(boneLineColor); GL.Vertex(leftStartPos); GL.Vertex(rightStartPos); GL.End(); GL.Begin(GL.LINES); GL.Color(boneLineColor); GL.Vertex(newStartPos); GL.Vertex(endPos); GL.End(); } // draw boundingBox Point result = new Point(); var slots = this._armature.GetSlots(); for (int i = 0; i < slots.Count; i++) { var slot = slots[i] as UnitySlot; var boundingBoxData = slot.boundingBoxData; if (boundingBoxData == null) { continue; } var bone = slot.parent; slot.UpdateTransformAndMatrix(); slot.UpdateGlobalTransform(); var tx = slot.globalTransformMatrix.tx; var ty = slot.globalTransformMatrix.ty; var boundingBoxWidth = boundingBoxData.width; var boundingBoxHeight = boundingBoxData.height; // switch (boundingBoxData.type) { case BoundingBoxType.Rectangle: { // #if UNITY_5_6_OR_NEWER GL.Begin(GL.LINE_STRIP); #else GL.Begin(GL.LINES); #endif GL.Color(boundingBoxLineColor); var leftTopPos = new Vector3(tx - boundingBoxWidth * 0.5f, ty + boundingBoxHeight * 0.5f, 0.0f); var leftBottomPos = new Vector3(tx - boundingBoxWidth * 0.5f, ty - boundingBoxHeight * 0.5f, 0.0f); var rightTopPos = new Vector3(tx + boundingBoxWidth * 0.5f, ty + boundingBoxHeight * 0.5f, 0.0f); var rightBottomPos = new Vector3(tx + boundingBoxWidth * 0.5f, ty - boundingBoxHeight * 0.5f, 0.0f); GL.Vertex(leftTopPos); GL.Vertex(rightTopPos); GL.Vertex(rightBottomPos); GL.Vertex(leftBottomPos); GL.Vertex(leftTopPos); GL.End(); } break; case BoundingBoxType.Ellipse: { } break; case BoundingBoxType.Polygon: { var vertices = (boundingBoxData as PolygonBoundingBoxData).vertices; #if UNITY_5_6_OR_NEWER GL.Begin(GL.LINE_STRIP); #else GL.Begin(GL.LINES); #endif GL.Color(boundingBoxLineColor); for (var j = 0; j < vertices.Count; j += 2) { slot.globalTransformMatrix.TransformPoint(vertices[j], vertices[j + 1], result); GL.Vertex3(result.x, result.y, 0.0f); } slot.globalTransformMatrix.TransformPoint(vertices[0], vertices[1], result); GL.Vertex3(result.x, result.y, 0.0f); GL.End(); } break; default: break; } } GL.PopMatrix(); } } /// public void Dispose(bool disposeProxy = true) { _disposeProxy = disposeProxy; if (_armature != null) { _armature.Dispose(); } } /// /// Get the Armature. /// /// /// DragonBones 4.5 /// en_US /// /// 获取骨架。 /// /// /// DragonBones 4.5 /// zh_CN public Armature armature { get { return _armature; } } /// /// Get the animation player /// /// /// DragonBones 4.5 /// en_US /// /// 获取动画播放器。 /// /// /// DragonBones 4.5 /// zh_CN public new AnimationDB animation { get { return _armature != null ? _armature.animation : null; } } /// /// The slots sorting mode /// /// DragonBones 4.5 /// en_US /// /// /// 插槽排序模式 /// /// DragonBones 4.5 /// zh_CN public SortingMode sortingMode { get { return _sortingMode; } set { if (_sortingMode == value) { return; } #if UNITY_5_6_OR_NEWER var isWarning = false; #else var isWarning = value == SortingMode.SortByOrder; #endif if (isWarning) { LogHelper.LogWarning("SortingMode.SortByOrder is userd by Unity 5.6 or highter only."); return; } _sortingMode = value; // #if UNITY_5_6_OR_NEWER if (_sortingMode == SortingMode.SortByOrder) { _sortingGroup = GetComponent(); if (_sortingGroup == null) { _sortingGroup = gameObject.AddComponent(); } } else { _sortingGroup = GetComponent(); if (_sortingGroup != null) { DestroyImmediate(_sortingGroup); } } #endif _UpdateSlotsSorting(); } } /// /// Name of the Renderer's sorting layer. /// /// DragonBones 4.5 /// en_US /// /// /// sorting layer名称。 /// /// DragonBones 4.5 /// zh_CN public string sortingLayerName { get { return _sortingLayerName; } set { if (_sortingLayerName == value) { //return; } _sortingLayerName = value; _UpdateSlotsSorting(); } } /// /// Renderer's order within a sorting layer. /// /// DragonBones 4.5 /// en_US /// /// /// 插槽按照sortingOrder在同一层sorting layer中排序 /// /// DragonBones 4.5 /// zh_CN public int sortingOrder { get { return _sortingOrder; } set { if (_sortingOrder == value) { //return; } _sortingOrder = value; _UpdateSlotsSorting(); } } /// /// The Z axis spacing of slot display objects /// /// DragonBones 4.5 /// zh_CN /// /// /// 插槽显示对象的z轴间隔 /// /// DragonBones 4.5 /// zh_CN public float zSpace { get { return _zSpace; } set { if (value < 0.0f || float.IsNaN(value)) { value = 0.0f; } if (_zSpace == value) { return; } _zSpace = value; _UpdateSlotsSorting(); } } /// /// - The armature color. /// /// DragonBones 4.5 /// en_US /// /// /// - 骨架的颜色。 /// /// DragonBones 4.5 /// zh_CN public ColorTransform color { get { return this._colorTransform; } set { this._colorTransform.CopyFrom(value); foreach (var slot in this._armature.GetSlots()) { slot._colorDirty = true; } } } #if UNITY_5_6_OR_NEWER internal UnityEngine.Rendering.SortingGroup _sortingGroup; public UnityEngine.Rendering.SortingGroup sortingGroup { get { return _sortingGroup; } } private void _UpdateSortingGroup() { //发现骨架有SortingGroup,那么子骨架也都加上,反之删除 _sortingGroup = GetComponent(); if (_sortingGroup != null) { _sortingMode = SortingMode.SortByOrder; _sortingLayerName = _sortingGroup.sortingLayerName; _sortingOrder = _sortingGroup.sortingOrder; foreach (UnitySlot slot in _armature.GetSlots()) { if (slot.childArmature != null) { var childArmatureProxy = slot.childArmature.proxy as UnityArmatureComponent; childArmatureProxy._sortingGroup = childArmatureProxy.GetComponent(); if (childArmatureProxy._sortingGroup == null) { childArmatureProxy._sortingGroup = childArmatureProxy.gameObject.AddComponent(); } childArmatureProxy._sortingGroup.sortingLayerName = _sortingLayerName; childArmatureProxy._sortingGroup.sortingOrder = _sortingOrder; } } } else { _sortingMode = SortingMode.SortByZ; foreach (UnitySlot slot in _armature.GetSlots()) { if (slot.childArmature != null) { var childArmatureProxy = slot.childArmature.proxy as UnityArmatureComponent; childArmatureProxy._sortingGroup = childArmatureProxy.GetComponent(); if (childArmatureProxy._sortingGroup != null) { DestroyImmediate(childArmatureProxy._sortingGroup); } } } } #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif _UpdateSlotsSorting(); } #endif private void _UpdateSlotsSorting() { if (_armature == null) { return; } if (!isUGUI) { #if UNITY_5_6_OR_NEWER if (_sortingGroup) { _sortingMode = SortingMode.SortByOrder; _sortingGroup.sortingLayerName = _sortingLayerName; _sortingGroup.sortingOrder = _sortingOrder; #if UNITY_EDITOR if (!Application.isPlaying) { EditorUtility.SetDirty(_sortingGroup); } #endif } #endif } // foreach (UnitySlot slot in _armature.GetSlots()) { var display = slot._renderDisplay; if (display == null) { continue; } slot._SetZorder(new Vector3(display.transform.localPosition.x, display.transform.localPosition.y, -slot._zOrder * (_zSpace + 0.001f))); if (slot.childArmature != null) { (slot.childArmature.proxy as UnityArmatureComponent)._UpdateSlotsSorting(); } #if UNITY_EDITOR if (!Application.isPlaying && slot.meshRenderer != null) { EditorUtility.SetDirty(slot.meshRenderer); } #endif } } #if UNITY_EDITOR private bool _IsPrefab() { return PrefabUtility.GetCorrespondingObjectFromSource(gameObject) == null && PrefabUtility.GetCorrespondingObjectFromSource(gameObject) != null; } #endif /// void Awake() { #if UNITY_EDITOR if (_IsPrefab()) { return; } #endif if (unityData != null && unityData.dragonBonesJSON != null && unityData.textureAtlas != null) { var dragonBonesData = UnityFactory.factory.LoadData(unityData, isUGUI); if (dragonBonesData != null && !string.IsNullOrEmpty(armatureName)) { UnityFactory.factory.BuildArmatureComponent(armatureName, unityData.dataName, null, null, gameObject, isUGUI); } } if (_armature != null) { #if UNITY_5_6_OR_NEWER if (!isUGUI) { _sortingGroup = GetComponent(); } #endif _UpdateSlotsSorting(); _armature.flipX = _flipX; _armature.flipY = _flipY; _armature.animation.timeScale = _timeScale; if (!string.IsNullOrEmpty(animationName)) { _armature.animation.Play(animationName, _playTimes); } } } void Start() { // this._closeCombineMeshs = true; //默认开启合并 if (this._closeCombineMeshs) { this.CloseCombineMeshs(); } else { this.OpenCombineMeshs(); } } void LateUpdate() { if (_armature == null) { return; } _flipX = _armature.flipX; _flipY = _armature.flipY; #if UNITY_5_6_OR_NEWER var hasSortingGroup = GetComponent() != null; if (hasSortingGroup != _hasSortingGroup) { _hasSortingGroup = hasSortingGroup; _UpdateSortingGroup(); } #endif } /// void OnDestroy() { if (_armature != null) { var armature = _armature; _armature = null; armature.Dispose(); if (!Application.isPlaying) { UnityFactory.factory._dragonBones.AdvanceTime(0.0f); } } _disposeProxy = true; _armature = null; } private void OpenCombineMeshs() { if (this.isUGUI) { return; } // var cm = gameObject.GetComponent(); if (cm == null) { cm = gameObject.AddComponent(); } // if (this._armature == null) { return; } var slots = this._armature.GetSlots(); foreach (var slot in slots) { if (slot.childArmature != null) { (slot.childArmature.proxy as UnityArmatureComponent).OpenCombineMeshs(); } } } public void CloseCombineMeshs() { this._closeCombineMeshs = true; // var cm = gameObject.GetComponent(); if (cm != null) { DestroyImmediate(cm); } if (this._armature == null) { return; } // var slots = this._armature.GetSlots(); foreach (var slot in slots) { if (slot.childArmature != null) { (slot.childArmature.proxy as UnityArmatureComponent).CloseCombineMeshs(); } } } } }