同事看了我的代码惊呼:居然是这么在Unity中用单例的

简介: 今天,同事问我:“在Unity中怎么用单例呀”然后我就把我写的代码甩过去了。同事:“哦,原来是这么用的,你来给我演示一下吧”

❤  一、前言

今天,同事问我:“在Unity中怎么用单例呀”

然后我就把我写的代码甩过去了。

同事:“哦,原来是这么用的,你来给我演示一下吧”


❤  二、单例模式介绍

首先要了解,单例模式是一种常用的软件设计模式,定义是单例对象的类只能允许一个实例存在,在许多时候整个系统只需要拥有一个全局对象,有利于协调系统整体的行为。

比如,服务器程序,将配置信息存放到一个文件中,然后使用一个单例对象进行读取,其他服务进程中的其他对象再通过这个单例去获取这些配置信息,简化了配置管理。

单例模式的结构图如下图所示:

网络异常,图片无法展示
|
那么,单例模式在Unity中又有那些应用场景呢:

1、在使用Unity开发项目的时候,经常会遇到需要一个管理类来管理一些全局的变量和方法,比如GameManager用于记录各种需要在整个游戏中用到数据。

2、一些需要从外部文档读取的数据,在其他脚本对象也需要用到的使用,也可以使用单例对象进行读取,其他对象再通过这个单例对象去获取数据。

假设有以下需求:

1、整个项目中有且只有一个DataManager单例对象 2、在DataManager单例对象中,需要去读取文档的数据,并且保存下载 3、在切换场景的时候DataManager对象不能被销毁 4、在不同的脚本中可以读取到DataManager单例对象读取的值

下面我们就来一步步实现单例对象下的DataManager。


❤  三、实现单例模式的DataManager

❤  3-1、定义单例对象

我们定义一个DataManager对象,继承于MonoBehaviour,具体代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DataManager : MonoBehaviour
{
    public static DataManager Instance;
    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}
复制代码

1、使用静态的DataManager属性Instance保证了它可以通过类进行访问,而不是通过实例化访问 2、继承MonoBehaviour类的实例是由Unity进行创建,不能通过构造函数创建 3、在Awake函数里面对Instance进行赋值,保证了这个属性可以第一时间初始化 4、使用DontDestroyOnLoad可以使这个挂载脚本的游戏对象在切换场景中也不会被销毁 5、DontDestroyOnLoad的参数使用(gameObject),这样切换场景中游戏对象不会被销毁,使用this只能保证当前脚本不会被销毁,但是对象销毁了,这个脚本也没有了。

创建完这个对象,在场景中也新建一个DataManager对象,将这个脚本拖到这个对象上:

网络异常,图片无法展示
|

❤  3-2、单例对象去读取数据保存下来

代码如下:

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class DataManager : MonoBehaviour
{
    public static DataManager Instance;
    string m_JsonContent;//临时文档数据
    RootData m_JsonData;//临时接收JSON解析数据
    //数据保存到这个List里面,其他脚本就可以调用到了
    public List<StationAllInfo> m_StationsAllInfo = new List<StationAllInfo>();
    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
    private void Start()
    {
        ReadJSONData();
    }
    void ReadJSONData()
    {
        string pathstations = Application.streamingAssetsPath + "/地铁站.json";
        using (StreamReader SR = new StreamReader(pathstations))
        {
            m_JsonContent = SR.ReadToEnd();
            Debug.Log(m_JsonContent);
            SR.Close();
            SR.Dispose();
            //保存JSON数据
            m_JsonData = JsonUtility.FromJson<RootData>(m_JsonContent);
        }
        for (int i = 0; i < m_JsonData.GisJosnDatas.Count; i++)
        {
            if (m_JsonData.GisJosnDatas[i].properties.LINE_ID != "")//剔除无用的信息,保存有用的信息
            {
                StationAllInfo item = new StationAllInfo();
                item.X = m_JsonData.GisJosnDatas[i].properties.X;
                item.Y = m_JsonData.GisJosnDatas[i].properties.Y;
                item.STACODE = m_JsonData.GisJosnDatas[i].properties.STACODE;
                item.S_NAME = m_JsonData.GisJosnDatas[i].properties.S_NAME;
                item.LINE_ID = m_JsonData.GisJosnDatas[i].properties.LINE_ID;
                //05 换成 5 (比如05号线 换成5号线)
                if (m_JsonData.GisJosnDatas[i].properties.LINE_ID.Substring(0, 1) == "0")
                {
                    item.LINE_NAME = m_JsonData.GisJosnDatas[i].properties.LINE_ID.Substring(1, 1) + "号线";
                }
                else
                {
                    switch (m_JsonData.GisJosnDatas[i].properties.LINE_ID)//对字母缩写的站名进行处理
                    {
                        case "fs":
                            item.LINE_NAME = "房山线";
                            break;
                        case "bt":
                            item.LINE_NAME = "八通线";
                            break;
                        case "yz":
                            item.LINE_NAME = "亦庄线";
                            break;
                        case "cp":
                            item.LINE_NAME = "昌平线";
                            break;
                        case "jc":
                            item.LINE_NAME = "机场线";
                            break;
                        default:
                            item.LINE_NAME = m_JsonData.GisJosnDatas[i].properties.LINE_ID + "号线";
                            break;
                    }
                }
                item.STYPE = m_JsonData.GisJosnDatas[i].properties.STYPE;
                m_StationsAllInfo.Add(item);
            }
        }
    }
}
复制代码

❤  3-3、在其他脚本中使用数据

我们新建一个UseData.cs脚本去使用数据:

using UnityEngine;
public class UseData : MonoBehaviour
{
    private void Update()
    {
        //点击键盘W 显示数据
        if (Input.GetKeyDown(KeyCode.W))
        {
            ShowData();
        }
    }
    private void ShowData()
    {
        for (int i = 0; i < DataManager.Instance.m_StationsAllInfo.Count; i++)
        {
            Debug.Log(DataManager.Instance.m_StationsAllInfo[i].X + " "
                +DataManager.Instance.m_StationsAllInfo[i].Y + " "
                + DataManager.Instance.m_StationsAllInfo[i].STACODE + " "
                + DataManager.Instance.m_StationsAllInfo[i].S_NAME + " "
                + DataManager.Instance.m_StationsAllInfo[i].LINE_ID + " "
                + DataManager.Instance.m_StationsAllInfo[i].LINE_NAME + " "
                + DataManager.Instance.m_StationsAllInfo[i].STYPE + " ");
        }
    }
}
复制代码

将这个脚本拖到场景中的对象上:

网络异常,图片无法展示
|

运行程序,敲击键盘W:

网络异常,图片无法展示
|

所有的值,都从单例对象DataManager的InStance的m_StationsAllInfo数组中读取出来了。

❤  3-4、切换场景读取数据

我们新建两个场景:Index和Next,然后Index场景中的对象上挂载脚本ChangeScenes.cs脚本,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class ChangeScenes : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
    }
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            SceneManager.LoadScene(1);
        }
    }
}
复制代码

也就是切换场景,然后在Index场景中新建一个DataManager对象,将DataManager脚本拖上去。

然后Next场景中随便找一个对象挂载UseData脚本,场景中不需要创建DataManager对象

然后将两个场景加到Build Setting中:

网络异常,图片无法展示
|

运行程序:

切换到Next场景,DataManager对象也存在:

网络异常,图片无法展示
|

敲击键盘W:

网络异常,图片无法展示
|

所有的值,都从上一个场景中的DataManager对象的挂载脚本的单例对象DataManager.cs的InStance的m_StationsAllInfo数组中读取出来了。


❤  四、后言

这是Unity使用单例的简单应用,最主要的几个知识点是;

1、对象切换场景不销毁

2、单例对象的静态属性

3、数据的保存

4、其他脚本用单例对象的数据的方法

结束,好好学习加油吧!



相关文章
|
6月前
|
存储 人工智能 C#
【Unity 3D】C#中数组、集合、栈、队列、哈希表、字典的讲解(附测试代码)
【Unity 3D】C#中数组、集合、栈、队列、哈希表、字典的讲解(附测试代码)
81 0
|
3月前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
72 1
|
3月前
|
图形学
小功能⭐️Unity UnityEvent实现代码的选择
小功能⭐️Unity UnityEvent实现代码的选择
|
3月前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
113 0
|
3月前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
80 0
|
3月前
|
图形学 开发者
【Unity光照艺术手册】掌握这些技巧,让你的游戏场景瞬间提升档次:从基础光源到全局光照,打造24小时不间断的视觉盛宴——如何运用代码与烘焙创造逼真光影效果全解析
【8月更文挑战第31天】在Unity中,合理的光照与阴影设置对于打造逼真环境至关重要。本文介绍Unity支持的多种光源类型,如定向光、点光源、聚光灯等,并通过具体示例展示如何使用着色器和脚本控制光照强度,模拟不同时间段的光照变化。此外,还介绍了动态和静态阴影、全局光照及光照探针等高级功能,帮助开发者创造丰富多样的光影效果,提升游戏沉浸感。
66 0
|
3月前
|
开发者 图形学 UED
深度解析Unity游戏开发中的性能瓶颈与优化方案:从资源管理到代码执行,全方位提升你的游戏流畅度,让玩家体验飞跃性的顺滑——不止是技巧,更是艺术的追求
【8月更文挑战第31天】《Unity性能优化实战:让你的游戏流畅如飞》详细介绍了Unity游戏性能优化的关键技巧,涵盖资源管理、代码优化、场景管理和内存管理等方面。通过具体示例,如纹理打包、异步加载、协程使用及LOD技术,帮助开发者打造高效流畅的游戏体验。文中提供了实用代码片段,助力减少内存消耗、提升渲染效率,确保游戏运行丝滑顺畅。性能优化是一个持续过程,需不断测试调整以达最佳效果。
90 0
|
3月前
|
图形学
小功能⭐️Unity改变代码执行顺序
小功能⭐️Unity改变代码执行顺序
|
5月前
|
图形学
【unity小技巧】unity通过代码进行更改后处理效果
【unity小技巧】unity通过代码进行更改后处理效果
65 0
|
5月前
|
图形学
【unity小技巧】手戳代码程序化绘制地形Terrain树和预制体物品、动物
【unity小技巧】手戳代码程序化绘制地形Terrain树和预制体物品、动物
50 0