- 👨💻个人主页:
- 👨💻 秩沅 原创
👨💻 专栏交流 | 🧧 |
---|---|
🟥unity100个实战基础✨ | 🎁 |
🟦 unity100个精华一记✨ | 🎁 |
🟩 unity50个demo案例教程✨ | 🎁 |
🟨 unity100个精华细节bug✨ | 🎁 |
目录
- 帧的概念
- 日志打印
- 反射机制
- api之——rigidbody
- api之——inspector可编辑变量+辅助特性
- api之——坐标系
- api之——生命函数
- api之——鼠标相关
- api 之——创建,获取,失灵,销毁
- api 之——父子关系
- api 之——退出
- api 之——transform组件篇
- api 之——vector实质
- api 之——mathf类
- api 之——三角函数
- api 之——向量
- api 之—— 四元数
- api 之——随机类
- api 之——gameobject类
- api 之——monobehavior类
- api 之—— input系统接口类
- api —— sendmessage消息发送机制
- api——动画基础
- api——时间time类
- api——协程
- api——物体的移动
- api——物体的旋转
- api——音频audio
- api——麦克风
- api——粒子系统
- api——trailrender拖尾渲染器
- api——碰撞器和触发器
- api——特殊文件夹
- api——资源加载(resource)
- api——camera相机 相关
- api——screen屏幕 相关
- api——动画控制器 相关
- api——屏幕相关
- api——场景(scene)加载
- api——screen组件
- api——application类
- api——cursor类
- api——范围检测physics.overlap
- api——射线检测physics.raycast
- 组件——线渲染器 linerenderer
- 组件—— 角色控制器character contorller
- 组件——platformeffector 2d(跳跃平台)
- 组件——eadg collider 2d(地形碰撞器)
- 组件—— nav mesh agent 导航寻路
- bug情况以及处置
帧的概念
fps (frames per second) : 即每秒钟帧数
- 60帧:
1秒更新60次画面
1s = 1000ms - 60帧:1帧为 1000ms/60=16.66ms
- 30帧:1帧为 1000ms/30=33.33ms
- 游戏卡顿的原因:
处理1帧游戏逻辑中的计算量过大,或cpu机能不行,不能在—帧的时间内处理完所有游戏逻辑
日志打印
debug.log(“this is a log message.”);
debug.logwarning(“this is a warning message!”);
debug.logerror(“this is an error message!”);
反射机制
场景的本质-配置文件-(场景类型文件右键通过记事本可以看到)
-
1.获取
rigidbody = this.getcomponent(); -
2.添加力
rigidbody.addforce(vector3.forward * 10);相对世界坐标世界坐标系 z轴正方向加了一个里加力过后 对象是否停止移动 是由阻力决定的如果阻力为0 那给了一个力过后 始终 是不会停止运动
-
-
让对象 相对于自己的面朝向动
相对世界坐标
rigidbody.addforce(this.transform.forward * 10);相对本地坐标
rigidbody.addrelativeforce(vector3.forward * 10);
-
api之——rigidbody
- 相对世界坐标
rigidbody.addtorque(vector3.up * 10); - 相对本地坐标
rigidbody.addrelativetorque(vector3.up * 10);
速度方向 是相对于 世界坐标系的
rigidbody.velocity = vector3.forward * 5;
如果要直接通过改变速度 来让其移动 一定要注意这一点
rigidbody.addexplosionforce(100, vector3.zero, 10);
模拟爆炸的力 一定是 所有希望产生爆炸效果影响的对象 都需要得到他们的刚体 来执行这个方法 才能都有效果
力的模式 主要的作用 就是 计算方式不同而已
由于计算方式的不同 最终的移动速度就会不同
- rigidbody.addforce(vector3.forward * 10,forcemode.acceleration);
字符 | 意义 |
---|---|
f | 力 |
t | 时间 |
m | 质量 |
v | 速度 |
动量定理 | ft = mv v = ft/m; |
-
1.acceleration
给物体增加一个持续的加速度,忽略其质量
字符 | 值 |
---|---|
f | (0,0,10) |
t | 0.02s |
m | 默认为1 |
v | 10*0.02/ 1 = 0.2m/s |
每物理帧移动 | 0.2m/s*0.02 = 0.004m |
-
2.force
给物体添加一个持续的力,与物体的质量有关
字符 | 值 |
---|---|
f | (0,0,10) |
t | 0.02s |
m | 2kg |
v | 10*0.02/ 2 = 0.1m/s |
每物理帧移动 | 0.1m/s*0.02 = 0.002m |
-
3.impulse
给物体添加一个瞬间的力,与物体的质量有关,忽略时间 默认为1
字符 | 值 |
---|---|
f | (0,0,10) |
t | 0.01s |
m | 2kg |
v | 10*1/ 2 = 5m/s |
每物理帧移动 | 5m/s*0.02 = 0.1m |
- 4.velocitychange
字符 | 值 |
---|---|
f | (0,0,10) |
t | 1s |
m | 1kg |
v | v = 10*1/ 1 = 10m/s |
每物理帧移动 | 10m/s*0.02 = 0.2m |
- rigidbody.issleeping())
- rigidbody.wakeup();——唤醒刚体
api之——inspector可编辑变量+辅助特性
☑️辅助特性:
- 字典 自定义类型 私有和被保护类型无法在inspector面板上显示
- 【serializefield】——将私有类型和保护类型可视化到面板上
- 【system.serializefield】——将自定义类型可视化到面板上
- 【hideininspector】——将公共变量隐藏
- 【header(“分组说明”)】——将可视化变量进行分组
- 【tooltip(“内容说明”)】——鼠标移动变量处时显示说明信息
- 【range(最小值,最大值)】——通过拖动条的方式来控制范围
- 【contextmenuitem(”变量名x“,“变量的方法名”)】——停在可视化变量上时显示方法,并可以点击调用–方法需要无参无返回
- 【contextmenu(”测试函数名")】——只为调式,右键选择方法执行
- 【multline(x)】——将字符串设置可见的x行
- 【textarea(3,4))】——添加滚动条来查看设置的文本区
+【disallowmultiplecomponent】-不让挂载多重脚本
api之——坐标系
①世界坐标系——transform…
②物体坐标系——transform.local…
③屏幕坐标系
④视口坐标系——用的较少,主要调整窗口
api之——生命函数
- 👨💻十大常见的生命函数
👨💻reset()://重置函数,
调用情况和时间:
编译器不运行的情况下 和 使用脚本组件reset功能的时候, 挂脚本的时候
调用次数: 1次
👨💻 awake(); //苏醒函数
调用情况和时间:
1.点击运行的时候
2.组件从失灵到激活的时候,但只调用一次
3.instantiate方法调用的时候
调用次数: 1次
👨💻onenable(); //组件调用函数
调用情况和时间: 组件从失灵到激活的时候,可多次实现
调用次数:只要组件有失灵到激活的状态就可调用 ,
👨💻strat():
调用情况和时间: 当游戏物体被激活,或者脚本组件被激活时调用 , (点击运行的时候也是会被激活)
调用次数: 1次
👨💻fixedupdate(每帧)
调用情况和时间: fixedupdate一般适用在相关物理引擎中。它的频 率是0.02秒,是固定的。
调用次数: 大概每秒50次左右、
fixedupdate & update & lateupdate的 区别详解
👨💻updata(每帧) ;
调用情况和时间: 在以上生命周期函数之后,每帧调用一次
调用次数: 大概每秒60次左右
变量赋值生效顺序:
👨💻lateupate(每帧):
调用情况和时间: 在update调用之后,并且也是每秒60帧左右(适用于物体移动后的视角跟随)
调用次数: 大概每秒60次左右
👨💻ongui(每帧)
- 它一般与界面化,渲染,ui等有关,实时执行,比如想在幕布上弄个按钮button
👨💻ondisable():
调用情况和时间: 和onenable差不多,但是disable是组件从完好到失活的状态, (相当于关闭组件的时候)
调用次数: 组件从激活到失灵的时候调用(二者前提是在游戏运行的时候)
👨💻onapplicationquit()
调用情况和时间: 当所有游戏物体退出时调用,适用于打包的时候
调用次数: 满足以上情况便调用
👨💻ondestroy();
调用情况和时间: 适用于物体的销毁,删除,以及游戏的停止退出时
调用次数: 满足以上情况便调用
👨💻总的执行顺序为:
- awake——onenable——start——fixedupdate——update——lateupdate——ongui——disenabel——ondestory
api之——鼠标相关
api 之——创建,获取,失灵,销毁
👨💻👍1.创建物体的三种方式
1.new 构造函数
2.instantiate 实例化方法
3.gameobject .creatprimtive(primitve type.cube);使用特别的api创建一些基本的游戏物体类型(原始几何体)
👨💻👍2.游戏物体的获取和查找
-
⭐ 获取
-
1.this
-
2.获取游戏物体的标签 gameobject.tag
-
3.获取游戏物体的名字 gameobject.name
-
4.获取游戏物体的层级 gameobject.layer
- 1.位置:this.transform.position
- 2.角度:this.transform.eulerangles
- 3,缩放大小:this.transform.lossyscale
1.子对象的获取
- 1.transform.getchild(序列号);
- 2.transform.getsiblingindex() -----获取同级索引(查找自已是父亲的第几个儿子)
- 3.transform.getcomponentinchildren< transform>(序列号);
2.父对象的获取
- 1.transform.parent();
3.project的资源获取–资源加载
- resources.load< gameobject>(“资源路径”)
4.根据脚本名获取
-
获取脚本的方法 如果获取失败 就是没有对应的脚本 会默认返回空
test t = this.getcomponent(“test”) as est;
print(t); -
根据type获取
t = this.getcomponent(typeof(test)) as test;
print(t); -
根据泛型获取 建议使用泛型获取 因为不用二次转换
t = this.getcomponent<test>();
⭐脚本的获取
-
脚本是否失活
this.enabled = false; -
1.得到自己挂载的单个脚本
test t = this.getcomponent(“test”) as test; -
2.得到自己挂载的多个脚本
lesson3[] array = this.getcomponents(); -
3.得到子对象挂载的脚本(它默认也会找自己身上是否挂载该脚本)
t = this.getcomponentinchildren<lesson3_test>(true); ——//ture表示失活了亦会寻找 -
4.得到父对象挂载的脚本(它默认也会找自己身上是否挂载该脚本)
t = this.getcomponentinparent<lesson3_test>(); -
5.尝试获取脚本
提供了一个更加安全的 获取单个脚本的方法 如果得到了 会返回true
⭐查找物体
- 1.gameobject,find()-----按照名字查找游戏对象 ,用太多会降低性能
- 2.gameobject,findobjecttype<>();------按照组件名来查找游戏物体
- 3.gameobject.findgameobjectwithtag()------按照游戏物体标签来查找游戏物体
- 4.多数查找与获取
gameobject[] enemygos= gameobject.findgameobjectswithtag("enemy");
for (int i = 0; i < enemygos.length; i++)
{
debug.log("查找到的敌人游戏物体名称是:"+enemygos[i].name);
}
⭐失灵
- 1.xx.setactive(false); --------应用于游戏物体xx为gameobject类型继承自object类
使得相应的脚本对象失灵 - 2.xx.enable = fasle;-----------应用于脚本/组件xx为组件类型,继承为copment类
使得相应游戏物体的组件失灵 - 3.xx.activeinhierarchy____判断该游戏物体是否是失活状态
⭐销毁
- 1.destroy()
- 2.detroy(xx , time)__延时销毁
👨💻👍3.继承
常见类的继承关系:
api 之——父子关系
-
不要爸爸了:this.transform.setparent(null);
-
认爸爸 :this.transform.setparent(gameobject.find(“爸爸名”).transform);
-
this.transform.setparent(gameobject.find(“father3”).transform, false);
true : 保留 世界坐标下的状态 和 父对象 进行计算 得到本地坐标系的信息 false : 不会保留 会直接把世界坐标系下的 位置角度缩放 直接赋值到 本地坐标系下
-
不要儿子了: this.transform.detachchildren();
-
得到儿子数量:this.transform.childcount
-
得到儿子信息: this.transform.getchild(0);
-
亲子鉴定:son.ischildof(this.transform)
-
得到自己是第几个儿子:son.getsiblingindex())
-
把自己变成太子: son.setasfirstsibling();
-
把自己变成最后的一个儿子: son.setaslastsibling();
-
直接设置自己是第几个儿子: son.setsiblingindex(1);
api 之——退出
- application.quit()———编译器下使用没用,只可以在打包之后,才有退出游戏的作用
api 之——transform组件篇
👨💻👍1.transform的位置信息
transform.position ----游戏物体trans组件的世界位置信息
transform.rotation----游戏物体的四元旋转信息
transform.enleraugle- —游戏物体的欧拉角的信息(也就是inspactor面板中的rotation信息)
transform.localposition/localrotion/localenleaugle--------表自身的自身信息
- 当前游戏物体的世界四元旋转值为——transform.rotation
- 当前游戏物体的自身大小为——transform.localscale
- 当前游戏物体的自身位置为——transform.localposition
- 当前游戏物体的自身四元旋转位置——transform.localrotation
- 当前游戏物体的世界欧拉角为——transform.eulerangles
- 当前游戏物体的自身欧拉角为——transform.localeulerangles
👨💻👍2.游戏物体的自身方向和世界轴方向
针对自身:
==transform.forword ==----向前z轴方向
transform.up------向上y轴方向
transform.right----向右x轴方向
针对世界:
vector.xx…
针对看向:
transform.lookat(某个方向)——一直看向某个方向
transform.lookat(某个物体)——一直看向某个物体
针对缩放
#region 知识点一 缩放
//相对世界坐标系
print(this.transform.lossyscale);
//相对本地坐标系(父对象)
print(this.transform.localscale);
- 当前的位置 + 我要动多长距离 == 得出最终所在的位置
this.transform.position = this.transform.position + this.transform.up * 1 * time.deltatime;
- 始终会朝向相对于自己的面朝向去动
this.transform.position += this.transform.forward * 1 * time.deltatime;
- 相对于世界坐标系的 z轴 动 始终是朝 世界坐标系 的 z轴正方向移动
this.transform.translate(vector3.forward * 1 * time.deltatime, space.world);
- 相对于世界坐标的 自己的面朝向去动 始终朝自己的面朝向移动
this.transform.translate(this.transform.forward * 1 * time.deltatime, space.world);
- 相对于自己的坐标系 下的 z轴正方向移动 始终朝自己的面朝向移动
this.transform.translate(vector3.forward * 1 * time.deltatime, space.self);
👨💻👍 3.用transform组件来进行查找(包含索引查找)
-
被创造的游戏物体的世界坐标位置是——xx.transform.position
-
当前transform组件挂载的游戏物体对象的名字是——transform.name
-
当前transform组件挂载的游戏对象的子对象的数量——transform.childcount
-
查找当前游戏物体的子对象的trans组件名称为——transform.find(“zz”)
-
查找当前游戏物体的第一个子对象——transform.getchild(0));
-
查找该游戏物体在父类中子对象的索引位置"——transform.getsiblingindex()
api 之——vector实质
👨💻👍1.vector2结构体的静态变量
1.vector2.up // 以下的形式pint之后是 (x,y)
2.vector2.down
3.vector2.left
4.vector2,riht
5.vector2.one //单位化之后的值
6.vetor2.zero // 原点的值
👨💻👍2.vector2 结构体的成员变量
1.x
2.y
3.xx.normalized //返回 单位化的值
4xx.magnitude //返回该向量的模长
5.xx.sqrmagnitude //返回该向量 模长的平方
‘’‘’‘’‘’‘’‘’
👨💻👍3.索引器的格式和存在的目的
1,格式
访问修饰符 + 数据类型+ this [ 索引类型 index]
{
get
set
}
2.目的:
简化结构体或者类成员的引用 (简化代码),可向数组用下标那样调用成员
👨💻👍4.vector2的公共函数-equrls()
equrls(); // 比较两个向量是否相等
用法 : xx1 . equals( xx2 );
👨💻👍5,vector2的静态方法
-
1.vector2.angle(); 返回两个向量的夹角
-
2.vevtor2.distance(): 返回两个点(向量)的距离
-
3.vetor2.lerp(a , b, t) ;返回两个向量的差值 (二维向量线性差值)
-
4.vecor.lerpunclamped(a,b,t) ; 在 a 与 b 之间按 t 进行线性插值,t 没有限制。
-
5.vector2.movetowards(a , b,t): t为限制向量的移动步频(可以理解为规定速度移动)、
-
6.vector2.max();
-
7.vector2.min();
-
8.vecotr2.smoothdamp(a,b,v ,t);平滑阻尼,可理解为汽车刹车效果,v为速度是二维向量,t为平滑时间
api 之——mathf类
👨💻👍1,mathf类的静态变量
✅math和mathf的区别:mathf是unity封装的类它在基于math数学类的基础上添加了适合unity游相关的方法
✅强制类型转换和向下取整&向下取整:除去c#中常用的三个强转 —ceiltoint() 和 floorint()
✅钳制函数mathf.clamp()
✅mathf.sigh()-判断正负
✅mathf.movetowords()——无限接近但不完全相等
✅mathf.smoothdamp()——先快后慢
//1.π - pi
//2.取绝对值 - abs
//3.向上取整 - ceiltoint
//4.向下取整 - floortoint
//5.钳制函数 - clamp
//6.获取最大值 - max
//7.获取最小值 - min
//8.一个数的n次幂 - pow
//9.四舍五入 - roundtoint
//10.返回一个数的平方根 - sqrt
//11.判断一个数是否是2的n次 - ispoweroftwo
//12.判断正负数 - sign
👨💻👍1,mathf类的静态变量
- print(mathf.deg2rad+“,度到弧度换算常量”);
- print(mathf.rad2deg+ “,弧度到度换算常量”);
- print(mathf.infinity+“正无穷大的表示形式”);
- print(mathf.negativeinfinity + “负无穷大的表示形式”);
- print(mathf.pi);
👨💻👍2,mathf类的静态函数
-
print(mathf.abs(-1.2f)+ “,-1.2的绝对值”);
-
print(mathf.acos(1)+“,1(以弧度为单位)的反余弦”);
-
print(mathf.floor(2.74f)+“,小于或等于2.74的最大整数”);
-
print(mathf.floortoint(2.74f)+“,小于或等于2.74的最大整数”);
-
mathf.lerp(1,2,0.5f) ——,a和b按参数t进行线性插值
-
mathf.lerpunclamped(1, 2, -0.5f)——,a和b按参数t进行线性插值
-
插值运算用法一
每帧改变start的值——变化速度先快后慢,位置无限接近,但是不会得到end位置
start = mathf.lerp(start, 10, time.deltatime); -
插值运算用法二
每帧改变t的值——变化速度匀速,位置每帧接近,当t>=1时,得到结果
time += time.deltatime;
result = mathf.lerp(start, 10, time);
👨💻👍3,mathf类中的 倒计时 函数
void update()
{
print("游戏倒计时:" + endtime);
endtime = mathf.movetowards(endtime,0,0.1f); //每次减0.01 直到endtime为0
}
api 之——三角函数
float rad = 1;
float anger = rad * mathf.rad2deg;
anger = 1;
rad = anger * mathf.deg2rad;
//注意:需要加上弧度值
mathf.sin(30 * mathf.deg2rad) //0.5
mathf.cos(60 * mathf.deg2rad) //0.5
-
弧度 = mathf.asin() / acos();
-
反三角函数得到的结果是 正弦或者余弦值对应的弧度
rad = mathf.asin(0.5f); //弧度 print(rad * mathf.rad2deg); //角度
【unity每日一记】让一个物体按余弦曲线移动—(三角函数的简单运用)
api 之——向量
位置 + 向量 = 平移位置
位置 - 向量 = 平移位置
位置 - 位置 = 向量
向量 - 位置 = 无意义
向量 * 向量 = 向量
向量 * 值 = 扩大模长
-
向量之间的距离 ——vector3.disrtance() 向量 和向量之间相减 a - b
-
0向量——vector.zero()
-
向量模长——vector3.magnitude() 相等于向量之间的距离
-
单位向量——vector3.normalized()适用于物体移动的时候的单位化计算
-
向量+向量 和向量+位置 的区别——前者为向量(高数中的向量相加)后者为相当于扩大作用结果是位置
-
位置-位置的几何意义——结果为向量 ,向量-向量 = 向量
-
向量的加减乘除 —— 加减应用于物体平移 乘除的进行缩放要用本地坐标
-
向量的点乘——vector3.dot 结果为余弦值,用来判断对象的大概方位(前后)和夹角
-
向量的叉乘——vector3.dot 结果为法向量垂直于两个向量构成的平面,判断(左右)
-
向量的线性差值运算——直线轨迹
vector3.lerp( s,e,t); ——s为开始值,e为最终值
①每帧改变s的值(先快后慢)—适合摄像机的跟随
②每帧改变t的值(匀速变化)—适合摄像机的跟随
线性插值
//1.先快后慢 每帧改变start位置 位置无限接近 但不会得到end位置
transform.position = vector3.lerp(
transform.position,target.position, time.deltatime);
//2.匀速 每帧改变时间 当t>=1时 得到结果
//当time>=1时 改变了目标位置后会直接瞬移到目标位置
if(nowtarget != target.position)
{
nowtarget = target.position;
time = 0;
startpos = b.position;
}
time += time.deltatime;
b.position = vector3.lerp(startpos, nowtarget, time);
- 向量的球形差值运算——弧形轨迹
vector3.slerp( s,e,t); ——s为开始值,e为最终值
对两个向量进行插值计算 t的取值范围为0~1
球形插值
c.position = vector3.slerp(vector3.right * 10, vector3.left * 10 +
vector3.up*0.1f, time*0.01f);
【unity每日一记】向量操作摄像机的移动(向量加减)
【unity每日一记】关于物体(敌方)检测—(向量点乘相关)
【unity每日一记】方位辨别—向量的叉乘点乘结合
api 之—— 四元数
1,绕着某个轴转x度,轴可以是任意轴(轴-角对)
2,避免了欧拉角中万向节死锁的问题
3,避免了欧拉角中角度变化不在(-180,180)范围内的问题
- 四元数解决了欧拉角中万向节死锁的问题
- 当unity中transform的x轴为90度是发生万向节死锁,此时不管移动y轴还是z轴,物体都往x轴进行旋转
假定四元数q绕着n轴旋转β度
//计算原理_绕x轴旋转60度
quaternion q = new quaternion(mathf.sin(30 * mathf.deg2rad),
0, 0, mathf.cos(30 * mathf.deg2rad));
- quaternion.angleaxis(角度数值,轴(向量))
//绕x轴旋转60度
quaternion q = quaternion.angleaxis(60, vector3.right);
1.四元数和欧拉角转换
-
欧拉角转四元数
quaternion a = quaternion.euler(60, 0, 0); -
四元数转欧拉角
a.eulerangles
2.旋转
四元数相乘代表旋转四元数
//四元数旋转方法
transform.rotation *= quaternion.angleaxis(30,vector3.forword);
3.单位化四元数
- [1,(0,0,0)]和[-1,(0,0,0)]都是单位四元数
表示没有旋转量 - quaternion.identity _用于对象角度初始化
instantiate(xxxx, vector3.zero, quaternion.identity);
4.四元数的差值运算
- 特点: lerp() 和slerp();官方建议一般用slerp();
- 先快后慢旋转
transform.rotation = quaternion.slerp(transform.rotation,
target.rotation, time.deltatime);
- 匀速旋转—— time>=1 到达目标
time += time.deltatime;
b.transform.rotation = quaternion.slerp(start,
target.rotation, time);
5.四元数的旋转看向——lookat的本质
quaternion a = quaternion.lookrotation(b.position - a.position);
//b - a = ab 向量 ,所以传入的是向量
transform.rotation = a;
【unity每日一记】进行发射,位置相关的方法总结
【unity每日一记】摄像机相关向量代码api大全
api 之——随机类
👨💻👍1,随机类的静态变量
-
随机数int和float
random.range()😕/int是左闭右开,float是左闭右闭 -
①随机出旋转数
random.rotantion -
②随机出的欧拉角
random.rotation.enluarangles -
③随机出的欧拉角转四元数
quteronion.luer.( random.rotation.enluarangles) -
④随机出的浮点数
random.vauler 范围是 【0,1) -
⑤按图形随机出数字 --应用于枪口的圆形子弹发射(fps)
random. insideunitcircle
👨💻👍2.随机类的静态函数
- ①范围内的随机数
random.range(0 ,4 ) 左闭右开->[ 0 , 4 )
random.range( 0, 4f ) 左闭右闭 -> [ 0 ,4 ] - ②伪随机数设置状态
random.initstate(1) 开启状态 - ③伪随机数
random.range( 0 , 4 ) 左闭右闭 -> [ 0 , 4 ]
api 之——gameobject类
-
名字: this.gameobject.name
-
是否激活:
this.gameobject.activeself -
是否是静态
this.gameobject.isstatic -
层级
this.gameobject.layer -
标签
this.gameobject.tag
gameobject.createprimitive(primitivetype.cube);——正方体
- 通过名字:gameobject.find(“名字”);
- 通过标签:gameobject.findgameobjectwithtag(“标签名”);
gameobject.instantiate(xx);
-
gameobject.destroy(xx)
destroy方法 本质上给这个对象加了一个移除标 一般情况下 它会在下一帧时把这个对象移除并从内存中移除 如果没有特殊需求 就是一定要马上移除一个对象的话 建议使用上面的 destroy方法 因为 是异步的 降低卡顿的几率
-
gameobject.dontdestroyonload( xx );
切换场景后物体会被删除,该api对象 过场景不被删除
- xx.addcomponent<脚本名>();
- this.gameobject.comparetag(“xx”)
- this.gameobject.tag == “xx”
- obj.setactive(false);
api 之——monobehavior类
- 🧠transform.enable()+transform.active
- 🧠xx.getcomponent<>()泛型获取
- 🧠xx.getcomponent() as xx
- 🧠xx.getcomponent(typeof()) as xx typey类型获取
- 🧠gameobject.name
- 🧠 new 脚本类型 [ ] yy / yy = this.getcomponents();//得到多个脚本
- 🧠 getcomponentinchrild/parent //子对象或父对象组件的获取
- 🧠更安全的获取脚本trygetcomponent<>();
👨💻👍1,鼠标回调事件函数
- 适用于界面操作
api 之—— input系统接口类
👨💻👍0,相关
- 输入相关的内容一定是哟啊写在update里面
- 长按和点按的区别在于有没有dwon和up
- 按任意键继续 – input.allkey()
- 得到输入的是哪个键(stirng)-inpout.inputstring()
- 得到鼠标的位置——input.mouseposition()
+getaxis 和 getaxisraw 的区别 ——后者返回的只有三个值 -1 0 1
👨💻👍1,连续检测(按键,鼠标)
- print(“当前玩家输入的水平方向的轴值是:”+input.getaxis(“horizontal”));
- print(“当前玩家输入的垂直方向的轴值是:” + input.getaxis(“vertical”));
- print(“当前玩家输入的水平方向的边界轴值是:” + input.getaxisraw(“horizontal”));
- print(“当前玩家输入的垂直方向的边界轴值是:” + input.getaxisraw(“vertical”));
- print(“当前玩家鼠标水平移动增量是:”+input.getaxis(“mouse x”));
- print(“当前玩家鼠标垂直移动增量是:” +input.getaxis(“mouse y”));
- 鼠标的某一个键按下 ——input.getmousebuttondown( 0/1/2)
- 得到鼠标的位置——input.getmouseposition()——起点在屏幕左下角
- 鼠标的滚动——input.mousescrolldeltta()——改变y轴的值
- 鼠标滚动的应用-------炮管的升降
👨💻👍2.连续检测(事件)
-
得到所有按钮的名字 ——input.getjoysticknames()
-
if (input.getbutton(“fire1”))
{
print(“当前玩家正在使用武器1进行攻击!”);
} -
if (input.getbutton(“fire2”))
{
print(“当前玩家正在使用武器2进行攻击!”);
} -
if (input.getbutton(“recoverskill”))
{
print(“当前玩家使用了恢复技能回血!”);
}
👨💻👍3.间隔检测(事件)
-
if (input.getbuttondown(“jump”))
{
print(“当前玩家按下跳跃键”);
} -
if (input.getbuttonup(“squat”))
{
print(“当前玩家松开蹲下建”);
} -
if (input.getkeydown(keycode.q))
{
print(“当前玩家按下q键”);
} -
if (input.anykeydown)
{
print(“当前玩家按下了任意一个按键,游戏开始”);
} -
if (input.getmousebutton(0))
{
print(“当前玩家按住鼠标左键”);
} -
if (input.getmousebuttondown(1))
{
print(“当前玩家按下鼠标右键”);
} -
if (input.getmousebuttonup(2))
{
print(“当前玩家抬起鼠标中键(从按下状态松开滚轮)”);
}
api —— sendmessage消息发送机制
👍仅发送消息给自己(以及身上的其他monobehaviour对象)
👍广播消息(向下发,所有子对象包括自己)
👍向上发送消息(父对象包含自己)
-
public void getmsg()
{
print(“测试对象本身接收到消息了”);
} -
public void getsrcmsg(string str)
{
print(“测试对象本身接收到的消息为:”+str);
}
api——动画基础
- animator
- 1,ipg -> ui and 2d
( 直接将图集进行拖拽给对象) 变成动画 - 2,代码更改速度
animator .speed - 3,代码实现动画的播放
animator.dispaly - 4,代码设置过度参数
animator.setfloat(“speed”, 1 ) - 5,代码实现动画的过度
情况一:
通过按键进行动画的播放
情况二:
和通过参数来进行动画的切换(取消勾选 has exit time)
animator.crossfade (“walk” , 0.1f) __值越小过渡的越快
animator.crossfadeinfixedtime(“run”, 0.5f);
- 如何判断animator中的动画是不是在播放,或者播放完成
- 获取当前正在播放的动画片段
- private animatorclipinfo[] stateinfo; //动画状态信息类声明
- stateinfo = animator.getcurrentanimatorclipinfo(0);
api——时间time类
👨💻👍1.成员变量
- timescale是什么
时间缩放因子
unity 中的. timescale 是一个时间缩放因子,它可以控制游戏中时间的流逝速度。 默认情况下, time. timescale 的值为1,表示时间以正常速度流逝。 如果将其设置为.5,则游戏中的时间流逝速度将减慢一半;
- time.deltatime ",
- time.unscaleddeltatime
不受timescale影响的帧间隔时间
- time.fixeddeltatime
执行物理或者其他固定帧率更新的时间间隔",fixeddeltatime是一个固定的时间增量。unity中默认fixeddeltatime为0.02秒,但fixedupdate并不是真的就0.02秒调用一次
-
time.fixedtime + ",表示fixedupdate(生命周期)已经执行的时间,可以作为自游戏启动以来的总时间(以物理或者其他固定帧率更新的时间间隔累计计算的),基本上是以0.02慢慢累加(有误差)
-
time.time + ",游戏开始以来的总时间、
-
time.time + “,游戏开始以来的总时间”
-
time.realtimesincestartup + “,游戏开始以来的实际时间”
-
time.smoothdeltatime + ",经过平滑处理的time.deltatime的时间
-
time.timesincelevelload + ",自加载上一个关卡以来的时间(进入了新场景后的时间)
- 时间停止
time.timescale = 0; - 恢复正常
time.timescale = 1; - 2倍速
time.timescale = 2;
time.framecount
👨💻👍慢动作功能 —时间成员变量
- ime.timescale
时间流逝的标度,可以用来慢放动作、它的默认值为1,为0.5时可将当前游戏程序中所有时间放慢到原来的0.5倍,若为3 则为原来的三倍
api——协程
👨💻👍1.协程的定义和用途
- 用法和用途
1.延时调用
ienumerator changestate() //协程迭代器的定义
{
//暂停几秒(协程挂起)
yield return new waitforseconds(2);
//暂停两秒后再切入走路的动画
animator.play("walk");`
}
2.和其他逻辑一起协同执行
*资源加载一般是一个比较耗时的操作,如果直接放在主线程中会导致游戏卡顿,通常会放到异步线程中去执行。
👨💻👍2.协程的启动和停止
void start()
{
启动方法一:
startcoroutine("changestate"); //括号内的是协程名
启动方法二:
startcoroutine(changestate());
启动方法三: //有参协程只能用该方法开启
ienumerator ie = changestate();
startcoroutine(ie);
协程停止方法
stopcoroutine("changestate");
stopcoroutine(changestate());
stopcoroutine(ie);
停止所有协程:
stopallcoroutines();
}
ienumerator changestate() //协程的定义
{
//暂停几秒(协程挂起)
yield return new waitforseconds(2);
//暂停两秒后再切入走路的动画
animator.play("walk");`
}
👨💻👍3.协程中的 yield
- yield return n 【n可以是任意数字或者 null】
- yield return new waitforseconds(n);
【n可以是任意数字】
- yield return new waitforendofframe();
ienumerator changestate()
{
//等待一帧 yield return n(n是任意数字)
yield return null;
yield return 100000;
print("转换成run状态了");
//在本帧帧末执行以下逻辑
yield return new waitforendofframe();
}
👨💻👍4.协程中的协程和有参协程
startcoroutine("createboss"); //启动协程
//协程1 功能实时实例化游戏物体
ienumerator createboss()
{
startcoroutine(setcreatecount(5));
while (true) //功能实时实例化游戏物体
{
if (bossnum>=bosscount)
{
yield break; //在协程中break前面要加 yield
}
instantiate(animator.gameobject);
bossnum++;
yield return new waitforseconds(2);
}
}
//协程2 功能实时实例化游戏物体
ienumerator setcreatecount(int num)
{
bosscount =num;
yield return null; //暂停一帧
---------------------
此时如果这里只是暂停一帧的话,
那么上面调该有参协程的协程体中,
后面的语句并未生效,因为暂停一帧后,
后面的方法已经执行了,
所以此时的bosscount并不等于有参传递的5
(当然bosscount是全局变量)
---------------------
}
- 1.本体为迭代器
- 2.协程调度器(可自己实现)
//ieunmrator接口中的两个成员:movenext_移动下一个 current——当前返回值
while(ie.movenext())
{
print(ie.current);
}
---
# api——invoke延时调用
---
👨💻👍1.延时调用
---
● invoke(“名字”,秒数)
● invokerepeating(“名字”,第一次秒数,之后每次调用间隔秒数)
+ 使用协程的延时调用也可以
+ 使用计时器-mathf.movetowords也可以达到延时调用的效果
```csharp
void start()
{
//调用
//invoke("creategris",3);
invokerepeating("creategris",1,1);
}
private void creategris()
{
instantiate(grisgo); //实例化
}
👨💻👍2.取消调用
● cancelinvoke(“方法名”);暂停当前延时调用该方法
● cancelinvoke();停止所有的延时调用方法
👨💻👍3.判断是否调用
● isinvoke(“方法名”);判断当前方法是否进行了延时调用
● isinvoke();停止程序中所有的延时调用
👨💻👍4,让方法只调用一次的方法
- 改变其判断的条件法:首先让其=ture 才进行,然后调用一次之后就变成 false,或者前面是==某个数值,后面就改变它的值
api——物体的移动
👨💻👍1.常用使物体移动的方法
-
1,movetowords 和线性差值进行两点间的移动
-
2,transform.position (利用监听键盘进行实时的位置变化移动)
-
3,通过刚体进行单向移动(xx.moveposition)
-
4,通过刚体的力进行牵引移动 xx.addforce( vector2.方向)
有两个参数的情况
xx.addforce( vector2.方向,forcemode2d.force 或者 impuse)
- 5,通过刚体速度进行移动 因为刚体速度是有大小和方向的
- 6,transform.translate(方向)/transform.translate(方向,世界轴/自身轴)
(物体朝某一个方向移动的方法)
方法 | 描述 |
---|---|
transform.translate(vector2.left) | 世界坐标方向 |
transform.translate(transform.left) | 自身坐标方向 |
transform.translate(vector2.left,space.world) | 世界坐标方向 |
transform.translate(vector2.left, space.self) | 自身坐标方向 |
transform.translate(transform.left ,space.self/world) | 自身坐标方向 |
👨💻👍2.细节
1.物理系统相关的api要放进去fixedupdate
2,受重力影响的程度 gravity scale
3,阻力 0linear drag 线性阻力
api——物体的旋转
👨💻👍常用使物体旋转的方法
- xx.moverotation(角度)
- xx.moverotationreapting( xx.rotation +角度 * time,deletime )
此时的rotion并不是四元数 ,在这里就是当前物体的度数
- transform.rotate( new vector3( 0 , y ,0) ); 按y轴旋转
- transform.rotate( vector2.forword ,space.self/world) ; 按z轴旋转
-
this.transform.rotate(new vector3(0, 10, 0) * time.deltatime);
第一个参数 相当于 是旋转的角度 每一帧 第二个参数 默认不填 就是相对于自己坐标系 进行的旋转
-
this.transform.rotate(new vector3(0, 10, 0) * time.deltatime, space.world);
-
this.transform.rotate(vector3.right, 10 * time.deltatime);
-
this.transform.rotate(vector3.right, 10 * time.deltatime, space.world);
参数一:是相对哪个轴进行转动 参数二:是转动的 角度 是多少 参数三:默认不填 就是相对于自己的坐标系 进行旋转
如果填 可以填写相对于 世界坐标系进行旋转
-
this.transform.rotatearound(vector3.zero, vector3.right, 10 * time.deltatime);
参数一:相当于哪一个点 转圈圈 参数二:相对于那一个点的 哪一个轴转圈圈 参数三:转的度数 旋转速度 * 时间
api——音频audio
👨💻👍常用操作
- 获取音频资源组件 : audiosource = getcomponent< audiosource>();
- 获取音频: public audioclip xx ; audiosouce.clip = xx clip译“片段”
- 音量设置:audiosource.volum =
- 开始播放的时间设置:audiosource.time =
- 静音: audiosource.mute = true;
- 播放: audiosource.paly( )
- 暂停:audiosource.pause( )
- 恢复播放:audiosource.unpause( )
- 停止:audiosource.stop( )
- 播放一次音效: audiosource.playoneshot(audioclip)
- 音量近大远小方法设置:
auodiosource.playclipatpoint( audioclip,transform.positon)
[ 音频片段audioclip 距离物体位置越近声音越大] - 是否在播放音效: audiosource.isplaying
👨💻👍audiosourse组件介绍
;
if( input.getkeydown(keycode.space) )
{
clip = microphone.start(null, false, 10, 44100);
}
参数一:设备名 传空使用默认设备
参数二:超过录制长度后 是否重头录制
参数三:录制时长
参数四:采样率
microphone.end(null);
if( input.getkeyup(keycode.space) )
{
microphone.end(null);
//第一次获取 没有才添加
audiosource s = this.getcomponent<audiosource>();
if (s == null)
s = this.gameobject.addcomponent<audiosource>();
s.clip = clip;
s.play();
#region 知识点四 获取音频数据用于存储或者传输
//规则 用于存储数组数据的长度 是用 声道数 * 剪辑长度
float[] f = new float[clip.channels * clip.samples];
clip.getdata(f, 0);
print(f.length);
#endregion
}
api——粒子系统
api——trailrender拖尾渲染器
api——碰撞器和触发器
-
碰撞到的对象碰撞器的信息
collision.collider -
碰撞对象的依附对象(gameobject)
collision.gameobject -
碰撞对象的依附对象的位置信息
collision.transform -
触碰点数
collision.contactcount -
接触点 具体的坐标
contactpoint[] pos = collision.contacts;
👨💻👍碰撞器
- oncollisionenter( coliision2d xx ) 当物体进入到本身的碰撞区时触发
- oncollisionstay( collision2d xx ) 当物体呆在本身的碰撞区域时触发
- oncoliisionexit( collision2d xx ) 当物体离开 本身的碰撞区域时触发
👨💻👍触发器
- is trigger
-
ontiggerenter ( collision2d xx ) 当物体进入到本身的碰撞区时触发
-
ontriggerstay( collision2d xx ) 当物体呆在本身的碰撞区域时触发
-
ontriggerexit( colidion2d xx ) 当物体离开 本身的碰撞区域时触发
-
✌️种类
box,胶囊,球形,车轮,网格,地形
-
✌️物理材质
-
✌️碰撞函数
api——特殊文件夹
- 特殊文件夹读写性
1.resources 可读 不可写 打包后找不到
2.application.streamingassetspath 可读 pc端可写 找得到
3.application.datapath 打包后找不到
4.application.persistentdatapath 可读可写找得到
该方式 获取到的路径 一般情况下 只在 编辑模式下使用
游戏发布过后 该路径就不存在了
- application.datapath
一般不获取路径只能使用resources相关api进行加载
- 注意:
手动创建 - 作用:
资源文件夹
1.需要通过resources相关api动态加载的资源需要放在其中
2.该文件夹下所有文件都会被打包出去
3.打包时unity会对其压缩加密
4.该文件夹打包后只读 只能通过resources相关api加载
- application.streamingassetspath
- 注意:
手动创建 - 作用:
流文件夹
1.打包出去不会被压缩加密,可以任由我们摆布
2.移动平台只读,pc平台可读可写
3.可以放入一些需要自定义动态加载的初始资源
4.不愿意放在resources中的资源可以放入streamingassets中
-
注意:
不需要手动创建 -
application.persistentdatapath
不同平台路径不一样 -
作用:
固定数据文件夹
1.所有平台都可读可写
2.一般用于放置动态下载或者动态创建的文件,游戏中创建或者获取的文件都放在其中(热更新会用到)
- 注意:
不需要手动创建 - 作用:
插件文件夹
不同平台的插件相关文件放在其中
比如ios和android平台
- 注意:
手动创建 - 作用:
编辑器文件夹
1.开发unity编辑器时,编辑器相关脚本放在该文件夹中
2.文件夹中内容不会被打包出去
-
注意:
手动创建 -
作用:
默认资源文件夹
一般unity自带资源都放在这个文件夹下
代码和资源优先被编译 -
一般不用
api——资源加载(resource)
——————— 同步加载———————
- resources(只能加载resources目录中的资源)
- assetbundle(只能加载ab资源,当前设备允许访问的路径都可以)
- www(可以加载任意处资源,包括项目外资源(如远程服务器))
- assetdatabase(只能加载assets目录下的资源,但只能用于editor)
- unitywebrequest(可以加载任意处资源,是www的升级版本)
关键字:@ ,as
void start()
{
object obj= resources.load("sound");
//audioclip ac = obj as audioclip;
audioclip ac = (audioclip)obj;
audiosource.playclipatpoint(ac, transform.position);
//resources.loadall<audioclip>("prefabs");
audioclip[] audioclips= resources.loadall<audioclip>("");
foreach (var item in audioclips)
{
debug.log(item);
}
//resources.unloadasset
}
-
c#中的回收机制是系统自动回收的,有多种回收机制,不像其他语言需要手动回收
注意:
//预设体对象加载需要实例化
//其它资源加载一般直接用
#endregion
以加载audioclip类型的资源为例:
- 根目录加载 resource.load< audioclip>(“voice”);
- 子目录加载 resource.load ( @ " 子目录名/ voice") ;
- 另一种形式:
object xx = resource.load(“voice”);
audioclip yy as xx ; // 显性类型转换 ,前提是二者兼容 - 加载同类型所有资源的方法:
①根目录加载: audioclip [] xx = resource.allload(" “) ;
②子目录加载:audioclip [] yy = resource.allload(” 子目录名");
- 1.预设体对象
object obj = resources.load("cube");
instantiate(obj);
- 2.音效资源
object obj3 = resources.load("music/bkmusic");
//我们不需要实例化 音效切片 我们只需要把数据 赋值到正确的脚本上即可
audios.clip = obj3 as audioclip;
audios.play();
- 3.文本资源
文本资源支持的格式——.txt .xml .bytes .json .html .csv …
textasset ta = resources.load("txt/test") as textasset;
//文本内容
ta.text
//字节数据组
ta.bytes);
- 4.图片
tex = resources.load("tex/testjpg") as texture;
——————— 异步加载———————
- resources.loadasync(“xxx”);
- 注意:
异步加载 不能马上得到加载的资源 至少要等待一帧
//通过事件监听
resourcerequest rq = resources.loadasync<texture>("tex/testjpg")
rq.completed += loadover;
//completed 是 resourcerequest 中的委托
// asyncoperation 是 resourcerequest 的父类
private void loadover( asyncoperation rq)
{
//在事件中添加结束标识逻辑,这样我们就知道异步加载完成了
print("加载结束");
//加载完成后 会保存在 resourcerequest类中的 asset object类型成员里
//此时实现赋值
picture = (rq as resourcerequest).asset as texture;
}
//通过协程的调度器自己判断是否加载结束
startcoroutine(load());
ienumerator load()
{
resourcerequest rq = resources.loadasync<texture>("tex/testjpg");
yield return rq;
// yield return rq会自己判断 该资源是否加载完毕了,加载完毕过后才继续执行后面的代码 ,因为resourcerequest 也是yieldinstruction的子类
//-------------------------------
//isdone 和 progress api的应用
while(!rq.isdone)
{
//打印当前的 加载进度
print(rq.progress);
yield return null;
}
//--------------------------------
picture = rq.asset as texture;
}
———————资源加载器———————
利用异步直接加载和委托的使用构成简单的资源加载器
using system.collections;
using system.collections.generic;
using unityengine;
using unityengine.events;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: 简单的资源管理器
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class resourcescontrol
{
static private resourcescontrol control;
static public resourcescontrol control => control;
private resourcescontrol()
{
}
public void addresources<t>(string name ,unityaction<t> source ) where t : object
{
resourcerequest yb = resources.loadasync<t>(name);
yb.completed += (reo) =>
{
source( (reo as resourcerequest).asset as t );
};
}
}
//外部调用
private void start()
{
gameobject shootball;
resourcescontrol.control.addresources<gameobject>("profabs/ball",(sphere)=> {
shootball = sphere;
} );
}
———————卸载资源———————
-
resources多次重复加载不会浪费内存
但是 会浪费性能(每次加载都会去查找取出,始终伴随一些性能消耗) -
1.卸载指定资源
resources.unloadasset 方法
注意:它只能用于一些 不需要实例化的内容 比如 图片 和 音效 文本等 一般情况下很少单独使用它
-
2.卸载未使用的资源
一般在过场景时和gc一起使用
resources.unloadunusedassets();
gc.collect();
api——camera相机 相关
- 🙈clear flags
-
🙈cullingmask选择层级进行渲染
-
🙈projection
-
🙈target texture 小地图应用
-
🙈occlusion culing 的勾选 优化性能 减少渲染
-
🙈渲染分辨率的设置了解 --性能相关
-
🙈分屏操作 viewport rect --应用于双人成行类的游戏
-
🙈静态成员
-
🙈委托
- 🙈成员变量
api——screen屏幕 相关
- 🅰️当前屏幕分辨率宽高的获取
——resolution r = sreen.currentresolution - 🅰️当前屏幕宽高的设置
——sreen.width &screen.heiht - 🅰️当前屏幕的休眠模式
——scree.sleeptimeout .newsleep - 🅰️窗口转换的四个模式
- 🅰️移动屏幕转向
api——动画控制器 相关
- 1,ipg -> ui and 2d
( 直接将图集进行拖拽给对象) 变成动画 - 2,代码更改速度
animator .speed - 3,代码实现动画的播放
animator.dispaly - 4,代码设置过度参数
animator.setfloat(“speed”, 1 ) - 5,代码实现动画的过度
情况一:
通过按键进行动画的播放
情况二:
和通过参数来进行动画的切换(取消勾选 has exit time)
animator.crossfade (“walk” , 0.1f) __值越小过渡的越快
animator.crossfadeinfixedtime(“run”, 0.5f);
api——屏幕相关
- 静态属性
常用
- resolution r = screen.currentresolution;
当前屏幕分辨率的宽_ r.width
- screen.width
- screen.height
screen.sleeptimeout = sleeptimeout.neversleep;
不常用
运行时是否全屏模式
- screen.fullscreen = true;
窗口模式 - 独占全屏fullscreenmode.exclusivefullscreen
- 全屏窗口fullscreenmode.fullscreenwindow
- 最大化窗口fullscreenmode.maximizedwindow
- 窗口模式fullscreenmode.windowed
screen.fullscreenmode = fullscreenmode.windowed;
-
允许自动旋转为左横向 home键在左
screen.autorotatetolandscapeleft = true;
-
允许自动旋转为右横向 home键在右
screen.autorotatetolandscaperight = true;
-
允许自动旋转到纵向 home键在下
screen.autorotatetoportrait = true;
-
允许自动旋转到纵向倒着看 home键在上
screen.autorotatetoportraitupsidedown = true;
screen.orientation = screenorientation.landscape;
静态方法
screen.setresolution(1920, 1080, false);
api——场景(scene)加载
👨💻👍加载场景的方法
- scenemanager.loadscene() ; 场景同步加载
- scenemanager.loadscenesasyn(); 场景异步加载
- scenemanage。getactivescene().name判断当前场景
- application.loadlevel():同步加载
- application.loadlevelasync():异步加载
- application.loadleveladdictive():同步附加式加载
- application.loadleveladdictiveasync():异步附加式加载
👨💻👍scenemanasger的操作
👍1.同步加载
scenemanager.load( 序列号) ;
scenemanager.load( “场景名”) ;
void start()
{
//scenemanager.loadscene(1);
//scenemanager.loadscene("triggertest");
}
缺点:加载时造成画面卡帧,因为,在未加载完成前画面是停止的,所以是卡帧现象
👍2.异步加载
如果当前场景 对象过多或者下一个场景对象过多
这个过程会非常的耗时 会让玩家感受到卡顿
所以异步切换就是来解决该问题的
-
scenemanager.loadasync(序列号)
-
scenemanager.loadasync(“场景名”)
-
startcoroutine(协程迭代器方法() ); //调用协程
-
asyncoperation 该类型翻译为异步操作 ,为下面获得异步场景的返回值
asyncoperation ao= scenemanager.loadsceneasync(2); -
ao.allowsceneactivation = true 激活场景
-
ao.progress 场景加载的进度
//-----1.通过事件回调函数 异步加载------
asyncoperation ss = scenemanager.loadsceneasync("xxxx");
ss.completed += (a) =>
{
print("加载结束");
};
ss.completed += loadover;
private void loadover(asyncoperation ao)
{
print("loadover");
}
//---------2.通过协程异步加载--------
void start()
{
//由于场景加载后就不会执行加载后的逻辑了,如果要保存就使用 dontdestroyonload(保留场景加载上个场景的东西)第一个异步方法不会出现该情况
dontdestroyonload(this.gameobject);
startcoroutine(loadscene("xxxx"));
}
ienumerator loadscene(string name)
{
asyncoperation ss= scenemanager.loadsceneasync(name);
//根据游戏规则 自定义进度条变化的条件
yield return ss;
//1.场景加载结束 更新20%
//2.动态加载怪物再更新20%
//3.动态加载场景模型进度条顶满
//4.加载结束隐藏进度条
}
场景异步加载 和 资源异步加载 一样
1.通过事件回调函数
2.协程异步加载
-
1.事件回调函数
优点:写法简单,逻辑清晰
缺点:只能加载完场景做一些事情 不能在加载过程中处理逻辑 -
2.协程异步加载
优点:可以在加载过程中处理逻辑,比如进度条更新等
缺点:写法较为麻烦,要通过协程
public class scenecontrol
{
private static scenecontrol instance = new scenecontrol();
public static scenecontrol instance => instance;
private scenecontrol() { }
public void loadscene(string name, unityaction action)
{
asyncoperation ss = scenecontrol.loadsceneasync(name);
ss.completed += (scene) =>
{
action();
};
}
}
---
# api——光源组件
---
---
👺组件api --window -light
---
☑️**三光——点光源,聚光灯,面光源(烘培模式开启)**--烘培-节约性能

☑️**光源模式**——实时,烘培,混合

☑️**颜色**——光源颜色

☑️**阴影**——生硬,柔和——效率区别
-
☑️**投影遮罩**——只适用聚光灯,需添加textuer

☑️**光晕开关 + 耀斑(聚光)**—— 前者是球形光(太阳蜡烛) 后者是人眼看到强光的效果 (耀斑有其对应的材质)

---
👺光设置面板界面 --window -light
---
**针对设置光源参数的默认值**
☑️**天空盒材质的更换**
☑️**太阳光源的设置**
☑️**fog雾开关**——雾面效果,性能消耗
☑️**耀斑的调节**
☑️**遮罩材质的更改**

---
# api——刚体相关
---
> **添加力的方法**
+ 1.获取
rigidbody = this.getcomponent<rigidbody>();
+ 2.添加力
rigidbody.addforce(vector3.forward * 10);
相对世界坐标世界坐标系 z轴正方向加了一个里加力过后 对象是否停止移动 是由阻力决定的如果阻力为0 那给了一个力过后 始终 是不会停止运动
+ 3. 让对象 相对于自己的面朝向动
相对世界坐标
rigidbody.addforce(this.transform.forward * 10);
相对本地坐标
rigidbody.addrelativeforce(vector3.forward * 10);
>**添加扭矩力,让其旋转**
+ 相对世界坐标
rigidbody.addtorque(vector3.up * 10);
+ 相对本地坐标
rigidbody.addrelativetorque(vector3.up * 10);
>**改变速度**
速度方向 是相对于 世界坐标系的
rigidbody.velocity = vector3.forward * 5;
如果要直接通过改变速度 来让其移动 一定要注意这一点
>.**模拟爆炸效果**
rigidbody.addexplosionforce(100, vector3.zero, 10);
模拟爆炸的力 一定是 所有希望产生爆炸效果影响的对象 都需要得到他们的刚体 来执行这个方法 才能都有效果
>**力的几种模式**
力的模式 主要的作用 就是 计算方式不同而已
由于计算方式的不同 最终的移动速度就会不同
+ rigidbody.addforce(vector3.forward * 10,forcemode.acceleration);
|字符 | 意义 |
|--|--|
| f |力 |
| t |时间|
| m |质量 |
| v |速度 |
| 动量定理 |ft = mv v = ft/m; |
+ **1.acceleration**
给物体增加一个持续的加速度,忽略其质量
|字符 | 值 |
|--|--|
| f |(0,0,10) |
| t |0.02s|
| m |默认为1|
| v |10*0.02/ 1 = 0.2m/s|
| 每物理帧移动 |0.2m/s*0.02 = 0.004m |
+ **2.force**
给物体添加一个持续的力,与物体的质量有关
|字符 | 值 |
|--|--|
| f |(0,0,10) |
| t |0.02s|
| m |2kg|
| v |10*0.02/ 2 = 0.1m/s|
| 每物理帧移动 |0.1m/s*0.02 = 0.002m |
+ **3.impulse**
给物体添加一个瞬间的力,与物体的质量有关,忽略时间 默认为1
|字符 | 值 |
|--|--|
| f |(0,0,10) |
| t |0.01s|
| m |2kg|
| v |10*1/ 2 = 5m/s
| 每物理帧移动 |5m/s*0.02 = 0.1m |
+ **4.velocitychange**
|字符 | 值 |
|--|--|
| f |(0,0,10) |
| t |1s|
| m |1kg|
| v |v = 10*1/ 1 = 10m/s
| 每物理帧移动 |10m/s*0.02 = 0.2m |
> **刚体是否休眠**
+ rigidbody.issleeping())
+ rigidbody.wakeup();——唤醒刚体
---
# api——camera组件
---
>**可编辑参数了解**
+ 🙈**clear flags**

+ 🙈**cullingmask选择层级进行渲染**
+ 🙈**projection**

+ 🙈**target texture 小地图应用**
+ 🙈**occlusion culing 的勾选 优化性能 减少渲染**
+ 🙈**渲染分辨率的设置了解** --性能相关
+ 🙈**分屏操作 viewport rect** --应用于双人成行类的游戏
>api


> **渲染相关委托**
```cpp
//摄像机剔除前处理的委托函数
camera.onprecull += (c) =>
{
};
//摄像机 渲染前处理的委托
camera.onprerender += (c) =>
{
};
//摄像机 渲染后 处理的委托
camera.onpostrender += (c) =>
{
};
-
设置主摄像机对象 上的深度
camera.main.depth = 10; -
世界坐标转屏幕坐标
z对应的 是3d物体离摄像机的距离
vector3 v = camera.main.worldtoscreenpoint(this.transform.position);
- 3.屏幕坐标转世界坐标
vector3 pos = input.mouseposition;
pos.z = 5;
obj.position = camera.main.screentoworldpoint(pos);
//改变z轴 是因为 如果不改 z默认为0转换过去的世界坐标系的点 永远都是一个点 可以理解为 视口 相交的焦点如果改变了z 那么转换过去的 世界坐标的点 就是相对于 摄像机前方多少的单位的横截面上的世界坐标点
api——screen组件
- 🅰️当前屏幕分辨率宽高的获取
——resolution r = sreen.currentresolution - 🅰️当前屏幕宽高的设置
——sreen.width &screen.heiht - 🅰️当前屏幕的休眠模式
——scree.sleeptimeout .newsleep - 🅰️窗口转换的四个模式
- 🅰️移动屏幕转向
api——application类
- 在unityengine命名空间下
- 作用:对程序运行的数据进行操作控制
- ❤️ application.loadlevel() ——老式场景资源加载的方法
- ❤️ application.quit()——退出游戏(前提是游戏已经打包后运行)
- ❤️ application.ispaly——是否是运行模式or编辑模式
api——cursor类
- 在unityengine命名空间下
- 鼠标的隐藏 ——cursor.visible();
- 鼠标的锁定,限制范围 cursorstate = cursorlockmode.下面三个
- 设置鼠标图片——cursor.setcursor(三个参数如下)
api——范围检测physics.overlap
- 首先了解组件——线渲染器 linerenderer
特点:
- 1.执行该句代码时 进行一次范围检测 它是瞬时的
- 2.范围检测相关api 并不会真正产生一个碰撞器 只是碰撞判断计算而已
共同参数:
- 参数一:物体中心点
- 参数二:物体的边长大小
- 参数三:物体的角度
- 参数四:检测指定层级(不填检测所有层)
- 参数五:是否忽略触发器 useglobal-使用全局设置 collide-检测触发器 ignore-忽略触发器 (不填使用useglobal)
- 返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
- physics.overlapbox ——返回值为数组,存储检测到的碰撞器
collider[] colliders = physics.overlapbox( vector3.zero, vector3.one,
quaternion.angleaxis(45, vector3.up),
1 << layermask.nametolayer("ui") |
1 << layermask.nametolayer("default"), querytriggerinteraction.useglobal);
- physics.overlapboxnonalloc——返回值为int 表示检测的数量(最多6个参数)
if(physics.overlapboxnonalloc(vector3.zero, vector3.one, 自定义数组名) != 0)
无角度参数
参数二为球半径
- physics.overlapsphere
colliders = physics.overlapsphere(vector3.zero, 5, 1 << layermask.nametolayer("default"));
- physics.overlapspherenonalloc——同box
if( physics.overlapspherenonalloc(vector3.zero, 5, colliders) != 0 )
参数一:半圆一中心点
参数二:半圆二中心点
参数三:半圆半径
- physics.overlapcapsule
colliders = physics.overlapcapsule(vector3.zero, vector3.up, 1, 1 << layermask.nametolayer("ui"), querytriggerinteraction.useglobal);
- physics.overlapcapsulenonalloc
if ( physics.overlapcapsulenonalloc(vector3.zero, vector3.up, 1, colliders ) != 0 )
api——射线检测physics.raycast
-
特点
只需要判断一条线和物体的碰撞情况
可以在指定点发射一个指定方向的射线
判断该射线与哪些碰撞器相交,得到对应对象
瞬时 -
应用场景
1.鼠标选择场景上一物体
2.fps射击游戏(无弹道-不产生实际的子弹对象进行移动)等
- ray x = new ray(vector3.right, vector3.forward);
参数一 | 参数二 |
---|---|
起点 | 方向 |
x.origin | x.direction |
-
ray xx = camera.main.screenpointtoray(input.mouseposition);
屏幕视口坐标转成射线——鼠标点击的地方变成射线 -
physics.raycast 无法检测碰到了谁,只会检测碰到了没有
最多有16个重载
physics.raycast常用参数 | 作用 |
---|---|
参数一 | 射线 |
参数二 | 检测的最大距离 超出这个距离不检测 |
参数三 | 检测指定层级(不填检测所有层) |
参数四 | 是否忽略触发器 useglobal-使用全局设置 collide-检测触发器 ignore-忽略触发器 不填使用useglobal |
返回值 | bool 当碰撞到对象时 返回 true 没有 返回false |
//第一种写法
physics.raycast(xx, 1000,
1 << layermask.nametolayer("层级名字"),
querytriggerinteraction.useglobal )
//第二种写法
physics.raycast(vector3.right, vector3.forward,
1 << layermask.nametolayer("层级名字"),
querytriggerinteraction.useglobal )
- raycasthit 物体信息类——得到相交的单个物体物理信息
raycasthit 在physics.raycast的应用 | 作用 |
---|---|
参数一 | 射线 |
参数二 | out raycasthit 为什么是out ?raycasthit是结构体 是值类型 out加上去就变成了引用类型,而raycasthit没有复制所以不用ref |
参数三 | 检测的最大距离 超出这个距离不检测 |
参数四 | 检测指定层级(不填检测所有层) |
参数五 | 是否忽略触发器 useglobal-使用全局设置 collide-检测触发器 ignore-忽略触发器 不填使用useglobal |
返回值 | bool 当碰撞到对象时 返回 true 没有 返回false |
//写法一
raycasthit yy;
if( physics.raycast(xx, out yy, 1000,
1<<layermask.nametolayer("层级名字"),
querytriggerinteraction.useglobal) )
//写法二
if( physics.raycast(vector3.right, vector3.forward, out yy, 1000,
1<<layermask.nametolayer("层级名字"),
querytriggerinteraction.useglobal) )
- 碰撞到物体的名字 yy.collider.gameobject.name;
- 碰撞到的点 yy.point
- 法线信息 yy.normal
- 碰撞到对象的位置 yy.transform.position
- 碰撞到对象 离自己的距离 yy.distance等等
- raycasthit[] xx= physics.raycastall——得到相交的多个物体物理信息
特点: 先碰到的在数组的后面
- physics.raycastnonalloc——返回的碰撞的数量 通过out得到数据
if((r3, xx, 1000, 1 << layermask.nametolayer("monster"),
querytriggerinteraction.useglobal) > 0 )
{
}
【unity每日一记】模仿fps射击,用弹痕作画的原理如此简单
【unity每日一记】拖拽放置类游戏的行为原来和这个api有关
组件——线渲染器 linerenderer
linerenderer是unity提供的一个用于画线的组件来在场景中绘制线段
一般可以用于
- 绘制攻击范围
- 武器红外线
- 辅助功能其它画线功能
-
代码动态添加一个线段
gameobject line = new gameobject(); line.name = "line"; linerenderer linerenderer = line.addcomponent<linerenderer>();
-
首尾相连
linerenderer.loop = true; -
开始结束宽
linerenderer.startwidth = 0.02f;
linerenderer.endwidth = 0.02f; -
开始结束颜色
-
linerenderer.startcolor = color.white; linerenderer.endcolor = color.red;
-
设置材质
m = resources.load<material>("xxx");
linerenderer.material = m;
- 设置点
先设置点的个数
—— linerenderer.positioncount = 4;
设置 对应每个点的位置
linerenderer.setpositions(new vector3[] { new vector3(0,0,0),
new vector3(0,0,5),
new vector3(5,0,5)});
linerenderer.setposition(3, new vector3(5, 0, 0));
-
是否使用世界坐标系
//决定了 是否随对象移动而移动 linerenderer.useworldspace = false;
-
让线段受光影响 会接受光数据 进行着色器计算
linerenderer.generatelightingdata = true;
组件—— 角色控制器character contorller
主要参数
-
1.是否接触地面——isgrounded();
-
2.受重力移动 —— simplemove();
-
3.不受重力移动——move();
-
4.碰撞器检测函数——oncontrollercolliderhit(controllercolliderhit hit)
-
加入角色控制器之前——不随镜头向前移动(上帝视角)
-
加入角色控制器之后——可以跟随镜头而向前移动(第一人称视角)
- 第三人称实践
using system.collections;
using system.collections.generic;
using unityengine;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: 玩家的移动
//___________创建者:___秩沅____
//_____________________________________
//-------------------------------------
public class playermove : monobehaviour
{
private float vertical;
private float horizontal;
private float mouseposition;
private charactercontroller player; //角色控制器
private vector3 movederictor; //移动的方向
public float velocity = 2f; //移动的速度
public float rovelocity = 10f;
private animator playeranimatior;
private void awake()
{
player = getcomponent<charactercontroller>();
playeranimatior = getcomponent<animator>();
}
private void fixedupdate()
{
vertical = input.getaxis("vertical") ;
horizontal = - input.getaxis("horizontal") ;
mouseposition = input.getaxis("mouse x");
//旋转
transform.localrotation *= quaternion.euler(0, mouseposition * rovelocity, 0);
if (vertical != 0 ||horizontal != 0)
{
//移动
playeranimatior.setfloat("speedws", (int)vertical);
playeranimatior.setfloat("speedad", (int)horizontal);
movederictor = new vector3(vertical, 0, horizontal);
print(movederictor.normalized);
/// movederictor = movederictor.normalized; //将方向变成单位向量
//transform.position= transform.position + movederictor.normalized*time .deltatime ;
player.simplemove(transform.forward * vertical );
player.simplemove(transform.right * -horizontal);
//getcomponent<rigidbody>().moveposition( transform.localposition + movederictor * velocity * time.deltatime); //速度*方向 = 向量
//此时物体并非跟着自己的旋转方向进行移动而是根据自身位置进行改变
//(白话:无法变成fps的第一视角进行当前视角当前前进)
}
}
private void mouserotation()
{
}
}
组件——platformeffector 2d(跳跃平台)
- 👺描述: 适用于添加障碍和陷阱,例如实现只能从上往下能碰撞的效果
- 👺图示:
组件——eadg collider 2d(地形碰撞器)
- 👺描述: 用线段实现隔离碰撞
- 👺图示:
组件—— nav mesh agent 导航寻路
文章详解入口【unity中的a星寻路】navigation导航寻路系统四大页签详解
🎶参数详解
nav mesh agent 代码相关
- agent.setdestination() ; ——>自动寻路设置目标点
- agent.isstopped = true; ——>停止寻路
bug情况以及处置
👨💻👍1.中文显示乱码现象的解决措施
- unity-hub–版本显示资源—date------resouces------scripttempelet--------81(文件名)->可自定义初始化界面
👨💻👍2.版本中存在老包升级情况
- windows – packge manager\
👨💻👍3.printf 和 debug.log的区别
1.debug.logwarning :显示警告、
2.debug.logerror:显示错误
⭐相关文章⭐
———————————————————
-本站最全-unity常用api大全(万字详解),不信你不收藏
-
-
-基于unity物体定点移动与模拟刹车的细节 gif 图文详解
————————————————————
⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!
发表评论