Unity入门学习:Day05
(十)四元数
是一种超复数(x,y,z,w),轴角对。按YZX顺序一个轴一个轴的转
例如,将一个物体绕Z轴旋转60度
cube.transform.rotation= new Quaternion(0,0,Mathf.Sin(30*Mathf.Deg2Rad),Mathf.Cos(30*Mathf.Deg2Rad))
Inspector面板中虽然是用Rotation这种欧拉角来显示的,但是底层旋转功能是用Quaternion来实现的。rotation显示的是Quaternion.Euler。
一、LookRotation:看向目标物体
//挂载在相机上public GameObject cube;public GameObject cylinder;// Start is called before the first frame updatevoid Start(){
//结果是相机看向了cubeVector3 relativePos = cube.transform.position - transform.position;Quaternion rotation = Quaternion.LookRotation(relativePos);transform.rotation = rotation;}
二、Angel:它可以计算两个旋转之间的夹角。与Vector3.Angle()作用是一样的。返回欧拉角度
//初始将cylinder绕y轴旋转90度,打印结果是90度。旋转-90度,也是打印90度。Debug.Log(Quaternion.Angle(cube.transform.rotation, cylinder.transform.rotation));
三、Euler:将一个欧拉形式的旋转转换成四元数形式的旋转。
//将cube的rotation值改为30,30,30
cube.transform.rotation = Quaternion.Euler(new Vector3(30,30,30));
四、FromToRotation:得到从一个方向到另一个方向的旋转。
//摄像机做一个旋转,旋转的值是本身的前方到cube上方之间的旋转值。
//Quaternion.FromToRotation(Quaternion From,Quaternion To);
transform.rotation= Quaternion.FromToRotation(transform.forward, cube.transform.up);
五、Slerp:基本意思就是球形插值地从一个角度旋转到另一个角度,其中,旋转匀速增加t。
//匀速看向cube目标物体transform.rotation = Quaternion.Slerp(transform.rotation, cube.transform.rotation, 0.01f);
六、四元数相乘
两个四元数相乘,得到的新的四元数,就是两个旋转角度的叠加。
(十一)对象池
取子物体或者生成新子物体函数
/// <summary>/// 从Pool里面拿出子对象或者生成新对象/// </summary>public void GetObjFromPoor(){ //如果缓存池不空,那么就从中拿出物体if (Pool.childCount > 0){//利用循环按照所需要的数量将池子中的物体拿出来,并且设置为可见,父节点设置为bulletFather//利用协程等待一定时间后,将子弹放回池子。for (int i = 0; i < numsWeNeed; i++){GameObject obj = FindChild("bullet", Pool).gameObject; obj.SetActive(true);obj.transform.parent = bulletFather;StartCoroutine(Delayed(obj));//开启协程} }//如果缓存池空了,生成新的物体else{InstiateByCircle();}}
将物体放回对象池
/// <summary>/// 将物体放回池子,设为false,状态置0./// </summary>/// <param name="obj"></param>public void PushObjToPoor(GameObject obj){obj.SetActive(false);放回池子的东西放在一个父节点下,便于管理obj.transform.position = Vector3.zero;obj.transform.parent = Pool.transform;}
协程函数
/// <summary>/// 协程函数,将物体放回池子/// </summary>/// <param name="obj"></param>/// <returns></returns>IEnumerator Delayed(GameObject obj){yield return new WaitForSeconds(delayTime);//3秒之后执行之后的语句PushObjToPoor(obj);}
案例示例:环形发射子弹
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Fire1 : MonoBehaviour
{public GameObject bt;//待生成的子弹预制体,通过resource加载public Transform bulletFather;//子弹挂载的父节点public Transform Pool;//对象池public float delayTime = 2;//协程函数等待时间public int numsWeNeed=12;//需要取出来的数量void Start(){bt= Resources.Load<GameObject>("bullet");}void Update(){//生成环形子弹,放到PoorActiveTrue根节点下if (Input.GetMouseButtonDown(0))GetObjFromPoor(); transform.rotation *= Quaternion.Euler(new Vector3(0,1,0));}/// <summary>/// 生成环形子弹/// </summary>/// <returns>环形子弹的列表</returns>public void InstiateByCircle(){for (int i = 0; i < 12; i++){GameObject obj = Instantiate(bt, transform.position, Quaternion.Euler(0, i * 30, 0)*transform.rotation);//生成的子弹都加入到bullets列表中//bullets.Add(obj);obj.transform.parent = bulletFather;obj.name = "bullet";StartCoroutine(Delayed(obj));//开启协程}}/// <summary>/// 协程函数,将物体放回池子/// </summary>/// <param name="obj"></param>/// <returns></returns>IEnumerator Delayed(GameObject obj){yield return new WaitForSeconds(delayTime);//3秒之后执行之后的语句PushObjToPoor(obj);}/// <summary>/// 从Pool里面拿出子对象或者生成新对象/// </summary>public void GetObjFromPoor(){ //如果缓存池不空,那么就从中拿出物体if (Pool.childCount > 0){//利用循环按照所需要的数量12将池子中的物体拿出来,并且设置为可见,父节点设置为bulletFather//利用协程等待一定时间后,将子弹放回池子。for (int i = 0; i < numsWeNeed; i++){GameObject obj = FindChild("bullet", Pool).gameObject; obj.SetActive(true);obj.transform.parent = bulletFather;StartCoroutine(Delayed(obj));//开启协程} }//如果缓存池空了,生成新的物体else{InstiateByCircle();}}/// <summary>/// 将物体放回池子,设为false,状态置0./// </summary>/// <param name="obj"></param>public void PushObjToPoor(GameObject obj){obj.SetActive(false);放回池子的东西放在一个父节点下,便于管理obj.transform.position = Vector3.zero;obj.transform.parent = Pool.transform;}/// <summary>/// 通过深度递归查找根节点下的某子物体Transform/// </summary>/// <param name="objectName">待查找的物体名称</param>/// <param name="Start">挂载脚本的物体,查找的起点</param>/// <returns>查找的结果</returns>Transform FindChild(string objectName, Transform Start)//2 4{if (objectName == Start.name) //起点位置即为要找的物体,找到就退出,这是退出条件return Start;if (Start.childCount < 1) //起点位置不能没有子物体,不然就退出,这是退出条件return null;#region 这才是递归的核心,深度递归 Transform obj = null;for (int i = 0; i < Start.childCount; i++){Transform t = Start.GetChild(i);obj = FindChild(objectName, t);if (obj != null){break;}}return obj;#endregion}
}
(十二)射线(Ray)
用射线去检测物体,返回检测信息
Unity默认情况下提供了 3 种射线检测器:
- Graphic Raycaster - 用于 UI 元素
- Physics 2D Raycaster - 用于 2D 物理元素
- 物理射线投射器 (Physics Raycaster) - 用于 3D 物理元素
由于学习2D为主,则主要关注Physics2D Raycaster。
Physics2D Raycaster
void Update(){//最基础的射线,被检测物体一定要有碰撞体RaycastHit2D info = Physics2D.Raycast(transform.position, Vector2.right);Debug.Log("被检测到物体的transform:"+info.transform);Debug.Log("被检测到物体的质心位置信息:" + info.centroid);Debug.Log("被检测到物体的碰撞体:" + info.collider); Debug.Log("从射线原点到撞击点的距离:" + info.distance);Debug.Log("射线上发生命中的距离的分数:" + info.fraction);Debug.Log("射线命中的表面的法线矢量:" + info.normal);Debug.Log("世界空间中射线命中碰撞体表面的点:" + info.point);Debug.Log("附加到命中的对象的 Rigidbody2D:" + info.rigidbody);//假如我要检测在Layer【14: "Enemy"】发生的碰撞//也就是说://int LayerID = 14//string LayerName = "Enemy"//使用Layer ID 检测在Layer14层发生的碰撞info = Physics2D.Raycast(transform.position, Vector2.right, default, 1 << 14);//使用Layer ID 检测在Layer12、14层发生的碰撞 (1 << 12) | (1 << 14) 表示包含12、14层 (不包含其余层)info = Physics2D.Raycast(transform.position, Vector2.right, default, (1 << 12) | (1 << 14));//使用Layer ID 检测不在Layer14层发生的碰撞 ~(1<<14) 表示不包含14层(包含其他所有层)info = Physics2D.Raycast(transform.position, Vector2.right, default, ~(1 << 14));}
(十三)异步加载和协程
异步加载不会引起代码阻塞;
协程:协程不是多线程,是假的“多线程”;
应用场景:1.WWW加载网络数据;2.异步加载资源、场景;
yield关键字是最重要的,直译是屈服、让步于,就是等待其他内容的执行,其他内容执行完了再回到这个协程执行剩下的语句。
下面看八道练习题帮助理解协程执行逻辑。
(1条消息) 八道练习题教你轻松学会运用Unity中的协程用法_听雨眠丨的博客-CSDN博客
1.开始协程:我们通过StartCoroutine()函数来调用协程函数。
调用协程的方法有两种,分别是StartCoroutine(/这里直接调用方法,添加参数/),另一种是StartCoroutine(/这里填写”字符串的方法名字”,方法参数/)。
第一种方法的优势在于可以调用多个参数的方法,后一种方法只能调用不含参数或只包含一个参数的协程方法。但是第一种方法不能通过StopCoroutine(/这里填写”字符串的方法名”/)来结束协程,只能通过StopAllCoroutines来结束。后一种则可以通过StopCoroutine来结束对正在执行的协程的调用。
2.停止协程
在一个协程开始后,同样会对应一个结束协程的方法StopCoroutine与StopAllCoroutines两种方式,但是需要注意的是,两者的使用需要遵循一定的规则,在介绍规则之前,同样介绍一下关于StopCoroutine重载:
StopCoroutine(string methodName):通过方法名(字符串)来进行
StopCoroutine(IEnumerator routine):通过方法形式来调用
StopCoroutine(Coroutine routine):通过指定的协程来关闭
刚刚我们说到他们的使用是有一定的规则的,那么规则是什么呢,答案是前两种结束协程方法的使用上,如果我们是使用StartCoroutine(string methodName)来开启一个协程的,那么结束协程就只能使用StopCoroutine(string methodName)和StopCoroutine(Coroutine routine)来结束协程。
3.暂停协程:使用yield关键字
yield return null; // 下一帧再执行后续代码
yield return 0; //下一帧再执行后续代码
yield return 6;//(任意数字) 下一帧再执行后续代码
yield break; //直接结束该协程的后续操作
yield return asyncOperation;//等异步操作结束后再执行后续代码
yield return StartCoroution(/*某个协程*/);//等待某个协程执行完毕后再执行后续代码
yield return WWW();//等待WWW操作完成后再执行后续代码
yield return new WaitForEndOfFrame();//等待帧结束,等待直到所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前执行
yield return new WaitForSeconds(0.3f);//等待0.3秒,一段指定的时间延迟之后继续执行,在所有的Update函数完成调用的那一帧之后(这里的时间会受到Time.timeScale的影响);
yield return new WaitForSecondsRealtime(0.3f);//等待0.3秒,一段指定的时间延迟之后继续执行,在所有的Update函数完成调用的那一帧之后(这里的时间不受到Time.timeScale的影响);
yield return WaitForFixedUpdate();//等待下一次FixedUpdate开始时再执行后续代码
yield return new WaitUntil()//将协同执行直到 当输入的参数(或者委托)为true的时候....如:yield return new WaitUntil(() => frame >= 10);
yield return new WaitWhile()//将协同执行直到 当输入的参数(或者委托)为false的时候.... 如:yield return new WaitWhile(() => frame < 10);
使用UniTask代替协程
1.UniTask有哪些优点
2.插件安装步骤
方法一:通过Git url连接安装(推荐)
在PackageManage里面通过链接来安装,注意如果电脑未安装git会报错。
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
方法二:下载压缩包插件安装
3.基础操作
参考:UniTask · 开发文档集合
(十四)特殊文件夹
参考自: Unity特殊文件夹以及各平台Application.xxxPath的路径图文详解教程
1. StreamingAssets ―― 二进制流 资源文件夹
默认情况下, Unity 是没有 StreamingAssets 文件夹的,我们需要自行创建
StreamingAssets 与 Resources 区别:
Resources文件夹下的资源打包发布时,会进行一次压缩和加密
StreamingAssets 文件夹下的资源打包发布时,原封不动(不进行任何处理)
所以 StreamingAssets 一般放置数据资源文件,比如 Json /Xml 等数据文件
在PC/MAC中可实现对文件的“增删改查”等操作,但在移动端是一个只读路径。
返回的路径 | Application.streamingAssetsPath |
Mac OS / Windows |
Application.dataPath + "/StreamingAssets"
|
iOS |
Application.dataPath + "/Raw"
|
Android |
"jar:file://" + Application.dataPath + "!/assets/"
|
在 Android
平台上使用压缩.apk
文件,streamingAsset
中的数据文件包含所以需要使用 UnityWebRequest
类访问资产,才可对数据进行正确读取
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;/// <summary>
/// 测试获取 StreamAssets 下的数据资源,(图片),并显示在UI上
/// </summary>
public class ChinarWebRequest : MonoBehaviour
{void Start(){StartCoroutine(SendUrl(Application.streamingAssetsPath + "/Chinar.png"));}/// <summary>/// 发起请求/// </summary>/// <param name="url">地址</param>private IEnumerator SendUrl(string url){using (UnityWebRequest uw = UnityWebRequest.Get(url)){yield return uw.SendWebRequest();if (uw.error != null){Debug.Log(uw.error);}else{if (uw.responseCode == 200) //200表示接受成功{Texture2D texture = new Texture2D(400, 350); //创建Texturetexture.LoadImage(uw.downloadHandler.data); //加载ImageSprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one / 2); //得到精灵对象GameObject.Find("Chinar-Image").GetComponent<Image>().sprite = sprite; //赋值到UI上}}}}
}
2.Persistent ―― 持久数据 文件夹
常用于存储一些可持久化的用户数据文件
此目录只对应一个应用程序,只要应用不被卸载 / 或是公司名且应用名称不做更改 / 此目录中的文件不会进行任何更改!
只能在应用程序运行时,才能读写操作,建议将获得的文件,或是用户的基本信息,等等数据文件,保存到此目录中。例如,将 AssetBundle
包中读取的数据,写入该目录中。
3.总结
Application.dataPath
|
此属性用于返回程序的数据文件所在文件夹的路径 | |
Application.streamingAssetsPath
|
|
|
Application.persistentDataPath
|
此属性用于返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件 | |
pplication.temporaryCachePath
|
|
各路径在几种平台下的目录:
Android | Windows | |
Application.dataPath
|
/data/app/xxx.xxx.xxx.apk | /Assets |
Application.streamingAssetsPath
|
jar:file:///data/app/xxx.xxx.xxx.apk/!/assets | /Assets/StreamingAssets |
Application.persistentDataPath
|
/data/data/xxx.xxx.xxx/files | C:/Users/xxxx/AppData/LocalLow/CompanyName/ProductName |
Application.temporaryCachePath
|
/data/data/xxx.xxx.xxx/cache | C:/Users/xxxx/AppData/Local/Temp/CompanyName/ProductName |
Unity入门学习:Day05相关推荐
- [Unity 学习] Unity 入门学习及第一个游戏
[Unity 学习] Unity 入门学习及第一个游戏 跟着教程做的一个小游戏,基本上说就算我这样的零基础,两个小时就能实现. 主要就是熟悉一下 C#和 Unity,做一个能跑的东西. 简单的 Dem ...
- 《Unity Shader入门精要》学习笔记第5章 开始Unity Shader学习之旅
本文章用于帮助自己学习,因此只记录一些个人认为比较重要或者还不够熟悉的内容. 原作者:http://blog.csdn.net/candycat1992/article/ 第五章 开始Unity Sh ...
- 三维地形制作软件 World Machine 基础入门学习教程
<World Machine课程>涵盖了你需要的一切,让你有一个坚实的基础来构建自己的高质量的电影或视频游戏地形. 你会学到什么 为渲染或游戏开发创建高分辨率.高细节的地形. 基于Worl ...
- Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR)
Unity Shader 学习笔记(33) 全局光照(GI).反射探针.线性空间和伽马空间.高动态范围(HDR) 参考书籍:<Unity Shader 入门精要> [<Real-Ti ...
- Unity 入门笔记 - 02 - 各种动画
Unity 入门笔记 - 02 - 各种动画 前言:上一篇笔记记录了从零开始安装软件,到搭建最基本的游戏场景和角色,最后开始接触了脚本代码.对unity游戏引擎的工作方式有了基本的认知.接下来开始进一 ...
- Shader Forge 入门学习(二) 实现发光、火焰燃烧、溶解、扭曲效果
引言:本篇博客主要记录ShaderForge的常用案例,包括外发光.火焰燃烧.溶解.扭曲等效果.由于内容较多会分成几篇博客记录.如果您对Shader Forge的常用操作还不熟悉,请先看 Unity3 ...
- 学习Unity需要学习哪些编程语言
答案是C#! Unity曾支持过三种语言的开发:C#,UnityScript(接近于JavaScript),Boo.但是,截止到今天,最新的Unity 2018版本已经完全弃用了UnityScript ...
- C#入门学习笔记(基于刘铁锰老师C#入门2014教学视频)【1】
C#入门学习笔记(基于刘铁锰老师C#入门2014教学视频)[1] 前言: 本笔记作为记录我从零开始学习C#的记录,为了unity的兴趣爱好自学一门C#,也算是寒假为自己充个电,希望这个寒假可以坚持下去 ...
- C#入门学习笔记(基于刘铁锰老师C#入门2014教学视频)【2】
C#入门学习笔记(基于刘铁锰老师C#入门2014教学视频)[2] 初识类和名称空间 前言: 本笔记作为记录我从零开始学习C#的记录,为了unity的兴趣爱好自学一门C#,也算是寒假为自己充个电,希望这 ...
最新文章
- Android9.0 新特性
- CentOS 6.5服务器安全加固及性能优化
- python自动登录教程_Python 实现自动登录+点击+滑动验证功能
- C++描述杭电OJ 2018.母牛的故事 ||
- MySQL 深潜 - 一文详解 MySQL Data Dictionary
- python 获取用户的一个输入值_Python中,用于获取用户输入的命令为:
- cmake cache变量_反复研究好几遍,我才发现关于 CMake 变量还可以这样理解!
- Evernote CEO给想做长久公司创业者的3个建议
- python实现给定一个列表,输出由各个位置除了自身元素外所有元素乘积组成的列表
- 自动把动态的jsp页面(或静态html)生成PDF文档,并且上传至服务器
- 手把手写Demo系列之车道线检测
- linux内核编程4部曲之一:linux内核编译(2.6.12版本)图文解说
- 误码率曲线matlab代码,matlab画误码率曲线
- Biopython -- Bio.Entrez module
- VMware桥接模式下虚拟机ping主机不通
- 对IPv6的理解以及其与IPv4的区别
- 自定义view系列---刮刮乐的实现
- 惠普硬盘测试工具_短DST未通过,详细教您惠普笔记本如何检测硬盘
- python做后端的优势_python做后端好吗
- CE_tutorial_game
热门文章
- Navicat下载,安装,PJ和简单使用的详细图文教程
- Java - 什么是IoC和DI?DI是如何实现的?
- 2021年危险化学品经营单位主要负责人考试及危险化学品经营单位主要负责人考试资料
- 年轻的战场--(抢了一个大沙发,老衲笑而不语,哈哈。。)
- 历届真题 杨辉三角形【第十二届】【省赛】【B组】
- antd 实现 sidebar 左侧菜单·记
- Synopsys VCS工具介绍
- 计算机C语言二级发证机构,全国高等学校计算机等级考试(壹级)证书的发证机关是哪个...
- 雅虎NCP:网络黄页的终结者
- 【苹果推信iMessage】群发安装软件sent with Invisible Ink“设置”应用