Created
May 23, 2023 15:21
-
-
Save junaid109/893e6c57b9a71acfacae3709f68650f1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class CarouselConstants : MonoBehaviour | |
{ | |
public enum CarouselType | |
{ | |
CarouselTypeLinear, | |
CarouselTypeScaledLinear, | |
CarouselTypeCoverFlow, | |
CarouselTypeScaledCoverFlow, | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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