Initial check-in for the 1.1 release, fixes include:
* Update to Line Renderer - updated scrip plus patches, now more code friendly for adding points * New Curved Layout component * ScrolTo script updated based on authors new version * UISoftAlphaMask updated to latest version * Added ScrollSpeed to Horizontal and Vertical Scroll Snap * Added Scroll Conflict Manager (untested) ToDo: * Test Scroll Conflict manager * Make the distance between pages on the H&V Scroll snaps configurable * Test Scroll Snap starting page fix * Review Reorderable List scrolling issue * Review Reorderable List Worldspace render issue --HG-- branch : develop_5.3pull/413/head
parent
f797c63cea
commit
3b5bdaaa5a
|
@ -30,9 +30,11 @@ namespace UnityEngine.UI.Extensions
|
||||||
[Tooltip("Flip the masks alpha value")]
|
[Tooltip("Flip the masks alpha value")]
|
||||||
public bool FlipAlphaMask = false;
|
public bool FlipAlphaMask = false;
|
||||||
|
|
||||||
[Tooltip("If Mask Scals Rect is given, and this value is true, the area around the mask will not be clipped")]
|
[Tooltip("If Mask Scaling Rect is given and this value is true, the area around the mask will not be clipped")]
|
||||||
public bool DontClipMaskScalingRect = false;
|
public bool DontClipMaskScalingRect = false;
|
||||||
|
|
||||||
|
[Tooltip("If set to true, this mask is applied to all child Text and Graphic objects belonging to this object.")]
|
||||||
|
public bool CascadeToALLChildren;
|
||||||
Vector3[] worldCorners;
|
Vector3[] worldCorners;
|
||||||
|
|
||||||
Vector2 AlphaUV;
|
Vector2 AlphaUV;
|
||||||
|
@ -41,7 +43,10 @@ namespace UnityEngine.UI.Extensions
|
||||||
Vector2 max = Vector2.one;
|
Vector2 max = Vector2.one;
|
||||||
Vector2 p;
|
Vector2 p;
|
||||||
Vector2 siz;
|
Vector2 siz;
|
||||||
|
Vector2 tp = new Vector2(.5f, .5f);
|
||||||
|
|
||||||
|
|
||||||
|
bool MaterialNotSupported; // UI items like toggles, we can stil lcascade down to them though :)
|
||||||
Rect maskRect;
|
Rect maskRect;
|
||||||
Rect contentRect;
|
Rect contentRect;
|
||||||
|
|
||||||
|
@ -75,11 +80,39 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
// For some reason, having the mask control on the parent and disabled stops the mouse interacting
|
// For some reason, having the mask control on the parent and disabled stops the mouse interacting
|
||||||
// with the texture layer that is not visible.. Not needed for the Image.
|
// with the texture layer that is not visible.. Not needed for the Image.
|
||||||
if (transform.parent.GetComponent<Mask>() == null)
|
if (transform.parent.GetComponent<Button>() == null && transform.parent.GetComponent<Mask>() == null)
|
||||||
transform.parent.gameObject.AddComponent<Mask>();
|
transform.parent.gameObject.AddComponent<Mask>();
|
||||||
|
|
||||||
transform.parent.GetComponent<Mask>().enabled = false;
|
if (transform.parent.GetComponent<Mask>() != null)
|
||||||
|
transform.parent.GetComponent<Mask>().enabled = false;
|
||||||
}
|
}
|
||||||
|
if (CascadeToALLChildren)
|
||||||
|
{
|
||||||
|
for (int c = 0; c < transform.childCount; c++)
|
||||||
|
{
|
||||||
|
SetSAM(transform.GetChild(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialNotSupported = mat == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSAM(Transform t)
|
||||||
|
{
|
||||||
|
SoftMaskScript thisSam = t.gameObject.GetComponent<SoftMaskScript>();
|
||||||
|
if (thisSam == null)
|
||||||
|
{
|
||||||
|
thisSam = t.gameObject.AddComponent<SoftMaskScript>();
|
||||||
|
|
||||||
|
}
|
||||||
|
thisSam.MaskArea = MaskArea;
|
||||||
|
thisSam.AlphaMask = AlphaMask;
|
||||||
|
thisSam.CutOff = CutOff;
|
||||||
|
thisSam.HardBlend = HardBlend;
|
||||||
|
thisSam.FlipAlphaMask = FlipAlphaMask;
|
||||||
|
thisSam.maskScalingRect = maskScalingRect;
|
||||||
|
thisSam.DontClipMaskScalingRect = DontClipMaskScalingRect;
|
||||||
|
thisSam.CascadeToALLChildren = CascadeToALLChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCanvas()
|
void GetCanvas()
|
||||||
|
@ -93,17 +126,14 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
canvas = t.gameObject.GetComponent<Canvas>();
|
canvas = t.gameObject.GetComponent<Canvas>();
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
t = GetParentTranform(t);
|
{
|
||||||
|
t = t.parent;
|
||||||
|
}
|
||||||
|
|
||||||
lvl++;
|
lvl++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform GetParentTranform(Transform t)
|
|
||||||
{
|
|
||||||
return t.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
SetMask();
|
SetMask();
|
||||||
|
@ -111,6 +141,11 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
void SetMask()
|
void SetMask()
|
||||||
{
|
{
|
||||||
|
if (MaterialNotSupported)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the two rectangle areas
|
// Get the two rectangle areas
|
||||||
maskRect = MaskArea.rect;
|
maskRect = MaskArea.rect;
|
||||||
contentRect = myRect.rect;
|
contentRect = myRect.rect;
|
||||||
|
@ -142,12 +177,15 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the centre offset
|
// Get the centre offset
|
||||||
centre = myRect.transform.InverseTransformPoint(MaskArea.transform.position);
|
|
||||||
|
|
||||||
if (maskScalingRect != null)
|
if (maskScalingRect != null)
|
||||||
{
|
{
|
||||||
centre = myRect.transform.InverseTransformPoint(maskScalingRect.transform.position);
|
centre = myRect.transform.InverseTransformPoint(maskScalingRect.transform.TransformPoint(maskScalingRect.rect.center));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
centre = myRect.transform.InverseTransformPoint(MaskArea.transform.TransformPoint(MaskArea.rect.center));
|
||||||
|
}
|
||||||
|
centre += (Vector2)myRect.transform.InverseTransformPoint(myRect.transform.position) - myRect.rect.center;
|
||||||
|
|
||||||
// Set the scale for mapping texcoords mask
|
// Set the scale for mapping texcoords mask
|
||||||
AlphaUV = new Vector2(maskRect.width / contentRect.width, maskRect.height / contentRect.height);
|
AlphaUV = new Vector2(maskRect.width / contentRect.width, maskRect.height / contentRect.height);
|
||||||
|
@ -162,9 +200,8 @@ namespace UnityEngine.UI.Extensions
|
||||||
max += siz;
|
max += siz;
|
||||||
|
|
||||||
// Now move these into texture space. 0 - 1
|
// Now move these into texture space. 0 - 1
|
||||||
min = new Vector2(min.x / contentRect.width, min.y / contentRect.height) + new Vector2(.5f, .5f);
|
min = new Vector2(min.x / contentRect.width, min.y / contentRect.height) + tp;
|
||||||
max = new Vector2(max.x / contentRect.width, max.y / contentRect.height) + new Vector2(.5f, .5f);
|
max = new Vector2(max.x / contentRect.width, max.y / contentRect.height) + tp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mat.SetFloat("_HardBlend", HardBlend ? 1 : 0);
|
mat.SetFloat("_HardBlend", HardBlend ? 1 : 0);
|
||||||
|
@ -173,13 +210,15 @@ namespace UnityEngine.UI.Extensions
|
||||||
mat.SetVector("_Min", min);
|
mat.SetVector("_Min", min);
|
||||||
mat.SetVector("_Max", max);
|
mat.SetVector("_Max", max);
|
||||||
|
|
||||||
mat.SetTexture("_AlphaMask", AlphaMask);
|
|
||||||
mat.SetInt("_FlipAlphaMask", FlipAlphaMask ? 1 : 0);
|
mat.SetInt("_FlipAlphaMask", FlipAlphaMask ? 1 : 0);
|
||||||
|
mat.SetTexture("_AlphaMask", AlphaMask);
|
||||||
|
|
||||||
mat.SetInt("_NoOuterClip", DontClipMaskScalingRect && maskScalingRect != null ? 1 : 0);
|
mat.SetInt("_NoOuterClip", DontClipMaskScalingRect && maskScalingRect != null ? 1 : 0);
|
||||||
|
|
||||||
if (!isText) // No mod needed for Text
|
if (!isText) // No mod needed for Text
|
||||||
|
{
|
||||||
mat.SetVector("_AlphaUV", AlphaUV);
|
mat.SetVector("_AlphaUV", AlphaUV);
|
||||||
|
}
|
||||||
|
|
||||||
mat.SetFloat("_CutOff", CutOff);
|
mat.SetFloat("_CutOff", CutOff);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8de815c5a2c592d4da033da3146168c5
|
||||||
|
timeCreated: 1463330156
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -14,7 +14,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
private Transform _screensContainer;
|
private Transform _screensContainer;
|
||||||
|
|
||||||
private int _screens = 1;
|
private int _screens = 1;
|
||||||
private int _startingScreen = 1;
|
private int _startingScreen = 2;
|
||||||
|
|
||||||
private bool _fastSwipeTimer = false;
|
private bool _fastSwipeTimer = false;
|
||||||
private int _fastSwipeCounter = 0;
|
private int _fastSwipeCounter = 0;
|
||||||
|
@ -28,6 +28,31 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
private int _containerSize;
|
private int _containerSize;
|
||||||
|
|
||||||
|
public int StartingScreen
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _startingScreen;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_startingScreen == value)
|
||||||
|
return;
|
||||||
|
if (value < _screens)
|
||||||
|
{
|
||||||
|
_startingScreen = 1;
|
||||||
|
}
|
||||||
|
else if (value > _screens)
|
||||||
|
{
|
||||||
|
_startingScreen = transform.childCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_startingScreen = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Tooltip("The gameobject that contains toggles which suggest pagination. (optional)")]
|
[Tooltip("The gameobject that contains toggles which suggest pagination. (optional)")]
|
||||||
public GameObject Pagination;
|
public GameObject Pagination;
|
||||||
|
|
||||||
|
@ -35,6 +60,8 @@ namespace UnityEngine.UI.Extensions
|
||||||
public GameObject NextButton;
|
public GameObject NextButton;
|
||||||
[Tooltip("Button to go to the previous page. (optional)")]
|
[Tooltip("Button to go to the previous page. (optional)")]
|
||||||
public GameObject PrevButton;
|
public GameObject PrevButton;
|
||||||
|
[Tooltip("Transition speed between pages. (optional)")]
|
||||||
|
public float transitionSpeed = 7.5f;
|
||||||
|
|
||||||
public Boolean UseFastSwipe = true;
|
public Boolean UseFastSwipe = true;
|
||||||
public int FastSwipeThreshold = 100;
|
public int FastSwipeThreshold = 100;
|
||||||
|
@ -65,7 +92,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_scroll_rect.horizontalNormalizedPosition = (float)(_startingScreen - 1) / (float)(_screens - 1);
|
_scroll_rect.horizontalNormalizedPosition = (float)(_startingScreen - 1) / (_screens - 1);
|
||||||
|
|
||||||
_containerSize = (int)_screensContainer.gameObject.GetComponent<RectTransform>().offsetMax.x;
|
_containerSize = (int)_screensContainer.gameObject.GetComponent<RectTransform>().offsetMax.x;
|
||||||
|
|
||||||
|
@ -82,7 +109,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
if (_lerp)
|
if (_lerp)
|
||||||
{
|
{
|
||||||
_screensContainer.localPosition = Vector3.Lerp(_screensContainer.localPosition, _lerp_target, 7.5f * Time.deltaTime);
|
_screensContainer.localPosition = Vector3.Lerp(_screensContainer.localPosition, _lerp_target, transitionSpeed * Time.deltaTime);
|
||||||
if (Vector3.Distance(_screensContainer.localPosition, _lerp_target) < 0.005f)
|
if (Vector3.Distance(_screensContainer.localPosition, _lerp_target) < 0.005f)
|
||||||
{
|
{
|
||||||
_lerp = false;
|
_lerp = false;
|
||||||
|
@ -202,6 +229,9 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
int _offset = 0;
|
int _offset = 0;
|
||||||
int _step = Screen.width;
|
int _step = Screen.width;
|
||||||
|
//Options to fix - stepping causes issues with overlap
|
||||||
|
//float _step = GameObject.FindObjectOfType<Canvas> ().GetComponent<RectTransform>().rect.width;
|
||||||
|
//int _step = (int)(transform.root.GetComponent<RectTransform>().sizeDelta.x);
|
||||||
int _dimension = 0;
|
int _dimension = 0;
|
||||||
|
|
||||||
int currentXPosition = 0;
|
int currentXPosition = 0;
|
||||||
|
@ -209,6 +239,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
for (int i = 0; i < _screensContainer.transform.childCount; i++)
|
for (int i = 0; i < _screensContainer.transform.childCount; i++)
|
||||||
{
|
{
|
||||||
RectTransform child = _screensContainer.transform.GetChild(i).gameObject.GetComponent<RectTransform>();
|
RectTransform child = _screensContainer.transform.GetChild(i).gameObject.GetComponent<RectTransform>();
|
||||||
|
_step = (int)child.rect.width * 3;
|
||||||
currentXPosition = _offset + i * _step;
|
currentXPosition = _offset + i * _step;
|
||||||
child.anchoredPosition = new Vector2(currentXPosition, 0f);
|
child.anchoredPosition = new Vector2(currentXPosition, 0f);
|
||||||
child.sizeDelta = new Vector2(gameObject.GetComponent<RectTransform>().rect.width, gameObject.GetComponent<RectTransform>().rect.height);
|
child.sizeDelta = new Vector2(gameObject.GetComponent<RectTransform>().rect.width, gameObject.GetComponent<RectTransform>().rect.height);
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
m_Tracker.Clear();
|
m_Tracker.Clear();
|
||||||
if (transform.childCount == 0)
|
if (transform.childCount == 0)
|
||||||
return;
|
return;
|
||||||
float fOffsetAngle = ((MaxAngle - MinAngle)) / (transform.childCount - 1);
|
float fOffsetAngle = ((MaxAngle - MinAngle)) / (transform.childCount);
|
||||||
|
|
||||||
float fAngle = StartAngle;
|
float fAngle = StartAngle;
|
||||||
for (int i = 0; i < transform.childCount; i++)
|
for (int i = 0; i < transform.childCount; i++)
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace UnityEngine.UI.Extensions
|
||||||
public GameObject NextButton;
|
public GameObject NextButton;
|
||||||
[Tooltip("Button to go to the previous page. (optional)")]
|
[Tooltip("Button to go to the previous page. (optional)")]
|
||||||
public GameObject PrevButton;
|
public GameObject PrevButton;
|
||||||
|
[Tooltip("Transition speed between pages. (optional)")]
|
||||||
|
public float transitionSpeed = 7.5f;
|
||||||
|
|
||||||
public Boolean UseFastSwipe = true;
|
public Boolean UseFastSwipe = true;
|
||||||
public int FastSwipeThreshold = 100;
|
public int FastSwipeThreshold = 100;
|
||||||
|
@ -82,7 +84,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
if (_lerp)
|
if (_lerp)
|
||||||
{
|
{
|
||||||
_screensContainer.localPosition = Vector3.Lerp(_screensContainer.localPosition, _lerp_target, 7.5f * Time.deltaTime);
|
_screensContainer.localPosition = Vector3.Lerp(_screensContainer.localPosition, _lerp_target, transitionSpeed * Time.deltaTime);
|
||||||
if (Vector3.Distance(_screensContainer.localPosition, _lerp_target) < 0.005f)
|
if (Vector3.Distance(_screensContainer.localPosition, _lerp_target) < 0.005f)
|
||||||
{
|
{
|
||||||
_lerp = false;
|
_lerp = false;
|
||||||
|
@ -202,6 +204,9 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
float _offset = 0;
|
float _offset = 0;
|
||||||
float _step = Screen.height;
|
float _step = Screen.height;
|
||||||
|
//Options to fix - stepping causes issues with overlap
|
||||||
|
//float _step = GameObject.FindObjectOfType<Canvas> ().GetComponent<RectTransform>().rect.height;
|
||||||
|
//int _step = (int)(transform.root.GetComponent<RectTransform>().sizeDelta.y);
|
||||||
float _dimension = 0;
|
float _dimension = 0;
|
||||||
|
|
||||||
Vector2 panelDimensions = gameObject.GetComponent<RectTransform>().sizeDelta;
|
Vector2 panelDimensions = gameObject.GetComponent<RectTransform>().sizeDelta;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/// Credit zge
|
/// Credit zge, jeremie sellam
|
||||||
/// Sourced from - http://forum.unity3d.com/threads/draw-circles-or-primitives-on-the-new-ui-canvas.272488/#post-2293224
|
/// Sourced from - http://forum.unity3d.com/threads/draw-circles-or-primitives-on-the-new-ui-canvas.272488/#post-2293224
|
||||||
|
/// Updated from - https://bitbucket.org/ddreaper/unity-ui-extensions/issues/65/a-better-uicircle
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
|
@ -10,10 +9,16 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
Texture m_Texture;
|
Texture m_Texture;
|
||||||
|
[Tooltip("The circular fill percentage of the primitive, affected by FixedToSegments")]
|
||||||
[Range(0, 100)]
|
[Range(0, 100)]
|
||||||
public int fillPercent = 100;
|
public int fillPercent = 100;
|
||||||
|
[Tooltip("Should the primitive fill draw by segments or absolute percentage")]
|
||||||
|
public bool FixedToSegments = false;
|
||||||
|
[Tooltip("Draw the primitive filled or as a line")]
|
||||||
public bool fill = true;
|
public bool fill = true;
|
||||||
|
[Tooltip("If not filled, the thickness of the primitive line")]
|
||||||
public float thickness = 5;
|
public float thickness = 5;
|
||||||
|
[Tooltip("The number of segments to draw the primitive, more segments = smoother primitive")]
|
||||||
[Range(0, 360)]
|
[Range(0, 360)]
|
||||||
public int segments = 360;
|
public int segments = 360;
|
||||||
|
|
||||||
|
@ -25,7 +30,6 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Texture to be used.
|
/// Texture to be used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -46,7 +50,6 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
this.thickness = (float)Mathf.Clamp(this.thickness, 0, rectTransform.rect.width / 2);
|
this.thickness = (float)Mathf.Clamp(this.thickness, 0, rectTransform.rect.width / 2);
|
||||||
|
@ -66,7 +69,6 @@ namespace UnityEngine.UI.Extensions
|
||||||
return vbo;
|
return vbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void OnPopulateMesh(VertexHelper vh)
|
protected override void OnPopulateMesh(VertexHelper vh)
|
||||||
{
|
{
|
||||||
float outer = -rectTransform.pivot.x * rectTransform.rect.width;
|
float outer = -rectTransform.pivot.x * rectTransform.rect.width;
|
||||||
|
@ -84,43 +86,75 @@ namespace UnityEngine.UI.Extensions
|
||||||
Vector2 pos1;
|
Vector2 pos1;
|
||||||
Vector2 pos2;
|
Vector2 pos2;
|
||||||
Vector2 pos3;
|
Vector2 pos3;
|
||||||
|
|
||||||
float f = (this.fillPercent / 100f);
|
if (FixedToSegments)
|
||||||
float degrees = 360f / segments;
|
|
||||||
int fa = (int)((segments + 1) * f);
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < fa; i++)
|
|
||||||
{
|
{
|
||||||
float rad = Mathf.Deg2Rad * (i * degrees);
|
float f = (this.fillPercent / 100f);
|
||||||
float c = Mathf.Cos(rad);
|
float degrees = 360f / segments;
|
||||||
float s = Mathf.Sin(rad);
|
int fa = (int)((segments + 1) * f);
|
||||||
|
|
||||||
uv0 = new Vector2(0, 1);
|
|
||||||
uv1 = new Vector2(1, 1);
|
for (int i = 0; i < fa; i++)
|
||||||
uv2 = new Vector2(1, 0);
|
|
||||||
uv3 = new Vector2(0, 0);
|
|
||||||
|
|
||||||
pos0 = prevX;
|
|
||||||
pos1 = new Vector2(outer * c, outer * s);
|
|
||||||
|
|
||||||
if (fill)
|
|
||||||
{
|
{
|
||||||
pos2 = Vector2.zero;
|
float rad = Mathf.Deg2Rad * (i * degrees);
|
||||||
pos3 = Vector2.zero;
|
float c = Mathf.Cos(rad);
|
||||||
|
float s = Mathf.Sin(rad);
|
||||||
|
|
||||||
|
uv0 = new Vector2(0, 1);
|
||||||
|
uv1 = new Vector2(1, 1);
|
||||||
|
uv2 = new Vector2(1, 0);
|
||||||
|
uv3 = new Vector2(0, 0);
|
||||||
|
|
||||||
|
StepThroughPointsAndFill(outer, inner, ref prevX, ref prevY, out pos0, out pos1, out pos2, out pos3, c, s);
|
||||||
|
|
||||||
|
vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
pos2 = new Vector2(inner * c, inner * s);
|
|
||||||
pos3 = prevY;
|
|
||||||
}
|
|
||||||
|
|
||||||
prevX = pos1;
|
|
||||||
prevY = pos2;
|
|
||||||
|
|
||||||
vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float tw = rectTransform.rect.width;
|
||||||
|
float th = rectTransform.rect.height;
|
||||||
|
|
||||||
|
float angleByStep = (fillPercent / 100f * (Mathf.PI * 2f)) / segments;
|
||||||
|
float currentAngle = 0f;
|
||||||
|
for (int i = 0; i < segments + 1; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
float c = Mathf.Cos(currentAngle);
|
||||||
|
float s = Mathf.Sin(currentAngle);
|
||||||
|
|
||||||
|
StepThroughPointsAndFill(outer, inner, ref prevX, ref prevY, out pos0, out pos1, out pos2, out pos3, c, s);
|
||||||
|
|
||||||
|
uv0 = new Vector2(pos0.x / tw + 0.5f, pos0.y / th + 0.5f);
|
||||||
|
uv1 = new Vector2(pos1.x / tw + 0.5f, pos1.y / th + 0.5f);
|
||||||
|
uv2 = new Vector2(pos2.x / tw + 0.5f, pos2.y / th + 0.5f);
|
||||||
|
uv3 = new Vector2(pos3.x / tw + 0.5f, pos3.y / th + 0.5f);
|
||||||
|
|
||||||
|
vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
|
||||||
|
|
||||||
|
currentAngle += angleByStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StepThroughPointsAndFill(float outer, float inner, ref Vector2 prevX, ref Vector2 prevY, out Vector2 pos0, out Vector2 pos1, out Vector2 pos2, out Vector2 pos3, float c, float s)
|
||||||
|
{
|
||||||
|
pos0 = prevX;
|
||||||
|
pos1 = new Vector2(outer * c, outer * s);
|
||||||
|
|
||||||
|
if (fill)
|
||||||
|
{
|
||||||
|
pos2 = Vector2.zero;
|
||||||
|
pos3 = Vector2.zero;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos2 = new Vector2(inner * c, inner * s);
|
||||||
|
pos3 = prevY;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevX = pos1;
|
||||||
|
prevY = pos2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
/// Credit jack.sydorenko
|
/// Credit jack.sydorenko, firagon
|
||||||
/// Sourced from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
|
/// Sourced from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
|
||||||
|
/// Updated/Refactored from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/#post-2528050
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -8,17 +9,55 @@ namespace UnityEngine.UI.Extensions
|
||||||
[AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
|
[AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
|
||||||
public class UILineRenderer : MaskableGraphic
|
public class UILineRenderer : MaskableGraphic
|
||||||
{
|
{
|
||||||
|
private enum SegmentType
|
||||||
|
{
|
||||||
|
Start,
|
||||||
|
Middle,
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum JoinType
|
||||||
|
{
|
||||||
|
Bevel,
|
||||||
|
Miter
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
|
||||||
|
|
||||||
|
// A bevel 'nice' join displaces the vertices of the line segment instead of simply rendering a
|
||||||
|
// quad to connect the endpoints. This improves the look of textured and transparent lines, since
|
||||||
|
// there is no overlapping.
|
||||||
|
private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
|
||||||
|
|
||||||
|
private static readonly Vector2 UV_TOP_LEFT = Vector2.zero;
|
||||||
|
private static readonly Vector2 UV_BOTTOM_LEFT = new Vector2(0, 1);
|
||||||
|
private static readonly Vector2 UV_TOP_CENTER = new Vector2(0.5f, 0);
|
||||||
|
private static readonly Vector2 UV_BOTTOM_CENTER = new Vector2(0.5f, 1);
|
||||||
|
private static readonly Vector2 UV_TOP_RIGHT = new Vector2(1, 0);
|
||||||
|
private static readonly Vector2 UV_BOTTOM_RIGHT = new Vector2(1, 1);
|
||||||
|
|
||||||
|
private static readonly Vector2[] startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER, UV_TOP_CENTER };
|
||||||
|
private static readonly Vector2[] middleUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_CENTER, UV_TOP_CENTER };
|
||||||
|
private static readonly Vector2[] endUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
|
||||||
|
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
Texture m_Texture;
|
private Texture m_Texture;
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
|
private Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
|
||||||
|
[SerializeField]
|
||||||
|
private Vector2[] m_points;
|
||||||
|
|
||||||
|
|
||||||
public float LineThickness = 2;
|
public float LineThickness = 2;
|
||||||
public bool UseMargins;
|
public bool UseMargins;
|
||||||
public Vector2 Margin;
|
public Vector2 Margin;
|
||||||
public Vector2[] Points;
|
|
||||||
public bool relativeSize;
|
public bool relativeSize;
|
||||||
|
|
||||||
|
public bool LineList = false;
|
||||||
|
public bool LineCaps = false;
|
||||||
|
public JoinType LineJoins = JoinType.Bevel;
|
||||||
|
|
||||||
public override Texture mainTexture
|
public override Texture mainTexture
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -65,11 +104,29 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Points to be drawn in the line.
|
||||||
|
/// </summary>
|
||||||
|
public Vector2[] Points
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_points;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_points == value)
|
||||||
|
return;
|
||||||
|
m_points = value;
|
||||||
|
SetAllDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnPopulateMesh(VertexHelper vh)
|
protected override void OnPopulateMesh(VertexHelper vh)
|
||||||
{
|
{
|
||||||
// requires sets of quads
|
if (m_points == null)
|
||||||
if (Points == null || Points.Length < 2)
|
return;
|
||||||
Points = new[] { new Vector2(0, 0), new Vector2(1, 1) };
|
|
||||||
var sizeX = rectTransform.rect.width;
|
var sizeX = rectTransform.rect.width;
|
||||||
var sizeY = rectTransform.rect.height;
|
var sizeY = rectTransform.rect.height;
|
||||||
var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
|
var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
|
||||||
|
@ -81,6 +138,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
sizeX = 1;
|
sizeX = 1;
|
||||||
sizeY = 1;
|
sizeY = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UseMargins)
|
if (UseMargins)
|
||||||
{
|
{
|
||||||
sizeX -= Margin.x;
|
sizeX -= Margin.x;
|
||||||
|
@ -91,82 +149,156 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
vh.Clear();
|
vh.Clear();
|
||||||
|
|
||||||
Vector2 prevV1 = Vector2.zero;
|
// Generate the quads that make up the wide line
|
||||||
Vector2 prevV2 = Vector2.zero;
|
var segments = new List<UIVertex[]>();
|
||||||
|
if (LineList)
|
||||||
for (int i = 1; i < Points.Length; i++)
|
|
||||||
{
|
{
|
||||||
var prev = Points[i - 1];
|
for (var i = 1; i < m_points.Length; i += 2)
|
||||||
var cur = Points[i];
|
{
|
||||||
prev = new Vector2(prev.x * sizeX + offsetX, prev.y * sizeY + offsetY);
|
var start = m_points[i - 1];
|
||||||
cur = new Vector2(cur.x * sizeX + offsetX, cur.y * sizeY + offsetY);
|
var end = m_points[i];
|
||||||
|
start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||||
|
end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||||
|
|
||||||
float angle = Mathf.Atan2(cur.y - prev.y, cur.x - prev.x) * 180f / Mathf.PI;
|
if (LineCaps)
|
||||||
|
{
|
||||||
|
segments.Add(CreateLineCap(start, end, SegmentType.Start));
|
||||||
|
}
|
||||||
|
|
||||||
var v1 = prev + new Vector2(0, -LineThickness / 2);
|
segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
|
||||||
var v2 = prev + new Vector2(0, +LineThickness / 2);
|
|
||||||
var v3 = cur + new Vector2(0, +LineThickness / 2);
|
|
||||||
var v4 = cur + new Vector2(0, -LineThickness / 2);
|
|
||||||
|
|
||||||
v1 = RotatePointAroundPivot(v1, prev, new Vector3(0, 0, angle));
|
if (LineCaps)
|
||||||
v2 = RotatePointAroundPivot(v2, prev, new Vector3(0, 0, angle));
|
{
|
||||||
v3 = RotatePointAroundPivot(v3, cur, new Vector3(0, 0, angle));
|
segments.Add(CreateLineCap(start, end, SegmentType.End));
|
||||||
v4 = RotatePointAroundPivot(v4, cur, new Vector3(0, 0, angle));
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 1; i < m_points.Length; i++)
|
||||||
|
{
|
||||||
|
var start = m_points[i - 1];
|
||||||
|
var end = m_points[i];
|
||||||
|
start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||||
|
end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||||
|
|
||||||
|
if (LineCaps && i == 1)
|
||||||
|
{
|
||||||
|
segments.Add(CreateLineCap(start, end, SegmentType.Start));
|
||||||
|
}
|
||||||
|
|
||||||
Vector2[] myUvs = uvs3;
|
segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
|
||||||
|
|
||||||
if (i > 1)
|
if (LineCaps && i == m_points.Length - 1)
|
||||||
vh.AddUIVertexQuad(SetVbo(new[] { prevV1, prevV2, v1, v2 }, myUvs));
|
{
|
||||||
|
segments.Add(CreateLineCap(start, end, SegmentType.End));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (i == 1)
|
// Add the line segments to the vertex helper, creating any joins as needed
|
||||||
myUvs = uvs;
|
for (var i = 0; i < segments.Count; i++)
|
||||||
else if (i == Points.Length - 1)
|
{
|
||||||
myUvs = uvs2;
|
if (!LineList && i < segments.Count - 1)
|
||||||
|
{
|
||||||
|
var vec1 = segments[i][1].position - segments[i][2].position;
|
||||||
|
var vec2 = segments[i + 1][2].position - segments[i + 1][1].position;
|
||||||
|
var angle = Vector2.Angle(vec1, vec2) * Mathf.Deg2Rad;
|
||||||
|
|
||||||
vh.AddUIVertexQuad(SetVbo(new[] { v1, v2, v3, v4 }, myUvs));
|
// Positive sign means the line is turning in a 'clockwise' direction
|
||||||
|
var sign = Mathf.Sign(Vector3.Cross(vec1.normalized, vec2.normalized).z);
|
||||||
|
|
||||||
|
// Calculate the miter point
|
||||||
|
var miterDistance = LineThickness / (2 * Mathf.Tan(angle / 2));
|
||||||
|
var miterPointA = segments[i][2].position - vec1.normalized * miterDistance * sign;
|
||||||
|
var miterPointB = segments[i][3].position + vec1.normalized * miterDistance * sign;
|
||||||
|
|
||||||
prevV1 = v3;
|
var joinType = LineJoins;
|
||||||
prevV2 = v4;
|
if (joinType == JoinType.Miter)
|
||||||
|
{
|
||||||
|
// Make sure we can make a miter join without too many artifacts.
|
||||||
|
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN)
|
||||||
|
{
|
||||||
|
segments[i][2].position = miterPointA;
|
||||||
|
segments[i][3].position = miterPointB;
|
||||||
|
segments[i + 1][0].position = miterPointB;
|
||||||
|
segments[i + 1][1].position = miterPointA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
joinType = JoinType.Bevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinType == JoinType.Bevel)
|
||||||
|
{
|
||||||
|
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN)
|
||||||
|
{
|
||||||
|
if (sign < 0)
|
||||||
|
{
|
||||||
|
segments[i][2].position = miterPointA;
|
||||||
|
segments[i + 1][1].position = miterPointA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segments[i][3].position = miterPointB;
|
||||||
|
segments[i + 1][0].position = miterPointB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var join = new UIVertex[] { segments[i][2], segments[i][3], segments[i + 1][0], segments[i + 1][1] };
|
||||||
|
vh.AddUIVertexQuad(join);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vh.AddUIVertexQuad(segments[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static Vector2 uvTopLeft = Vector2.zero;
|
|
||||||
static Vector2 uvBottomLeft = new Vector2(0, 1);
|
|
||||||
|
|
||||||
static Vector2 uvTopCenter = new Vector2(0.5f, 0);
|
private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)
|
||||||
static Vector2 uvBottomCenter = new Vector2(0.5f, 1);
|
{
|
||||||
|
if (type == SegmentType.Start)
|
||||||
|
{
|
||||||
|
var capStart = start - ((end - start).normalized * LineThickness / 2);
|
||||||
|
return CreateLineSegment(capStart, start, SegmentType.Start);
|
||||||
|
}
|
||||||
|
else if (type == SegmentType.End)
|
||||||
|
{
|
||||||
|
var capEnd = end + ((end - start).normalized * LineThickness / 2);
|
||||||
|
return CreateLineSegment(end, capEnd, SegmentType.End);
|
||||||
|
}
|
||||||
|
|
||||||
static Vector2 uvTopRight = new Vector2(1, 0);
|
Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
|
||||||
static Vector2 uvBottomRight = new Vector2(1, 1);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
static Vector2[] uvs = new[] { uvTopLeft, uvBottomLeft, uvBottomCenter, uvTopCenter };
|
private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type)
|
||||||
|
{
|
||||||
static Vector2[] uvs2 = new[] { uvTopCenter, uvBottomCenter, uvBottomRight, uvTopRight };
|
var uvs = middleUvs;
|
||||||
|
if (type == SegmentType.Start)
|
||||||
static Vector2[] uvs3 = new[] { uvTopCenter, uvBottomCenter, uvBottomCenter, uvTopCenter };
|
uvs = startUvs;
|
||||||
|
else if (type == SegmentType.End)
|
||||||
|
uvs = endUvs;
|
||||||
|
|
||||||
|
Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * LineThickness / 2;
|
||||||
|
var v1 = start - offset;
|
||||||
|
var v2 = start + offset;
|
||||||
|
var v3 = end + offset;
|
||||||
|
var v4 = end - offset;
|
||||||
|
return SetVbo(new[] { v1, v2, v3, v4 }, uvs);
|
||||||
|
}
|
||||||
|
|
||||||
protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
|
protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
|
||||||
{
|
{
|
||||||
UIVertex[] vbo = new UIVertex[4];
|
UIVertex[] vbo = new UIVertex[4];
|
||||||
for (int i = 0; i < vertices.Length; i++)
|
for (int i = 0; i < vertices.Length; i++)
|
||||||
{
|
{
|
||||||
var vert = UIVertex.simpleVert;
|
var vert = UIVertex.simpleVert;
|
||||||
vert.color = color;
|
vert.color = color;
|
||||||
vert.position = vertices[i];
|
vert.position = vertices[i];
|
||||||
vert.uv0 = uvs[i];
|
vert.uv0 = uvs[i];
|
||||||
vbo[i] = vert;
|
vbo[i] = vert;
|
||||||
}
|
}
|
||||||
return vbo;
|
return vbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
|
|
||||||
{
|
|
||||||
Vector3 dir = point - pivot; // get point direction relative to pivot
|
|
||||||
dir = Quaternion.Euler(angles) * dir; // rotate it
|
|
||||||
point = dir + pivot; // calculate rotated point
|
|
||||||
return point; // return it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,11 +13,12 @@ namespace UnityEngine.UI.Extensions
|
||||||
Texture m_Texture;
|
Texture m_Texture;
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
|
Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
|
||||||
|
[SerializeField]
|
||||||
|
private Vector2[] m_points;
|
||||||
|
|
||||||
public float LineThickness = 2;
|
public float LineThickness = 2;
|
||||||
public bool UseMargins;
|
public bool UseMargins;
|
||||||
public Vector2 Margin;
|
public Vector2 Margin;
|
||||||
public Vector2[] Points;
|
|
||||||
public bool relativeSize;
|
public bool relativeSize;
|
||||||
|
|
||||||
public override Texture mainTexture
|
public override Texture mainTexture
|
||||||
|
@ -66,11 +67,29 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Points to be drawn in the line.
|
||||||
|
/// </summary>
|
||||||
|
public Vector2[] Points
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_points;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (m_points == value)
|
||||||
|
return;
|
||||||
|
m_points = value;
|
||||||
|
SetAllDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnPopulateMesh(VertexHelper vh)
|
protected override void OnPopulateMesh(VertexHelper vh)
|
||||||
{
|
{
|
||||||
// requires sets of quads
|
// requires sets of quads
|
||||||
if (Points == null || Points.Length < 2)
|
if (m_points == null || m_points.Length < 2)
|
||||||
Points = new[] { new Vector2(0, 0), new Vector2(1, 1) };
|
m_points = new[] { new Vector2(0, 0), new Vector2(1, 1) };
|
||||||
var capSize = 24;
|
var capSize = 24;
|
||||||
var sizeX = rectTransform.rect.width;
|
var sizeX = rectTransform.rect.width;
|
||||||
var sizeY = rectTransform.rect.height;
|
var sizeY = rectTransform.rect.height;
|
||||||
|
@ -83,23 +102,23 @@ namespace UnityEngine.UI.Extensions
|
||||||
sizeX = 1;
|
sizeX = 1;
|
||||||
sizeY = 1;
|
sizeY = 1;
|
||||||
}
|
}
|
||||||
// build a new set of points taking into account the cap sizes.
|
// build a new set of m_points taking into account the cap sizes.
|
||||||
// would be cool to support corners too, but that might be a bit tough :)
|
// would be cool to support corners too, but that might be a bit tough :)
|
||||||
var pointList = new List<Vector2>();
|
var pointList = new List<Vector2>();
|
||||||
pointList.Add(Points[0]);
|
pointList.Add(m_points[0]);
|
||||||
var capPoint = Points[0] + (Points[1] - Points[0]).normalized * capSize;
|
var capPoint = m_points[0] + (m_points[1] - m_points[0]).normalized * capSize;
|
||||||
pointList.Add(capPoint);
|
pointList.Add(capPoint);
|
||||||
|
|
||||||
// should bail before the last point to add another cap point
|
// should bail before the last point to add another cap point
|
||||||
for (int i = 1; i < Points.Length - 1; i++)
|
for (int i = 1; i < m_points.Length - 1; i++)
|
||||||
{
|
{
|
||||||
pointList.Add(Points[i]);
|
pointList.Add(m_points[i]);
|
||||||
}
|
}
|
||||||
capPoint = Points[Points.Length - 1] - (Points[Points.Length - 1] - Points[Points.Length - 2]).normalized * capSize;
|
capPoint = m_points[m_points.Length - 1] - (m_points[m_points.Length - 1] - m_points[m_points.Length - 2]).normalized * capSize;
|
||||||
pointList.Add(capPoint);
|
pointList.Add(capPoint);
|
||||||
pointList.Add(Points[Points.Length - 1]);
|
pointList.Add(m_points[m_points.Length - 1]);
|
||||||
|
|
||||||
var TempPoints = pointList.ToArray();
|
var Tempm_points = pointList.ToArray();
|
||||||
if (UseMargins)
|
if (UseMargins)
|
||||||
{
|
{
|
||||||
sizeX -= Margin.x;
|
sizeX -= Margin.x;
|
||||||
|
@ -113,10 +132,10 @@ namespace UnityEngine.UI.Extensions
|
||||||
Vector2 prevV1 = Vector2.zero;
|
Vector2 prevV1 = Vector2.zero;
|
||||||
Vector2 prevV2 = Vector2.zero;
|
Vector2 prevV2 = Vector2.zero;
|
||||||
|
|
||||||
for (int i = 1; i < TempPoints.Length; i++)
|
for (int i = 1; i < Tempm_points.Length; i++)
|
||||||
{
|
{
|
||||||
var prev = TempPoints[i - 1];
|
var prev = Tempm_points[i - 1];
|
||||||
var cur = TempPoints[i];
|
var cur = Tempm_points[i];
|
||||||
prev = new Vector2(prev.x * sizeX + offsetX, prev.y * sizeY + offsetY);
|
prev = new Vector2(prev.x * sizeX + offsetX, prev.y * sizeY + offsetY);
|
||||||
cur = new Vector2(cur.x * sizeX + offsetX, cur.y * sizeY + offsetY);
|
cur = new Vector2(cur.x * sizeX + offsetX, cur.y * sizeY + offsetY);
|
||||||
|
|
||||||
|
@ -148,7 +167,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
uvs = new[] { uvTopLeft, uvBottomLeft, uvBottomCenter, uvTopCenter };
|
uvs = new[] { uvTopLeft, uvBottomLeft, uvBottomCenter, uvTopCenter };
|
||||||
else if (i == TempPoints.Length - 1)
|
else if (i == Tempm_points.Length - 1)
|
||||||
uvs = new[] { uvTopCenter, uvBottomCenter, uvBottomRight, uvTopRight };
|
uvs = new[] { uvTopCenter, uvBottomCenter, uvBottomRight, uvTopRight };
|
||||||
|
|
||||||
vh.AddUIVertexQuad(SetVbo(new[] { v1, v2, v3, v4 }, uvs));
|
vh.AddUIVertexQuad(SetVbo(new[] { v1, v2, v3, v4 }, uvs));
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4a1735d6bfaf3e5479675d80bf6619a9
|
||||||
|
timeCreated: 1463330124
|
||||||
|
licenseType: Pro
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -6,100 +6,221 @@ Simply place the script on the ScrollRect that contains the selectable children
|
||||||
and drag'n'drop the RectTransform of the options "container" that we'll be scrolling.*/
|
and drag'n'drop the RectTransform of the options "container" that we'll be scrolling.*/
|
||||||
|
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
[RequireComponent(typeof(ScrollRect))]
|
[RequireComponent(typeof(ScrollRect))]
|
||||||
[AddComponentMenu("UI/Extensions/UIScrollToSelection")]
|
[AddComponentMenu("UI/Extensions/UIScrollToSelection")]
|
||||||
public class UIScrollToSelection : MonoBehaviour {
|
public class UIScrollToSelection : MonoBehaviour
|
||||||
|
{
|
||||||
//*** ATTRIBUTES ***//
|
|
||||||
[Header("[ References ]")]
|
|
||||||
[SerializeField]
|
|
||||||
private RectTransform layoutListGroup;
|
|
||||||
|
|
||||||
[Header("[ Settings ]")]
|
|
||||||
[SerializeField]
|
|
||||||
private float scrollSpeed = 10f;
|
|
||||||
|
|
||||||
//*** PROPERTIES ***//
|
|
||||||
// REFERENCES
|
|
||||||
protected RectTransform LayoutListGroup {
|
|
||||||
get {return layoutListGroup;}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SETTINGS
|
|
||||||
protected float ScrollSpeed {
|
|
||||||
get {return scrollSpeed;}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VARIABLES
|
|
||||||
protected RectTransform TargetScrollObject {get; set;}
|
|
||||||
protected RectTransform ScrollWindow {get; set;}
|
|
||||||
protected ScrollRect TargetScrollRect {get; set;}
|
|
||||||
|
|
||||||
//*** METHODS - PUBLIC ***//
|
|
||||||
|
|
||||||
|
|
||||||
//*** METHODS - PROTECTED ***//
|
|
||||||
protected virtual void Awake (){
|
|
||||||
TargetScrollRect = GetComponent<ScrollRect>();
|
|
||||||
ScrollWindow = TargetScrollRect.GetComponent<RectTransform>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Start (){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Update (){
|
|
||||||
ScrollRectToLevelSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
//*** METHODS - PRIVATE ***//
|
|
||||||
private void ScrollRectToLevelSelection (){
|
|
||||||
// check main references
|
|
||||||
bool referencesAreIncorrect = (TargetScrollRect == null || LayoutListGroup == null || ScrollWindow == null);
|
|
||||||
|
|
||||||
if (referencesAreIncorrect == true){
|
//*** ATTRIBUTES ***//
|
||||||
return;
|
[Header("[ Settings ]")]
|
||||||
}
|
[SerializeField]
|
||||||
|
private ScrollType scrollDirection;
|
||||||
|
[SerializeField]
|
||||||
|
private float scrollSpeed = 10f;
|
||||||
|
|
||||||
// get calculation references
|
[Header("[ Input ]")]
|
||||||
EventSystem events = EventSystem.current;
|
[SerializeField]
|
||||||
RectTransform selection =
|
private bool cancelScrollOnInput = false;
|
||||||
events.currentSelectedGameObject != null ?
|
[SerializeField]
|
||||||
events.currentSelectedGameObject.GetComponent<RectTransform>() :
|
private List<KeyCode> cancelScrollKeycodes = new List<KeyCode>();
|
||||||
null;
|
|
||||||
|
|
||||||
// check if scrolling is possible
|
//*** PROPERTIES ***//
|
||||||
if (selection == null ||
|
// REFERENCES
|
||||||
selection.transform.parent != LayoutListGroup.transform)
|
protected RectTransform LayoutListGroup
|
||||||
{
|
{
|
||||||
return;
|
get { return TargetScrollRect != null ? TargetScrollRect.content : null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// move the current scroll rect to correct position
|
// SETTINGS
|
||||||
float selectionPos = -selection.anchoredPosition.y;
|
protected ScrollType ScrollDirection
|
||||||
|
{
|
||||||
|
get { return scrollDirection; }
|
||||||
|
}
|
||||||
|
protected float ScrollSpeed
|
||||||
|
{
|
||||||
|
get { return scrollSpeed; }
|
||||||
|
}
|
||||||
|
|
||||||
float elementHeight = LayoutListGroup.rect.height / LayoutListGroup.transform.childCount;
|
// INPUT
|
||||||
float maskHeight = ScrollWindow.rect.height;
|
protected bool CancelScrollOnInput
|
||||||
float listPixelAnchor = LayoutListGroup.anchoredPosition.y;
|
{
|
||||||
|
get { return cancelScrollOnInput; }
|
||||||
|
}
|
||||||
|
protected List<KeyCode> CancelScrollKeycodes
|
||||||
|
{
|
||||||
|
get { return cancelScrollKeycodes; }
|
||||||
|
}
|
||||||
|
|
||||||
// get the element offset value depending on the cursor move direction
|
// CACHED REFERENCES
|
||||||
float offlimitsValue = 0;
|
protected RectTransform ScrollWindow { get; set; }
|
||||||
|
protected ScrollRect TargetScrollRect { get; set; }
|
||||||
|
|
||||||
if (selectionPos < listPixelAnchor){
|
// SCROLLING
|
||||||
offlimitsValue = listPixelAnchor - selectionPos;
|
protected EventSystem CurrentEventSystem
|
||||||
} else if (selectionPos + elementHeight > listPixelAnchor + maskHeight){
|
{
|
||||||
offlimitsValue = (listPixelAnchor + maskHeight) - (selectionPos + elementHeight);
|
get { return EventSystem.current; }
|
||||||
}
|
}
|
||||||
|
protected GameObject LastCheckedGameObject { get; set; }
|
||||||
|
protected GameObject CurrentSelectedGameObject
|
||||||
|
{
|
||||||
|
get { return EventSystem.current.currentSelectedGameObject; }
|
||||||
|
}
|
||||||
|
protected RectTransform CurrentTargetRectTransform { get; set; }
|
||||||
|
protected bool IsManualScrollingAvailable { get; set; }
|
||||||
|
|
||||||
// move the target scroll rect
|
//*** METHODS - PUBLIC ***//
|
||||||
TargetScrollRect.verticalNormalizedPosition +=
|
|
||||||
(offlimitsValue / LayoutListGroup.rect.height) * Time.deltaTime * scrollSpeed;
|
|
||||||
|
//*** METHODS - PROTECTED ***//
|
||||||
// save last object we were "heading to" to prevent blocking
|
protected virtual void Awake()
|
||||||
TargetScrollObject = selection;
|
{
|
||||||
}
|
TargetScrollRect = GetComponent<ScrollRect>();
|
||||||
}
|
ScrollWindow = TargetScrollRect.GetComponent<RectTransform>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Start()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Update()
|
||||||
|
{
|
||||||
|
UpdateReferences();
|
||||||
|
CheckIfScrollingShouldBeLocked();
|
||||||
|
ScrollRectToLevelSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
//*** METHODS - PRIVATE ***//
|
||||||
|
private void UpdateReferences()
|
||||||
|
{
|
||||||
|
// update current selected rect transform
|
||||||
|
if (CurrentSelectedGameObject != LastCheckedGameObject)
|
||||||
|
{
|
||||||
|
CurrentTargetRectTransform = (CurrentSelectedGameObject != null) ?
|
||||||
|
CurrentSelectedGameObject.GetComponent<RectTransform>() :
|
||||||
|
null;
|
||||||
|
|
||||||
|
// unlock automatic scrolling
|
||||||
|
if (CurrentSelectedGameObject != null &&
|
||||||
|
CurrentSelectedGameObject.transform.parent == LayoutListGroup.transform)
|
||||||
|
{
|
||||||
|
IsManualScrollingAvailable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastCheckedGameObject = CurrentSelectedGameObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckIfScrollingShouldBeLocked()
|
||||||
|
{
|
||||||
|
if (CancelScrollOnInput == false || IsManualScrollingAvailable == true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < CancelScrollKeycodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (Input.GetKeyDown(CancelScrollKeycodes[i]) == true)
|
||||||
|
{
|
||||||
|
IsManualScrollingAvailable = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScrollRectToLevelSelection()
|
||||||
|
{
|
||||||
|
// check main references
|
||||||
|
bool referencesAreIncorrect = (TargetScrollRect == null || LayoutListGroup == null || ScrollWindow == null);
|
||||||
|
|
||||||
|
if (referencesAreIncorrect == true || IsManualScrollingAvailable == true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectTransform selection = CurrentTargetRectTransform;
|
||||||
|
|
||||||
|
// check if scrolling is possible
|
||||||
|
if (selection == null || selection.transform.parent != LayoutListGroup.transform)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// depending on selected scroll direction move the scroll rect to selection
|
||||||
|
switch (ScrollDirection)
|
||||||
|
{
|
||||||
|
case ScrollType.VERTICAL:
|
||||||
|
UpdateVerticalScrollPosition(selection);
|
||||||
|
break;
|
||||||
|
case ScrollType.HORIZONTAL:
|
||||||
|
UpdateHorizontalScrollPosition(selection);
|
||||||
|
break;
|
||||||
|
case ScrollType.BOTH:
|
||||||
|
UpdateVerticalScrollPosition(selection);
|
||||||
|
UpdateHorizontalScrollPosition(selection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateVerticalScrollPosition(RectTransform selection)
|
||||||
|
{
|
||||||
|
// move the current scroll rect to correct position
|
||||||
|
float selectionPosition = -selection.anchoredPosition.y;
|
||||||
|
|
||||||
|
float elementHeight = selection.rect.height;
|
||||||
|
float maskHeight = ScrollWindow.rect.height;
|
||||||
|
float listAnchorPosition = LayoutListGroup.anchoredPosition.y;
|
||||||
|
|
||||||
|
// get the element offset value depending on the cursor move direction
|
||||||
|
float offlimitsValue = GetScrollOffset(selectionPosition, listAnchorPosition, elementHeight, maskHeight);
|
||||||
|
|
||||||
|
// move the target scroll rect
|
||||||
|
TargetScrollRect.verticalNormalizedPosition +=
|
||||||
|
(offlimitsValue / LayoutListGroup.rect.height) * Time.deltaTime * scrollSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateHorizontalScrollPosition(RectTransform selection)
|
||||||
|
{
|
||||||
|
// move the current scroll rect to correct position
|
||||||
|
float selectionPosition = selection.anchoredPosition.x;
|
||||||
|
|
||||||
|
float elementWidth = selection.rect.width;
|
||||||
|
float maskWidth = ScrollWindow.rect.width;
|
||||||
|
float listAnchorPosition = -LayoutListGroup.anchoredPosition.x;
|
||||||
|
|
||||||
|
// get the element offset value depending on the cursor move direction
|
||||||
|
float offlimitsValue = -GetScrollOffset(selectionPosition, listAnchorPosition, elementWidth, maskWidth);
|
||||||
|
|
||||||
|
// move the target scroll rect
|
||||||
|
TargetScrollRect.horizontalNormalizedPosition +=
|
||||||
|
(offlimitsValue / LayoutListGroup.rect.width) * Time.deltaTime * scrollSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetScrollOffset(float position, float listAnchorPosition, float targetLength, float maskLength)
|
||||||
|
{
|
||||||
|
if (position < listAnchorPosition)
|
||||||
|
{
|
||||||
|
return listAnchorPosition - position;
|
||||||
|
}
|
||||||
|
else if (position + targetLength > listAnchorPosition + maskLength)
|
||||||
|
{
|
||||||
|
return (listAnchorPosition + maskLength) - (position + targetLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*** ENUMS ***//
|
||||||
|
public enum ScrollType
|
||||||
|
{
|
||||||
|
VERTICAL,
|
||||||
|
HORIZONTAL,
|
||||||
|
BOTH
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -76,18 +76,9 @@
|
||||||
float4 worldPosition : TEXCOORD1;
|
float4 worldPosition : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline float UnityGet2DClipping (in float2 position, in float4 clipRect)
|
|
||||||
{
|
|
||||||
float2 inside = step(clipRect.xy, position.xy) * step(position.xy, clipRect.zw);
|
|
||||||
return inside.x * inside.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed4 _Color;
|
fixed4 _Color;
|
||||||
fixed4 _TextureSampleAdd;
|
fixed4 _TextureSampleAdd;
|
||||||
|
|
||||||
bool _UseClipRect;
|
|
||||||
float4 _ClipRect;
|
|
||||||
|
|
||||||
bool _UseAlphaClip;
|
bool _UseAlphaClip;
|
||||||
|
|
||||||
float4 _ProgressColor;
|
float4 _ProgressColor;
|
||||||
|
@ -151,9 +142,6 @@
|
||||||
color.a *= a;
|
color.a *= a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_UseClipRect)
|
|
||||||
color *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
|
||||||
|
|
||||||
if (_UseAlphaClip)
|
if (_UseAlphaClip)
|
||||||
clip(color.a - 0.001);
|
clip(color.a - 0.001);
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
Pass
|
Pass
|
||||||
{
|
{
|
||||||
CGPROGRAM
|
CGPROGRAM
|
||||||
|
// Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members _ProgressColor,_Value,_Min,_Max,_Mul,_CutOff)
|
||||||
|
#pragma exclude_renderers d3d11 xbox360
|
||||||
#pragma vertex vert
|
#pragma vertex vert
|
||||||
#pragma fragment frag
|
#pragma fragment frag
|
||||||
|
|
||||||
|
@ -71,20 +73,10 @@
|
||||||
half2 texcoord : TEXCOORD0;
|
half2 texcoord : TEXCOORD0;
|
||||||
float4 worldPosition : TEXCOORD1;
|
float4 worldPosition : TEXCOORD1;
|
||||||
float4 worldPosition2 : COLOR1;
|
float4 worldPosition2 : COLOR1;
|
||||||
};
|
|
||||||
|
|
||||||
inline float UnityGet2DClipping (in float2 position, in float4 clipRect)
|
|
||||||
{
|
|
||||||
float2 inside = step(clipRect.xy, position.xy) * step(position.xy, clipRect.zw);
|
|
||||||
return inside.x * inside.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed4 _Color;
|
fixed4 _Color;
|
||||||
fixed4 _TextureSampleAdd;
|
fixed4 _TextureSampleAdd;
|
||||||
|
|
||||||
bool _UseClipRect;
|
|
||||||
float4 _ClipRect;
|
|
||||||
|
|
||||||
bool _UseAlphaClip;
|
bool _UseAlphaClip;
|
||||||
|
|
||||||
float4 _ProgressColor;
|
float4 _ProgressColor;
|
||||||
|
@ -95,6 +87,16 @@
|
||||||
|
|
||||||
int _FlipAlphaMask = 0;
|
int _FlipAlphaMask = 0;
|
||||||
|
|
||||||
|
sampler2D _MainTex;
|
||||||
|
sampler2D _AlphaMask;
|
||||||
|
|
||||||
|
float2 _Min;
|
||||||
|
float2 _Max;
|
||||||
|
|
||||||
|
float2 _Mul;
|
||||||
|
|
||||||
|
float _CutOff;
|
||||||
|
int _NoOuterClip;
|
||||||
v2f vert(appdata_t IN)
|
v2f vert(appdata_t IN)
|
||||||
{
|
{
|
||||||
v2f OUT;
|
v2f OUT;
|
||||||
|
@ -113,20 +115,11 @@
|
||||||
return OUT;
|
return OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampler2D _MainTex;
|
|
||||||
sampler2D _AlphaMask;
|
|
||||||
|
|
||||||
float2 _Min;
|
|
||||||
float2 _Max;
|
|
||||||
|
|
||||||
float2 _Mul;
|
|
||||||
|
|
||||||
float _CutOff;
|
|
||||||
int _NoOuterClip;
|
|
||||||
|
|
||||||
fixed4 frag(v2f IN) : SV_Target
|
fixed4 frag(v2f IN) : SV_Target
|
||||||
{
|
{
|
||||||
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
|
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
|
||||||
|
|
||||||
|
|
||||||
// Do we want to clip the image to the Mask Rectangle?
|
// Do we want to clip the image to the Mask Rectangle?
|
||||||
|
@ -151,9 +144,6 @@
|
||||||
color *= a;
|
color *= a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_UseClipRect)
|
|
||||||
color *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
|
||||||
|
|
||||||
if (_UseAlphaClip)
|
if (_UseAlphaClip)
|
||||||
clip(color.a - 0.001);
|
clip(color.a - 0.001);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Unity UI Extensions",
|
"name": "Unity UI Extensions",
|
||||||
"version": "1.0.6.1",
|
"version": "1.1.0.0",
|
||||||
"description": "An extension project for the Unity3D UI system, all crafted and contributed by the awesome Unity community",
|
"description": "An extension project for the Unity3D UI system, all crafted and contributed by the awesome Unity community",
|
||||||
"author": "Simon darkside Jackson <@SimonDarksideJ>",
|
"author": "Simon darkside Jackson <@SimonDarksideJ>",
|
||||||
"contributors": [{
|
"contributors": [{
|
||||||
|
|
Loading…
Reference in New Issue