Unity入门

发布于:2025-04-15 ⋅ 阅读:(19) ⋅ 点赞:(0)


笔记主要包含脚本简介, GameObjectTimeTransform等六大组件以及光源物理音效三大系统的简单入门,除了概念就是API,坚持学完赶紧做项目吧,有一说一还是很枯燥的,be a 无情的 API learner

Unity脚本基础

大基础

依附基类:MonoBehaviour

tips:依附了该基类的类不能实例化,只能挂载(表现形式为把写好的脚本拖到对象上)到具体的对象上产生实例化的效果

限制只能挂一个相同脚本特性:[DisallowMultipleComponent]

的概念:一秒内循环的次数,如1秒60帧需要每次循环的时间达到16.66ms,30帧需要达到33.33ms

Unity里输出日志:

  • Debug.log("输出的内容")=》没有继承Mono基类
  • print("输出的内容")=>继承了Mono基类(你也是python?)

生命周期函数

unity运行时的本质是一个死循环,不断执行下面这些生命周期函数

下面的顺序即为执行时的顺序(但是又看到一个说法,说是FixedUpdate不一定在Update前调用,要根据它实际的物理时间来看)

  • Awake():只在开始时的初始化时调用一次,可看作类似于构造函数
  • OnEnable():对象在激活(Inspector窗口左上角打勾)时调用
  • Start():只在开始时的帧更新时调用一次
  • FixedUpdate():物理模块的更新,自设定的帧更新(左上角编辑中程序环境中Time一项中设置)
  • Update():帧更新,主要处理逻辑的地方
  • LateUpdate():比上面慢一点的帧更新,通常用来更新摄像机(在两个帧更新当中通常处理动画相关,避免渲染出问题)
  • OnDisable():与OnEnable()对应,对象在失活时调用
  • OnDestroy():删除对象时调用

tips:这些函数并不是Mono中的成员函数,unity在运行脚本时通过反射查看是否有这些函数,如果有才执行相关逻辑,所以如果不用这些函数就不要生命,会损失效率

Inspector窗口显示

如果有公有成员变量,将会自动显示在该窗口

常用特性

  • [SerializeField]:使私有和保护修饰的成员变量能够显示
  • [HideInInspector]:使公有的成员变量不显示
  • [Serializable]:使自定义类型显示(该特性在System中)

tips:字典和自定义类型不会显示,自定义类型可以通过加特性显示,而字典无论如何都无法显示

辅助特性

  • [Header("组名")]:用于将不同的变量进行分组
  • [Tooltip("说明")]:对变量的额外说明,鼠标指向变量即可看到
  • [Space()]:变量与变量之间间隔距离
  • [Range(x,y)]:拖条改值,x和y为上下限
  • [Multiline(x)]:将字符串改成x行显示,按↑↓拖条
  • [TextArea(x,y)]:字符串改为最小x行显示,最大y行显示,比y大可以用滚轮拖条
  • [ContextMenuItem("按钮名称","方法")]:让变量有方法可用,右键相关变量即可用
  • [ContextMenu("方法")]:让方法能在运行中使用

MnonBehaviour基类

成员变量

  • 类名变量gameObject:有name的属性,获取相关脚本名称
  • 位置变量transform:有position位置,ealerAngles角度,lossyscale缩放大小的属性
  • 激活变量enabled:判断对象是否激活

成员方法

  • ※※※ 获取脚本GetComponent

    • 最常用方便的泛型式获取GetComponent<"脚本名称">()

    • 按照名字获取GetComponent("脚本名称")

    • 按照类型获取GetComponent(typedef(脚本名称))

      tips:后两种获取的为Mnon基类,要使用需要将其as为脚本类型,较为麻烦,后续也不再阐述这两种方法

  • 获取多个脚本GetComponent<>()

    • 该方法会返回数组,需要用数组接住
    • 或者提前声明一个list,将其作为参数传入
  • 获取后代脚本GetComponentInChildren<>():参数为true时可以找到失活对象的脚本

  • 获取多个后代脚本GetComponentsInChildren<>():同上

  • 获取前辈脚本GetComponentInparent<>()

  • 获取多个前辈脚本GetComponentsInparent<>()

  • 尝试获取脚本TryGetComponent<>():未获取对象会返回false,等效于使用GetComponent方法获取脚本后判空执行逻辑

组件GameObject

成员变量gameObject

属性有name名称,activeSelf是否激活,isStatic是否为静态,layer查看层次,tag查看标签,transform看到位置

静态方法

  • 创建几何体CreatePrimitive(PrimitiveType.xxx):xxx为具体的几何体
  • 用名字找一个对象Find("名字")
  • 用标签找一个对象FindWithTag("标签")FindGameObjectWithTag("标签")
  • 用标签找多个对象FindGameObjectsWithTag("标签")(以上几种均不能找到失活对象)

另外的,还有Object(unity里的基类,不是c#里那个,Mono往上找也继承了它)里面的方法找对象方法FindObjectOfType<脚本名称>()

tips:这几种找对象的方法均不常用,效率太低了

  • 实例化(克隆)对象Instantiate(obj):动态创建对象,在运行时把预设体或对象拖到obj处,这里的obj是一个提前声明一个GameObjectObject也可以点出这个方法)
  • 延迟删除对象Destroy(见后):一帧后删除,异步的,可减少长停顿的概率;若为删对象,参数(obj,希望延迟删除的时间);若为删脚本,参数(脚本名称)
  • 立即删除对象DestroyImmediate():不建议使用,效率低
  • 过场景不删对象DontDestroyOnLoad(this.gameObject):参数通常为这个

成员方法

使用其中的方法前要先new一个,但new的时候其实就创建出一个新物体了

GameObject obj = new GameObject("物体名字",typeof("希望挂载的脚本名"),......)
  • 为对象添加脚本AddComponent(typeof(脚本名称)),该方法和前面提到的缺陷一样,还要as,所以一般使用泛型式AddComponent<脚本名称>()
  • 得到脚本:与Mono基类成员方法部分获取脚本一致
  • 标签比较CompareTag("标签"):返回T/F
  • 设置活性SetActive(bool)
  • 广播之通知自己执行什么SendMessage("函数名"):在自己身上的所有脚本里去找这个函数来执行
  • 广播之把后代也找一下BroadcaseMessage("函数名")
  • 广播之把前辈也找一下SendMessageUpwards("函数名")

tips:广播用的少,效率低

组件Time

静态成员变量

  • 时间缩放Time.timeScale:为0时表现为时停,为1时正常流速,为2时二倍速
  • 帧间隔时间(最近一次循环的时间)Time.deltaTime:可用于计算位移,该时间会受timeScale影响(即与其相乘后得出结果),对应的有Time.unScaleDeltaTime不受timeScale影响
  • 从游戏开始到现在的时间Time.time:受timeScale影响,对应的有Time.unscaledTime不受其影响
  • 物理帧间隔时间Time.fixedDeltaTime:受timeScale影响,可在左上角进行Project Setting设置,对应的有Time.fixedUnscaledDeltaTime不受其影响
  • 帧数Time.frameCount

组件Transform

不要搞混:transform本质是一个Transfoem类,它是Mono基类中的一个成员,使用它和使用Transform是一个效果,直接使用this.transform更为快捷,当然this也可以直接省略

Vector3结构体基础

基本概念

即包含x,y,z三个坐标的一个结构体向量表示

常用向量表示

Vector3.zero表示(0,0,0),one表示(1,1,1),相应的rightleftforwardbackupdown分别为三组表示x轴,z轴,y轴上的三组向量=》世界坐标系下的方向

常用方法

Vector3.Distance(Vector v1, Vector v2):计算两点间距离

位置与位移

位置position

本质是一个Vector3

  • 世界坐标系下的坐标transform.position
  • 相对于父对象的坐标transform.localPosition:该数值与右边面板上的一致

改变位置时只能整体改变,如让position直接加上new Vector3(x,y,z)

如果要单独改,采用向量形式,如加上Vector3.up * 10

自己坐标系下方向的表示:transform.forward或者其他五个

位移 = 方向 * 速度 * 时间

自己算位移:如transform.position += transform.forward * 1 * Time.deltaTime,时间通常使用帧间隔时间

如果要采用世界坐标下的方向,则为Vector3.forward

API计算位移(通下计算位移的方法)transform.Translate(位移多少,相对的坐标系):第一个参数即上面的右式,第二个参数默认相对自己,若要改变,有Space.World/Self来改变

坑点Translate实际上在算偏移量,如果用自己坐标下transform作为第一个参数,且相对于自己Self,则会产生一个不服预期的新方向去动,即一般不用这两者进行搭配

角度与旋转

3d数学中的四元数transform.rotation

下面为对角度的使用,本质还是Vector3

  • 世界坐标系下的角度transform.eulerAngles
  • 相对于父对象的角度transform.localEulerAngles:同理,界面上一致

改变角度也一样不能单独设置,只能整体改变

API计算自转(通常不自己算)transform.Rotate(转的角度,相对的坐标系):与计算位移时基本一致,但是此处不能使用transform.forward这种直接表示,要去new一个Vector3去乘角度(时间 * 速度)

通用下的自转重载用):transform.Rotate(相对于哪个轴,角度,相对的坐标系):这里相对于哪个轴就可以用Vector.forward此类向量表示了

绕某点转transform.RotateAround(绕谁转,绕谁的哪个轴,角度):可以用来模拟太阳系,这里这个“谁”传他的Vector就行

缩放与看向

缩放

  • 世界坐标系下的缩放transform.lossyScale
  • 相对于父对象的缩放transform.localScale

一样,只能整体改,但是,相对于世界的不能改,只能得(层级叠加下,子类会乘上父类的缩放值造成意想不到的结果)

=》但是呢又是但是,可以间接做到:没有父对象的时候,改local就是相对于世界的

没API,要改只能自己加来算(悲)

看向

某游戏里按滚轮锁敌

transform.LookAt(谁):传Vector或者Transform都行

小技巧:可以在脚本里定义一个Transform,运行时拖过去

其实还有相对于哪个轴的参数,但没必要,默认是相对于y轴的,以我们的head为例,看别人的时候一般只会绕着y轴左右转,,,

父子关系

对父对象操作

获取父对象transform.parent:对该项.name可获取父对象名称

设置当前对象的父对象:

  • 自己认父transform.parent = GameObject.Find("父对象名称").transform:设置为null可断绝父子关系
  • API认父transform.SetParent(父对象transform, 是否改变世界坐标):对第二个参数,为true时会和父对象算相对位置,视觉上当前对象位置不变;为false时是将世界坐标直接赋值给父子关系中自己的坐标,保持面板上前后坐标的一致

对子对象操作

扔了所有儿子transform.DetachChildren()

获取子对象Transform[] sons = transform.Find("子对象名称")

  • GameObject.Find()不同,这里获取的直接是子对象的transform,但是泛用性比GameObject的差,只能找子对象,基于此,效率会比GameObject那个要高一点
  • 同时该方法可以找到失活对象
  • 儿子可能有多个,所以要用数组来存,用sons.childCount可获取儿子数量,sons.Getchild(下标)可获取具体的儿子,这两者结合可以遍历儿子

单个子对象的操作

假设现在有public成员Transform son,对哪个儿子操作在运行时拖过去即可

  • 判断自己是不是某人的儿子son.IsChildOf(某人的transform):你是不是我爸
  • 得到自己是第几个儿子son.GetSiblingIndex():我是几房的
  • 将自己设置为0号长子son.SetAsFirstSibling():谋权篡位
  • 将自己设置为最小的幼子son.SetAsLastSibling():博得宠爱
  • 将自己设置为n号儿子son.SetsiblingIndex(n):当n不合法时会自动设置为幼子

坐标转换

世界=》本地

可用于判断相对位置,用的不多

  • 点坐标的转换transform.InverseTransformPoint(要转换的世界坐标向量Vector3):受缩放影响,返回值即为本地坐标向量(就是画两个坐标系算不同的位置)
  • 方向的转换:transform.InverseTransformDirection(Vector3)不受缩放影响,transform.InverseTransformVector()受缩放影响(本质上是方向向量的平移)

本地=》世界

重点,有什么用呢=》特效创建:创建一个技能对象后,让他留在原地进行攻击范围的判断,不因为自己转向而跟着转向(王者荣耀安琪拉二技能也没跟着你跑吧)

  • 点坐标的转换transform.TransformPoint(Vector3):受缩放影响
  • 方向的转换:上面那个部分去掉Inverse即可(偷个懒)

组件Input与Screen

输入系统Input

比较重要的成员

鼠标位置Input.mousePosition:原点在左下角,会返回一个向量,z恒等于零

鼠标输入

  • Input.GetMouseButtonDown(n):在按下时检测,n=0时检测左键,=1时检测右键,=2时检测中键
  • Input.GetMouseButtonUp(n):在抬起时检测
  • Input.GetMouseButton(n):按下抬起都检测,即检测长按(拖动某个物体?)

检测中键滚动Input.mouseScrollDelta:返回向量,y=1时向上滚动,=0时没动,=-1时向下滚动

键盘输入

  • Input.GetKeyDown(哪个键):按下检测,一般使用KeyCode枚举来.出具体的键,不易出错,当前也可以用字符串去匹配,但是字符必须是小写
  • Input.GetKeyUp(哪个键):抬起检测
  • Input.GetKey(哪个键):长按

检测默认轴输入:控制位移旋转的,嗯…相当于对上面的检测鼠标键盘再封装一层,就不用写个if来做相关逻辑判断了

  • Input.GetAxis("哪个轴"):这个轴可以去Project Settings里的Input Manager里查,比如说Horizontal水平控制a和d,Vertical垂直控制w和s,Mouse XMouse Y控制鼠标移动等等,按下对应一组键后实际上是在-1到1之间渐变
  • Input.GetAxisRaw("哪个轴"):没有渐变

相对不重要的

鼠标

检测任意键或鼠标长按Input.anykey:经典按任意键继续

检测任意键按下Input.anykeyDown

检测一帧键盘输入Input.inputString:可以和上面那个配合做改键

手柄

得到按键名称Input.GetJoystickNames()

手柄键输入Input.GetButtonDown("哪个键"):这个是按下检测,还有抬起和长按不再赘述了

移动端触摸

不是说这个不重要,只是以后可能不在这里面检测,好像有专门的虚拟手柄UI

触摸数量Input.touchCount

具体的触摸对象Touch t1 = touches[0]:有了对象还可以t1.position看位置,t1.deltaPosition相对屏幕上方位置

允许多点触碰Input.multiTouchEnabled = true

陀螺仪Input.gyro.enabled = true开启,.gravity重力加速度,.attitude旋转四元数,.rotatioRate转速

屏幕Screen

比较重要的成员

获取显示器屏幕分辨率Screen.currentResolution:返回一个Resolution结构体

设置游戏里屏幕窗口宽高Screen.width/height

设置屏幕休眠模式Screen.sleepTimeout = SleepTimeout.NeverSleep/SystemSetting:这个实际上是int类型的赋值,SleepTimeout是一个类,.出来的那两项是它里面的常量

设置分辨率Screen.SetResolution(x, y, 是否全屏):一般移动端不用

相对不重要的

设置全屏Screen.fullScreen = true

以下在发布上有,一般不在这边设置

窗口模式Screen.fullScreenMode = FullScreenMode.FullScreenMode是一个枚举,有独占全屏,全屏窗口,最大化窗口和窗口模式四种

是否自动屏幕转向Screen.autorateTolandscapeLeft:左边转,同理有右边转,下边转是autorotateToPortrait,上边转是autorotateToPortraitUpsideDown

指定显示方向Screen.orientation = ScreenOrientation.ScreenOrientation也是一个枚举,有水平方向等等

组件Camera

面板参数

点开一般项目创建时自带的主摄像机main camera

  • Clear Flags:3d用skybox,2d用Solid color
  • Culling Mask:要画哪些layer剔除
  • Projection:透视还是正交,和坐标轴那边那个一样
  • Depth:两个摄像机叠加显示时,需要将该项改为不同值,该项越高,越后被渲染,同时较深的Clear Flags要改为Depth only
  • Target Texture:从Project栏右键创建Render Texture,可以用来贴底片做小地图
  • Viewport Rect:分屏
  • Target Display:更改Game窗口中显示的Dieplay

代码控制

摄像机成员

获取摄像机数量Camera.allCamerasCount

获取所有的摄像机Camera.allCameras

相关委托Camera.CameraCallback,这里的CameraCallback是一个类型,有以下三类

  • onPrecull:剔除前处理,不渲染被挡住的
  • onPreRender:渲染前处理
  • onPostRender:渲染后处理

获取主摄像机Camera.main:实际上是获取Tag为主摄的,但一般这样种Tag只有一个

摄像机对象成员

以获取的main.可以找到面板上所有的参数

世界转Game屏幕坐标main.WorldToScreenPoint(世界坐标):返回的Vector3中z表示物体离当前摄像机有多远=》可以用来做血条

屏幕转世界坐标main.ScreenToWorldPoint(屏幕坐标):这里的屏幕坐标,可以先用Input.mousePosition获取x,y,但是要填z,不能直接传,z坐标表示一个切出来的横截面离摄像机的距离(摄像机的视角是发散出去的)

光源系统

可以到商店里获取光源资源,自带的Store里的Standard里,现在好像没了?

光源面板参数

和主摄像机一样,点开一般项目创建会自带一个光源Directional Light

  • Type:4种光源类型,有一个是烘焙(算好贴图,节约性能)下才能用
  • ModeRealtime实时,Baked先算好直接放,Mixed两种的叠加
  • Intensity:亮度
  • Shadow Type:阴影类型,NoShadowsHardShadows生硬(带刺的影子),SoftShadows柔和
  • Cookie:贴图资源,光源资源拖到这
  • Draw Halo:球形光环
  • Flare:耀斑(强化光泽的)
  • Culling Mash:让指定Layer不受影响,剔除

以下为比较少用的

  • Indirect Multiplier:反射后是否更弱
  • RealtimeShadows栏:Strength暗度,Resdution分辨率,Bias离光距离,Normal Bias延法线收缩距离,Near Panel近裁减面
  • Render Mode:渲染优先级,Auto运行时确定,Important逼真,像素单位级别渲染,Notimportant快速渲染

代码控制

定义一个publicLight light,可以用light.出上面所有的参数,其他暂时没必要

光系统面板参数

Windows=>Rendering=>Light Settings找到

Environment

  • Skybox Material:天空盒材质,建一个材质后Shader做这个
  • Sun Source:太阳来源
  • Environment Lights:环境光

Other Settings

  • Fog:雾开关
  • Halo Texture:光环纹理
  • Halo Strength:光环可见性
  • Flare Fade Speed:耀斑淡出时间
  • Flare Strength:耀斑可见性
  • Spot Cookie:贴图形状

物理系统之碰撞检测

产生碰撞的条件:两个物体都要有碰撞器Collider,并且至少有一个物体有刚体RigidBody

碰撞时产生的力实际上是作用到刚体上,与别的物体碰到后自己的刚体受到力的改变从而产生位移,碰撞器是决定物体体积

刚体RigidBody

右下角加脚本组件可以找到

面板参数

  • Mass:质量,单位kg
  • Drag:空气阻力
  • Angular Drag:扭矩阻力(阻碍旋转的力)
  • Use Gravity:是否受重力影响
  • Is Kinematic:打开后物体将不会受碰撞影响,只能通过transform改变位置
  • Interpolate:插值运算(使运动变得平滑),NoneInterpolate由上一帧预测,Extrapolate由下一帧估计(这里的帧指的是物理帧)
  • Collision Detection:碰撞检测模式(防止体积太小直接穿过去了,比如说两帧间刚好跳过某物体,视觉上就是直接穿过去了没有发生碰撞),Discrete离散,Continuous连续,Continuous Speculative连续检测,Continuous Dynamic连续动态,这四项性能消耗从低到高,离散会把其他同化,不同的两种模式匹配会有不同的效果(比如两个连续会变成离散的处理,遇到问题再查表)
  • Constraints:约束限制,约束哪个轴,哪个轴上就不会有位移
  • Info:当前状态

代码控制刚体加力

刚体加力的本质是给了一个带方向的速度(啊物理学的冲刷)

获取刚体RigidBody rigidBody = GetComponent<RigidBody>():这是Mono基类的那个方法

添加力rigidBody.AddForce(Vector3向量):相对于世界,当然,参数也可以是transform去获取向量,加的方向不同(参考Transform部分),对应的相对于本地rigidBody.AddRelativeForce(向量)

添加扭矩阻力(旋转)rigidBody.AddTorque(向量):相对于世界,对应的相对于本地rigidBody.AddRelativeTorque(向量)

改变速度rigidBody.velocity = 向量

模拟爆炸rigidBody.AddExplosionForce(100, Vector3.zoro, 10):参数分别为力的大小,爆炸中心坐标,半径(只影响挂在了该脚本的)

添加力还有重载rigidBody.AddForce(向量, 力的模式):力的模式ForceMode可以改变力的运算方式,这是个枚举,有Acceleration给一个持续加速度,忽略质量,Force给一个持续的力(最正常),Impulse给一个瞬时力,忽略时间,VelocityChange给一个瞬时速度,忽略质量和时间(这里的忽略实际上是赋值为1,是拿动量定理Ft = mv算的速度)

添加力场(常力):这是个脚本,右边添加

Tips:有的时候(拿物体斜着去碰)为了节约性能刚体会自动休眠不起作用,可以添加代码if (rigidBody.IsSleeping) rigidBody.Wakeup()叫醒它

碰撞器Collider

右下角加脚本组件,但一般自带,毕竟要表示体积

分类

性能高(常用):盒装Box,球状Sphere,胶囊状Capsule

准确率高:网格Mesh(无数个小三角形搭起来,效果极好CPU也很烧),轮胎(环状)Wheel,地形Terrain

Tips:异形物体的表示可通过多种碰撞器的组合,但是组合后只有给父对象加刚体才能整体进行碰撞检测,给儿子加没用

共同参数

每个碰撞器参数都不一样,但有一部分是相同的

  • ※※※IsTrigger:勾选即认为是触发器=》不参与碰撞,只进行检测,用于事件检测(穿透攻击或者说是主角进入了某个场景触发剧情)
  • Meterial:物理材质,决定碰撞的方式
  • Center:对象局部空间中的中心点位置,即体积碰撞时计算的实际位置

物理材质的创建:Assets右键找到Physic Meterial创建调整后拖到上面的参数一栏

物理材质相关参数设置

  • Friction:摩擦力(分为动静两个)
  • Bounciness:弹力
  • Combine:碰撞力的组合(分为摩擦力和弹力两种)

各自参数

盒状:Size调整大小

球状:Radius半径

胶囊状:Radius底面半径,Height高度,Direction朝向

网格:Convex有刚体后勾选这个才能碰撞其他网格,Cooking OptionsMesh

轮胎:创建后无法显示,必须依赖其他物体(成为儿子),在父对象上点刚体后才能显示

地形:以后再看,有专门的课时

相关代码控制

碰撞检测函数

特殊生命周期函数(严格上来讲是事件的回调,不是真正的生命周期函数),在FixedUpdateUpdate中间调用,也是属于反射自动调用的类型

  • OnCollisionEnter(Collision collision):发生碰撞时接触时执行,写法就这样,碰的时候就把碰自己那个传进去了(这个Collision实际上是一个事件
  • OnCollisionExit(Collision collision):离开时执行
  • OnCollisionStay(Collision collision)有摩擦力时执行

得碰撞器脚本collision.collider:除了这个,还可以得gameObjecttransform,相当于是碰撞了后我就可以得到你所有信息

有多少点触碰collision.contractCount

得到触碰点的坐标ContactPoint[] = collision.contacts

触发器检测响应函数

也是特殊生命周期函数,要生效必须勾选碰撞器参数里的isTrigger

  • OnTriggerEnter(Collider collider):接触时调用,可以用来判断子弹打人扣血(这里的Collider是碰撞器的基类,即所有碰撞器组件脚本都继承)
  • OnTriggerExit(Collider collider):分开时调用
  • OnTriggerStay(Collider collider)重叠时调用

同样的,collider.可以得到触发者的所有信息

其他注意事项
  • 满足碰撞的条件后双方都调用函数
  • 六个函数一般选择性写,正常都为private,可以加virtual让子类重写
  • 异形物体要调用这六个函数,刚体必须在父对象身上

音效系统

支持的音频格式:wav,mp3,ogg,aiff

添加时也是比较暴力的,外面的直接拖到Assets就行(右键也可以)

设置导入音源的面板参数

右下角可以预览,这些参数不追求什么效果的话一般不怎么调

  • Force To Mono:多声道转单声道,二级选项Normalize是否标准化
  • Load in Background:后台加载,不卡主线程(可以节约性能,游戏运行时卡的不行了可以勾这个)
  • Ambisonic:主体混响声
  • LoadType:加载类型,Decompress OnLoad不压缩,适合小音效,直接全部放内存里,加载很快,内存受罪,Compress in memory压缩,适合大音效,内存占用小,但加载比较慢,Streaming流,几乎不占内存了,但是CPU受罪,经典性能换内存
  • Preload Audio Data:预加载,勾了进场就开始加载
  • Compresion Format:压缩方式,PCM几乎不压缩,Vorbis压一点,ADPCM压出来噪音
  • Onality:音频质量,不适用于PCK/ADPCM/HEVAG
  • Sample Rate Setting:采样率,Preserve Sample Rate保持,Optimize Sample Rate优化,Override手动覆盖

音频源AudioSource

右下角先加脚本

面板参数

说实话,如果某个参数太过专业看不懂,一般情况下应该不会去改它,看不懂的话真正要实现这个效果的时候再去学吧。。

  • AudioClip:把你导入设置好的音源拖过来,就可以在运行时播放
  • Output:默认输出到音频监听器,可以改到混音器
  • Mute:静音
  • Bypass Effect:开关滤波器
  • Bypass Listener Effects:开关所有监听器
  • Bypass Reverb Zones:开关所有混响区
  • Play On Awake:对象创建时播放音量(此时一阵强劲的音乐响起…)
  • Loop:循环播放(Boss战磨死Boss选手有了共鸣)
  • Priority:优先级(多个音乐叠加时起作用,但一般不会出现这种情况)
  • Volume:音量
  • Pitch:音高(好像是播放速度)
  • Stereo Pan:左右声道
  • Spatial Blend:受3D空间影响的程度(越远越小这种意思)
  • Peverb Zone Mix:混响区输出信号量
  • 3D Sound Settings:声音远近的进阶设置,会受到Spatial Blend参数影响(成正比)
    • Doppler Level:多普勒效果(音乐方面的专业知识)
    • Spread:扩散角度(立体还是多声道)
    • Volume Rolloff:声音衰减速度,Logarithmic Rolloff靠近时声音很大,远离后衰减很快,Linear Rolloff越远越小,Custom Rolloff曲线图设置
    • Min/Max Distance:最小距离内保持的最大音量,以及超出最距离后音量消失

代码控制

获取音频源AudioSource audioSource = GetComponent<AuioSource>():还还还是Mono那个

播放audioSource.Play():等效于停止暂停audioSource.UnPause()。。。

停止audioSource.Stop()

暂停audioSource.Pause()

延迟播放audioSource.PlayDelayed(延迟的秒数)

以上这几种就算没勾选Play ON Awake也可以控制

检测播放完毕audioSource.isPlaying

动态控制播放的三种方法

  • 直接挂一个音频源脚本用上面的方法播放
  • Instantiate(obj):实例化一个挂在音效脚本的对象,这个方法无法去管理该对象,所以很少用
  • 再创建一个音频源脚本对象,设置它的clip成员(就是音频文件,和参数面板第一个一个类型)后,让这个新的脚本去播放

音效监听器AudioListener

这个脚本相当于是耳朵,默认挂在眼睛(主摄像机)身上

主摄像机一般就是主角的视角,而有了这个脚本后,音频源播放的音乐才行被听到

所以必须要有一个,但一般也只有一个

麦克风Microphone

获取设备麦克风Microphone.devices

开始录制Microphone.Start(null, false, 10, 30000):返回一个AudioClip对象,第一个参数是设备名,null即默认,第二个参数表示超出录制长度后是否重新录制,第三个参数是录制时长,第四个参数为采样率

结束录制Microphone.End(null):参数为设备名

获取数据(有了录制后返回的AudioClip clip

AudioClip clip = Microphone.Start(null, false, 10, 30000);
float[] f = new float[clip.channels * clip.samples];//声道数*剪辑长度=采样率,即上面的30000
clip.GetData(f, 0);//数据保存在f中,第二个参数为偏移,默认为0

其他实践小知识点

场景切换与退出游戏

场景切换SceneManager.LoadScene("场景名"):要切换的场景必须加载到场景列表中,在File=》Build Settings里设置

还有一个已经过时的方法Application.LoadLevel("场景名"),可能会在老项目中见到

退出游戏Application.Quie():发布后这条语句才会有用

鼠标设置

隐藏鼠标Cursor.visible = false

锁定鼠标Cursor.LockState = CursorLockMode.CursorLockMode是一个枚举,None不锁,Locked限制在屏幕中心点,Confined限制在窗口内(锁住了后esc出来)

设置鼠标图片Cursor.SetCursor(图片,相对图片左上角的偏移,光标模式):定义一个publicTextur2D成员,界面上拖过去,下面的设置最好设置为Cursor类型透视,偏移是一个向量,光标模式一般填CursorMode.Auto

随机数与自带委托

随机数Random.Range(x, y):获取int时为[ ),获取float时为[ ] (这个Random是unity自带的,要用c#那个必须要引入System,并且指明System.Random)

委托UnityAction:用法和c#的Action一样,没有func一样的有返回值委托

模型

基本概念:(骨骼,表现动作)+(网格面片,表现轮廓)+(贴图,表现颜色)=》后两者是必须的,这样才能有一个静态模型

支持格式:fbx(推荐),dae,3ds,dxf,obj

导好fbx模型最好面朝z轴,注意缩放大小单位(一般是美术去做模型并导出,但导出时需要告诉他们这两点)

笔记到这里就结束了,学完这个还做不了小项目,要赶紧学数据持久化和GUI,快学吧快学吧。。。。

学习资料来源:b站唐老狮