diff --git a/CommunityEntity.UI.Draggable.cs b/CommunityEntity.UI.Draggable.cs new file mode 100644 index 0000000..606c0e6 --- /dev/null +++ b/CommunityEntity.UI.Draggable.cs @@ -0,0 +1,493 @@ +using Object = UnityEngine.Object; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.EventSystems; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Facepunch; +using Facepunch.Extend; +using System.IO; + +#if CLIENT + +public partial class CommunityEntity +{ + + public class Draggable : UIBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IDropHandler { + + //reusable for world corners + public static Vector3[] corners = new Vector3[4]; + + #region Config + + // if the draggable should be allowed to be dragged out of the parent's bounds + public bool limitToParent = false; + // how far the draggable should be allowed to be dragged, -1 to disable + public float maxDistance = -1f; + public float scaledMaxDistance => maxDistance * rt.lossyScale.x; + // if the Draggable should be allowed to swap places with other draggables + public bool allowSwapping = false; + // if 2 Draggables get swapped, should their anchors get swapped aswell? + public bool swapAnchors = false; + // if false, the draggable will return to its anchor when dropped unless swapped with another draggable or parented to a slot + public bool dropAnywhere = true; + // the alpha the group should have while being dragged + public float dragAlpha = 1f; + // the filter tag to use when interacting with slots + public string filter = null; + // this setting allows us to somewhat customize what parent will be used for the limiting parent + public int parentLimitIndex = 1; + // used to add additional padding to the parent bounds check + public Vector2 parentPadding = Vector2.zero; + // what type of position should be sent back + public PositionSendType positionRPC; + // if true, the draggable will not return to its orignal position in the hirarchy, and will instead stay at the front of the dragParent + public bool keepOnTop = false; + + public Vector2 anchorOffset = Vector2.zero; + + #endregion + + #region Values + + // references to components + public CanvasGroup canvasGroup; + public RectTransform rt; + + // transform references + public Transform dragParent => (limitToParent ? limitParent : canvas); + public RectTransform limitParent; // for the keeping it within bounds + public Transform realParent; // the parent when its not being dragged + public Transform canvas; // the first canvas this is in, gets parented to it while getting dragged + public int index; // the original sibling index. used to re-insert the draggable in the correct place in its hirarchy + + // the world rect of the limitParent + public Rect parentWorldRect; + private (Vector3, Vector3) _scalePosAtLastCache; // the scale & position when this was last cached, to check if it needs to be re-cached + + // a shadow object used to hold the draggable's initial position, this object's RectTransform matches the anchormin/max & offsetmin/max of the draggable + // this keeps the initial position aligned to the parent after resizing occurs, regardless of if offsets or anchors are used + public GameObject anchorObj; + public Vector2 anchor => (Vector2)anchorObj.transform.position; + + // use to return the draggable if dropAnywhere is false, other scripts may set this value in their OnDrop calls + public Vector2 lastDropPosition; + public Vector2 offset; // distance the panel has been dragged from its anchor + + // a reference to the parent slot if inside of one + public Slot slot; + + // set by other Scripts if the position was set, in those cases the script is responsible for sending the appropriate RPC + public bool wasSnapped = false; + + private bool _initialized; + + // callbacks + string name; + public Action onDragCallback; + public Action onDropCallback; + + #endregion + + #region Core + + // call to initialize the Draggable, marking it as ready + public void Init(){ + // setup values + rt = (transform as RectTransform); + canvasGroup = GetComponent(); + canvas = GetComponentInParent().transform; + realParent = rt.parent; + index = rt.GetSiblingIndex(); + + name = gameObject.name; + + // bounds setup + FindParentLimit(); + + // anchor setup + if(anchorObj == null) + CreateAnchor(); + lastDropPosition = anchor; + + _initialized = true; + } + + public void OnDestroy(){ + if(anchorObj != null) + UnityEngine.Object.Destroy(anchorObj); + } + + public void OnBeginDrag(PointerEventData eventData) + { + if(!_initialized) + return; + + if(ShouldDie()) + return; + + TryRefreshParentBounds(); + + // set this again incase the game resizes since the last time this has been dropped + lastDropPosition = rt.position; + // center the draggable onto the mouse + var mousePos = eventData.pointerCurrentRaycast.screenPosition; + if(limitToParent){ + // ensure parent limits arent breached + LimitToParent(mousePos - lastDropPosition); + } else { + rt.position = mousePos; + } + offset = mousePos - anchor; + + + canvasGroup.blocksRaycasts = false; + canvasGroup.alpha = dragAlpha; + realParent = rt.parent; + rt.SetParent(dragParent); + if(limitToParent) + rt.SetAsLastSibling(); // because chances are we're already parented to it + + onDragCallback?.Invoke(name); + } + + public void OnDrag(PointerEventData eventData) + { + if(!_initialized) + return; + // set the offset after scaling + offset += eventData.delta; + + // use distance constraint + if(maxDistance > 0f){ + LimitToRange(); + return; + } + + // use parent constraint + if(limitToParent){ + LimitToParent(eventData.delta); + return; + } + + // no constraints + rt.position = anchor + offset; + } + + public void OnEndDrag(PointerEventData eventData) + { + if(!_initialized) + return; + + if(ShouldDie()) + return; + + if(!wasSnapped) + SendDragRPC(); + + wasSnapped = false; + + canvasGroup.blocksRaycasts = true; + canvasGroup.alpha = 1f; + if(!keepOnTop){ + rt.SetParent(realParent); + rt.SetSiblingIndex(index); + } + onDropCallback?.Invoke(name); + + if(!dropAnywhere){ + rt.position = lastDropPosition; + offset = lastDropPosition - anchor; + return; + } + + lastDropPosition = rt.position; + } + + // to support swapping + public void OnDrop(PointerEventData eventData) + { + if(!_initialized) + return; + + if(ShouldDie()) + return; + + if(!allowSwapping) + return; + + // if this panel is in a slot, let the slot handle the matching & potential swapping + if(slot != null){ + // resends the event to the parent and up + ExecuteEvents.ExecuteHierarchy(transform.parent.gameObject, eventData, ExecuteEvents.dropHandler); + return; + } + + var draggedObj = eventData.pointerDrag.GetComponent(); + if(draggedObj == null) + return; + + // prevent sending the DragRPC regardless. because the player intended to swap it, not drag it. + if(!draggedObj.dropAnywhere) + draggedObj.wasSnapped = true; + + if(!draggedObj.allowSwapping) + return; + + // if the 2 objects are on seperate canvases, dont swap + if(draggedObj.canvas != canvas) + return; + + // if the draggable is in a slot i dont fit inside of + if(draggedObj.slot != null && !Slot.FitsIntoSlot(this, draggedObj.slot)) + return; + + // cant swap because the draggable's position is too far away + if(scaledMaxDistance > 0f && Vector2.Distance(draggedObj.lastDropPosition, anchor) > scaledMaxDistance) + return; + + // if swapping would violate the draggable's constraints + if(draggedObj.limitToParent && !draggedObj.parentWorldRect.Contains(draggedObj.lastDropPosition)) + return; + + // incase a resize occured + TryRefreshParentBounds(); + + // if swapping would violate our own's constraints + if(limitToParent && !parentWorldRect.Contains(draggedObj.lastDropPosition)) + return; + + Draggable.Swap(draggedObj, this); + } + + #endregion + + #region helpers + + // checks if the distance dragged is larger than maxDistance & limits the position if so + private void LimitToRange(){ + if(maxDistance < 0f) + return; + + if(Vector2.Distance(offset, Vector2.zero) <= scaledMaxDistance) + rt.position = anchor + offset; + else + rt.position = anchor + (offset.normalized * scaledMaxDistance); + } + + // compares world rects to ensure the object stays within the parent + private void LimitToParent(Vector2 delta) + { + if (!limitToParent) + return; + + var p = parentWorldRect; + var c = GetWorldRect(rt); + + var mousePos = anchor + offset; + float paddingX = (c.size.x / 2); + float paddingY = (c.size.y / 2); + rt.position = ConfineToRect(p, mousePos, new Vector2(parentPadding.x + (c.size.x / 2), parentPadding.y + (c.size.y / 2))); + } + + // returns the position after confining it to the rect's bounds with the provided padding respected + public static Vector2 ConfineToRect(Rect rect, Vector2 position, Vector2 padding) + { + Vector2 size = rect.size; + Vector2 center = rect.center; + // if x is outside of the rect's x, set x to the edge of the rect & apply padding + if ((position.x - padding.x) < rect.xMin) + position.x = center.x - ((size.x / 2) - padding.x); + else if ((position.x + padding.x) >= rect.xMax) + { + position.x = center.x + ((size.x / 2) - padding.x); + } + // same with y + if ((position.y - padding.y) < rect.yMin) + position.y = center.y - ((size.y / 2) - padding.y); + else if ((position.y + padding.y) >= rect.yMax) + { + position.y = center.y + ((size.y / 2) - padding.y); + } + + return position; + } + + // add a gameobject to reference as the anchor position, this makes the anchor position resizing proof + private void CreateAnchor(){ + anchorObj = new GameObject("Shadow Anchor", typeof(RectTransform)); + var anchorRT = (anchorObj.transform as RectTransform); + anchorRT.SetParent(limitParent); + anchorRT.anchorMin = rt.anchorMin; + anchorRT.anchorMax = rt.offsetMax; + anchorRT.offsetMin = rt.offsetMin; + anchorRT.offsetMax = rt.offsetMax; + anchorRT.localPosition = limitParent.InverseTransformPoint(rt.position); + if(anchorOffset != Vector2.zero){ + anchorRT.offsetMin = new Vector2(anchorRT.offsetMin.x + anchorOffset.x, anchorRT.offsetMin.y + anchorOffset.y); + anchorRT.offsetMax = new Vector2(anchorRT.offsetMax.x + anchorOffset.x, anchorRT.offsetMax.y + anchorOffset.y); + } + } + + // finds the parent to use as a limit based on the parentLimitIndex setting + private void FindParentLimit(){ + limitParent = rt; + if(parentLimitIndex < 1){ + parentLimitIndex = 1; + } + for(int i = 0; i < parentLimitIndex; i++){ + limitParent = TryGetRectParent(limitParent); + Slot potentialSlot = limitParent.GetComponent(); + if(potentialSlot){ + // only set our parent as the slot if its actually the first one we encounter + if(slot == null){ + slot = potentialSlot; + slot.content = this; + } + // always skip slots when looking for the limitParent + limitParent = TryGetRectParent(limitParent); + } + } + // force a refresh + _scalePosAtLastCache = (Vector3.zero, Vector3.zero); + TryRefreshParentBounds(); + + // returns parent if its a rectTransform. this may not be the case if the parent is a root layer + static RectTransform TryGetRectParent(RectTransform current){ + var potentialParent = (current.parent as RectTransform); + if(potentialParent != null) + return potentialParent; + + return current; + } + } + + // check if this draggable should die, this covers if the real parent gets destroyed while this object is detached from it + public bool ShouldDie(){ + if(realParent.gameObject != null) + return false; + + UnityEngine.Object.Destroy(gameObject); + + return true; + } + + // sets the appropiate transform index + public void SetIndex(int index){ + this.index = index; + rt.SetSiblingIndex(index); + } + // re-caches the parent's world rect + public void TryRefreshParentBounds(){ + var current = (limitParent.lossyScale, limitParent.position); + if(current == _scalePosAtLastCache) + return; + + if(limitToParent) + parentWorldRect = GetWorldRect(limitParent); + + _scalePosAtLastCache = current; + } + + // used via the json API + public void MoveToAnchor(){ + rt.position = anchor; + lastDropPosition = rt.position; + offset = Vector2.zero; + } + + // used via the json API + public void RebuildAnchor(){ + UnityEngine.Object.Destroy(anchorObj); + CreateAnchor(); + } + + public Vector2 PositionForRPC(){ + Vector2 pos = rt.position; + Rect parent = parentWorldRect; + return positionRPC switch{ + PositionSendType.NormalizedScreen => new Vector2(pos.x / Screen.width, 1 - (pos.y / Screen.height)), + PositionSendType.NormalizedParent => new Vector2((pos.x - parent.xMin) / parent.width, (pos.y - parent.yMin) / parent.height), + PositionSendType.Relative => (pos - lastDropPosition) / rt.lossyScale, + PositionSendType.RelativeAnchor => (pos - anchor) / rt.lossyScale, + }; + } + // packetsize go brrrr + public void SendDragRPC(){ + ClientInstance.ServerRPC("DragRPC", gameObject.name, PositionForRPC(), (byte)positionRPC); + } + + // the same as the extension method, but without the allocation + public Rect GetWorldRect(RectTransform transform){ + transform.GetWorldCorners(corners); + return new Rect(corners[0], corners[2] - corners[0]); + } + + // packetsize go brrrr + public static void SendDropRPC(string draggedName, string draggedSlot, string swappedName, string swappedSlot){ + ClientInstance.ServerRPC("DropRPC", draggedName, draggedSlot, swappedName, swappedSlot); + } + + public static void Swap(Draggable from, Draggable to){ + // set this incase a resize occured since the last time this got dragged + to.lastDropPosition = to.rt.position; + + // get variables of draggable + var oldParent = from.realParent; + var oldIndex = from.index; + var oldPosition = from.lastDropPosition; + var oldAnchor = from.anchor; + var oldAnchorObj = from.anchorObj; + var oldAnchorParent = from.anchorObj.transform.parent; + var oldSlot = from.slot; + + // update the draggable + from.lastDropPosition = to.lastDropPosition; + from.rt.position = to.lastDropPosition; + from.realParent = to.realParent; + //from.rt.SetParent(to.realParent); // probably not needed because the from object should always be in drag mode + from.SetIndex(to.index); + if(from.swapAnchors){ + from.anchorObj = to.anchorObj; + to.anchorObj.transform.SetParent(from.anchorObj.transform.parent); + } + from.offset = from.lastDropPosition - from.anchor; + if(from.slot){ + from.slot.content = null; + from.slot = to.slot; + if(from.slot) + from.slot.content = from; + } + + // update this panel + to.lastDropPosition = oldPosition; + to.rt.position = oldPosition; + to.rt.SetParent(oldParent); + to.realParent = oldParent; + to.SetIndex(oldIndex); + if(to.swapAnchors){ + to.anchorObj = oldAnchorObj; + to.anchorObj.transform.SetParent(oldAnchorParent); + } + to.offset = to.lastDropPosition - to.anchor; + if(oldSlot){ + to.slot = oldSlot; + oldSlot.content = to; + } + from.wasSnapped = true; + SendDropRPC(from.gameObject.name, from.slot?.gameObject.name, to.gameObject.name, to.slot?.gameObject.name); + } + + #endregion + + public enum PositionSendType : byte{ + NormalizedScreen, + NormalizedParent, + Relative, + RelativeAnchor + } + } +} +#endif diff --git a/CommunityEntity.UI.Slot.cs b/CommunityEntity.UI.Slot.cs new file mode 100644 index 0000000..6945195 --- /dev/null +++ b/CommunityEntity.UI.Slot.cs @@ -0,0 +1,128 @@ +using Object = UnityEngine.Object; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.EventSystems; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Facepunch; +using Facepunch.Extend; +using System.IO; + +#if CLIENT + +public partial class CommunityEntity +{ + + public class Slot : UIBehaviour, IDropHandler { + + + #region Config + + // the filter tag for the slot. if both Draggable & slot have a filter tag that dont match the slot is denied + public string filter = null; + + #endregion + + #region Values + + public Draggable content; + + public Transform canvas; + + private bool _initialized; + + #endregion + + #region Core + + // call to initialize the Draggable, marking it as ready + public void Init(){ + content = GetComponentInChildren(); + canvas = GetComponentInParent().transform; + + _initialized = true; + } + + // to support swapping + public void OnDrop(PointerEventData eventData) + { + if(!_initialized) + return; + + var draggedObj = eventData.pointerDrag.GetComponent(); + + if(draggedObj.ShouldDie()) + return; + + if(draggedObj == content) + return; + + // prevent sending the DragRPC regardless. because the player intended to attach it, not drag it. + if(!draggedObj.dropAnywhere) + draggedObj.wasSnapped = true; + + // if the dragging object is on seperate canvases, dont parent + if(draggedObj.canvas != canvas) + return; + + if(!FitsIntoSlot(draggedObj, this)) + return; + + // cant swap because the draggable's position is too far away + if(draggedObj.scaledMaxDistance > 0f && Vector2.Distance(draggedObj.lastDropPosition, transform.position) > draggedObj.scaledMaxDistance) + return; + + // if swapping would violate the draggable's constraints + if(draggedObj.limitToParent && !draggedObj.parentWorldRect.Contains(eventData.pointerCurrentRaycast.screenPosition)) + return; + + if(content != null){ + // cant swap because the draggable's position is too far away from the current content's anchor + if(content.scaledMaxDistance > 0f && Vector2.Distance(draggedObj.lastDropPosition, content.anchor) > content.scaledMaxDistance) + return; + + // incase a resize occured + content.TryRefreshParentBounds(); + + // if swapping would violate the current content's constraints + if(content.limitToParent && !content.parentWorldRect.Contains(draggedObj.lastDropPosition)) + return; + + if(draggedObj.slot != null && !FitsIntoSlot(content, draggedObj.slot)) + return; + + Draggable.Swap(draggedObj, content); + return; + } + + if(draggedObj.slot != null) + draggedObj.slot.content = null; + content = draggedObj; + draggedObj.slot = this; + draggedObj.realParent = this.transform; + draggedObj.lastDropPosition = transform.position; + if(draggedObj.dropAnywhere) + draggedObj.rt.position = this.transform.position; + draggedObj.offset = draggedObj.lastDropPosition - draggedObj.anchor; + draggedObj.wasSnapped = true; + Draggable.SendDropRPC(draggedObj.gameObject.name, draggedObj.slot?.gameObject.name, null, null); + } + + #endregion + + #region Helpers + + // checks filters + public static bool FitsIntoSlot(Draggable drag, Slot slot){ + if(slot.filter == null) + return true; + + return drag.filter == slot.filter; + } + + #endregion + } +} +#endif diff --git a/CommunityEntity.UI.cs b/CommunityEntity.UI.cs index fffbf08..cf3a6dc 100644 --- a/CommunityEntity.UI.cs +++ b/CommunityEntity.UI.cs @@ -405,6 +405,23 @@ T GetOrAddComponent() where T : Component rt.offsetMin = Vector2Ex.Parse( obj.GetString( "offsetmin", "0.0 0.0" ) ); if ( ShouldUpdateField( "offsetmax" ) ) rt.offsetMax = Vector2Ex.Parse( obj.GetString( "offsetmax", "1.0 1.0" ) ); + + + + // some Update only fields to allow reparenting of draggables if needed + if (allowUpdate && obj.ContainsKey( "setParent" ) ){ + var newParentName = obj.GetString( "setParent", null ); + if(!string.IsNullOrEmpty(newParentName)){ + var newParent = FindPanel(newParentName); + if(newParent) + rt.SetParent(newParent.transform); + } + } + if(allowUpdate && obj.ContainsKey( "setTransformIndex" ) ){ + var newIndex = obj.GetInt("setTransformIndex", -1); + if(newIndex >= 0) + rt.SetSiblingIndex(newIndex); + } } break; } @@ -436,6 +453,69 @@ T GetOrAddComponent() where T : Component c.command = obj.GetString( "command" ); } + break; + } + case "Draggable": + { + var drag = go.GetComponent(); + if(!drag){ + drag = go.AddComponent(); + go.AddComponent(); + } + + if( ShouldUpdateField("limitToParent")) + drag.limitToParent = obj.GetBoolean("limitToParent", false); + if( ShouldUpdateField("maxDistance")) + drag.maxDistance = obj.GetFloat("maxDistance", -1f); + if( ShouldUpdateField("allowSwapping")) + drag.allowSwapping = obj.GetBoolean("allowSwapping", false); + if( ShouldUpdateField("dropAnywhere")) + drag.dropAnywhere = obj.GetBoolean("dropAnywhere", true); + if( ShouldUpdateField("dragAlpha")) + drag.dragAlpha = obj.GetFloat("dragAlpha", 1f); + if( ShouldUpdateField("parentLimitIndex")) + drag.parentLimitIndex = obj.GetInt("parentLimitIndex", 1); + if( ShouldUpdateField("filter")) + drag.filter = obj.GetString("filter", null); + if( ShouldUpdateField("parentPadding")) + drag.parentPadding = Vector2Ex.Parse(obj.GetString("parentPadding", "0 0")); + if( ShouldUpdateField("anchorOffset")) + drag.anchorOffset = Vector2Ex.Parse(obj.GetString("anchorOffset", "0 0")); + if( ShouldUpdateField("keepOnTop")) + drag.keepOnTop = obj.GetBoolean("keepOnTop", false); + + var preferredDefault = Draggable.PositionSendType.NormalizedScreen; + // find a better default depending on specified settings + if(drag.maxDistance > 0f){ + preferredDefault = Draggable.PositionSendType.RelativeAnchor; + } else if(drag.limitToParent){ + preferredDefault = Draggable.PositionSendType.NormalizedParent; + } + + if( ShouldUpdateField("positionRPC")) + drag.positionRPC = ParseEnum(obj.GetString("positionRPC", null), preferredDefault); + + // some Update only fields to trigger certain functions + if(allowUpdate & obj.ContainsKey("moveToAnchor")) + drag.MoveToAnchor(); + if(allowUpdate & obj.ContainsKey("rebuildAnchor")) + drag.RebuildAnchor(); + + drag.Init(); + + HandleEnableState(obj, drag); + break; + } + case "Slot": + { + var slot = GetOrAddComponent(); + + if(ShouldUpdateField("filter")) + slot.filter = obj.GetString("filter", null); + + slot.Init(); + + HandleEnableState(obj, slot); break; } case "NeedsKeyboard": diff --git a/Tests/DraggableTest.json b/Tests/DraggableTest.json new file mode 100644 index 0000000..a32ecc7 --- /dev/null +++ b/Tests/DraggableTest.json @@ -0,0 +1,1428 @@ +[ + { + "name": "UI", + "parent":"Overlay", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.04 0.04 0.04 0.99", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "1 1" + }, + { + "type":"NeedsCursor" + } + ] + }, + { + "name": "Container1", + "parent":"UI", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.15 0.15 0.15 0.7", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.5 1", + "anchormax": "0.5 1", + "offsetmin": "-620 -340", + "offsetmax": "-220 -20" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.1" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.05" + } + ] + }, + { + "name": "Container1_bg", + "parent":"Container1", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/effects/crossbreed/fx gradient skewed.png", + "color": "0.25 0.05 0.05 0.2", + }, + { + "type":"RectTransform", + "offsetmax": "0 0" + }, + ] + }, + { + "parent": "Container1", + "components": + [ + { + "type":"RectTransform", + "offsetmin": "35 5", + "offsetmax": "-35 -5" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''type'': ''Draggable'',", + "color": "0.6 0.6 0.6 0.3", + "fontSize":24, + "align": "TopLeft" + } + ] + }, + { + "name": "drag1", + "parent":"Container1", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gradient-circle.png", + "color": "1 0.7 0.7 1" + }, + { + "type":"RectTransform", + "anchormin": "0.5 0.5", + "anchormax": "0.5 0.5", + "offsetmin": "-50 -50", + "offsetmax": "50 50" + }, + { + "type": "Draggable" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "drag1", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gameui/mlrs/mlrs_target_circle_fade.png", + "color": "0.6 1 1 0.1", + }, + ] + }, + { + "parent": "drag1", + "components": + [ + { + "type":"UnityEngine.UI.Text", + "text":"Draggable", + "color": "0.6 0.6 0.6 1.0", + "fontSize":20, + "align": "MiddleCenter" + } + ] + }, + { + "name": "Container2", + "parent":"UI", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.15 0.15 0.15 0.7", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.5 1", + "anchormax": "0.5 1", + "offsetmin": "-200 -340", + "offsetmax": "200 -20" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.1" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.05" + } + ] + }, + { + "name": "Container2_bg", + "parent":"Container2", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/effects/crossbreed/fx gradient skewed.png", + "color": "0.25 0.05 0.05 0.2", + }, + { + "type":"RectTransform", + "offsetmax": "0 0" + }, + ] + }, + { + "name": "Container2_circle", + "parent":"Container2", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gameui/mlrs/mlrs_dotted_circle.png", + "color": "1 1 1 0.2", + }, + { + "type":"RectTransform", + "anchormin": "0.5 0.5", + "anchormax": "0.5 0.5", + "offsetmin": "-100 -150", + "offsetmax": "100 50" + }, + ] + }, + { + "parent": "Container2", + "components": + [ + { + "type":"RectTransform", + "offsetmin": "35 5", + "offsetmax": "-35 -5" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''type'': ''Draggable'', ''maxDistance'': 100.0, ''dropAnywhere'': false", + "color": "0.6 0.6 0.6 0.3", + "fontSize":24, + "align": "TopLeft" + } + ] + }, + { + "name": "drag2", + "parent":"Container2", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gradient-circle.png", + "color": "1 0.7 0.7 1" + }, + { + "type":"RectTransform", + "anchormin": "0.5 0.5", + "anchormax": "0.5 0.5", + "offsetmin": "-50 -100", + "offsetmax": "50 0" + }, + { + "type": "Draggable", + "maxDistance": 100, + "dropAnywhere": false + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "drag2", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gameui/mlrs/mlrs_target_circle_fade.png", + "color": "0.6 1 1 0.1", + }, + ] + }, + { + "parent": "drag2", + "components": + [ + { + "type":"UnityEngine.UI.Text", + "text":"Draggable", + "color": "0.6 0.6 0.6 1.0", + "fontSize":20, + "align": "MiddleCenter" + } + ] + }, + { + "name": "Container3", + "parent":"UI", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.15 0.15 0.15 0.7", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.5 1", + "anchormax": "0.5 1", + "offsetmin": "220 -340", + "offsetmax": "620 -20" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.1" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.05" + } + ] + }, + { + "name": "Container3_bg", + "parent":"Container3", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/effects/crossbreed/fx gradient skewed.png", + "color": "0.25 0.05 0.05 0.2", + }, + { + "type":"RectTransform", + "offsetmax": "0 0" + }, + ] + }, + { + "parent": "Container3", + "components": + [ + { + "type":"RectTransform", + "offsetmin": "35 5", + "offsetmax": "-35 -5" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''type'': ''Draggable'', ''limitToParent'': true", + "color": "0.6 0.6 0.6 0.3", + "fontSize":24, + "align": "TopLeft" + } + ] + }, + { + "name": "drag3", + "parent":"Container3", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gradient-circle.png", + "color": "1 0.7 0.7 1" + }, + { + "type":"RectTransform", + "anchormin": "0.5 0.5", + "anchormax": "0.5 0.5", + "offsetmin": "-50 -50", + "offsetmax": "50 50" + }, + { + "type": "Draggable", + "limitToParent": true + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "drag3", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/gameui/mlrs/mlrs_target_circle_fade.png", + "color": "0.6 1 1 0.1", + }, + ] + }, + { + "parent": "drag3", + "components": + [ + { + "type":"UnityEngine.UI.Text", + "text":"Draggable", + "color": "0.6 0.6 0.6 1.0", + "fontSize":20, + "align": "MiddleCenter" + } + ] + }, + { + "name": "Container4", + "parent":"UI", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.15 0.15 0.15 0.7", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.5 1", + "anchormax": "0.5 1", + "offsetmin": "-620 -680", + "offsetmax": "-220 -360" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.1" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.05" + } + ] + }, + { + "name": "Container4_bg", + "parent":"Container4", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/effects/crossbreed/fx gradient skewed.png", + "color": "0.25 0.05 0.05 0.2", + }, + { + "type":"RectTransform", + "offsetmax": "0 0" + }, + ] + }, + { + "name": "entry1", + "parent":"Container4", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.24 0.2 0.2 1", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.03 0.825", + "anchormax": "0.97 0.975" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry1_icon", + "parent":"entry1", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/menu_dots.png", + "color": "1 1 1 0.8", + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "5 5", + "offsetmax": "45 45" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry1_content", + "parent":"entry1", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "55 5", + "offsetmax": "370 45" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''type'': ''Draggable'',", + "color": "0.6 0.6 0.6 0.5", + "fontSize":24, + "align": "MiddleLeft" + } + ] + }, + { + "name": "entry2", + "parent":"Container4", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.28 0.19 0.19 1", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.03 0.625", + "anchormax": "0.97 0.775" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry2_icon", + "parent":"entry2", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/menu_dots.png", + "color": "1 1 1 0.8", + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "5 5", + "offsetmax": "45 45" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry2_content", + "parent":"entry2", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "55 5", + "offsetmax": "370 45" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''limitToParent'': true,", + "color": "0.6 0.6 0.6 0.5", + "fontSize":24, + "align": "MiddleLeft" + } + ] + }, + { + "name": "entry3", + "parent":"Container4", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.32 0.18 0.18 1", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.03 0.425", + "anchormax": "0.97 0.575" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry3_icon", + "parent":"entry3", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/menu_dots.png", + "color": "1 1 1 0.8", + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "5 5", + "offsetmax": "45 45" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry3_content", + "parent":"entry3", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "55 5", + "offsetmax": "370 45" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''allowSwapping'': true,", + "color": "0.6 0.6 0.6 0.5", + "fontSize":24, + "align": "MiddleLeft" + } + ] + }, + { + "name": "entry4", + "parent":"Container4", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.36 0.17 0.17 1", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.03 0.225", + "anchormax": "0.97 0.375" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry4_icon", + "parent":"entry4", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/menu_dots.png", + "color": "1 1 1 0.8", + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "5 5", + "offsetmax": "45 45" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry4_content", + "parent":"entry4", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "55 5", + "offsetmax": "370 45" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''dropAnywhere'': false,", + "color": "0.6 0.6 0.6 0.5", + "fontSize":24, + "align": "MiddleLeft" + } + ] + }, + { + "name": "entry5", + "parent":"Container4", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.40 0.16 0.16 1", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.03 0.025", + "anchormax": "0.97 0.175" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry5_icon", + "parent":"entry5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/menu_dots.png", + "color": "1 1 1 0.8", + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "5 5", + "offsetmax": "45 45" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "entry5_content", + "parent":"entry5", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0 0", + "offsetmin": "55 5", + "offsetmax": "370 45" + }, + { + "type":"UnityEngine.UI.Text", + "text":"''dragAlpha'': 0.8", + "color": "0.6 0.6 0.6 0.5", + "fontSize":24, + "align": "MiddleLeft" + } + ] + }, + { + "name": "Container5", + "parent":"UI", + "components": + [ + { + "type":"UnityEngine.UI.RawImage", + "color": "0.15 0.15 0.15 0.7", + "sprite": "Assets/Content/UI/UI.Background.Tile.psd" + }, + { + "type":"RectTransform", + "anchormin": "0.5 1", + "anchormax": "0.5 1", + "offsetmin": "-200 -680", + "offsetmax": "620 -360" + } + ] + }, + { + "name": "Container5_bg", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/effects/crossbreed/fx gradient skewed.png", + "color": "0.25 0.05 0.05 0.2", + }, + { + "type":"RectTransform", + "offsetmax": "0 0" + }, + ] + }, + { + "name": "SlotInfoContainer", + "parent":"Container5", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "10 -310", + "offsetmax": "270 -10" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "name": "SlotHeader", + "parent":"SlotInfoContainer", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "5 -50", + "offsetmax": "250 -5" + }, + { + "type":"UnityEngine.UI.Text", + "text":"Slots", + "color": "0.7 0.7 0.7 0.9", + "fontSize":36, + "align": "TopLeft" + } + ] + }, + { + "name": "SlotInfo", + "parent":"SlotInfoContainer", + "components": + [ + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "5 -250", + "offsetmax": "250 -55" + }, + { + "type":"UnityEngine.UI.Text", + "text":"Slots are non Draggable panels that can hold a single draggable. they come with a primitive filter string that allows them to limit what draggables they will accept", + "color": "0.6 0.6 0.6 0.7", + "fontSize":22, + "align": "TopLeft" + } + ] + }, + { + "name": "drag4", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/circle_closed_white_toedge.png", + "color": "0.3 0.25 0.25 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "280 -80", + "offsetmax": "350 -10" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "drag4", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.circlegradient.png", + "color": "0.1 0 0 0.4", + }, + ] + }, + { + "name": "drag5", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/circle_closed_white_toedge.png", + "color": "0.3 0.25 0.25 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "360 -80", + "offsetmax": "430 -10" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8 + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "drag5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.circlegradient.png", + "color": "0.1 0 0 0.4", + }, + ] + }, + { + "name": "drag6", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/circle_closed_white_toedge.png", + "color": "0.3 0.6 0.25 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "440 -80", + "offsetmax": "510 -10" + }, + { + "type": "Draggable", + "limitToParent": true, + "allowSwapping": true, + "dropAnywhere": false, + "dragAlpha": 0.8, + "filter": "greenOnly" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "drag6", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.circlegradient.png", + "color": "0.1 0 0 0.4", + } + ] + }, + { + "name": "slot1", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.rounded.tga", + "color": "0.2 0.15 0.15 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "620 -100", + "offsetmax": "710 -10" + }, + { + "type": "Slot" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "slot1", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/add.png", + "color": "0.8 0.1 0.1 0.3", + }, + { + "type":"RectTransform", + "offsetmin": "5 5", + "offsetmax": "-5 -5" + } + ] + }, + { + "name": "slot2", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.rounded.tga", + "color": "0.2 0.15 0.15 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "720 -100", + "offsetmax": "810 -10" + }, + { + "type": "Slot" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "slot2", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/add.png", + "color": "0.8 0.1 0.1 0.3", + }, + { + "type":"RectTransform", + "offsetmin": "5 5", + "offsetmax": "-5 -5" + } + ] + }, + { + "name": "slot3", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.rounded.tga", + "color": "0.2 0.15 0.15 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "620 -200", + "offsetmax": "710 -110" + }, + { + "type": "Slot" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "slot3", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/add.png", + "color": "0.8 0.1 0.1 0.3", + }, + { + "type":"RectTransform", + "offsetmin": "5 5", + "offsetmax": "-5 -5" + } + ] + }, + { + "name": "slot4", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.rounded.tga", + "color": "0.2 0.15 0.15 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "720 -200", + "offsetmax": "810 -110" + }, + { + "type": "Slot" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "slot4", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/add.png", + "color": "0.8 0.1 0.1 0.3", + }, + { + "type":"RectTransform", + "offsetmin": "5 5", + "offsetmax": "-5 -5" + } + ] + }, + { + "name": "slot5", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.rounded.tga", + "color": "0.15 0.4 0.15 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "620 -300", + "offsetmax": "710 -210" + }, + { + "type": "Slot", + "filter": "greenOnly" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "slot5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/add.png", + "color": "0.1 0.8 0.1 0.3", + }, + { + "type":"RectTransform", + "offsetmin": "5 5", + "offsetmax": "-5 -5" + } + ] + }, + { + "name": "slot6", + "parent":"Container5", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/content/ui/ui.rounded.tga", + "color": "0.15 0.4 0.15 1" + }, + { + "type":"RectTransform", + "anchormin": "0 1", + "anchormax": "0 1", + "offsetmin": "720 -300", + "offsetmax": "810 -210" + }, + { + "type": "Slot", + "filter": "greenOnly" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "2 2", + "color": "0 0 0 0.06" + }, + { + "type": "UnityEngine.UI.Outline", + "distance": "4 4", + "color": "0 0 0 0.025" + } + ] + }, + { + "parent": "slot6", + "components": + [ + { + "type":"UnityEngine.UI.Image", + "sprite": "assets/icons/add.png", + "color": "0.1 0.8 0.1 0.3", + }, + { + "type":"RectTransform", + "offsetmin": "5 5", + "offsetmax": "-5 -5" + } + ] + }, + { + "name": "Button88", + "parent": "UI", + "components": + [ + { + "type":"UnityEngine.UI.Button", + "close":"UI", + "color": "0.9 0.8 0.3 0.8", + }, + { + "type":"RectTransform", + "anchormin": "0 0", + "anchormax": "0.03 0.04" + } + ] + }, + { + "parent": "Button88", + "components": + [ + { + "type":"UnityEngine.UI.Text", + "text":"x", + "fontSize":18, + "align": "MiddleCenter" + } + ] + } +]