Unity中一些小技巧

在unity中有一些小技巧,不能像人物的移动,攻击等有好几种方式可以用来单独成章,因此就把一些内容比较少,但是比较重要的内容放在一起合成一章,内容将会持续更新

1.人物死亡动画的播放:人物死亡后,需要用到Destory()函数对其进行销毁,但是想让其播放完死亡动画后再对其进行销毁,这个时候有两种方法,第一就是利用携程函数,等待一段时间后再执行销毁函数;第二(也是最常用的)就是利用动画事件的方法,在死亡的人的控制脚本上添加一个死亡函数,随后在死亡动画的最后一帧上添加动画事件

2.时间增量Time.deltaTime:表示每帧的时间间隔,这个一般用来写在update里面,因为update刷新的帧率与电脑性能有关系,有些电脑一秒可以120帧(Time.deltaTime=1/120),有些电脑一秒60帧(Time.deltaTime=1/60

 Vector2 position = transform.position;
  position.x = position.x + speed * horizontal;//这里的 horizonta横向轴
  position.y = position.y + speed * vertical ;
  transform.position = position;

通过这个公式可以知道在(只看x)如果update一秒刷新120帧(假如速度为10),那么 一秒后游戏对象的x坐标增加了120个单位,如果update一秒刷新60帧那么 一秒后游戏对象的x坐标增加了60个单位,这样就会导致相同的一秒钟,不同电脑上,运行的距离不一样

如果增加Time.deltaTime

 Vector2 position = transform.position;
  position.x = position.x + speed *Time.deltaTime* horizontal;//这里的 horizonta横向轴
  position.y = position.y + speed*Time.deltaTime * vertical ;
  transform.position = position;

 这样的话在120帧的update中Time.deltaTime=1/120,position.x = position.x + (10*1/120* horizontal);这样执行120次,一秒后游戏对象的x坐标增加了10个单位,在60帧的update中Time.deltaTime=1/60,position.x = position.x + (10*1/60* horizontal);这样执行60次,一秒后游戏对象的x坐标增加了10个单位,这样就控制了不同的刷新率但是一秒钟的移动距离是相同的

总结:这里 speed *Time.deltaTime就把每帧移动距离变成了每秒的移动距离

3.玩家的二段跳跃 :实现玩家二段跳跃,一般来说是给玩家脚底添加一个碰撞器然后判断是否接触地面,接触地面时设置重置跳跃次数

在制作二段跳之前,首先要设置一个跳跃次数,要在跳跃次数大于0的情况下才能执行跳跃,跳跃完成后跳跃次数减一,代码如下

 public float jumpspeed;//跳跃速度

 public int jumpCount=2;//跳跃次数

 void Update()
    {
        if(jumpCount > 0)
        {
            Jump();
        }

    }

void Jump()//跳跃函数
    {      
        if (Input.GetKeyDown(KeyCode.K))
        {
            Vector2 jumpVel = new Vector2(M_Rigidbody2D.velocity.x, jumpspeed);
            M_Rigidbody2D.velocity = jumpVel;
            jumpCount--;//完成一次跳跃后,跳跃次数减一
        }   
    }

区别就是在于重置跳跃次数函数, 目前来说检测是否接触地面的方法有两种(不用射线):

第一种(使用标签)将脚底的碰撞器勾选为一个触发器,将地面的标签设置为Ground,随后在进入触发器的函数中重置跳跃次数,代码如下

private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Ground")
        {
            jumpCount = 2;
        }
    }

第二种(使用图层)将地面的图层设置为Ground在start中获取到脚底的碰撞器,再写一个判断重置函数,如果碰到地面图层就重置,代码如下:

private bool isGround;//判断是否接触地面

private BoxCollider2D myFeet;//脚底的碰撞器
void Start()
{
myFeet = GetComponent<BoxCollider2D>();
}

void CheckTouch()//这个需要在update中调用

{

  //这里如果碰到地面图层就返回true

  isGround = myFeet.IsTouchingLayers(LayerMask.GetMask("Ground"));

  if(isGround)

  {

    jumpCount=2;

  }

}

4.单例模式: 单例模式通俗来讲目的就是一个类只能有一个实例(也就是它只能被实例化一次,只存在一个对象),在unity中的使用场景经常是用来制作UI比如血条,代码如下:

   public static UIHealthBar Instance { get; private set; } //这里是使用快捷属性的方法     
   private void Awake()
    {

        //这里是关键,相当于是把当前的对象赋值给Instance字段(自动创建的),这时Instance

        就相当于是当前类的对象,并且只有一个
        Instance = this;//设置静态实例为当前对象,这个this就与之前的gameobject差不多
    }

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

5.游戏对象的遮罩问题(2D图形渲染顺序):首先要清楚unity中存在排序图层 (Sorting Layer) 和图层中的顺序 (Order in Layer)

注意在创建游戏对象后,unity默认游戏对象的排序图层为为default,图层中的顺序为0,这个时候就会出现后创建的在上方的情况,即使在层级窗口改变游戏对象的上下顺序也不行,应该更改排序图层或者图层顺序即可

6.2D人物卡墙,旋转问题:在游戏中如果设置一堵墙,当玩家跳跃起来按住方向键不松手时,人物会卡在墙上,直到松开方向键,才会掉落;有时人物还会出现旋转

(1)卡墙:首先创建一个2d的物理材质创建-》2D-》物理材质2D

 再将物理材质的摩擦系数改为0,随后将该物理材质添加给碰撞器即可

 (2)关于人物在墙边缘会旋转的情况:只需要在人物的Rigidbody 2D 添加约束实现,将z轴冻结即可

7.关于 gameObject.CompareTag和gameObject.tag:这两者的在使用的效果是一样的,但是只是会有运行所花的时间区别,前者必后者所花时间少,因此更建议使用前者,至于两者时间不同的原因在于CompareTag是GameObject中定义的一个方法可以直接进行比较而.tag作为GameObject中的属性先要get,set一遍然后再通过字符串进行比较,所以多花了时间。

8.游戏对象和组件用代码激活的方式:在脚本中,用代码激活游戏对象和激活游戏对象上组件是有区别的,激活游戏对象时gameobject.SetActive(true),激活组件时,以碰撞器为例gameobject.Ge tComponent<BoxCollider>().enabled=true;

9.暂停游戏:暂停游戏可以使用Time.timeScale=0;也就是让时间缩放等于0,同理想要制作慢放或者快放的效果设置Time.timeScale即可

10.人物发生抖动:当在Upadte中使用Translate和MoveTowards时,人物和一些建筑碰撞就会出现人物抖动的情况,这是因为Unity把物理运动时放在FixUpdate中计算的,有因为FixUpdate是要比Update先计算的,如果把Translate和MoveTowards放在Update中,就会出现在执行update那一帧的移动后,人物的图片通过电脑渲染已经进入墙体一部分(Translate和MoveTowards是改变物体位置),在进行下一次FixUpdate时计算物理运动就会把人物弹出墙外,导致人物出现抖动

11.UI显示文字模糊:当制作UI文字显示得很模糊时,可以通过改变文本组件的Scale和Font Size的大小调整,Scale越小,Font Size越大,文字越清晰

12.加载文件中的资源:Resources这是一个Unity提供的类,它有一个Load()方法,该方法是用来加载Resources文件中的的资源用的,使用时需要在Assets中创建一个名为Resources的文件夹,然后将需要使用的资源放在该文件夹下,Resource.Load();//这里参数就是文件的名称,但是要注意这里的返回值是GameObject,如果需要其它类型比如Spirte类型,就需要加泛型Resource.Load<Spirte>(文件名);

13.Animator和Animation的简单区别:

Animation是一种简单的动画组件,先简单介绍使用上的区别,这里想要播放动画时直接在代码中

Animation(对象).clip=AnimationClip(对象),这一步就相当于把Animation中的动画赋值为想要播放的动画clip,然后Animation(对象).Play();播放动画;还有中方式就是Animator.Play("动画名称");注意这里的动画名称是要在Animator动画器中存在的。

 Animator比起animation就复杂了,但也更强大了,Animator一般用于骨骼动画人型,目前就不详细介绍,这是控制器在控制器中可以看见一些状态,比如stop,run等,这些动画就可以通过通过控制参数控制切换,在控制器中还存在一个混合树,和子状态机这两个的东西,混合树的作用是,这两者我理解的是比如人物在进行移动时有走,跑等动作用将这些需要融合的动画就可以放在混合树里面,子状态机可以理解为是不需要融合的动作,比如一段攻击,二段攻击,跳跃和下落等就可以放在子状态机中,混合树是通过参数设置播放对应的AnimationClip,等以后涉及到动画篇时再详细讲解

14.Vector2向量的一些基本用法:二维向量和三维的用法大概一致;例如有一个Vector2 V2=new Vector2(1,1);常用的就是求V2的模长,和把V2单位化,都有两种方法

  (1)求模长:V2.magnitude(模长);V2.sqrMagnitude(模场的平方); V2.SqrMagnitude()(这个也是求模长的平方);前两个和第三个的区别就是,前两个是Vector2的成员变量,第三个是Vector2的方法,前两个不会改变原本V2的值,第三个会改变V2的值

     (2)求单位化:V2.normalized;V2.Normalize();单位化同理

15.OnTriggerEnter2D触发器函数:在使用触发器函数时要注意有两点,1.collison碰撞的物体对象上必须有刚体组件,2.这里的collider(也就是碰撞的区域)无论是否勾选了IsTrigger都会触发这个函数

16.输入检测:轴可以在编辑-》项目设置-》输入管理器中可以查看并修改轴的参数

//连续检测的意思就是如果玩家一直在触发某个按键,那么它就会持续返回值

//连续检测(移动),这里返回的是值

Input.GetAxis("Horizontal")//水平方向的轴,返回值为-1到1的连续,也就是返回值是渐变的

Input.GetAxis("Vertical")//垂直方向的轴值

Input.GetAxisRaw("Horizontal")//水平方向的边界轴值,返回值就只用-1和1,不是连续的

Input.GetAxisRaw("Vertical")//垂直方向的边界轴值

Input.GetAxis("Mouse X")//鼠标水平移动增量,返回值是连续的

Input.GetAxis("Mouse Y")//鼠标垂直移动增量

//连续检测(事件),这里返回的是true或者false

Input.GetButton("Fire1")//鼠标右键

Input.GetButton("Fire2")//鼠标左键

//间隔检测事件就在按键按下后检测一次,也就是只返回一个值

//间隔检测(事件),这里返回的是true或者false

Input.GetButtonDown("Jump")

Input.GetKeyDown(KeyCode.Q)//这是键

Input.GetButtonUp("Squat")//这是自定义的轴

Input.anyKeyDown//任意键

Input.GetMouseButton(0)//鼠标左键,1是右键,2是鼠标中轮

17.时间的输出:

Time.deltaTime;//完成上一帧所用的时间(以秒为单位)

Time.fixedDeltaTime;//执行物理或者其他固定帧率更新的时间间隔(因此是固定的)

Time.time;//游戏开始以来的总时间,会受Time.timeScale的影响

Time.fixedTime;//自游戏启动以来的总时间(以物理或者其他固定帧率更新的时间间隔累计计算的)

Time.realtimeSinceStartup;//游戏开始以来的实际时间,不会受到Time.timeScale影响

Time.smoothDeltaTime;//经过平滑处理的Time.deltaTime的时间

Time.timeScale;//时间缩放,可以用来慢放动作

Time.timeSinceLevelLoad;//当前关卡所花的时间

Time.time在游戏暂停的时候不增长,结束暂停后会把这段暂停的时间加上去,Time.realtimeSinceStartup不管暂不暂停都增长。

18.复杂地形创建碰撞体:可以使用2D 边缘组件

19.运动拖尾效果:制作尾部流光特效可以使用拖尾渲染器组件

20.判断人物是否接触地面:可以直接在人物脚本上写OnCollisionEnter2D函数,在该函数中重置是否接触地面的布尔变量

21.玩家输入:获取玩家的输入最好放在Update中完成

22.人物翻转有几种方式:第一直接在transform中调用rotation进行旋转,第二在Sprite Renderer中调用翻转

23.隐藏字段:可以使用[HideInInspector]将public字段在检查器中隐藏

24.销毁物体:销毁物体Destroy函数,1参数(游戏对象),2参数(游戏对象,多少秒销毁)

25.跨越平台跳跃:人物可以从下往上跳上平台使用的是PlatForm Effector2D组件,记得把碰撞器勾选由效果器触发(将旋转偏移为0表面弧度180度就会出现下方可以跳上去),如果想要下来有两种方式1.将表面弧度设置为90度,2.将旋转偏移设置为180

26.抖动函数:PingPong函数用来实现数值在设定的范围内来回变动,Mathf.PingPong(Time.time),最大范围),第一个参数相当于x轴,第二个相当于y轴,x需要不断变化y才能不断变化,想象成cos函数

27.获取相机:可以在代码中使用Camera.main获取摄像机(摄像机的标签要是Camera)

28.控制声音仅播放一次:控制声音在播放时不再播放(也就是持续按下才会播放)可以使用if(!audioSource.isPlaying){audioSource.Play()};

29.任何动画切换:动画切换,当一个动画可以由仍以状态切换过去时,就可以从anystate状态连接过去,但是不能连接会任何状态

30.UI锚点:UI中Anchor锚点是用来保持图片的中心轴点与锚点的距离不变的,锚点的边的作用是让图片的边与锚点的边保持不变的

31.UI输入框:UI中文本的输入框使用的是InputField组件,其子物体PlaceHolder中的Text组件内容是文本框默认显示,子物体Text中的Text组件内容则是获取用户输入的内容,InputField组件中的Text也会显示子物体子物体Text中的Text组件内容

32.UI单选框:UI中Toggle组件是单选框,可以使用Toggle Group组件讲将多个单选框组合成一个相互影响的单选框

33.UI技能冷却效果:Sprite Render组件中的绘制模式简单:缩放图片最常规的变形方式;已切片:上下边框只会边长,左右边框只会变高,边框里面的内容变形;已平铺:图片会根据内容进行平铺。Image组件中的图像类型类似,有个已填充:如果不设置就和简单一样,,其中的FillMethod配合Fill Amount可以用来做CD效果的UI

34.UI中Canvas的三种渲染模式:Canvas的三种渲染模式分别是Screen Space -Overlay(屏幕空间—覆盖),Screen Space - Camera(屏幕空间—摄像机),World Space(世界空间)

        (1)Screen Space -Overlay:可以理解为画布紧贴着摄像机的镜头,也就是说在该画布上的所有内容都会在游戏对象之前,都会把游戏对象覆盖(那两个都在该画布上的,Sort Order 值越大越靠上,如果Sort Order 值一样,那在Hierarchy 层级中越靠下的会越显示在上方,这与渲染顺序有关)

       (2)Screen Space - Camera:它就是相当于在摄像机和UI画布之间嗨哟一段距离,当物体在摄像机和UI画布之间时,游戏物体就会在UI前面,当游戏物体在UI后面是,当然也就会被UI遮盖

       (3)World Space:这就相当于是一个跟随游戏物体的UI,它可以不是全屏大小的,比如玩家的头上需要显示血量,或者NPC头上需要显示对话框,这种就不能用全屏的UI来做,就相当于是一个局部UI

35.延时调用方法:1.协程,2.Invoke(“方法名”,多少秒后调用);3.InvokeRepeating(“方法名”,多少秒后开始第一次调用,间隔多少秒后重复调用),Invoke和协程的区别在于,用Invoke方法调用的函数不能带参数,协程就能够调用方法时携带参数

36.UGUI局部坐标轴:在UGUI中,切换成局部坐标后旋转物体,虽然游戏物体旋转了,可是坐标轴还是没有改变,可以点击Rect Transform中的这个就能看见

 37.设置子物体到UGUI上:在使用transform.SetParent时要注意,要是想要将子物体(没在UGUI上),设置到UGUI上,如果子物体的缩放已经合适,那么transform.SetParent(父物体,false)这里需要有false,不要让它再次缩放

38.鼠标点击事件和按钮重合:当游戏中有按钮和鼠标点击触发事件事,不想点击按钮时触发点击点击事件,这个时候可以就用EventSystem.current.IsPointerOverGameObject()来判断是否点击到UI上(这里指按钮),如果点击到按钮就可以不用触发点击事件,当存在背景再ui上时,可以取消勾选取消背景对鼠标点击事件的检测

39.Unity中使用VS不出现提示功能:Unity使用VS编译器出现了生命周期函数不能提示的功能,这个时候可以打开你项目所在的文件夹找到这三个文件并删除,再重新用unity打开项目即可

 40.加载场景:加载场景可以用UnityEngine.SceneManagement.SceneManager.LoadScene(0);或者书写头文件using UnityEngine.SceneManagement;随后就能SceneManager.LoadScene(0)

41.JSON存取读取文档的坑:在进行读档存档时,Unity使用自带的JsonUtility反序列化的时候,如果对象继承自MonoBehavior或者ScriptableObject,使用JsonUtility.FromJson的时候就会报错ArgumentException: Cannot deserialize JSON to new instances of type ‘xxx.',这个时候有两种解决办法,1.该类继承的MonoBehavior删除掉(因为这个类只用来保存数据,不会用来实例化对象(因为在unity中脚本挂载在游戏对象上的关键是需要继承自MonoBehavior类),可以删掉) 2.使用JsonUtility.FromJsonOverwrite(Json的字符串,存储在哪个对象上(需要类保持一致))

42.不能用new对MonoBehavior声明对象:在Unity中,继承于MonoBehavior的对象,要避免使用new关键字来创建,而必须使用AddComponent或Instantiate函数来创建,这种对象也要尽量避免使用构造函数,对应的初始化工作要在对应的Awake和Start函数中进行

猜你喜欢

转载自blog.csdn.net/qq_62947569/article/details/128471283