Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。简单来说,Unity3D不单单可以做游戏,还可以通过相关接口与API来进行设备的交互【例如虚拟仿真】
前言
大家好,我是雨涵,也可以叫我大山(大山这个名字比较亲切一些,不管叫哪一个都是不错的),这篇文章内容可能会超级的长,但是记录的东西绝对是我从学生转变到工作就业之后的工作笔记,本来寻思着写一些最基础的内容,但是后来转念一想,与其长篇幅的去赘述动一动鼠标键盘就能找到的东西,岂不是浪费宝贵的学习时间,毕竟学习的时间就少,大部分时间都用在了思考功能如何实现以及打游戏以及摸鱼看剧上。
正文内容
UI功能篇
这一篇主要说明的是一些常用的UI功能,也会附带着相关的代码,具体怎么用,都会有注释的,毕竟注释可不能少的呦!!!
UI滚动效果
先看一张动态的图,看一下具体是什么效果

这里用到的组件主要就是Scroll View 组件,并在Scroll View 的content身上放上Content Size Fitter以及Grid Layut Group这两个组件(在这里建议哈:尽量少用Grid Layout Group,多了会影响一定性能),里面的参数就自定义吧,需要多大的尺寸自行调整即可。
基础滚动列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
| using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI;
public enum PageScrollType { Horizontal, Vertical } public class PageScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler {
#region 字段 protected ScrollRect rect; protected int pageCount; private RectTransform content; protected float[] pages; public float moveTime = 0.3f; private float timer = 0; private float startMovePos; protected int currentPage = 0; private bool isDraging = false; private bool isMoving = false; public bool IsAutoScroll; public float AutoScrollTime = 2; private float AutoScrollTimer = 0; public PageScrollType pageScrollType = PageScrollType.Horizontal; public float vertical; #endregion
#region 事件 public Action<int> OnPageChange; #endregion
#region Unity回调 protected virtual void Start() { Init(); } protected virtual void Update() { ListenerMove(); ListenerAutoScroll(); vertical = rect.verticalNormalizedPosition; } public void OnEndDrag(PointerEventData eventData) { this.ScrollToPage(CaculateMinDistancePage()); isDraging = false; AutoScrollTimer = 0; } public void OnBeginDrag(PointerEventData eventData) { isDraging = true; } #endregion #region 方法 public void Init() { rect = transform.GetComponent<ScrollRect>(); if (rect == null) { throw new System.Exception(" 未查询到ScrollRect! "); } content = transform.Find("Viewport/Content").GetComponent<RectTransform>(); pageCount = content.childCount; if (pageCount == 1) { throw new System.Exception("只有一页,不用进行分页滚动!"); } pages = new float[pageCount]; for (int i = 0; i < pages.Length; i++) { switch (pageScrollType) { case PageScrollType.Horizontal: pages[i] = i * (1.0f / (float)(pageCount - 1)); break; case PageScrollType.Vertical: pages[i] = 1 - i * (1.0f / (float)(pageCount - 1)); break; } } } public void ListenerMove() { if (isMoving) { timer += Time.deltaTime * (1 / moveTime); switch (pageScrollType) { case PageScrollType.Horizontal: rect.horizontalNormalizedPosition = Mathf.Lerp(startMovePos, pages[currentPage], timer); break; case PageScrollType.Vertical: rect.verticalNormalizedPosition = Mathf.Lerp(startMovePos, pages[currentPage], timer); break; } if (timer >= 1) { isMoving = false; } } } public void ListenerAutoScroll() {
if (isDraging) { return; } if (IsAutoScroll) { AutoScrollTimer += Time.deltaTime; if (AutoScrollTimer >= AutoScrollTime) { AutoScrollTimer = 0; currentPage++; currentPage %= pageCount; ScrollToPage(currentPage); } } }
public void ScrollToPage(int page) { isMoving = true; this.currentPage = page; timer = 0; switch (pageScrollType) { case PageScrollType.Horizontal: startMovePos = rect.horizontalNormalizedPosition; break; case PageScrollType.Vertical: startMovePos = rect.verticalNormalizedPosition; break; } if (OnPageChange != null) OnPageChange(this.currentPage); } public int CaculateMinDistancePage() { int minPage = 0; for (int i = 1; i < pages.Length; i++) { switch (pageScrollType) { case PageScrollType.Horizontal:
if (Mathf.Abs(pages[i] - rect.horizontalNormalizedPosition) < Mathf.Abs(pages[minPage] - rect.horizontalNormalizedPosition)) { minPage = i; } break; case PageScrollType.Vertical:
if (Mathf.Abs(pages[i] - rect.verticalNormalizedPosition) < Mathf.Abs(pages[minPage] - rect.verticalNormalizedPosition)) { minPage = i; } break; } } return minPage; } #endregion }
|
Scale 缩放滚动列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class ScalePageScrollView : PageScrollView { #region 字段 protected GameObject[] items; public float currentScale = 1f; public float otherScale = 0.6f; public int lastPage; public int nextPage; #endregion
#region Unity回调 protected override void Start() { base.Start(); items = new GameObject[pageCount]; for (int i = 0; i < pageCount; i++) { items[i] = transform.Find("Viewport/Content").GetChild(i).gameObject; }
} protected override void Update() { base.Update(); ListenerScale(); } #endregion public void ListenerScale() {
for (int i = 0; i < pages.Length; i++) { if ( pages[i] <= rect.horizontalNormalizedPosition ) { lastPage = i; } }
for (int i = 0; i < pages.Length; i++) { if (pages[i] > rect.horizontalNormalizedPosition) { nextPage = i; break; } }
if ( nextPage == lastPage ) { return; }
float percent = (rect.horizontalNormalizedPosition - pages[lastPage]) / ( pages[nextPage] - pages[lastPage] ); items[lastPage].transform.localScale = Vector3.Lerp(Vector3.one * currentScale, Vector3.one * otherScale, percent); items[nextPage].transform.localScale = Vector3.Lerp(Vector3.one * currentScale, Vector3.one * otherScale, 1 - percent);
for (int i = 0; i < items.Length; i++) { if (i != lastPage && i != nextPage) { items[i].transform.localScale = Vector3.one * otherScale; }
} } }
|
旋转滚动列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotationScaleScrollView : ScalePageScrollView { public float rotation; protected override void Update() { base.Update(); ListenerItemRotation(); } public void ListenerItemRotation() {
if (nextPage == lastPage) return; float percent = (rect.horizontalNormalizedPosition - pages[lastPage]) / (pages[nextPage] - pages[lastPage]);
if (nextPage > currentPage) { items[lastPage].transform.localRotation = Quaternion.Euler(-Vector3.Lerp(Vector3.zero, new Vector3(0, rotation, 0), percent)); items[nextPage].transform.localRotation = Quaternion.Euler(Vector3.Lerp(Vector3.zero, new Vector3(0, rotation, 0), 1 - percent)); } else { items[lastPage].transform.localRotation = Quaternion.Euler(-Vector3.Lerp(Vector3.zero, new Vector3(0, rotation, 0), percent)); items[nextPage].transform.localRotation = Quaternion.Euler(Vector3.Lerp(Vector3.zero, new Vector3(0, rotation, 0), 1 - percent)); }
for (int i = 0; i < items.Length; i++) {
if ( i != lastPage && i != nextPage ) { if (i < currentPage) { items[i].transform.localRotation = Quaternion.Euler(new Vector3(0, -rotation, 0)); } else if (i == currentPage) { } else if (i > currentPage) { items[i].transform.localRotation = Quaternion.Euler(new Vector3(0, rotation, 0)); } } } } }
|
不规则UI按钮

本来开开心心的琢磨如何实现功能,后来发现这UI也不是规则的呀,后来整了半天,总算是琢磨出一套方案
- 创建一个Camera,重命名为UICamera,设置Culling Mask为UI,设置相机的投射模式(Projection)为正交模式(Orthographic),注意主摄像机的Culling Mask去掉UI层。
Canvas使用Screen Space - Camera模式,并赋值UICamera。【注意,UICamera
不需要Audio Listener
,直接去掉。】
在Button
的子节点创建一个空节点(这里重命名为IrregularUIBtnMgr
),挂上IrregularUIBtnMgr
脚本(脚本代码见文章最下面),会自动挂上Polygon Collider 2D
组件,将坐标归零。
选中IrregularUIBtnMgr
节点,点击Polygon Collider 2D
组件中的Edit Collider
旁边的按钮,即可直接编辑多边形碰撞形状。
最后要调节Width
和Height
,确保包住整个不规则碰撞区域。
最后是代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.UI;
[RequireComponent(typeof(PolygonCollider2D))] public class IrregularUIBtnMgr : Image { private PolygonCollider2D _polygon = null; private PolygonCollider2D polygon { get { if (_polygon == null) _polygon = GetComponent<PolygonCollider2D>(); return _polygon; } } protected IrregularUIBtnMgr() { useLegacyMeshGeneration = true; }
protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); }
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera) { return polygon.OverlapPoint(eventCamera.ScreenToWorldPoint(screenPoint)); }
#if UNITY_EDITOR protected override void Reset() { base.Reset(); transform.position = Vector3.zero; float w = (rectTransform.sizeDelta.x * 0.5f) + 0.1f; float h = (rectTransform.sizeDelta.y * 0.5f) + 0.1f; polygon.points = new Vector2[] { new Vector2(-w,-h), new Vector2(w,-h), new Vector2(w,h), new Vector2(-w,h) }; } #endif }
#if UNITY_EDITOR [CustomEditor(typeof(IrregularUIBtnMgr), true)] public class UIPolygonInspector : Editor { public override void OnInspectorGUI() { } } #endif
|
自定义UI按钮框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| using UnityEngine; using System.Collections; using UnityEngine.UI; public class PolygonUIMesh : Graphic { private void OnGUI() { SetAllDirty(); } protected override void OnPopulateMesh(VertexHelper vh) { if (transform.childCount <= 2) return; Color32 color32 = color; vh.Clear(); foreach (Transform child in transform) vh.AddVert(child.localPosition, color32, new Vector2(0f, 0f)); for (int i = 0; i < (transform.childCount - 2); i++) vh.AddTriangle(i + 1, i + 2, 0); } private void OnDrawGizmos() { if (transform.childCount == 0) return; for (int i = 0; i < transform.childCount; i++) Gizmos.DrawSphere(transform.GetChild(i).position, 2.55f); } }
|
特效篇
移动端篇
最近想着准备做一个手游玩,但是想了半天如果自己做登录,服务器运营的成本又太高,突然灵机一动,可以接入SDK,后来看了QQ的登录,发现有点麻烦,后来选择了TapTap登录,接入也比较简单
具体的参考文档(还是比较详细,按照相关操作一般能实现基本内容,但是剩下的肯定是需要自己去实现的):TapTap 开发者文档
这里就阐述一些比较常用的功能如何实现
首先肯定是需要先到TapTap开发者,申请个人开发者,毕竟得需要Client ID和Client Token,到时候需要使用到
最后我是雨涵,多记点笔记