Unity游戏开发UI框架(3)

这应该是最后一篇文章了。
前面的内容都是通过调用MySceneManager,进行状态(场景)切换,也就是核心就在他,一切的所有的内容都是围绕他进行的。控制了中枢MySceneManager,就控制了整个场景的切换。
同样的UI方面的处理也是一样的。唯一特别的就是LoadingPanel的处理,有那么一点点不同。之后详细说。
其他界面的处理思路和状态的处理一模一样的。但是考虑到UI有很多种,其中有全屏的(还分为透明和不透明的),有半屏的。这两个区别就是显示全屏的UI,后面的其他UI可以不用显示了,但是那种透明的界面,或者Tips的界面,还是能看到后面的UI,也就是层级的问题。![例如注册界面后面的登录界面还是能看到的,就不能把Login关闭或者隐藏](https://img-blog.csdnimg.cn/20210509151523706.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2E3Mjc2NzQ2NTA=,size_16,color_FFFFFF,t_70#pic_center)

至于具体怎么处理要看个人吧,我使用的枚举作为标记区分;
先上管理类:
一、UI管理类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class UIManager : MonoBehaviour
{
    private static Transform canvas;
    public static Transform Canvas
    {
        get
        {
            if (canvas == null)
            {
               canvas= GameObject.FindWithTag("Canvas").transform;             
            }
            return canvas;
        }
    }
    /// <summary>
    /// 已经加载过的Panel;
    /// </summary>
    private static Dictionary<PanelNameEnum, BasePanel> m_panelDic = new Dictionary<PanelNameEnum, BasePanel>();

    public static BasePanel LoadPanel(PanelNameEnum panelEnum, PanelNameEnum prePanel)//传入显示的界面,参数自己;
    {      
        BasePanel target = null;
        string pName = Enum.GetName(typeof(PanelNameEnum), panelEnum);
        if (!m_panelDic.TryGetValue(panelEnum,out target))
        {
        	//通过名字uiprefabs(自己定义的)加载AB包,以及AB包的资源(想要加载的Panel);
            GameObject t= ABManager.Instance.LoadAssets<GameObject>("uiprefabs", pName);
            GameObject temp = Instantiate(t, Canvas, false);
            temp.name = pName;
            target= temp.GetComponent<BasePanel>();
            m_panelDic.Add(panelEnum, target);            
        };
        //根据他的枚举类型,决定当前的这个之前的panel是否需要隐藏;
        if(prePanel!=PanelNameEnum.None)
             SwitchEnumPanel(target.ScreenEnu, m_panelDic[prePanel]);
        target.gameObject.SetActive(true);
        target.transform.SetParent(Canvas,false);
        target.transform.SetAsLastSibling();
        return target;
    }
    //Loading 专用加载;传数据或者传递方法以后在补充;
    public static BasePanel LoadPanel(string title=null,string content=null,string imageName=null)
    {
        BasePanel target=null;
        string pName = Enum.GetName(typeof(PanelNameEnum), PanelNameEnum.LoadingPanel);
        if (!m_panelDic.TryGetValue(PanelNameEnum.LoadingPanel, out target))
        {
            GameObject t = ABManager.Instance.LoadAssets<GameObject>("uiprefabs", pName);
            GameObject temp = Instantiate(t, Canvas, false);
            temp.name = pName;
            target = temp.GetComponent<BasePanel>();
            m_panelDic.Add(PanelNameEnum.LoadingPanel, target);
        };
        target.gameObject.SetActive(true);
        target.transform.SetParent(Canvas, false);
        target.transform.SetAsLastSibling();
        if(target is LoadingPanel)
        {
            (target as LoadingPanel).ShowContent(title, content, imageName);
        }
        return target;
    }

    //参数panel是即将要打开的。
    private static void SwitchEnumPanel(PanelScreenEnum panel,BasePanel panelName)
    {      
        switch (panel)
        {
            case PanelScreenEnum.FullScreen:
                panelName.ISShow(false);
                break;
            case PanelScreenEnum.HalfScreen:
                panelName.ISShow(true);
                break;
            case PanelScreenEnum.Tips:
                panelName.ISShow(true);
                break;
           
            default:
                break;
        }

    }
    public static void DestoryPanel(PanelNameEnum panelEnum)
    {
        if (m_panelDic.ContainsKey(panelEnum))
        {
            BasePanel temp = m_panelDic[panelEnum];
            m_panelDic.Remove(panelEnum);
            Destroy(temp.gameObject);
        }
        else
        {
            MDebug.LogError($"Please Check {panelEnum},Don't Destory!!!");
        }
    }
    public static void HideTargetPanel(PanelNameEnum panelEnum)
    {
        BasePanel target = null;
        if (m_panelDic.TryGetValue(panelEnum, out target))
        {
            target.ISShow(false);
        }
    }
    public static void HideAllPanel()
    {
        if (m_panelDic == null)
        {
            MDebug.LogError("panelDic is null, please Check!!!");
        }
        foreach (var item in m_panelDic.Values)
        {
            item.ISShow(false);
        }
    }

    /// <summary>
    /// 谨慎使用;
    /// </summary>
    public static void ClearPanelDic()
    {
        foreach (var item in m_panelDic.Values)
        {
            Destroy(item.obj);
        }
        m_panelDic.Clear();
        GC.Collect();
    }
}

二、UI的基类

public abstract class BasePanel : MonoBehaviour
{
	//表示该UIPanel是全屏的还是其他的;
    protected PanelScreenEnum screenEnu = PanelScreenEnum.HalfScreen;
    //名字的枚举实际上就是要么通过名字字符串直接加载,要么就是通过枚举加载,这个加载的方式是和UIManager自己定义的有关的,怎么写都行;只是我用的枚举而已。
    protected PanelNameEnum nameEnum;
    public void Awake()
    {
   		//数据初始化,不一定用得到;       
        InitData();
    }
    public void OnUpdate()
    {
    	//刷新UI的逻辑;
        UpdateUI();
    }
    public GameObject obj
    {
        get
        {
            return gameObject;
        }       
    }

    public PanelScreenEnum ScreenEnu
    {
        get => screenEnu;
    }
    public PanelNameEnum NameEnum { get => nameEnum; }

    public void ISShow(bool isShow)
    {

        obj.SetActive(isShow);
    }
    protected virtual void UpdateUI() { }
    protected abstract void InitData();
}

三、单独把Loading界面拿出来

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;

public class LoadingPanel : BasePanel
{
    [SerializeField]
    private Image m_Bg;
    public Slider m_Slider;
    public Text  m_title_text;
    public Text m_Content;
    public Text showSliderValue_text;
    protected override void InitData()
    {
        this.screenEnu = PanelScreenEnum.FullScreen;
        this.nameEnum = PanelNameEnum.LoadingPanel;
        MessageManager.AddListener("loading", DoValueSlider);
    }
    public void OnDestroy()
    {
        MessageManager.RemoveFunc("loaidng");
    }
    public void DoValueSlider(float num)
    {
        m_Slider.value = num;
        MDebug.Log("Loading界面的进度值 m_Slider.value:" + m_Slider.value);
        if (num >= 0.8999)
        {
            m_Slider.value = 1;
        }
        showSliderValue_text.text = (m_Slider.value * 100).ToString() + "%";
    }
    public void ShowContent(string title = null, string content = null, string imageName = null)
    {
        if (title != null && content != null)
            m_title_text.text = title;
        m_Content.text = content;
        if (imageName != null && imageName!=string.Empty)
        {
            MDebug.Log(imageName != string.Empty);
            MDebug.Log(imageName!=null);
            m_Bg = ABManager.Instance.LoadAssets<Image>("iamgebg", imageName);
        }
    }
}

注意: MessageManager.AddListener(“loading”, DoValueSlider);在界面一打开的时候我就把这个消息注册到消息盒子里面去了,在那执行的呢?还记得场景管理类中吗?进入每个场景,就首先通过UIManager加载了loading界面,因此也就把这个委托注册到MessageManager这个雷中秋u了。然后,通过MySceneManager执行了LoadSceneMsg管理类中的异步加载场景的方法,在这个方法里面, 执行了MessageManager.DoFunc(“loading”, async.progress);通过传入两个参数,执行了之前注册的委托DoValueSlider。当加载完成以后,我又重新移除了这个方法。如果销毁这个界面,那么就自动移除了这个方法。
while (async.progress < 0.9f)
{
MDebug.Log(“async.progress” + async.progress);
MessageManager.DoFunc(“loading”, async.progress);
yield return null;
}

到此为止,框架算是完成了。因为有部分东西其实还是不合理,但是我实在是懒得改了……自行解决就行了。

下面这个是关于音乐相关处理:
四、其他播放音乐的管理。同样的特效也是这个道理,没什么好说的。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MusicManager :AutoSingleton<MusicManager>
{
    private AudioClip buttonClip;
    private AudioClip bgClip;
    private AudioClip otherClip;
    private GameObject audioSource;
    private AudioSource buttonAudioSource;
    private AudioSource bgAudioSource;
    private AudioSource otherAudioSource;

    private void Awake()
    {
        CreatAudioSource();
        PlayBGAudio(true);
    }
    private void CreatAudioSource()
    {
        if (audioSource == null)
        {
            audioSource = new GameObject("AudioSourceComponent");
            DontDestroyOnLoad(audioSource);
            MDebug.Log("创建了物体AudioSource");
        }
        if (buttonAudioSource == null)
        {
            GameObject go = new GameObject("buttonAudioSource");
            go.transform.SetParent(audioSource.transform);
            buttonAudioSource = go.AddComponent<AudioSource>();
        }
        if (bgAudioSource == null)
        {
            GameObject go = new GameObject("bgAudioSource");
            bgAudioSource = go.AddComponent<AudioSource>();
            go.transform.SetParent(audioSource.transform);
        }
        if (otherAudioSource == null)
        {
            GameObject go = new GameObject("otherAudioSource");
            otherAudioSource = go.AddComponent<AudioSource>();
            go.transform.SetParent(audioSource.transform);
        }
    }
    public void OnMyClickClip()
    {
        if (buttonClip == null)
            buttonClip = ABManager.Instance.LoadAssets<AudioClip>("audio", "buttonClip");
        buttonAudioSource.clip = buttonClip;
        buttonAudioSource.mute = false;
        buttonAudioSource.loop = false;
        buttonAudioSource.Play();
    }
    public void PlayBGAudio(bool isPlay)
    {
        if (bgClip == null)
        {
            bgClip = ABManager.Instance.LoadAssets<AudioClip>("audio", "zanyong_bg");
        }
        bgAudioSource.clip = bgClip;
        buttonAudioSource.mute = false;
        buttonAudioSource.loop = true;
        bgAudioSource.Play();
    }
}

搞定!!!以后有空可能会写一点关于Shader的东西吧,也可能会写一些关于Ai相关的FSM啊,GOAP之类的,自动寻路之类的。我要说但是了,实在时间不太多(懒的另一种说法),基本除了在学习就是学习(这个是真的),其余时间睡觉了。我属于死宅那种……
我到现在游戏开发工作满打满算才两年,实际上也是个新手,说是啥也不会也不为过。最开始走了不少弯路,最近半年对shader比较感兴趣,所以不务正业玩了很久的shader,我对写代码感兴趣,所以不爱玩连连看,连连看也就了解的比较少吧。这个工程呢,下面我贴出来就行了,本来想自己写个demo玩的,但是美术资源不好找,最近又有新的学习目标,就搁浅了。过段时间和约好的三个大佬(一个地编,一个特效,一个前端主程),正在忽悠一个原画小哥,打算抽空忽悠一个模型过来,人凑齐了可能会一起做个小游戏玩吧。

工程里里面超了几个sahder代码,挺简单但是蛮好玩的。我就不删除了。
链接: https://pan.baidu.com/s/1qS0neCerO0FJ2sVK_tGYWQ 密码: vpdu

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity游戏中,MVC框架可以帮助我们更好地管理UI。MVC是一种将代码的功能进行划分的设计框架,主要原理是将软件用户界面和业务逻辑分离,提高代码的可扩展性、可复用性、可维护性和灵活性。 在Unity中,我们可以将MVC框架应用到游戏UI设计中。举个例子来说,当游戏要发布节日活动,并且需要相应地更改游戏UI时,使用MVC框架可以将UI的功能分开,达到低耦合的效果。这样,当替换UI时,其他功能不会受到影响,提高游戏的质量。 在Unity开发过程中,许多公司都使用了MVC的逻辑模式,即数据模型-视图-控制器。数据模型负责存储和管理游戏数据,视图负责显示用户界面,而控制器负责处理用户输入和更新数据模型。通过将这些功能分离,我们可以更好地组织和管理UI代码,提高开发效率。 所以,通过应用MVC框架,我们可以更好地管理Unity游戏UI,提高代码的可维护性和可扩展性,同时也能提高游戏的质量和用户体验。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【Unity3D日常开发Unity3d中使用MVC框架](https://blog.csdn.net/q764424567/article/details/83788696)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Unity框架——MVC框架](https://blog.csdn.net/Htlas/article/details/79076201)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值