Skip to content

Instantly share code, notes, and snippets.

@junaid109
Created May 23, 2023 15:21
Show Gist options
  • Save junaid109/893e6c57b9a71acfacae3709f68650f1 to your computer and use it in GitHub Desktop.
Save junaid109/893e6c57b9a71acfacae3709f68650f1 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CanvasItemScale : MonoBehaviour
{
public CanvasScaler target;
public RectTransform targetTransform;
public Vector2 min, usingSize;
public float scaleLevel = 2;
public bool doScale = false;
private void Start()
{
targetTransform.sizeDelta = new Vector2(Screen.width, Screen.height);
usingSize = new Vector2(Screen.width, Screen.height);
print($"the screen width Y: {Screen.width} and height: X: {Screen.height} ");
}
void Update()
{
if (target.referenceResolution.x != Screen.width || target.referenceResolution.y != Screen.height)
{
if(doScale && (Screen.width / target.referenceResolution.x) % scaleLevel != 0 || (Screen.height / target.referenceResolution.y) % scaleLevel != 0)
{
usingSize.x = Screen.width;
usingSize.y = Screen.height;
while(usingSize. x < min.x || usingSize.y < min.y)
{
usingSize *= scaleLevel;
}
//target.referenceResolution = usingSize;
targetTransform.sizeDelta = usingSize * scaleLevel;
}
else
{
//targetTransform.sizeDelta = new Vector2(Screen.width, Screen.height);
targetTransform.sizeDelta = usingSize;
//target.referenceResolution = new Vector2(Screen.width, Screen.height);
}
}
}
}
using UnityEngine;
public class CarouselConstants : MonoBehaviour
{
public enum CarouselType
{
CarouselTypeLinear,
CarouselTypeScaledLinear,
CarouselTypeCoverFlow,
CarouselTypeScaledCoverFlow,
};
}
using System;
using System.Collections.Generic;
using DG.Tweening;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[Serializable]
public class CarouselEvent : UnityEvent<int, int>
{
}
/// <summary>
/// This class handles the carousel behaviour mechanic
/// </summary>
public class CarouselController : MonoBehaviour
{
//public Canvas _canvas;
public RectTransform canvasRect;
public CarouselEvent onCellClickedEvent;
public CarouselConstants.CarouselType _carouselType = CarouselConstants.CarouselType.CarouselTypeLinear;
public ScrollRect _scroll;
public RectTransform _scrollRT;
// to hold the cells
public RectTransform _panel;
// Center to compare the distance for each objects
public RectTransform _center;
// Cell created by auto create
public GameObject _cell;
[Tooltip("Cell should snap to center after scrolling is finished")]
public bool _shouldFocusCenter = true;
[Tooltip("Cell should snap to center when being seleted")]
public bool _shouldCenterSelect = true;
[Tooltip("If the controller should auto create default cells")]
public bool _shouldAutoCreateCells = true;
[Tooltip("Loop carousel")] public bool _shouldLoop = true;
[Tooltip("Vertical or horizontal scroll")]
public bool _isHorizontal = true;
[Tooltip("Update button description automatically")]
public bool _shouldUpdateDesc;
public bool isSubMenu;
[Tooltip("Total cells to auto create")]
public int _totalCells = 5;
public float _cellGap = 25f;
public float _focusSpeed = 5f;
public float cellWidth;
public float scaleFactor;
public float _scaleSpeed = 5f;
public float _rotateSpeed = 5f;
public bool cellSizeExpand = false;
public AnimationCurve movementCurve;
public float _moveSpeed = 10f;
// When the scroll velocity is below this threshold, start focusing
public float _focusCenterVelocityThreshold = 50f;
public Vector3 _scaleRatio = new Vector3(1, 1, 1);
public Vector3 _coverflowAngles = new Vector3(0, 80, 0);
// Hold all cells
public List<GameObject> m_cellContainer = new List<GameObject>();
public Vector3 _newScale;
private int _arcLength;
// Boundary is dynamically calculated based on total cells
private Vector3 _boundary;
private int _centerCellIndex;
// Will be true, while we drag the panel
private bool _dragging;
private Vector3 _dragStartPos;
private Vector3 _final;
private float _height;
private bool _isCircularMovment;
[SerializeField]
private bool _isSubMenuVod = false;
// Used for cell style calculation
private Vector3 _newPos;
private Vector3 _newRot;
private Vector3 _offset;
private int _offsetIndex;
private int _selectIndex = -1;
private int _tempCenterIndex = -1;
public float _width;
private readonly Color32 fadeColor = new Color32(255, 255, 255, 50);
private readonly Color32 fullColor = new Color32(255, 255, 255, 255);
private int lastScreenWidth = 0;
private int lastScreenHeight = 0;
private Vector3 _cellItemScale = new Vector3(0.72f, 0.72f, 1.0f);
private Vector3 _cellDefaultItemScale = new Vector3(0.7f, 0.7f, 1.0f);
private void LateUpdate()
{
// Udpate scroll settings in real time
_scroll.horizontal = _isHorizontal;
_scroll.vertical = !_isHorizontal;
SetupCells(false);
CheckBoundary();
FindCenterCellIndex();
CheckAutoFocus();
CheckCenterSelect();
}
private void OnEnable()
{
// #if UNITY_EDITOR
// _cellGap = 900;
// #endif
//
// #if UNITY_ANDROID
// _cellGap = 0;
// #endif
// Get the start position here so the center offset will always be zero
_dragStartPos = _panel.position;
// Default center cell is zero
_centerCellIndex = 0;
/// Load all Images from /Resources/ShowImages path
LoadCells();
// Setup cells with high speed so they appear to be instant movement
SetupCells(true);
if (isSubMenu)
{
scaleFactor = .4f;
cellWidth = .4f;
return;
}
scaleFactor = .7f;
cellWidth = .7f;
}
private void Start()
{
InitialiseCellList();
}
public void InitialiseCellList()
{
if (m_cellContainer.Count != 0)
return;
var items = _panel.transform.GetComponentsInChildren<CellController>();
foreach (var item in items)
{
m_cellContainer.Add(item.gameObject);
}
}
public void AddToCellList(Transform[] items)
{
if (m_cellContainer.Count > 6)
return;
foreach (var item in items)
{
m_cellContainer.Add(item.gameObject);
}
//InitialiseCellList();
}
private void OnDisable()
{
//UnloadCells();
}
private void Update()
{
if (lastScreenWidth != Screen.width || lastScreenHeight != Screen.height)
{
lastScreenWidth = Screen.width;
lastScreenHeight = Screen.height;
UpdateCellParams();
}
}
// we configure our menu item layout so it fits different width's
private void UpdateCellParams()
{
if (isSubMenu)
{
if (_isSubMenuVod)
{
switch (Screen.width)
{
case 800:
_cellGap = -720;
break;
case 1280:
_cellGap = -630;
break;
case 1920:
_cellGap = -500;
break;
case 2160:
_cellGap = -450;
break;
case 2340:
_cellGap = -450;
break;
case 2560:
_cellGap = -390;
break;
case 2960:
_cellGap = -490;
break;
case 3840:
_cellGap = -140;
break;
}
return;
}
switch (Screen.width)
{
case 800:
_cellGap = -720;
break;
case 1280:
_cellGap = -630;
break;
case 1920:
_cellGap = -500;
break;
case 2160:
_cellGap = -450;
break;
case 2340:
_cellGap = -450;
break;
case 2560:
_cellGap = -540;
break;
case 2960:
_cellGap = -300;
break;
case 3840:
_cellGap = -140;
break;
}
return;
}
switch (Screen.width)
{
case 800:
_cellGap = -754f;
break;
case 1280:
_cellGap = -678.9f;
break;
case 1920:
_cellGap = -445;
_center.localPosition = new Vector3(_center.localPosition.x, -558.61f, 0f);
break;
case 2160:
_cellGap = -397;
_center.localPosition = new Vector3(-1798.1f, -558.61f, 0f);
break;
case 2340:
_cellGap = -450;
_center.localPosition = new Vector3(_center.localPosition.x, -558.61f, 0f);
break;
case 2560:
_cellGap = -302;
_center.localPosition = new Vector3(-1798.1f, -568f, 0f);
break;
case 2960:
_cellGap = -191f;
_center.localPosition = new Vector3(_center.localPosition.x, -570.5f, 0f);
break;
case 3840:
_cellGap = -15.9f;
_center.localPosition = new Vector3(-1826.9f, -566.2f, 0f);
break;
}
// if (Camera.main != null)
// {
//
//
// if (Camera.main.aspect >= 1.7) // 16:9
// {
// _cellGap = -728;
// _center.localPosition = new Vector3(_center.position.x, -558.61f, 0f);
// }
//
// if (Camera.main.aspect > 1.6) // 5:3
// {
//
// }
//
// if (Camera.main.aspect == 1.6) // 16:10
// {
//
// }
//
// if (Camera.main.aspect >= 1.5) // 3:2
// {
//
// }
// else
// {
// //4:3
// }
// }
}
//When an item is dragged we apply offset to give slight increase in width and height
public void StartDrag()
{
//Debug.Log("StartDrag");
// Reset select index so it won't focus on last select index
_selectIndex = -1;
_dragging = true;
_dragStartPos = _panel.position;
if (isSubMenu)
{
scaleFactor = 0.4f;
cellWidth = 0.4f;
return;
}
if (!cellSizeExpand) return;
scaleFactor = .65f;
cellWidth = .65f;
}
public void EndDrag()
{
//Debug.Log("EndDrag");
_dragging = false;
if (isSubMenu)
{
scaleFactor = 0.4f;
cellWidth = 0.4f;
return;
}
if (!cellSizeExpand) return;
scaleFactor = .7f;
cellWidth = .7f;
}
/// <summary>
/// If we are dynamically create the cells and their content
/// we instantiate based on number of cells
/// </summary>
public void AddCell()
{
// Add the current center cell
if (_cell == null)
return;
var go = Instantiate(_cell, _panel);
AddCellData(go, m_cellContainer.Count);
// Last cell, we just add
// Otherwise, we insert
if (_centerCellIndex >= m_cellContainer.Count - 1)
m_cellContainer.Add(go);
else
m_cellContainer.Insert(_centerCellIndex + 1, go);
// Recaluclate the arc length
_arcLength = 360 / m_cellContainer.Count;
_scroll.velocity = Vector3.zero;
}
private void ScrollWithSelection(RectTransform _scrollRect, RectTransform _content)
{
var selected = EventSystem.current.currentSelectedGameObject;
if (selected == null || selected == null) return;
if (selected.transform.parent != _content.transform) return;
var selectedRectTransform = selected.GetComponent<RectTransform>();
var scrollViewMinY = _content.anchoredPosition.y;
var scrollViewMaxY = _content.anchoredPosition.y + _scrollRect.rect.height;
var selectedPositionY =
Mathf.Abs(selectedRectTransform.anchoredPosition.y) + selectedRectTransform.rect.height / 2;
// If selection below scroll view
if (selectedPositionY > scrollViewMaxY)
{
var newY = selectedPositionY - _scrollRect.rect.height;
_content.anchoredPosition = new Vector2(_content.anchoredPosition.x, newY);
}
// If selection above scroll view
else if (Mathf.Abs(selectedRectTransform.anchoredPosition.y) < scrollViewMinY)
{
_content.anchoredPosition =
new Vector2(_content.anchoredPosition.x, Mathf.Abs(selectedRectTransform.anchoredPosition.y)
- selectedRectTransform.rect.height / 2);
}
}
public void RemoveCenterCell()
{
RemoveCell(_centerCellIndex);
}
public void RemoveCell(int index)
{
if (m_cellContainer.Count <= 0)
return;
if (index < 0 || index >= m_cellContainer.Count)
return;
// Remove the current center cell
var go = m_cellContainer[index];
RemoveCellData(go);
m_cellContainer.Remove(go);
Destroy(go);
if (m_cellContainer.Count > 0)
_arcLength = 360 / m_cellContainer.Count;
else
_arcLength = 360;
}
private void LoadCells()
{
if (_shouldAutoCreateCells)
for (var i = 0; i < _totalCells; ++i)
AddCell();
else
// Get all the child cells from panel
for (var i = 0; i < _panel.childCount; ++i)
{
var go = _panel.GetChild(i).gameObject;
m_cellContainer.Add(go);
AddCellData(go, i);
}
}
private void UnloadCells()
{
while (m_cellContainer.Count != 0) RemoveCell(0);
m_cellContainer.Clear();
}
private void OnCellBtnCallback(object sender, CellEventArgs e)
{
var index = e.Index;
for (var i = 0; i < m_cellContainer.Count; ++i)
if (m_cellContainer[i] == (sender as CellController).gameObject)
//Debug.Log("select index: " + i);
index = i;
if (onCellClickedEvent != null)
onCellClickedEvent.Invoke(index, e.Index);
// Check if we should center the selected cell
if (_shouldCenterSelect)
{
_selectIndex = index;
_scroll.velocity = Vector3.zero;
}
}
private void AddCellData(GameObject go, int index)
{
var cc = go.GetComponent<CellController>();
if (cc == null)
return;
cc._index = index;
cc.name = "" + cc._index;
if (_shouldUpdateDesc)
cc.UpdateDesc("btn " + cc._index);
cc.Clicked += OnCellBtnCallback;
}
private void RemoveCellData(GameObject go)
{
var cc = go.GetComponent<CellController>();
if (cc == null)
return;
cc.Clicked -= OnCellBtnCallback;
}
private void SetupCells(bool instantUpdate)
{
for (var i = 0; i < m_cellContainer.Count; i++)
{
var rt = m_cellContainer[i].GetComponent<RectTransform>();
if (rt == null)
continue;
_newPos = Vector3.zero;
_newScale = new Vector3(1, 1, 1);
_newRot = Vector3.zero;
_offset = _panel.position - _dragStartPos;
_offsetIndex = i - _centerCellIndex;
_isCircularMovment = false;
// Consider the canvas scale
_width = (rt.rect.width + _cellGap) * canvasRect.localScale.x;
switch (_carouselType)
{
case CarouselConstants.CarouselType.CarouselTypeLinear:
{
_newPos.x = _width * _offsetIndex;
var scaleRatio = Mathf.Clamp(1 - Mathf.Abs(2 / (_scrollRT.rect.width / 2)), 0.1f, 200f) *
scaleFactor;
_newScale = new Vector3(scaleRatio * _scaleRatio.x, scaleRatio * _scaleRatio.y,
scaleRatio * _scaleRatio.z);
}
break;
case CarouselConstants.CarouselType.CarouselTypeScaledLinear:
{
_newPos.x = cellWidth * _width * _offsetIndex;
var dis = Vector3.Distance(rt.position, _center.position);
// Make sure it is not too small nor not too big
var scaleRatio = Mathf.Clamp(1 - Mathf.Abs(dis / (_scrollRT.rect.width / 2)), 0.1f, 200f) *
scaleFactor;
_newScale = new Vector3(scaleRatio * _scaleRatio.x, scaleRatio * _scaleRatio.y,
scaleRatio * _scaleRatio.z);
}
break;
case CarouselConstants.CarouselType.CarouselTypeCoverFlow:
{
_newPos.x = _width * _offsetIndex;
if (_offsetIndex < 0)
_newRot = -_coverflowAngles;
else if (_offsetIndex > 0) _newRot = _coverflowAngles;
}
break;
case CarouselConstants.CarouselType.CarouselTypeScaledCoverFlow:
{
_newPos.x = _width * _offsetIndex;
var dis = Vector3.Distance(rt.position, _center.position);
// Make sure it is not too small nor not too big
var scaleRatio = Mathf.Clamp(1 - Mathf.Abs(dis / (_scrollRT.rect.width / 2)), 0.1f, 100);
_newScale = new Vector3(scaleRatio * _scaleRatio.x, scaleRatio * _scaleRatio.y,
scaleRatio * _scaleRatio.z);
if (_offsetIndex < 0)
_newRot = -_coverflowAngles;
else if (_offsetIndex > 0) _newRot = _coverflowAngles;
}
break;
}
// Only allow one direction at a time
if (!_isHorizontal)
{
_newPos.y = _newPos.x;
_newPos.x = 0;
_newRot.x = _newRot.y;
_newRot.y = 0;
}
_final = _center.position + _newPos + _offset;
if (instantUpdate || _isCircularMovment)
{
rt.position = _final;
rt.localScale = _newScale;
rt.localRotation = Quaternion.Euler(_newRot);
_panel.ForceUpdateRectTransforms();
}
else
{
rt.position = Vector3.Lerp(rt.position, _final, movementCurve.Evaluate(Time.deltaTime) * _moveSpeed);
rt.localScale = Vector3.Lerp(rt.localScale, _newScale, Time.deltaTime * _scaleSpeed);
rt.localRotation = Quaternion.Lerp(rt.localRotation, Quaternion.Euler(_newRot),
Time.deltaTime * _rotateSpeed);
}
}
}
private void CheckAutoFocus()
{
if (!_shouldFocusCenter)
return;
if (_selectIndex != -1)
return;
if (_dragging)
return;
if (_isHorizontal && Mathf.Abs(_scroll.velocity.x) > _focusCenterVelocityThreshold)
return;
if (_isHorizontal == false && Mathf.Abs(_scroll.velocity.y) > _focusCenterVelocityThreshold)
return;
if (m_cellContainer.Count == 0)
return;
//Debug.Log("Start auto focus");
_dragStartPos = _panel.position;
}
[Button]
public void OnCarouselPreviousItem(int itemIndex)
{
var index = itemIndex;
if (index > m_cellContainer.Count || index < 0) return;
if (onCellClickedEvent != null)
onCellClickedEvent.Invoke(index, itemIndex);
// Check if we should center the selected cell
if (_shouldCenterSelect)
{
_selectIndex = itemIndex;
_scroll.velocity = Vector3.zero;
}
}
[Button]
public void OnCarouselNextItem(int itemIndex)
{
var index = itemIndex;
if (index > m_cellContainer.Count || index < 0) return;
if (onCellClickedEvent != null)
onCellClickedEvent.Invoke(index, itemIndex);
// Check if we should center the selected cell
if (_shouldCenterSelect)
{
_selectIndex = index;
_scroll.velocity = Vector3.zero;
}
}
private void CheckCenterSelect()
{
if (!_shouldCenterSelect)
return;
if (_dragging)
return;
if (_selectIndex == -1)
return;
if (m_cellContainer.Count == 0)
return;
// Stop velocity
_scroll.velocity = Vector3.zero;
_centerCellIndex = _selectIndex;
_dragStartPos = _panel.position;
}
private void FindCenterCellIndex()
{
if (m_cellContainer.Count == 0)
return;
_tempCenterIndex = -1;
for (var i = 0; i < m_cellContainer.Count; i++)
// If there is non selected, we just select the first one
if (_tempCenterIndex == -1)
{
_tempCenterIndex = i;
}
else
{
// Find the nearest one as the center one
var rhdGo = m_cellContainer[i];
var centerGo = m_cellContainer[_tempCenterIndex];
var lhdGo = m_cellContainer[i - 1];
if(!_dragging)
ApplySelectionEffect(rhdGo, centerGo, lhdGo);
//ApplySelectionEffect(m_cellContainer[_centerCellIndex+1], m_cellContainer[_centerCellIndex], m_cellContainer[_centerCellIndex-1]);
// Find the center index by shortest distance
var oldDis = Vector3.Distance(centerGo.transform.position, _center.position);
var dis = Vector3.Distance(rhdGo.transform.position, _center.position);
if (dis < oldDis)
{
_tempCenterIndex = i;
}
}
_centerCellIndex = _tempCenterIndex;
// Debug.Log("Center index: " + _centerCellIndex);
CalculateDragOffset();
}
private void ApplySelectionEffect(GameObject rhdGo, GameObject centerGo, GameObject lhdGo)
{
rhdGo.GetComponent<CanvasGroup>().DOFade(0.2f, 0.5f);
centerGo.GetComponent<CanvasGroup>().DOFade(1.0f, 0.5f);
lhdGo.GetComponent<CanvasGroup>().DOFade(0.2f, 0.5f);
rhdGo.GetComponent<CellController>().outlineEffect.SetActive(false);
centerGo.GetComponent<CellController>().outlineEffect.SetActive(true);
lhdGo.GetComponent<CellController>().outlineEffect.SetActive(false);
rhdGo.GetComponent<CellController>().videoOverlay.color = fadeColor;
centerGo.GetComponent<CellController>().videoOverlay.color = fullColor;
if (!isSubMenu)
{
rhdGo.GetComponent<CellController>().bannerImage.gameObject.SetActive(false);
centerGo.GetComponent<CellController>().bannerImage.gameObject.SetActive(true);
lhdGo.GetComponent<CellController>().bannerImage.gameObject.SetActive(false);
rhdGo.gameObject.transform.localScale = _cellDefaultItemScale;
centerGo.gameObject.transform.localScale = _cellItemScale;
lhdGo.gameObject.transform.localScale = _cellDefaultItemScale;
}
rhdGo.GetComponent<CellController>().SetDefault();
centerGo.GetComponent<CellController>().SetHighlight();
lhdGo.GetComponent<CellController>().SetDefault();
// rhdGo.GetComponentInChildren<UIOutline>(true)._outlineWidth = 10f;
// centerGo.GetComponentInChildren<UIOutline>(true)._outlineWidth = 200f;
// lhdGo.GetComponentInChildren<UIOutline>(true)._outlineWidth = 10f;
}
private void CalculateDragOffset()
{
if (m_cellContainer.Count == 0)
return;
if (_centerCellIndex < 0 || _centerCellIndex >= m_cellContainer.Count)
return;
var center = m_cellContainer[_centerCellIndex].GetComponent<RectTransform>();
_dragStartPos = _panel.position + (_center.position - center.position);
}
private void CheckBoundary()
{
if (_cell == null)
return;
if (!_shouldLoop)
return;
if (m_cellContainer.Count == 0)
return;
var rt = _cell.GetComponent<RectTransform>();
if (rt == null)
return;
var cellWidth = (rt.rect.width + _cellGap) * canvasRect.localScale.x;
var cellHeight = (rt.rect.height + _cellGap) * canvasRect.localScale.y;
// Calculate the boundaries
_boundary.x = m_cellContainer.Count * cellWidth;
_boundary.y = m_cellContainer.Count * cellHeight;
var leftBoundary = _center.position.x - _boundary.x / 2;
var rightBoundary = _center.position.x + _boundary.x / 2;
var upBoundary = _center.position.y + _boundary.y / 2;
var downBoundary = _center.position.y - _boundary.y / 2;
// We only check the right most or left most
if (_isHorizontal)
{
//if ((_panel.position - m_dragDir).x < 0)
{
var go = m_cellContainer[0];
if (go.transform.position.x < leftBoundary)
//Debug.Log("left");
UpdateBoundaryCell(go, new Vector3(rightBoundary, go.transform.position.y, go.transform.position.z),
false);
}
//else if ((_panel.position - m_dragDir).x > 0)
{
var go = m_cellContainer[m_cellContainer.Count - 1];
if (go.transform.position.x > rightBoundary)
//Debug.Log("right");
UpdateBoundaryCell(go, new Vector3(leftBoundary, go.transform.position.y, go.transform.position.z),
true);
}
}
else
{
//if ((_panel.position - m_dragDir).y < 0)
{
var go = m_cellContainer[0];
if (go.transform.position.y < downBoundary)
//Debug.Log("down");
UpdateBoundaryCell(go, new Vector3(go.transform.position.x, upBoundary, go.transform.position.z),
false);
}
//else if ((_panel.position - m_dragDir).y > 0)
{
var go = m_cellContainer[m_cellContainer.Count - 1];
if (go.transform.position.y > upBoundary)
//Debug.Log("up");
UpdateBoundaryCell(go, new Vector3(go.transform.position.x, downBoundary, go.transform.position.z),
true);
}
}
}
private void UpdateBoundaryCell(GameObject passGO, Vector3 newPos, bool isInsert)
{
//Debug.Log("panel pos: " + _panel.position + " center pos: " + _center.position);
passGO.transform.position = newPos;
//int newCenterIndex = m_centerCellIndex;
GameObject selectGO = null;
if (_selectIndex != -1)
selectGO = m_cellContainer[_selectIndex];
if (isInsert)
{
m_cellContainer.Remove(passGO);
m_cellContainer.Insert(0, passGO);
}
else
{
m_cellContainer.Remove(passGO);
m_cellContainer.Add(passGO);
}
// If there is a select index, we need to update it as well
// because container array has been updated
if (selectGO) _selectIndex = m_cellContainer.IndexOf(selectGO);
}
public void Select()
{
if(m_cellContainer[_selectIndex] != null)
m_cellContainer[_selectIndex].GetComponentInChildren<Button>().onClick.Invoke();
}
}
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class CellEventArgs : EventArgs
{
public int Index;
public CellEventArgs(int i)
{
Index = i;
}
}
/// <summary>
/// This class handles the individual cells within the carousel scroll view
/// </summary>
public class CellController : MonoBehaviour
{
public event EventHandler<CellEventArgs> Clicked;
public UnityEvent OnCentered;
public UnityEvent OnDisabled;
public int _index;
public Text _desc;
public GameObject outlineEffect;
[FormerlySerializedAs("fade")] public TweenSequencer bannerImage;
public Image videoOverlay;
public Image outline;
private readonly Color32 normalState = new Color32(255,255,255,255);
private readonly Color32 highlighState = new Color32(0,129,138,255);
public bool isBtnCentered = false;
public bool scaleOffset = false;
private void Awake()
{
if(bannerImage == null)
bannerImage = GetComponent<TweenSequencer>();
}
public void ToggleOutline(bool toggle)
{
outlineEffect.SetActive(toggle);
}
public void ScaleButton()
{
this.transform.localScale = new Vector3(.9f, .9f, 1f);
}
public void UpdateDesc(string desc)
{
if (_desc == null)
return;
_desc.text = desc;
}
public void OnBtnDown()
{
Clicked?.Invoke(this, new CellEventArgs(_index));
}
public void OnButtonCentered()
{
if (isBtnCentered)
{
FadeIn();
}
OnCentered?.Invoke();
}
public void SetDefault()
{
outline.color = normalState;
}
public void SetHighlight()
{
outline.color = highlighState;
}
public void FadeIn()
{
bannerImage.FadeIn();
}
public void FadeOut()
{
bannerImage.FadeOut();
}
}
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasRenderer))]
public class UIOutline : MaskableGraphic
{
[SerializeField] Texture m_Texture;
[SerializeField, Range(0f, 500f)] public float _outlineWidth = 100f;
[SerializeField, Range(0f, 500f)] public float _cornerRadius = 50f;
[SerializeField, Range(1, 20)] public int _cornerSegments = 1;
[SerializeField, Range(0f, 1f)] public float _mappingBias = 0.5f;
[SerializeField] public bool _fillCenter;
private Vector3[] _corners = new Vector3[4];
private List<UIVertex> _verts = new List<UIVertex>();
public override Texture mainTexture => m_Texture == null ? s_WhiteTexture : m_Texture;
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
SetVerticesDirty();
SetMaterialDirty();
}
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
// Clamp corner radius
var rect = rectTransform.rect;
var clampedCornerRadius = Mathf.Min((Mathf.Min(rect.width, rect.height) / 2f), _cornerRadius);
// Offset corner based on clamped corner radius
rectTransform.GetLocalCorners(_corners);
_corners[0] += new Vector3(clampedCornerRadius, clampedCornerRadius, 0f);
_corners[1] += new Vector3(clampedCornerRadius, -clampedCornerRadius, 0f);
_corners[2] += new Vector3(-clampedCornerRadius, -clampedCornerRadius, 0f);
_corners[3] += new Vector3(-clampedCornerRadius, clampedCornerRadius, 0f);
// Calculate dimensions
var height = _corners[1].y - _corners[0].y;
var width = _corners[2].x - _corners[1].x;
var edgeLengths = new[] { height, width, height, width };
var circumference = 2f * Mathf.PI * Mathf.Lerp(clampedCornerRadius, clampedCornerRadius + _outlineWidth, _mappingBias);
var around = height * 2f + width * 2f + circumference;
var cornerLength = circumference / 4f;
var segmentLength = cornerLength / _cornerSegments;
var vert = new UIVertex { color = color };
_verts.Clear();
// Create corners
var u = 0f;
for (var c = 0; c < 4; c++)
{
// Create verts
var origin = _corners[c];
for (var i = 0; i < _cornerSegments + 1; i++)
{
var angle = (float)i / _cornerSegments * Mathf.PI / 2f + Mathf.PI * 0.5f - Mathf.PI * c * 1.5f;
var direction = new Vector3(Mathf.Cos(-angle), Mathf.Sin(-angle), 0f);
vert.position = origin + direction * clampedCornerRadius;
vert.uv0 = new Vector2(u, 0f);
_verts.Add(vert);
vert.position = origin + direction * (clampedCornerRadius + _outlineWidth);
vert.uv0 = new Vector2(u, 1f);
_verts.Add(vert);
if (_fillCenter)
{
vert.position = rect.center;
vert.uv0 = new Vector2(u, 0f);
_verts.Add(vert);
}
if (i < _cornerSegments)
u += segmentLength / around;
else
u += edgeLengths[c] / around;
}
}
// Add end verts
vert = _verts[0];
vert.uv0 = new Vector2(1f, 0f);
_verts.Add(vert);
vert = _verts[1];
vert.uv0 = new Vector2(1f, 1f);
_verts.Add(vert);
if (_fillCenter)
{
vert = _verts[2];
vert.uv0 = new Vector2(1f, 1f);
_verts.Add(vert);
}
// Add verts to VertexHelper
foreach (var vertex in _verts)
vh.AddVert(vertex);
// Add triangles to VertexHelper
if (_fillCenter)
{
for (var v = 0; v < vh.currentVertCount - 3; v += 3)
{
vh.AddTriangle(v, v + 1, v + 4);
vh.AddTriangle(v, v + 4, v + 3);
vh.AddTriangle(v + 2, v, v + 3);
vh.AddTriangle(v + 2, v + 3, v + 5);
}
}
else
{
for (var v = 0; v < vh.currentVertCount - 2; v += 2)
{
vh.AddTriangle(v, v + 1, v + 3);
vh.AddTriangle(v, v + 3, v + 2);
}
}
}
}
Shader "UI/UIOutline"
{
Properties
{
_StencilComp("Stencil Comparison", Float) = 8
_Stencil("Stencil ID", Float) = 0
_StencilOp("Stencil Operation", Float) = 0
_StencilWriteMask("Stencil Write Mask", Float) = 255
_StencilReadMask("Stencil Read Mask", Float) = 255
_ColorMask("Color Mask", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0
[HideInInspector]_MainTex("MainTex", 2D) = "white" {}
_InsideColor("InsideColor", Color) = (0,0,0,0)
_OutsideColor("OutsideColor", Color) = (0,0,0,0)
_Falloff("Falloff", Range( 0 , 10)) = 1
_InnerGlow("InnerGlow", Range( 0 , 1)) = 1
_AlphaBoost("AlphaBoost", Range( 0 , 5)) = 1
_SoftenEdgeWidth("SoftenEdgeWidth", Range( 0 , 1)) = 0
_SpeedA("SpeedA", Vector) = (0,0,0,0)
_SpeedB("SpeedB", Vector) = (0,0,0,0)
_TilingA("TilingA", Vector) = (0,0,0,0)
_TilingB("TilingB", Vector) = (0,0,0,0)
}
SubShader
{
LOD 0
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" }
Stencil
{
Ref [_Stencil]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
CompFront [_StencilComp]
PassFront [_StencilOp]
FailFront Keep
ZFailFront Keep
CompBack Always
PassBack Keep
FailBack Keep
ZFailBack Keep
}
Cull Off
Lighting Off
ZWrite Off
ZTest[unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask[_ColorMask]
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_ALPHACLIP
#include "UnityShaderVariables.cginc"
#define ASE_NEEDS_FRAG_COLOR
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
uniform float4 _ClipRect;
uniform float4 _OutsideColor;
uniform float4 _InsideColor;
uniform sampler2D _MainTex;
uniform float2 _TilingA;
uniform float2 _SpeedA;
uniform float2 _TilingB;
uniform float2 _SpeedB;
uniform float _Falloff;
uniform float _InnerGlow;
uniform float _AlphaBoost;
uniform float _SoftenEdgeWidth;
v2f vert(appdata_t IN )
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = IN.vertex;
OUT.worldPosition.xyz += float3(0, 0, 0) ;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color;
return OUT;
}
fixed4 frag(v2f IN ) : SV_Target
{
float mulTime33 = _Time.y * _SpeedA.x;
float mulTime49 = _Time.y * _SpeedA.y;
float2 appendResult31 = (float2(mulTime33 , mulTime49));
float2 texCoord16 = IN.texcoord.xy * _TilingA + appendResult31;
float mulTime52 = _Time.y * _SpeedB.x;
float mulTime53 = _Time.y * _SpeedB.y;
float2 appendResult51 = (float2(mulTime52 , mulTime53));
float2 texCoord45 = IN.texcoord.xy * _TilingB + appendResult51;
float2 texCoord35 = IN.texcoord.xy * float2( 1,1 ) + float2( 0,0 );
float temp_output_63_0 = saturate( pow( ( 1.0 - texCoord35.y ) , _Falloff ) );
float lerpResult70 = lerp( ( ( ( tex2D( _MainTex, texCoord16 ).r + tex2D( _MainTex, texCoord45 ).r ) / 2.0 ) * IN.color.a * temp_output_63_0 ) , ( IN.color.a * temp_output_63_0 ) , ( temp_output_63_0 * _InnerGlow ));
float lerpResult101 = lerp( 1.0 , saturate( ( texCoord35.y * (200.0 + (_SoftenEdgeWidth - 0.0) * (0.5 - 200.0) / (1.0 - 0.0)) ) ) , saturate( (0.0 + (_SoftenEdgeWidth - 0.0) * (1.0 - 0.0) / (0.01 - 0.0)) ));
float temp_output_67_0 = saturate( ( lerpResult70 * _AlphaBoost * lerpResult101 ) );
float3 lerpResult59 = lerp( (_OutsideColor).rgb , (_InsideColor).rgb , temp_output_67_0);
float4 appendResult23 = (float4(( lerpResult59 * (IN.color).rgb ) , temp_output_67_0));
half4 color = appendResult23;
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#ifdef UNITY_UI_ALPHACLIP
clip(color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
CustomEditor "ASEMaterialInspector"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment