一、封装组件代码
1.前言
当我们创建一个面板的时候,实现面板淡出淡入的效果,需要获取Canvas Group组件中的通道Alpha值,通过改变Alpha的值(0到1淡出,1-0淡入的效果)来改变。
问题:这时候会发现当我们创建多个面板的时候,都需要重复上面的步骤(需要添加Canvas Group组件,获取Alpha值),这会显得很繁琐和代码的重复性很大。
解决:这时候我们可以通过创建一个基类(也就是父类),在父类中实现组件的添加,可以充分把继承和封装思想写入到untiy实践项目中
2.代码实现:
新建一个基类basePanle,声明需要添加的组件类型,以及需要修改的属性值。
在这里需要注意的是:声明抽象方法的必须在抽象类中生成,并且父类中的所有方法都应该可以被子类所重写的,即方法都要标注为virtual,采用虚函数声明。当然了,相应的子类可以访问父类中的方法,那么父类中的方法的修饰符的访问权限当然需要提升了,在这里我们使用protected修饰符来定义。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class basePanle : MonoBehaviour //基类
{
//首先每个继承basePanle的物体是不是都要添加一个透明度CanvasGroup组件
private CanvasGroup canvasGroup;
//速度:淡入淡出的速度
float alphaSpeed = 10f;
//当对象被唤醒的时候,是不是要添加canvasGroup组件
//游戏对象被激活,自动帮我们调用Awake方法
protected virtual void Awake() //可以被继承,所以权限要确保子类(派生类)能够被访问;virtual派生类进行重写要用虚函数
{
//获取当前的canvasGroup组件 this指代当前的对象
canvasGroup = this.gameObject.GetComponent<CanvasGroup>();
//如果组件不存在,则需要添加一个组件
if(canvasGroup == null)
{
this.gameObject.AddComponent<CanvasGroup>();
}
}
protected virtual void Start()
{
Init();
}
//抽象方法 提示我们必须要实现这个方法 讲ui的时候可能 需要初始化一些参数,把它写到一个方法里面
public abstract void Init();
}
再次新建一个子类Panle,来继承基类(basePanle)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Panel : basePanle
{
public override void Init()
{
}
}
将子类代码挂载到untiy中的面板panle中,当我们运行项目的时候,会自动运行面板挂载的panle脚本文件,在Panle脚本文件中重写了Init()方法,同时父类中监测到游戏对象被激活,自动帮我们调用Awake方法完成组件的创建。这也就是相对于通过代码的编写完成每次的重复组件的添加操作。
二、untiy的单例模式
1.前言
在上面我们简单实现了使用代码创建了一个组件,并成功实现了面板内容的淡入淡出效果,但是我们思考,如果以后需要创建多种不同的组件,还是通过代码实现该怎么去实现,并且太多的类型该如何去处理和定义,这时候我们引入了Unity中C#单例模式使用,通过单例模式我们可以实现集中管理好,现阶段理解的就是上述的意思
一、单例模式优点 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问; 意味着在内存中,只存在一个实例,减少了内存开销;
二、单例模式特点 只存在唯一一个实例; 提供统一对外访问接口,使得全局可对该单例的唯一实例进行访问; 自行实例化(私有构造函数,不允许外界对其进行实例化)。
2.实现
在这里我们通过代码实现一个简单的面板,里面包含文字和按钮,简单实现淡出这个UI登录界面的这个小案例。
导入图片的时候,图片拖入图像源之前要先把图像的纹理类型改为下面类型
我们先创建一个面板LoginPanle,里面包含登录按钮和图片,创建好后,将LoginPanle作为预制体拖入到UI文件夹中,创建好LoginPanle脚本文件,将脚本文件挂载到面板中。
LoginPanle脚本文件
继承了父类basePanle。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoginPanle : basePanle
{
public override void Init()
{
}
}
UIManager脚本文件
这里面编写的代码现阶段理解较为复杂,可以理解为就是一个集中管理器,里面的内部实现逻辑就是实现创建面板的步骤,当以后有需要去创建新的类型的时候,也是通过这样的模板逻辑来接进行创建,在这里我们是通过字典来存储
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager
{
private Transform canvasTrans;
//只实例化一次 静态成员变量返回该实例对象
public static UIManager Instance = new UIManager();
//创建一个字典来存储 string代表面板,basePanle代表脚本类,因为所有的派生类都可以使用基类basePanle表示
private Dictionary<string,basePanle> palneDic = new Dictionary<string,basePanle>();
//将每个面板拆分成一个个预制件,需要的时候使用,不需要的时候不显示
//因为一旦canvas显示了说明ui管理器开始运作了,可以在构造方法里面进行初始化canvas
//创建一个构造方法
private UIManager()
{
//使用克隆一个canvas 注意的是这里要使用GameObject.的方式,因为这里没有继承MonoBehaviour
GameObject canvas = GameObject.Instantiate(Resources.Load<GameObject>("UI/Canvas"));
//面板应该是canvas的孩子:面板.transform.parent = canvas.transform
canvasTrans = canvas.transform;
//当我场景切换的时候可能界面还是保存的,也就说不能直接销毁
GameObject.DontDestroyOnLoad(canvas); //跳转场景的时候不销毁canvas
}
//显示的方法:设计思想:我们等一下每一个预制体都挂载到一个面板脚本上,
//这个面板脚本的积累就是basePanle,等一下面板名我们直接使用类名就好了
//注意:预制件的名字最好和脚本文件的名字一样
public T showpanle<T>() where T : basePanle //限制面板必须是继承basePanle
{
//通过泛型的名字来控制是否显示 那这里就要获取泛型的名字
string pathName = typeof(T).Name; //获取泛型对应的名字
//创建一个面板,确定是否在字典中
if (palneDic.ContainsKey(pathName))
{
//如果有说明已经显示了,就直接返回
return palneDic[pathName] as T; //需要的是T类型,但是字典里面存储的是basePanle类型,这时候需要使用语法糖转化成T类型
}
//如果没有显示过 那么需要创建一个对象来作为canvas的孩子,同时往字典添加键值对,字典中存储的都是当前系那是的面板
GameObject panel = GameObject.Instantiate(Resources.Load<GameObject>("UI/"+pathName));
//将当前的面板加入字典,成为其中的一员
panel.transform.parent = canvasTrans;
//添加字典当中
palneDic.Add(pathName, panel.GetComponent<T>());
//调用淡入方法
panel.GetComponent<T>().showMe(); //T代表的就是它挂载的脚本
return panel.GetComponent<T>();
}
}
UI管理器的好处:
有了UI管理器我们想要谁显示直接传入面板名字即可,不需要去关联太多面板。
编写Main脚本文件,将脚本文件挂载到主相机中,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
UIManager.Instance.showpanle<LoginPanle>();
}
// Update is called once per frame
void Update()
{
}
}
basePanle脚本文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public abstract class basePanle : MonoBehaviour //基类
{
//创建一个委托 untiy内置了一个委托
private UnityAction callback;
//首先每个继承basePanle的物体是不是都要添加一个透明度CanvasGroup组件
private CanvasGroup canvasGroup;
//速度:淡入淡出的速度
float alphaSpeed = 10f;
//创建一个布尔值来记录当前的状态
bool isShow = false;
//当对象被唤醒的时候,是不是要添加canvasGroup组件
//游戏对象被激活,自动帮我们调用Awake方法---添加组件
protected virtual void Awake() //可以被继承,所以权限要确保子类(派生类)能够被访问;virtual派生类惊进行重写要用虚函数
{
//如果组件不存在,则需要添加一个组件
if (canvasGroup == null)
{
this.gameObject.AddComponent<CanvasGroup>();
}
//获取当前的canvasGroup组件 this指代当前的对象
canvasGroup = this.gameObject.GetComponent<CanvasGroup>();
}
protected virtual void Start()
{
Init();
}
//抽象方法 提示我们必须要实现这个方法 讲ui的时候可能 需要初始化一些参数,把它写到一个方法里面
public abstract void Init();
//实现淡出的方法,修饰符公开.透明度从0开始变化,最后变成1
public void showMe()
{
canvasGroup.alpha = 0;
isShow = true;
}
//实现淡入的方法 返回挂载的脚本
//callback 可以方便的调用另一个脚本的方法
public void hideMe(UnityAction callback) //隐藏完我们一般销毁游戏对象 在调用的地方传入一个回调函数,在这里面进行执行
{
canvasGroup.alpha = 1;
isShow = false;
//移除游戏对象
if (callback != null) callback.Invoke(); //调用传进来的委托函数
}
private void Update()
{
Debug.Log($"1111:{canvasGroup.alpha}");
//判断当前的显示状态
if (isShow && canvasGroup.alpha <1)
{
//显示:透明度0-》1 一定要加上Time.deltaTime,否则一下子会超过1
canvasGroup.alpha += alphaSpeed * Time.deltaTime;
if (canvasGroup.alpha >= 1)
{
canvasGroup.alpha = 1;
}
}else if (!isShow &&canvasGroup.alpha>0)
{
//淡出效果 透明度1-》0
canvasGroup.alpha -= alphaSpeed * Time.deltaTime;
if (canvasGroup.alpha <= 0)
{
canvasGroup.alpha = 0;
}
}
}
}
需要注意的是:Canvas画布和LoginPanle都是作为预制体通过代码实现的。并且当我们调用
UIManager.Instance.showpanle<LoginPanle>();
showpanle方法里面的参数的名称要和你的预制体的名称是一致的,否则会找不到,并且加载资源的时候文件路径也要一一对应。
最终效果如下:
这时候我们发现明明面板成为预制体之前位置是好的,但是我们通过代码插入的时候会发现位置发生变化了,原因是因为我们在设置parent的时候,应该使用setparent方法来插入到字典
panel.transform.SetParent(canvasTrans, false); //false表示相对于父元素
针对于# Unity中的刚体和碰撞体组件可以参考下面这篇文章 blog.csdn.net/weixin_4314…