目录
1、加载场景,显示进度
2、Image渐变色
3、获取物体所有的材质,并且改变这些材质的Shader
4、检查tag列表中是否有tag,没有该tag添加此tag
5、Dotween对数值进行递增或递减
6、鼠标双击
7、获取模型Bound中心点
8、绘制相机视野
9、编辑器扩展,复制物体的Position和Roation
10、鼠标拖动物体移动
11、逐渐注视目标方向旋转
12、对象池
1、加载场景,显示进度
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SceneLoadTool : MonoBehaviour
{
///
/// 要加载场景的名称
///
public string SceneName;
///
/// 加载进度显示界面
///
public GameObject LoadingPanel;
///
/// 加载进度条
///
public Slider LoadSlider;
///
/// 加载进度文字
///
public Text txt_LoadProcess;
///
/// 进度条速度
///
private float loadSpeed = 1;
///
/// 进度条最终进度值
///
private float loadTargetValue = 0;
public void StartLoadScene()
{
LoadSlider.value = 0;
StartCoroutine(LoadScene(SceneName));
}
IEnumerator LoadScene(string sceneName)
{
LoadingPanel.SetActive(true);
AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
operation.allowSceneActivation = false;
while (!operation.isDone)
{
loadTargetValue = operation.progress;
if (operation.progress >= 0.9f)
{
loadTargetValue = 1;
}
if (!loadTargetValue.Equals(LoadSlider.value))
{
LoadSlider.value = Mathf.Lerp(LoadSlider.value, loadTargetValue,Time.deltaTime * loadSpeed); //插值,让进度条流畅
if (Mathf.Abs(LoadSlider.value - loadTargetValue) < 0.01f)
{
LoadSlider.value = loadTargetValue;
}
}
txt_LoadProcess.text =(int)(LoadSlider.value * 100) + "%";
if ((int)(LoadSlider.value * 100) == 100)
{
operation.allowSceneActivation = true; //允许异步加载完毕后自动切换场景
}
yield return null;
}
}
}
2、Image渐变色
using UnityEngine;
using UnityEngine.UI;
///
/// 挂Image组件上
///
[AddComponentMenu("UI/Effects/Gradient")]
public class GradientColor : BaseMeshEffect
{
public Color Color1 = Color.white;
public Color Color2 = Color.white;
[Range(-180f, 180f)] public float Angle = -90.0f;
public override void ModifyMesh(VertexHelper vh)
{
if (enabled)
{
var rect = graphic.rectTransform.rect;
var dir = RotationDir(Angle);
var localPositionMatrix = LocalPositionMatrix(rect, dir);
var vertex = default(UIVertex);
for (var i = 0; i < vh.currentVertCount; i++)
{
vh.PopulateUIVertex(ref vertex, i);
var localPosition = localPositionMatrix * vertex.position;
vertex.color *= Color.Lerp(Color2, Color1, localPosition.y);
vh.SetUIVertex(vertex, i);
}
}
}
public struct Matrix2x3
{
public float m00, m01, m02, m10, m11, m12;
public Matrix2x3(float m00, float m01, float m02, float m10, float m11, float m12)
{
this.m00 = m00;
this.m01 = m01;
this.m02 = m02;
this.m10 = m10;
this.m11 = m11;
this.m12 = m12;
}
public static Vector2 operator *(Matrix2x3 m, Vector2 v)
{
float x = (m.m00 * v.x) - (m.m01 * v.y) + m.m02;
float y = (m.m10 * v.x) + (m.m11 * v.y) + m.m12;
return new Vector2(x, y);
}
}
private Matrix2x3 LocalPositionMatrix(Rect rect, Vector2 dir)
{
float cos = dir.x;
float sin = dir.y;
Vector2 rectMin = rect.min;
Vector2 rectSize = rect.size;
float c = 0.5f;
float ax = rectMin.x / rectSize.x + c;
float ay = rectMin.y / rectSize.y + c;
float m00 = cos / rectSize.x;
float m01 = sin / rectSize.y;
float m02 = -(ax * cos - ay * sin - c);
float m10 = sin / rectSize.x;
float m11 = cos / rectSize.y;
float m12 = -(ax * sin + ay * cos - c);
return new Matrix2x3(m00, m01, m02, m10, m11, m12);
}
private Vector2 RotationDir(float angle)
{
float angleRad = angle * Mathf.Deg2Rad;
float cos = Mathf.Cos(angleRad);
float sin = Mathf.Sin(angleRad);
return new Vector2(cos, sin);
}
}
3、获取物体所有的材质,并且改变这些材质的Shader
#region 获取物体所有的材质,并且改变这些材质的Shader
private Renderer[] rendArray;
private List materials = new List();
///
/// 获取物体上所有的材质,并改变这些材质的Shader
///
private void GetModelAllMaterialsAndChange(GameObject gameObject, Shader targetShader)
{
materials.Clear();
rendArray = gameObject.transform.GetComponentsInChildren(true);
for (int i = 0; i < rendArray.Length; i++)
{
Material[] mats = rendArray[i].materials;
for (int j = 0; j < mats.Length; j++)
{
materials.Add(mats[j]);
}
}
for (int i = 0; i < materials.Count; i++)
{
materials[i].shader = targetShader;
}
}
#endregion
4、检查tag列表中是否有tag,没有该tag添加此tag
///
/// 检查tag列表中是否有tag,没有该tag添加此tag
///
/// 所要设设置的tag
public static void SetGameObjectTag(GameObject gameObject, string tag)
{
if (!UnityEditorInternal.InternalEditorUtility.tags.Equals(tag)) //如果tag列表中没有这个tag
{
UnityEditorInternal.InternalEditorUtility.AddTag(tag); //在tag列表中添加这个tag
}
gameObject.tag = tag;
}
5、Dotween对数值进行递增或递减
float startNum = 0f;
float targetNum = 1f;
public void DOTweenNum(Action cb)
{
DOTween.To(() => startNum, x => startNum = x, targetNum, 10).
SetEase(Ease.Linear).OnComplete(() => {
cb?.Invoke();
});
}
void Update()
{
if (Input.GetKeyDown(KeyCode.F8))
{
DOTweenNum(()=> { Debug.Log($"******{startNum}*****"); });
}
}
6、鼠标双击
using System;
using UnityEngine;
public class DoubleClickMouseButton : MonoBehaviour
{
///
/// 鼠标双击的间隔
///
private float doubleClickTime = 0.2f;
///
/// 上一次点击鼠标抬起的时间
///
private double lastClickTime;
void Start()
{
lastClickTime = Time.realtimeSinceStartup;
}
private void Update()
{
DoubleClickMouseButtonEvent(0, () =>
{
//ToDo 双击所要执行的事件
});
}
///
/// 鼠标双击执行的事件
///
/// 鼠标按键
/// 双击需要执行的事件
private void DoubleClickMouseButtonEvent(int mouseBtnIndex, Action action)
{
if (Input.GetMouseButtonDown(mouseBtnIndex)) //双击鼠标右键聚焦
{
if (Time.realtimeSinceStartup - lastClickTime < doubleClickTime)
{
action();
}
lastClickTime = Time.realtimeSinceStartup;
}
}
}
7、获取模型Bound中心点
using UnityEngine;
namespace MT_Exterensions
{
public static class GameObjectExtensions
{
public static Bounds CalculatePreciseBounds(this GameObject gameObject)
{
Bounds bounds = new Bounds();
bool flag = false;
MeshFilter[] componentsInChildren1 = gameObject.GetComponentsInChildren();
if (componentsInChildren1.Length != 0)
{
bounds = GetMeshBounds(componentsInChildren1[0].gameObject, componentsInChildren1[0].sharedMesh);
flag = true;
for (int index = 1; index < componentsInChildren1.Length; ++index)
bounds.Encapsulate(GetMeshBounds(componentsInChildren1[index].gameObject,
componentsInChildren1[index].sharedMesh));
}
SkinnedMeshRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren();
if (componentsInChildren2.Length != 0)
{
Mesh mesh = new Mesh();
if (!flag)
{
componentsInChildren2[0].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[0].gameObject, mesh);
}
for (int index = 1; index < componentsInChildren2.Length; ++index)
{
componentsInChildren2[index].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[index].gameObject, mesh);
}
Object.Destroy(mesh);
}
return bounds;
}
private static Bounds GetMeshBounds(GameObject gameObject, Mesh mesh)
{
Bounds bounds = new Bounds();
Vector3[] vertices = mesh.vertices;
if (vertices.Length != 0)
{
bounds = new Bounds(gameObject.transform.TransformPoint(vertices[0]), Vector3.zero);
for (int index = 1; index < vertices.Length; ++index)
bounds.Encapsulate(gameObject.transform.TransformPoint(vertices[index]));
}
return bounds;
}
public static Bounds CalculateBounds(this GameObject gameObject, bool localSpace = false)
{
Vector3 position = gameObject.transform.position;
Quaternion rotation = gameObject.transform.rotation;
Vector3 localScale = gameObject.transform.localScale;
if (localSpace)
{
gameObject.transform.position = Vector3.zero;
gameObject.transform.rotation = Quaternion.identity;
gameObject.transform.localScale = Vector3.one;
}
Bounds bounds1 = new Bounds();
Renderer[] componentsInChildren = gameObject.GetComponentsInChildren();
if (componentsInChildren.Length != 0)
{
Bounds bounds2 = componentsInChildren[0].bounds;
bounds1.center = bounds2.center;
bounds1.extents = bounds2.extents;
for (int index = 1; index < componentsInChildren.Length; ++index)
{
Bounds bounds3 = componentsInChildren[index].bounds;
bounds1.Encapsulate(bounds3);
}
}
if (localSpace)
{
gameObject.transform.position = position;
gameObject.transform.rotation = rotation;
gameObject.transform.localScale = localScale;
}
return bounds1;
}
///
/// 获取模型的Bounds
///
///
///
public static Bounds CalculateModelBounds(GameObject gameObject)
{
Bounds bounds = gameObject.CalculateBounds(false);
return bounds;
}
}
}
8、绘制相机视野
using UnityEngine;
///
/// 绘制相机视野范围
///
public class ShowCameraFieldOfView : MonoBehaviour
{
private Camera mainCamera;
private void OnDrawGizmos()
{
if (mainCamera == null)
mainCamera = Camera.main;
Gizmos.color = Color.green;
//设置gizmos的矩阵
Gizmos.matrix = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one);
Gizmos.DrawFrustum(Vector3.zero, mainCamera.fieldOfView, mainCamera.farClipPlane, mainCamera.nearClipPlane, mainCamera.aspect);
}
}
9、编辑器扩展,复制物体的Position和Roation
using UnityEditor;
using UnityEngine;
///
/// 放在Editor目录下
/// 选中物体之后,在扩展窗口选择复制的选项,就可以将选中的物体的transform信息位置复制下来,然后在要复制的地方Ctrl+V就可以复制出来
///
public class CopyObjTransformData : Editor
{
///
/// 复制Position
///
[UnityEditor.MenuItem("复制节点Transform信息/复制坐标")]
static void CopyXYZ()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localPosition.x + "f,"
+ obj.transform.localPosition.y + "f,"
+ obj.transform.localPosition.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
///
/// 复制Rotation
///
[UnityEditor.MenuItem("复制节点Transform信息/复制旋转")]
static void CopyObjRotation()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localEulerAngles.x + "f," + obj.transform.localEulerAngles.y + "f," +
obj.transform.localEulerAngles.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
}
10、鼠标拖动物体移动
using System.Collections;
using UnityEngine;
///
/// 完成两个步骤:
// 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系
// 2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
///
public class DragObjMove : MonoBehaviour
{
void Start()
{
StartCoroutine(OnMouseDown());
}
IEnumerator OnMouseDown()
{
//将物体由世界坐标系转换为屏幕坐标系
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标
Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
while (Input.GetMouseButton(0))
{
//得到现在鼠标的2维坐标系位置
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
//curPosition就是物体应该的移动向量赋给transform的position属性
transform.position = curPosition;
yield return new WaitForFixedUpdate(); //这个很重要,循环执行
}
}
}
11、逐渐注视目标方向旋转
///
/// 逐渐注视目标点旋转
///
/// 变换组件
/// 目标点
/// 旋转速度
public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
{
Vector3 dir = targetPos - targetTF.position;
LookDirection(targetTF, dir, rotateSpeed);
}
///
/// 逐渐注视目标方向旋转
///
/// 变换组件
/// 目标方向
/// 旋转速度
public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
{
//如果需要注视零方向
if (targetDir == Vector3.zero) return;
//transform.LookAt(目标点); 一帧旋转到位
Quaternion dir = Quaternion.LookRotation(targetDir);
targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
}
12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 对象池
///
public class GameObjectPool : MonoSingleton
{
//1.对象池
private Dictionary> cache;
//private Dictionary> obj = new Dictionary>();
//初始化:在对象创建时执行一次
protected override void Init()
{
base.Init();
cache = new Dictionary>();
}
//2.创建对象
///
/// 通过对象池创建对象
///
/// 需要创建的对象种类
/// 需要创建的预制件
/// 创建的位置
/// 创建的旋转
///
public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
{
//在池中查找
GameObject tempGo = FindUsableObject(key);
//如果没有找到
if (tempGo == null)
{
//创建物体
tempGo = Instantiate(prefab);
//加入池中
Add(key, tempGo);
//将通过对象池创建的物体,存入对象池子物体列表中。
tempGo.transform.SetParent(transform);
}
//使用
UseObject(tempGo, pos, dir);
return tempGo;
}
private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
{
//先设置位置
go.transform.position = pos;
go.transform.rotation = dir;
//再启用物体
go.SetActive(true);
//重置通过对象池创建物体的所有脚本对象
foreach (var item in go.GetComponentsInChildren())
{
item.OnReset();
}
}
private void Add(string key, GameObject tempGo)
{
//如果池中没有键 则 添加键
if (!cache.ContainsKey(key)) cache.Add(key, new List());
//将物体加入池中
cache[key].Add(tempGo);
}
private GameObject FindUsableObject(string key)
{
if (cache.ContainsKey(key))
{
// public delegate bool Predicate(T obj);
//查找池中禁用的物体
return cache[key].Find(o => !o.activeInHierarchy);
}
return null;
}
//3.即时回收
public void CollectObject(GameObject go)
{
go.SetActive(false);
}
//4.延迟回收
public void CollectObject(GameObject go, float delay)
{
StartCoroutine(DelayCollect(go, delay));
}
private IEnumerator DelayCollect(GameObject go, float delay)
{
yield return new WaitForSeconds(delay);
CollectObject(go);
}
//5.清空
public void ClearAll()
{
//将字典中所有键存入集合
List listKey =new List(cache.Keys);
foreach (var item in listKey)
{
//遍历集合元素 删除字典记录
Clear(item);
}
}
public void Clear(string key)
{
//倒序删除
for (int i = cache[key].Count -1; i>=0 ; i--)
{
Destroy(cache[key][i]);
}
//在字典集合中清空当前记录(集合列表)
cache.Remove(key);
}
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
///
/// 获取动画状态机animator的动画clip的播放持续时长
///
///
///
///
public float GetClipLength(Animator animator, string clipName)
{
if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
return 0;
// 获取所有的clips
var clips = animator.runtimeAnimatorController.animationClips;
if (null == clips || clips.Length <= 0) return 0;
AnimationClip clip;
for (int i = 0, len = clips.Length; i < len; ++i)
{
clip = clips[i];
if (null != clip && clip.name == clipName)
return clip.length;
}
return 0f;
}
using UnityEngine; using UnityEngine.UI; ////// 挂Image组件上 /// [AddComponentMenu("UI/Effects/Gradient")] public class GradientColor : BaseMeshEffect { public Color Color1 = Color.white; public Color Color2 = Color.white; [Range(-180f, 180f)] public float Angle = -90.0f; public override void ModifyMesh(VertexHelper vh) { if (enabled) { var rect = graphic.rectTransform.rect; var dir = RotationDir(Angle); var localPositionMatrix = LocalPositionMatrix(rect, dir); var vertex = default(UIVertex); for (var i = 0; i < vh.currentVertCount; i++) { vh.PopulateUIVertex(ref vertex, i); var localPosition = localPositionMatrix * vertex.position; vertex.color *= Color.Lerp(Color2, Color1, localPosition.y); vh.SetUIVertex(vertex, i); } } } public struct Matrix2x3 { public float m00, m01, m02, m10, m11, m12; public Matrix2x3(float m00, float m01, float m02, float m10, float m11, float m12) { this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m10 = m10; this.m11 = m11; this.m12 = m12; } public static Vector2 operator *(Matrix2x3 m, Vector2 v) { float x = (m.m00 * v.x) - (m.m01 * v.y) + m.m02; float y = (m.m10 * v.x) + (m.m11 * v.y) + m.m12; return new Vector2(x, y); } } private Matrix2x3 LocalPositionMatrix(Rect rect, Vector2 dir) { float cos = dir.x; float sin = dir.y; Vector2 rectMin = rect.min; Vector2 rectSize = rect.size; float c = 0.5f; float ax = rectMin.x / rectSize.x + c; float ay = rectMin.y / rectSize.y + c; float m00 = cos / rectSize.x; float m01 = sin / rectSize.y; float m02 = -(ax * cos - ay * sin - c); float m10 = sin / rectSize.x; float m11 = cos / rectSize.y; float m12 = -(ax * sin + ay * cos - c); return new Matrix2x3(m00, m01, m02, m10, m11, m12); } private Vector2 RotationDir(float angle) { float angleRad = angle * Mathf.Deg2Rad; float cos = Mathf.Cos(angleRad); float sin = Mathf.Sin(angleRad); return new Vector2(cos, sin); } }
3、获取物体所有的材质,并且改变这些材质的Shader
#region 获取物体所有的材质,并且改变这些材质的Shader
private Renderer[] rendArray;
private List materials = new List();
///
/// 获取物体上所有的材质,并改变这些材质的Shader
///
private void GetModelAllMaterialsAndChange(GameObject gameObject, Shader targetShader)
{
materials.Clear();
rendArray = gameObject.transform.GetComponentsInChildren(true);
for (int i = 0; i < rendArray.Length; i++)
{
Material[] mats = rendArray[i].materials;
for (int j = 0; j < mats.Length; j++)
{
materials.Add(mats[j]);
}
}
for (int i = 0; i < materials.Count; i++)
{
materials[i].shader = targetShader;
}
}
#endregion
4、检查tag列表中是否有tag,没有该tag添加此tag
///
/// 检查tag列表中是否有tag,没有该tag添加此tag
///
/// 所要设设置的tag
public static void SetGameObjectTag(GameObject gameObject, string tag)
{
if (!UnityEditorInternal.InternalEditorUtility.tags.Equals(tag)) //如果tag列表中没有这个tag
{
UnityEditorInternal.InternalEditorUtility.AddTag(tag); //在tag列表中添加这个tag
}
gameObject.tag = tag;
}
5、Dotween对数值进行递增或递减
float startNum = 0f;
float targetNum = 1f;
public void DOTweenNum(Action cb)
{
DOTween.To(() => startNum, x => startNum = x, targetNum, 10).
SetEase(Ease.Linear).OnComplete(() => {
cb?.Invoke();
});
}
void Update()
{
if (Input.GetKeyDown(KeyCode.F8))
{
DOTweenNum(()=> { Debug.Log($"******{startNum}*****"); });
}
}
6、鼠标双击
using System;
using UnityEngine;
public class DoubleClickMouseButton : MonoBehaviour
{
///
/// 鼠标双击的间隔
///
private float doubleClickTime = 0.2f;
///
/// 上一次点击鼠标抬起的时间
///
private double lastClickTime;
void Start()
{
lastClickTime = Time.realtimeSinceStartup;
}
private void Update()
{
DoubleClickMouseButtonEvent(0, () =>
{
//ToDo 双击所要执行的事件
});
}
///
/// 鼠标双击执行的事件
///
/// 鼠标按键
/// 双击需要执行的事件
private void DoubleClickMouseButtonEvent(int mouseBtnIndex, Action action)
{
if (Input.GetMouseButtonDown(mouseBtnIndex)) //双击鼠标右键聚焦
{
if (Time.realtimeSinceStartup - lastClickTime < doubleClickTime)
{
action();
}
lastClickTime = Time.realtimeSinceStartup;
}
}
}
7、获取模型Bound中心点
using UnityEngine;
namespace MT_Exterensions
{
public static class GameObjectExtensions
{
public static Bounds CalculatePreciseBounds(this GameObject gameObject)
{
Bounds bounds = new Bounds();
bool flag = false;
MeshFilter[] componentsInChildren1 = gameObject.GetComponentsInChildren();
if (componentsInChildren1.Length != 0)
{
bounds = GetMeshBounds(componentsInChildren1[0].gameObject, componentsInChildren1[0].sharedMesh);
flag = true;
for (int index = 1; index < componentsInChildren1.Length; ++index)
bounds.Encapsulate(GetMeshBounds(componentsInChildren1[index].gameObject,
componentsInChildren1[index].sharedMesh));
}
SkinnedMeshRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren();
if (componentsInChildren2.Length != 0)
{
Mesh mesh = new Mesh();
if (!flag)
{
componentsInChildren2[0].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[0].gameObject, mesh);
}
for (int index = 1; index < componentsInChildren2.Length; ++index)
{
componentsInChildren2[index].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[index].gameObject, mesh);
}
Object.Destroy(mesh);
}
return bounds;
}
private static Bounds GetMeshBounds(GameObject gameObject, Mesh mesh)
{
Bounds bounds = new Bounds();
Vector3[] vertices = mesh.vertices;
if (vertices.Length != 0)
{
bounds = new Bounds(gameObject.transform.TransformPoint(vertices[0]), Vector3.zero);
for (int index = 1; index < vertices.Length; ++index)
bounds.Encapsulate(gameObject.transform.TransformPoint(vertices[index]));
}
return bounds;
}
public static Bounds CalculateBounds(this GameObject gameObject, bool localSpace = false)
{
Vector3 position = gameObject.transform.position;
Quaternion rotation = gameObject.transform.rotation;
Vector3 localScale = gameObject.transform.localScale;
if (localSpace)
{
gameObject.transform.position = Vector3.zero;
gameObject.transform.rotation = Quaternion.identity;
gameObject.transform.localScale = Vector3.one;
}
Bounds bounds1 = new Bounds();
Renderer[] componentsInChildren = gameObject.GetComponentsInChildren();
if (componentsInChildren.Length != 0)
{
Bounds bounds2 = componentsInChildren[0].bounds;
bounds1.center = bounds2.center;
bounds1.extents = bounds2.extents;
for (int index = 1; index < componentsInChildren.Length; ++index)
{
Bounds bounds3 = componentsInChildren[index].bounds;
bounds1.Encapsulate(bounds3);
}
}
if (localSpace)
{
gameObject.transform.position = position;
gameObject.transform.rotation = rotation;
gameObject.transform.localScale = localScale;
}
return bounds1;
}
///
/// 获取模型的Bounds
///
///
///
public static Bounds CalculateModelBounds(GameObject gameObject)
{
Bounds bounds = gameObject.CalculateBounds(false);
return bounds;
}
}
}
8、绘制相机视野
using UnityEngine;
///
/// 绘制相机视野范围
///
public class ShowCameraFieldOfView : MonoBehaviour
{
private Camera mainCamera;
private void OnDrawGizmos()
{
if (mainCamera == null)
mainCamera = Camera.main;
Gizmos.color = Color.green;
//设置gizmos的矩阵
Gizmos.matrix = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one);
Gizmos.DrawFrustum(Vector3.zero, mainCamera.fieldOfView, mainCamera.farClipPlane, mainCamera.nearClipPlane, mainCamera.aspect);
}
}
9、编辑器扩展,复制物体的Position和Roation
using UnityEditor;
using UnityEngine;
///
/// 放在Editor目录下
/// 选中物体之后,在扩展窗口选择复制的选项,就可以将选中的物体的transform信息位置复制下来,然后在要复制的地方Ctrl+V就可以复制出来
///
public class CopyObjTransformData : Editor
{
///
/// 复制Position
///
[UnityEditor.MenuItem("复制节点Transform信息/复制坐标")]
static void CopyXYZ()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localPosition.x + "f,"
+ obj.transform.localPosition.y + "f,"
+ obj.transform.localPosition.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
///
/// 复制Rotation
///
[UnityEditor.MenuItem("复制节点Transform信息/复制旋转")]
static void CopyObjRotation()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localEulerAngles.x + "f," + obj.transform.localEulerAngles.y + "f," +
obj.transform.localEulerAngles.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
}
10、鼠标拖动物体移动
using System.Collections;
using UnityEngine;
///
/// 完成两个步骤:
// 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系
// 2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
///
public class DragObjMove : MonoBehaviour
{
void Start()
{
StartCoroutine(OnMouseDown());
}
IEnumerator OnMouseDown()
{
//将物体由世界坐标系转换为屏幕坐标系
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标
Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
while (Input.GetMouseButton(0))
{
//得到现在鼠标的2维坐标系位置
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
//curPosition就是物体应该的移动向量赋给transform的position属性
transform.position = curPosition;
yield return new WaitForFixedUpdate(); //这个很重要,循环执行
}
}
}
11、逐渐注视目标方向旋转
///
/// 逐渐注视目标点旋转
///
/// 变换组件
/// 目标点
/// 旋转速度
public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
{
Vector3 dir = targetPos - targetTF.position;
LookDirection(targetTF, dir, rotateSpeed);
}
///
/// 逐渐注视目标方向旋转
///
/// 变换组件
/// 目标方向
/// 旋转速度
public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
{
//如果需要注视零方向
if (targetDir == Vector3.zero) return;
//transform.LookAt(目标点); 一帧旋转到位
Quaternion dir = Quaternion.LookRotation(targetDir);
targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
}
12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 对象池
///
public class GameObjectPool : MonoSingleton
{
//1.对象池
private Dictionary> cache;
//private Dictionary> obj = new Dictionary>();
//初始化:在对象创建时执行一次
protected override void Init()
{
base.Init();
cache = new Dictionary>();
}
//2.创建对象
///
/// 通过对象池创建对象
///
/// 需要创建的对象种类
/// 需要创建的预制件
/// 创建的位置
/// 创建的旋转
///
public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
{
//在池中查找
GameObject tempGo = FindUsableObject(key);
//如果没有找到
if (tempGo == null)
{
//创建物体
tempGo = Instantiate(prefab);
//加入池中
Add(key, tempGo);
//将通过对象池创建的物体,存入对象池子物体列表中。
tempGo.transform.SetParent(transform);
}
//使用
UseObject(tempGo, pos, dir);
return tempGo;
}
private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
{
//先设置位置
go.transform.position = pos;
go.transform.rotation = dir;
//再启用物体
go.SetActive(true);
//重置通过对象池创建物体的所有脚本对象
foreach (var item in go.GetComponentsInChildren())
{
item.OnReset();
}
}
private void Add(string key, GameObject tempGo)
{
//如果池中没有键 则 添加键
if (!cache.ContainsKey(key)) cache.Add(key, new List());
//将物体加入池中
cache[key].Add(tempGo);
}
private GameObject FindUsableObject(string key)
{
if (cache.ContainsKey(key))
{
// public delegate bool Predicate(T obj);
//查找池中禁用的物体
return cache[key].Find(o => !o.activeInHierarchy);
}
return null;
}
//3.即时回收
public void CollectObject(GameObject go)
{
go.SetActive(false);
}
//4.延迟回收
public void CollectObject(GameObject go, float delay)
{
StartCoroutine(DelayCollect(go, delay));
}
private IEnumerator DelayCollect(GameObject go, float delay)
{
yield return new WaitForSeconds(delay);
CollectObject(go);
}
//5.清空
public void ClearAll()
{
//将字典中所有键存入集合
List listKey =new List(cache.Keys);
foreach (var item in listKey)
{
//遍历集合元素 删除字典记录
Clear(item);
}
}
public void Clear(string key)
{
//倒序删除
for (int i = cache[key].Count -1; i>=0 ; i--)
{
Destroy(cache[key][i]);
}
//在字典集合中清空当前记录(集合列表)
cache.Remove(key);
}
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
///
/// 获取动画状态机animator的动画clip的播放持续时长
///
///
///
///
public float GetClipLength(Animator animator, string clipName)
{
if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
return 0;
// 获取所有的clips
var clips = animator.runtimeAnimatorController.animationClips;
if (null == clips || clips.Length <= 0) return 0;
AnimationClip clip;
for (int i = 0, len = clips.Length; i < len; ++i)
{
clip = clips[i];
if (null != clip && clip.name == clipName)
return clip.length;
}
return 0f;
}
////// 检查tag列表中是否有tag,没有该tag添加此tag /// /// 所要设设置的tag public static void SetGameObjectTag(GameObject gameObject, string tag) { if (!UnityEditorInternal.InternalEditorUtility.tags.Equals(tag)) //如果tag列表中没有这个tag { UnityEditorInternal.InternalEditorUtility.AddTag(tag); //在tag列表中添加这个tag } gameObject.tag = tag; }
5、Dotween对数值进行递增或递减
float startNum = 0f;
float targetNum = 1f;
public void DOTweenNum(Action cb)
{
DOTween.To(() => startNum, x => startNum = x, targetNum, 10).
SetEase(Ease.Linear).OnComplete(() => {
cb?.Invoke();
});
}
void Update()
{
if (Input.GetKeyDown(KeyCode.F8))
{
DOTweenNum(()=> { Debug.Log($"******{startNum}*****"); });
}
}
6、鼠标双击
using System;
using UnityEngine;
public class DoubleClickMouseButton : MonoBehaviour
{
///
/// 鼠标双击的间隔
///
private float doubleClickTime = 0.2f;
///
/// 上一次点击鼠标抬起的时间
///
private double lastClickTime;
void Start()
{
lastClickTime = Time.realtimeSinceStartup;
}
private void Update()
{
DoubleClickMouseButtonEvent(0, () =>
{
//ToDo 双击所要执行的事件
});
}
///
/// 鼠标双击执行的事件
///
/// 鼠标按键
/// 双击需要执行的事件
private void DoubleClickMouseButtonEvent(int mouseBtnIndex, Action action)
{
if (Input.GetMouseButtonDown(mouseBtnIndex)) //双击鼠标右键聚焦
{
if (Time.realtimeSinceStartup - lastClickTime < doubleClickTime)
{
action();
}
lastClickTime = Time.realtimeSinceStartup;
}
}
}
7、获取模型Bound中心点
using UnityEngine;
namespace MT_Exterensions
{
public static class GameObjectExtensions
{
public static Bounds CalculatePreciseBounds(this GameObject gameObject)
{
Bounds bounds = new Bounds();
bool flag = false;
MeshFilter[] componentsInChildren1 = gameObject.GetComponentsInChildren();
if (componentsInChildren1.Length != 0)
{
bounds = GetMeshBounds(componentsInChildren1[0].gameObject, componentsInChildren1[0].sharedMesh);
flag = true;
for (int index = 1; index < componentsInChildren1.Length; ++index)
bounds.Encapsulate(GetMeshBounds(componentsInChildren1[index].gameObject,
componentsInChildren1[index].sharedMesh));
}
SkinnedMeshRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren();
if (componentsInChildren2.Length != 0)
{
Mesh mesh = new Mesh();
if (!flag)
{
componentsInChildren2[0].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[0].gameObject, mesh);
}
for (int index = 1; index < componentsInChildren2.Length; ++index)
{
componentsInChildren2[index].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[index].gameObject, mesh);
}
Object.Destroy(mesh);
}
return bounds;
}
private static Bounds GetMeshBounds(GameObject gameObject, Mesh mesh)
{
Bounds bounds = new Bounds();
Vector3[] vertices = mesh.vertices;
if (vertices.Length != 0)
{
bounds = new Bounds(gameObject.transform.TransformPoint(vertices[0]), Vector3.zero);
for (int index = 1; index < vertices.Length; ++index)
bounds.Encapsulate(gameObject.transform.TransformPoint(vertices[index]));
}
return bounds;
}
public static Bounds CalculateBounds(this GameObject gameObject, bool localSpace = false)
{
Vector3 position = gameObject.transform.position;
Quaternion rotation = gameObject.transform.rotation;
Vector3 localScale = gameObject.transform.localScale;
if (localSpace)
{
gameObject.transform.position = Vector3.zero;
gameObject.transform.rotation = Quaternion.identity;
gameObject.transform.localScale = Vector3.one;
}
Bounds bounds1 = new Bounds();
Renderer[] componentsInChildren = gameObject.GetComponentsInChildren();
if (componentsInChildren.Length != 0)
{
Bounds bounds2 = componentsInChildren[0].bounds;
bounds1.center = bounds2.center;
bounds1.extents = bounds2.extents;
for (int index = 1; index < componentsInChildren.Length; ++index)
{
Bounds bounds3 = componentsInChildren[index].bounds;
bounds1.Encapsulate(bounds3);
}
}
if (localSpace)
{
gameObject.transform.position = position;
gameObject.transform.rotation = rotation;
gameObject.transform.localScale = localScale;
}
return bounds1;
}
///
/// 获取模型的Bounds
///
///
///
public static Bounds CalculateModelBounds(GameObject gameObject)
{
Bounds bounds = gameObject.CalculateBounds(false);
return bounds;
}
}
}
8、绘制相机视野
using UnityEngine;
///
/// 绘制相机视野范围
///
public class ShowCameraFieldOfView : MonoBehaviour
{
private Camera mainCamera;
private void OnDrawGizmos()
{
if (mainCamera == null)
mainCamera = Camera.main;
Gizmos.color = Color.green;
//设置gizmos的矩阵
Gizmos.matrix = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one);
Gizmos.DrawFrustum(Vector3.zero, mainCamera.fieldOfView, mainCamera.farClipPlane, mainCamera.nearClipPlane, mainCamera.aspect);
}
}
9、编辑器扩展,复制物体的Position和Roation
using UnityEditor;
using UnityEngine;
///
/// 放在Editor目录下
/// 选中物体之后,在扩展窗口选择复制的选项,就可以将选中的物体的transform信息位置复制下来,然后在要复制的地方Ctrl+V就可以复制出来
///
public class CopyObjTransformData : Editor
{
///
/// 复制Position
///
[UnityEditor.MenuItem("复制节点Transform信息/复制坐标")]
static void CopyXYZ()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localPosition.x + "f,"
+ obj.transform.localPosition.y + "f,"
+ obj.transform.localPosition.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
///
/// 复制Rotation
///
[UnityEditor.MenuItem("复制节点Transform信息/复制旋转")]
static void CopyObjRotation()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localEulerAngles.x + "f," + obj.transform.localEulerAngles.y + "f," +
obj.transform.localEulerAngles.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
}
10、鼠标拖动物体移动
using System.Collections;
using UnityEngine;
///
/// 完成两个步骤:
// 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系
// 2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
///
public class DragObjMove : MonoBehaviour
{
void Start()
{
StartCoroutine(OnMouseDown());
}
IEnumerator OnMouseDown()
{
//将物体由世界坐标系转换为屏幕坐标系
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标
Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
while (Input.GetMouseButton(0))
{
//得到现在鼠标的2维坐标系位置
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
//curPosition就是物体应该的移动向量赋给transform的position属性
transform.position = curPosition;
yield return new WaitForFixedUpdate(); //这个很重要,循环执行
}
}
}
11、逐渐注视目标方向旋转
///
/// 逐渐注视目标点旋转
///
/// 变换组件
/// 目标点
/// 旋转速度
public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
{
Vector3 dir = targetPos - targetTF.position;
LookDirection(targetTF, dir, rotateSpeed);
}
///
/// 逐渐注视目标方向旋转
///
/// 变换组件
/// 目标方向
/// 旋转速度
public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
{
//如果需要注视零方向
if (targetDir == Vector3.zero) return;
//transform.LookAt(目标点); 一帧旋转到位
Quaternion dir = Quaternion.LookRotation(targetDir);
targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
}
12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 对象池
///
public class GameObjectPool : MonoSingleton
{
//1.对象池
private Dictionary> cache;
//private Dictionary> obj = new Dictionary>();
//初始化:在对象创建时执行一次
protected override void Init()
{
base.Init();
cache = new Dictionary>();
}
//2.创建对象
///
/// 通过对象池创建对象
///
/// 需要创建的对象种类
/// 需要创建的预制件
/// 创建的位置
/// 创建的旋转
///
public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
{
//在池中查找
GameObject tempGo = FindUsableObject(key);
//如果没有找到
if (tempGo == null)
{
//创建物体
tempGo = Instantiate(prefab);
//加入池中
Add(key, tempGo);
//将通过对象池创建的物体,存入对象池子物体列表中。
tempGo.transform.SetParent(transform);
}
//使用
UseObject(tempGo, pos, dir);
return tempGo;
}
private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
{
//先设置位置
go.transform.position = pos;
go.transform.rotation = dir;
//再启用物体
go.SetActive(true);
//重置通过对象池创建物体的所有脚本对象
foreach (var item in go.GetComponentsInChildren())
{
item.OnReset();
}
}
private void Add(string key, GameObject tempGo)
{
//如果池中没有键 则 添加键
if (!cache.ContainsKey(key)) cache.Add(key, new List());
//将物体加入池中
cache[key].Add(tempGo);
}
private GameObject FindUsableObject(string key)
{
if (cache.ContainsKey(key))
{
// public delegate bool Predicate(T obj);
//查找池中禁用的物体
return cache[key].Find(o => !o.activeInHierarchy);
}
return null;
}
//3.即时回收
public void CollectObject(GameObject go)
{
go.SetActive(false);
}
//4.延迟回收
public void CollectObject(GameObject go, float delay)
{
StartCoroutine(DelayCollect(go, delay));
}
private IEnumerator DelayCollect(GameObject go, float delay)
{
yield return new WaitForSeconds(delay);
CollectObject(go);
}
//5.清空
public void ClearAll()
{
//将字典中所有键存入集合
List listKey =new List(cache.Keys);
foreach (var item in listKey)
{
//遍历集合元素 删除字典记录
Clear(item);
}
}
public void Clear(string key)
{
//倒序删除
for (int i = cache[key].Count -1; i>=0 ; i--)
{
Destroy(cache[key][i]);
}
//在字典集合中清空当前记录(集合列表)
cache.Remove(key);
}
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
///
/// 获取动画状态机animator的动画clip的播放持续时长
///
///
///
///
public float GetClipLength(Animator animator, string clipName)
{
if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
return 0;
// 获取所有的clips
var clips = animator.runtimeAnimatorController.animationClips;
if (null == clips || clips.Length <= 0) return 0;
AnimationClip clip;
for (int i = 0, len = clips.Length; i < len; ++i)
{
clip = clips[i];
if (null != clip && clip.name == clipName)
return clip.length;
}
return 0f;
}
using System;
using UnityEngine;
public class DoubleClickMouseButton : MonoBehaviour
{
///
/// 鼠标双击的间隔
///
private float doubleClickTime = 0.2f;
///
/// 上一次点击鼠标抬起的时间
///
private double lastClickTime;
void Start()
{
lastClickTime = Time.realtimeSinceStartup;
}
private void Update()
{
DoubleClickMouseButtonEvent(0, () =>
{
//ToDo 双击所要执行的事件
});
}
///
/// 鼠标双击执行的事件
///
/// 鼠标按键
/// 双击需要执行的事件
private void DoubleClickMouseButtonEvent(int mouseBtnIndex, Action action)
{
if (Input.GetMouseButtonDown(mouseBtnIndex)) //双击鼠标右键聚焦
{
if (Time.realtimeSinceStartup - lastClickTime < doubleClickTime)
{
action();
}
lastClickTime = Time.realtimeSinceStartup;
}
}
}
7、获取模型Bound中心点
using UnityEngine;
namespace MT_Exterensions
{
public static class GameObjectExtensions
{
public static Bounds CalculatePreciseBounds(this GameObject gameObject)
{
Bounds bounds = new Bounds();
bool flag = false;
MeshFilter[] componentsInChildren1 = gameObject.GetComponentsInChildren();
if (componentsInChildren1.Length != 0)
{
bounds = GetMeshBounds(componentsInChildren1[0].gameObject, componentsInChildren1[0].sharedMesh);
flag = true;
for (int index = 1; index < componentsInChildren1.Length; ++index)
bounds.Encapsulate(GetMeshBounds(componentsInChildren1[index].gameObject,
componentsInChildren1[index].sharedMesh));
}
SkinnedMeshRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren();
if (componentsInChildren2.Length != 0)
{
Mesh mesh = new Mesh();
if (!flag)
{
componentsInChildren2[0].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[0].gameObject, mesh);
}
for (int index = 1; index < componentsInChildren2.Length; ++index)
{
componentsInChildren2[index].BakeMesh(mesh);
bounds = GetMeshBounds(componentsInChildren2[index].gameObject, mesh);
}
Object.Destroy(mesh);
}
return bounds;
}
private static Bounds GetMeshBounds(GameObject gameObject, Mesh mesh)
{
Bounds bounds = new Bounds();
Vector3[] vertices = mesh.vertices;
if (vertices.Length != 0)
{
bounds = new Bounds(gameObject.transform.TransformPoint(vertices[0]), Vector3.zero);
for (int index = 1; index < vertices.Length; ++index)
bounds.Encapsulate(gameObject.transform.TransformPoint(vertices[index]));
}
return bounds;
}
public static Bounds CalculateBounds(this GameObject gameObject, bool localSpace = false)
{
Vector3 position = gameObject.transform.position;
Quaternion rotation = gameObject.transform.rotation;
Vector3 localScale = gameObject.transform.localScale;
if (localSpace)
{
gameObject.transform.position = Vector3.zero;
gameObject.transform.rotation = Quaternion.identity;
gameObject.transform.localScale = Vector3.one;
}
Bounds bounds1 = new Bounds();
Renderer[] componentsInChildren = gameObject.GetComponentsInChildren();
if (componentsInChildren.Length != 0)
{
Bounds bounds2 = componentsInChildren[0].bounds;
bounds1.center = bounds2.center;
bounds1.extents = bounds2.extents;
for (int index = 1; index < componentsInChildren.Length; ++index)
{
Bounds bounds3 = componentsInChildren[index].bounds;
bounds1.Encapsulate(bounds3);
}
}
if (localSpace)
{
gameObject.transform.position = position;
gameObject.transform.rotation = rotation;
gameObject.transform.localScale = localScale;
}
return bounds1;
}
///
/// 获取模型的Bounds
///
///
///
public static Bounds CalculateModelBounds(GameObject gameObject)
{
Bounds bounds = gameObject.CalculateBounds(false);
return bounds;
}
}
}
8、绘制相机视野
using UnityEngine;
///
/// 绘制相机视野范围
///
public class ShowCameraFieldOfView : MonoBehaviour
{
private Camera mainCamera;
private void OnDrawGizmos()
{
if (mainCamera == null)
mainCamera = Camera.main;
Gizmos.color = Color.green;
//设置gizmos的矩阵
Gizmos.matrix = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one);
Gizmos.DrawFrustum(Vector3.zero, mainCamera.fieldOfView, mainCamera.farClipPlane, mainCamera.nearClipPlane, mainCamera.aspect);
}
}
9、编辑器扩展,复制物体的Position和Roation
using UnityEditor;
using UnityEngine;
///
/// 放在Editor目录下
/// 选中物体之后,在扩展窗口选择复制的选项,就可以将选中的物体的transform信息位置复制下来,然后在要复制的地方Ctrl+V就可以复制出来
///
public class CopyObjTransformData : Editor
{
///
/// 复制Position
///
[UnityEditor.MenuItem("复制节点Transform信息/复制坐标")]
static void CopyXYZ()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localPosition.x + "f,"
+ obj.transform.localPosition.y + "f,"
+ obj.transform.localPosition.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
///
/// 复制Rotation
///
[UnityEditor.MenuItem("复制节点Transform信息/复制旋转")]
static void CopyObjRotation()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localEulerAngles.x + "f," + obj.transform.localEulerAngles.y + "f," +
obj.transform.localEulerAngles.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
}
10、鼠标拖动物体移动
using System.Collections;
using UnityEngine;
///
/// 完成两个步骤:
// 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系
// 2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
///
public class DragObjMove : MonoBehaviour
{
void Start()
{
StartCoroutine(OnMouseDown());
}
IEnumerator OnMouseDown()
{
//将物体由世界坐标系转换为屏幕坐标系
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标
Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
while (Input.GetMouseButton(0))
{
//得到现在鼠标的2维坐标系位置
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
//curPosition就是物体应该的移动向量赋给transform的position属性
transform.position = curPosition;
yield return new WaitForFixedUpdate(); //这个很重要,循环执行
}
}
}
11、逐渐注视目标方向旋转
///
/// 逐渐注视目标点旋转
///
/// 变换组件
/// 目标点
/// 旋转速度
public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
{
Vector3 dir = targetPos - targetTF.position;
LookDirection(targetTF, dir, rotateSpeed);
}
///
/// 逐渐注视目标方向旋转
///
/// 变换组件
/// 目标方向
/// 旋转速度
public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
{
//如果需要注视零方向
if (targetDir == Vector3.zero) return;
//transform.LookAt(目标点); 一帧旋转到位
Quaternion dir = Quaternion.LookRotation(targetDir);
targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
}
12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 对象池
///
public class GameObjectPool : MonoSingleton
{
//1.对象池
private Dictionary> cache;
//private Dictionary> obj = new Dictionary>();
//初始化:在对象创建时执行一次
protected override void Init()
{
base.Init();
cache = new Dictionary>();
}
//2.创建对象
///
/// 通过对象池创建对象
///
/// 需要创建的对象种类
/// 需要创建的预制件
/// 创建的位置
/// 创建的旋转
///
public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
{
//在池中查找
GameObject tempGo = FindUsableObject(key);
//如果没有找到
if (tempGo == null)
{
//创建物体
tempGo = Instantiate(prefab);
//加入池中
Add(key, tempGo);
//将通过对象池创建的物体,存入对象池子物体列表中。
tempGo.transform.SetParent(transform);
}
//使用
UseObject(tempGo, pos, dir);
return tempGo;
}
private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
{
//先设置位置
go.transform.position = pos;
go.transform.rotation = dir;
//再启用物体
go.SetActive(true);
//重置通过对象池创建物体的所有脚本对象
foreach (var item in go.GetComponentsInChildren())
{
item.OnReset();
}
}
private void Add(string key, GameObject tempGo)
{
//如果池中没有键 则 添加键
if (!cache.ContainsKey(key)) cache.Add(key, new List());
//将物体加入池中
cache[key].Add(tempGo);
}
private GameObject FindUsableObject(string key)
{
if (cache.ContainsKey(key))
{
// public delegate bool Predicate(T obj);
//查找池中禁用的物体
return cache[key].Find(o => !o.activeInHierarchy);
}
return null;
}
//3.即时回收
public void CollectObject(GameObject go)
{
go.SetActive(false);
}
//4.延迟回收
public void CollectObject(GameObject go, float delay)
{
StartCoroutine(DelayCollect(go, delay));
}
private IEnumerator DelayCollect(GameObject go, float delay)
{
yield return new WaitForSeconds(delay);
CollectObject(go);
}
//5.清空
public void ClearAll()
{
//将字典中所有键存入集合
List listKey =new List(cache.Keys);
foreach (var item in listKey)
{
//遍历集合元素 删除字典记录
Clear(item);
}
}
public void Clear(string key)
{
//倒序删除
for (int i = cache[key].Count -1; i>=0 ; i--)
{
Destroy(cache[key][i]);
}
//在字典集合中清空当前记录(集合列表)
cache.Remove(key);
}
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
///
/// 获取动画状态机animator的动画clip的播放持续时长
///
///
///
///
public float GetClipLength(Animator animator, string clipName)
{
if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
return 0;
// 获取所有的clips
var clips = animator.runtimeAnimatorController.animationClips;
if (null == clips || clips.Length <= 0) return 0;
AnimationClip clip;
for (int i = 0, len = clips.Length; i < len; ++i)
{
clip = clips[i];
if (null != clip && clip.name == clipName)
return clip.length;
}
return 0f;
}
using UnityEngine; ////// 绘制相机视野范围 /// public class ShowCameraFieldOfView : MonoBehaviour { private Camera mainCamera; private void OnDrawGizmos() { if (mainCamera == null) mainCamera = Camera.main; Gizmos.color = Color.green; //设置gizmos的矩阵 Gizmos.matrix = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one); Gizmos.DrawFrustum(Vector3.zero, mainCamera.fieldOfView, mainCamera.farClipPlane, mainCamera.nearClipPlane, mainCamera.aspect); } }
9、编辑器扩展,复制物体的Position和Roation
using UnityEditor;
using UnityEngine;
///
/// 放在Editor目录下
/// 选中物体之后,在扩展窗口选择复制的选项,就可以将选中的物体的transform信息位置复制下来,然后在要复制的地方Ctrl+V就可以复制出来
///
public class CopyObjTransformData : Editor
{
///
/// 复制Position
///
[UnityEditor.MenuItem("复制节点Transform信息/复制坐标")]
static void CopyXYZ()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localPosition.x + "f,"
+ obj.transform.localPosition.y + "f,"
+ obj.transform.localPosition.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
///
/// 复制Rotation
///
[UnityEditor.MenuItem("复制节点Transform信息/复制旋转")]
static void CopyObjRotation()
{
GameObject obj = UnityEditor.Selection.activeGameObject;
if (obj != null)
{
string ret = obj.transform.localEulerAngles.x + "f," + obj.transform.localEulerAngles.y + "f," +
obj.transform.localEulerAngles.z + "f";
GUIUtility.systemCopyBuffer = ret;
}
}
}
10、鼠标拖动物体移动
using System.Collections;
using UnityEngine;
///
/// 完成两个步骤:
// 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系
// 2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
///
public class DragObjMove : MonoBehaviour
{
void Start()
{
StartCoroutine(OnMouseDown());
}
IEnumerator OnMouseDown()
{
//将物体由世界坐标系转换为屏幕坐标系
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标
Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
while (Input.GetMouseButton(0))
{
//得到现在鼠标的2维坐标系位置
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
//curPosition就是物体应该的移动向量赋给transform的position属性
transform.position = curPosition;
yield return new WaitForFixedUpdate(); //这个很重要,循环执行
}
}
}
11、逐渐注视目标方向旋转
///
/// 逐渐注视目标点旋转
///
/// 变换组件
/// 目标点
/// 旋转速度
public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
{
Vector3 dir = targetPos - targetTF.position;
LookDirection(targetTF, dir, rotateSpeed);
}
///
/// 逐渐注视目标方向旋转
///
/// 变换组件
/// 目标方向
/// 旋转速度
public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
{
//如果需要注视零方向
if (targetDir == Vector3.zero) return;
//transform.LookAt(目标点); 一帧旋转到位
Quaternion dir = Quaternion.LookRotation(targetDir);
targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
}
12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 对象池
///
public class GameObjectPool : MonoSingleton
{
//1.对象池
private Dictionary> cache;
//private Dictionary> obj = new Dictionary>();
//初始化:在对象创建时执行一次
protected override void Init()
{
base.Init();
cache = new Dictionary>();
}
//2.创建对象
///
/// 通过对象池创建对象
///
/// 需要创建的对象种类
/// 需要创建的预制件
/// 创建的位置
/// 创建的旋转
///
public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
{
//在池中查找
GameObject tempGo = FindUsableObject(key);
//如果没有找到
if (tempGo == null)
{
//创建物体
tempGo = Instantiate(prefab);
//加入池中
Add(key, tempGo);
//将通过对象池创建的物体,存入对象池子物体列表中。
tempGo.transform.SetParent(transform);
}
//使用
UseObject(tempGo, pos, dir);
return tempGo;
}
private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
{
//先设置位置
go.transform.position = pos;
go.transform.rotation = dir;
//再启用物体
go.SetActive(true);
//重置通过对象池创建物体的所有脚本对象
foreach (var item in go.GetComponentsInChildren())
{
item.OnReset();
}
}
private void Add(string key, GameObject tempGo)
{
//如果池中没有键 则 添加键
if (!cache.ContainsKey(key)) cache.Add(key, new List());
//将物体加入池中
cache[key].Add(tempGo);
}
private GameObject FindUsableObject(string key)
{
if (cache.ContainsKey(key))
{
// public delegate bool Predicate(T obj);
//查找池中禁用的物体
return cache[key].Find(o => !o.activeInHierarchy);
}
return null;
}
//3.即时回收
public void CollectObject(GameObject go)
{
go.SetActive(false);
}
//4.延迟回收
public void CollectObject(GameObject go, float delay)
{
StartCoroutine(DelayCollect(go, delay));
}
private IEnumerator DelayCollect(GameObject go, float delay)
{
yield return new WaitForSeconds(delay);
CollectObject(go);
}
//5.清空
public void ClearAll()
{
//将字典中所有键存入集合
List listKey =new List(cache.Keys);
foreach (var item in listKey)
{
//遍历集合元素 删除字典记录
Clear(item);
}
}
public void Clear(string key)
{
//倒序删除
for (int i = cache[key].Count -1; i>=0 ; i--)
{
Destroy(cache[key][i]);
}
//在字典集合中清空当前记录(集合列表)
cache.Remove(key);
}
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
///
/// 获取动画状态机animator的动画clip的播放持续时长
///
///
///
///
public float GetClipLength(Animator animator, string clipName)
{
if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
return 0;
// 获取所有的clips
var clips = animator.runtimeAnimatorController.animationClips;
if (null == clips || clips.Length <= 0) return 0;
AnimationClip clip;
for (int i = 0, len = clips.Length; i < len; ++i)
{
clip = clips[i];
if (null != clip && clip.name == clipName)
return clip.length;
}
return 0f;
}
using System.Collections; using UnityEngine; ////// 完成两个步骤: // 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系 // 2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离 //将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离 /// public class DragObjMove : MonoBehaviour { void Start() { StartCoroutine(OnMouseDown()); } IEnumerator OnMouseDown() { //将物体由世界坐标系转换为屏幕坐标系 Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标 Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z)); while (Input.GetMouseButton(0)) { //得到现在鼠标的2维坐标系位置 Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z); //将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量 Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset; //curPosition就是物体应该的移动向量赋给transform的position属性 transform.position = curPosition; yield return new WaitForFixedUpdate(); //这个很重要,循环执行 } } }
11、逐渐注视目标方向旋转
///
/// 逐渐注视目标点旋转
///
/// 变换组件
/// 目标点
/// 旋转速度
public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
{
Vector3 dir = targetPos - targetTF.position;
LookDirection(targetTF, dir, rotateSpeed);
}
///
/// 逐渐注视目标方向旋转
///
/// 变换组件
/// 目标方向
/// 旋转速度
public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
{
//如果需要注视零方向
if (targetDir == Vector3.zero) return;
//transform.LookAt(目标点); 一帧旋转到位
Quaternion dir = Quaternion.LookRotation(targetDir);
targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
}
12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 对象池
///
public class GameObjectPool : MonoSingleton
{
//1.对象池
private Dictionary> cache;
//private Dictionary> obj = new Dictionary>();
//初始化:在对象创建时执行一次
protected override void Init()
{
base.Init();
cache = new Dictionary>();
}
//2.创建对象
///
/// 通过对象池创建对象
///
/// 需要创建的对象种类
/// 需要创建的预制件
/// 创建的位置
/// 创建的旋转
///
public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
{
//在池中查找
GameObject tempGo = FindUsableObject(key);
//如果没有找到
if (tempGo == null)
{
//创建物体
tempGo = Instantiate(prefab);
//加入池中
Add(key, tempGo);
//将通过对象池创建的物体,存入对象池子物体列表中。
tempGo.transform.SetParent(transform);
}
//使用
UseObject(tempGo, pos, dir);
return tempGo;
}
private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
{
//先设置位置
go.transform.position = pos;
go.transform.rotation = dir;
//再启用物体
go.SetActive(true);
//重置通过对象池创建物体的所有脚本对象
foreach (var item in go.GetComponentsInChildren())
{
item.OnReset();
}
}
private void Add(string key, GameObject tempGo)
{
//如果池中没有键 则 添加键
if (!cache.ContainsKey(key)) cache.Add(key, new List());
//将物体加入池中
cache[key].Add(tempGo);
}
private GameObject FindUsableObject(string key)
{
if (cache.ContainsKey(key))
{
// public delegate bool Predicate(T obj);
//查找池中禁用的物体
return cache[key].Find(o => !o.activeInHierarchy);
}
return null;
}
//3.即时回收
public void CollectObject(GameObject go)
{
go.SetActive(false);
}
//4.延迟回收
public void CollectObject(GameObject go, float delay)
{
StartCoroutine(DelayCollect(go, delay));
}
private IEnumerator DelayCollect(GameObject go, float delay)
{
yield return new WaitForSeconds(delay);
CollectObject(go);
}
//5.清空
public void ClearAll()
{
//将字典中所有键存入集合
List listKey =new List(cache.Keys);
foreach (var item in listKey)
{
//遍历集合元素 删除字典记录
Clear(item);
}
}
public void Clear(string key)
{
//倒序删除
for (int i = cache[key].Count -1; i>=0 ; i--)
{
Destroy(cache[key][i]);
}
//在字典集合中清空当前记录(集合列表)
cache.Remove(key);
}
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
///
/// 获取动画状态机animator的动画clip的播放持续时长
///
///
///
///
public float GetClipLength(Animator animator, string clipName)
{
if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
return 0;
// 获取所有的clips
var clips = animator.runtimeAnimatorController.animationClips;
if (null == clips || clips.Length <= 0) return 0;
AnimationClip clip;
for (int i = 0, len = clips.Length; i < len; ++i)
{
clip = clips[i];
if (null != clip && clip.name == clipName)
return clip.length;
}
return 0f;
}
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; ///13、将角度限制在360/// 对象池 /// public class GameObjectPool : MonoSingleton{ //1.对象池 private Dictionary > cache; //private Dictionary > obj = new Dictionary >(); //初始化:在对象创建时执行一次 protected override void Init() { base.Init(); cache = new Dictionary >(); } //2.创建对象 /// /// 通过对象池创建对象 /// /// 需要创建的对象种类 /// 需要创建的预制件 /// 创建的位置 /// 创建的旋转 ///public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir) { //在池中查找 GameObject tempGo = FindUsableObject(key); //如果没有找到 if (tempGo == null) { //创建物体 tempGo = Instantiate(prefab); //加入池中 Add(key, tempGo); //将通过对象池创建的物体,存入对象池子物体列表中。 tempGo.transform.SetParent(transform); } //使用 UseObject(tempGo, pos, dir); return tempGo; } private void UseObject(GameObject go,Vector3 pos, Quaternion dir) { //先设置位置 go.transform.position = pos; go.transform.rotation = dir; //再启用物体 go.SetActive(true); //重置通过对象池创建物体的所有脚本对象 foreach (var item in go.GetComponentsInChildren ()) { item.OnReset(); } } private void Add(string key, GameObject tempGo) { //如果池中没有键 则 添加键 if (!cache.ContainsKey(key)) cache.Add(key, new List ()); //将物体加入池中 cache[key].Add(tempGo); } private GameObject FindUsableObject(string key) { if (cache.ContainsKey(key)) { // public delegate bool Predicate (T obj); //查找池中禁用的物体 return cache[key].Find(o => !o.activeInHierarchy); } return null; } //3.即时回收 public void CollectObject(GameObject go) { go.SetActive(false); } //4.延迟回收 public void CollectObject(GameObject go, float delay) { StartCoroutine(DelayCollect(go, delay)); } private IEnumerator DelayCollect(GameObject go, float delay) { yield return new WaitForSeconds(delay); CollectObject(go); } //5.清空 public void ClearAll() { //将字典中所有键存入集合 List listKey =new List (cache.Keys); foreach (var item in listKey) { //遍历集合元素 删除字典记录 Clear(item); } } public void Clear(string key) { //倒序删除 for (int i = cache[key].Count -1; i>=0 ; i--) { Destroy(cache[key][i]); } //在字典集合中清空当前记录(集合列表) cache.Remove(key); } }
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if (result<0)
{
result+=360f;
}
return result;
}
14、获取动画状态机animator的动画clip的播放持续时长
////// 获取动画状态机animator的动画clip的播放持续时长 /// /// /// ///public float GetClipLength(Animator animator, string clipName) { if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController) return 0; // 获取所有的clips var clips = animator.runtimeAnimatorController.animationClips; if (null == clips || clips.Length <= 0) return 0; AnimationClip clip; for (int i = 0, len = clips.Length; i < len; ++i) { clip = clips[i]; if (null != clip && clip.name == clipName) return clip.length; } return 0f; }
end



