【组件初始化链条】简化Unity组件的初始化

简介

在游戏脚本中我们通过借助GetComponent或TryGetComponent方法获取组件,所以当需要获取较多组件时,我们不可避免地要书写一些重复代码,为了提升代码简洁程度,简化组件初始化逻辑,本文以"组件初始化链条"为核心探索组件的初始化。

我们对于组件初始化面临以下几个问题:

1.当需要从同一个游戏对象上获取不同组件时,如何简化?

2.当获取组件时还需要对组件进行初始化或者获取组件的字段或属性,如何简化?

3.当需要从多个游戏对象上获取相同类型组件时,如何简化?

事实上,组件获取的逻辑大同小异,主要依赖于GetComponent或TryGetComponent方法,所以我们只需要关注从哪个GameObject 上获取哪个Component 即可,如果涉及到对组件进行一些自定义的处理,我们则可以借助委托类型的参数。除此之外,对于当前脚本而言,所需要的组件往往是必要的,缺一不可,所以我们仅关注所有组件是否被正确初始化,通过"组件初始化链条"则可以获取一个总的初始化结果值,如果需要自定义初始化结果值的收集可以自行改进本文代码。

相较于手动初始化,我们需要重复书写GetComponent或TryGetComponent方法的调用,并且需要手动对每个组件的初始化结果值进行收集,这并不利于开发者专注于游戏逻辑的开发。

采用统一的组件初始化方式,有利于团队协作,提升整体开发效率,方便组件初始化相关Bug的检测和处理。

代码示例

ComponentInitChain.cs

cs 复制代码
using System;
using UnityEngine;

/// <summary>
/// 组件初始化链条
/// </summary>
public class ComponentInitChain
{
    private GameObject gameObject;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="gameObject">组件所挂载的游戏对象</param>
    public ComponentInitChain(GameObject gameObject)
    {
        this.gameObject = gameObject;
    }

    /// <summary>
    /// 初始化组件
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <param name="component">组件的引用变量</param>
    /// <returns>当前组件初始化链条实例</returns>
    public ComponentInitChain InitComponent<T>(out T component) where T : Component
    {
        if (gameObject == null || !gameObject.TryGetComponent(out component)) component = null;
        return this;
    }

    /// <summary>
    /// 初始化组件
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <param name="component">组件的引用变量</param>
    /// <param name="componentDeal">组件获取后的初始化处理</param>
    /// <returns>当前组件初始化链条实例</returns>
    public ComponentInitChain InitComponent<T>(out T component, Action<T> componentDeal) where T : Component
    {
        if (gameObject == null || !gameObject.TryGetComponent(out component)) component = null;
        if (component != null) componentDeal(component);
        return this;
    }

    /// <summary>
    /// 初始化组件
    /// </summary>
    /// <typeparam name="T0">组件类型0</typeparam>
    /// <typeparam name="T1">组件类型1</typeparam>
    /// <param name="component">T0类型组件的引用变量</param>
    /// <param name="component1">T1类型组件的引用变量</param>
    /// <returns>初始化结果值,组件均正确初始化则返回true,否则返回false</returns>
    public bool InitComponent<T0, T1>(out T0 component, out T1 component1) where T0 : Component where T1 : Component
    {
        InitComponent(out component).InitComponent(out component1);
        if (component == null || component1 == null) return false;
        return true;
    }

    /// <summary>
    /// 初始化组件
    /// </summary>
    /// <typeparam name="T0">组件类型0</typeparam>
    /// <typeparam name="T1">组件类型1</typeparam>
    /// <typeparam name="T2">组件类型2</typeparam>
    /// <param name="component">T0类型组件的引用变量</param>
    /// <param name="component1">T1类型组件的引用变量</param>
    /// <param name="component2">T2类型组件的引用变量</param>
    /// <returns>初始化结果值,组件均正确初始化则返回true,否则返回false</returns>
    public bool InitComponent<T0, T1, T2>(out T0 component, out T1 component1, out T2 component2)
    where T0 : Component where T1 : Component where T2 : Component
    {
        InitComponent(out component).InitComponent(out component1).InitComponent(out component2);
        if (component == null || component1 == null || component2 == null) return false;
        return true;
    }

    /// <summary>
    /// 初始化组件
    /// </summary>
    /// <typeparam name="T0">组件类型0</typeparam>
    /// <typeparam name="T1">组件类型1</typeparam>
    /// <typeparam name="T2">组件类型2</typeparam>
    /// <typeparam name="T3">组件类型3</typeparam>
    /// <param name="component">T0类型组件的引用变量</param>
    /// <param name="component1">T1类型组件的引用变量</param>
    /// <param name="component2">T2类型组件的引用变量</param>
    /// <param name="component3">T3类型组件的引用变量</param>
    /// <returns>初始化结果值,组件均正确初始化则返回true,否则返回false</returns>
    public bool InitComponent<T0, T1, T2, T3>(out T0 component, out T1 component1, out T2 component2, out T3 component3)
    where T0 : Component where T1 : Component where T2 : Component where T3 : Component
    {
        InitComponent(out component).InitComponent(out component1).InitComponent(out component2).InitComponent(out component3);
        if (component == null || component1 == null || component2 == null || component3 == null) return false;
        return true;
    }
}

ComponentsInitChain.cs

cs 复制代码
using System.Linq;
using UnityEngine;

/// <summary>
/// 组成集初始化链条
/// </summary>
public class ComponentsInitChain
{
    /// <summary>
    /// 初始化组件集
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <param name="components">组件集的引用变量</param>
    /// <param name="gameObjects">组件所挂载的游戏对象集</param>
    /// <returns>组件集初始化结果值,若所有组件成功初始化则返回true,否则返回false</returns>
    public static bool InitComponents<T>(in T[] components, params GameObject[] gameObjects) where T : Component
    {
        if (components == null || components.Length == 0) return false;
        if (gameObjects == null || gameObjects.Length == 0) return false;
        if (components.Length == gameObjects.Length)
        {
            for (int i = 0; i < gameObjects.Length; i++)
            {
                components[i] = gameObjects[i].GetComponent<T>();
            }
            return components.All(c => c != null);
        }
        return false;
    }

    /// <summary>
    /// 初始化组件集
    /// </summary>
    /// <typeparam name="T0">组件类型0</typeparam>
    /// <typeparam name="T1">组件类型1</typeparam>
    /// <param name="component">T0类型组件的引用变量</param>
    /// <param name="component1">T1类型组件的引用变量</param>
    /// <param name="gameObjects">T0、T1类型组件所挂载的游戏对象</param>
    /// <returns>组件初始化结果值,若所有组件成功初始化则返回true,否则返回false</returns>
    public static bool InitComponents<T0, T1>(out T0 component, out T1 component1, params GameObject[] gameObjects)
    where T0 : Component where T1 : Component
    {
        component = null;
        component1 = null;
        if (gameObjects?.Length == 2)
        {
            component = gameObjects[0].GetComponent<T0>();
            component1 = gameObjects[1].GetComponent<T1>();
        }
        return component != null && component1 != null;
    }

    /// <summary>
    /// 初始化组件集
    /// </summary>
    /// <typeparam name="T0">组件类型0</typeparam>
    /// <typeparam name="T1">组件类型1</typeparam>
    /// <typeparam name="T2">组件类型2</typeparam>
    /// <param name="component">T0类型组件的引用变量</param>
    /// <param name="component1">T1类型组件的引用变量</param>
    /// <param name="component2">T2类型组件的引用变量</param>
    /// <param name="gameObjects">T0、T1、T2类型组件所挂载的游戏对象</param>
    /// <returns>组件初始化结果值,若所有组件成功初始化则返回true,否则返回false</returns>
    public static bool InitComponents<T0, T1, T2>(out T0 component, out T1 component1, out T2 component2, params GameObject[] gameObjects)
    where T0 : Component where T1 : Component where T2 : Component
    {
        component = null;
        component1 = null;
        component2 = null;
        if (gameObjects?.Length == 3)
        {
            component = gameObjects[0].GetComponent<T0>();
            component1 = gameObjects[1].GetComponent<T1>();
            component2 = gameObjects[2].GetComponent<T2>();
        }
        return component != null && component1 != null && component2 != null;
    }

    /// <summary>
    /// 初始化组件集
    /// </summary>
    /// <typeparam name="T0">组件类型0</typeparam>
    /// <typeparam name="T1">组件类型1</typeparam>
    /// <typeparam name="T2">组件类型2</typeparam>
    /// <typeparam name="T3">组件类型3</typeparam>
    /// <param name="component">T0类型组件的引用变量</param>
    /// <param name="component1">T1类型组件的引用变量</param>
    /// <param name="component2">T2类型组件的引用变量</param>
    /// <param name="component3">T3类型组件的引用变量</param>
    /// <param name="gameObjects">T0、T1、T2、T3类型组件所挂载的游戏对象</param>
    /// <returns>组件初始化结果值,若所有组件成功初始化则返回true,否则返回false</returns>
    public static bool InitComponents<T0, T1, T2, T3>(out T0 component, out T1 component1, out T2 component2, out T3 component3, params GameObject[] gameObjects)
    where T0 : Component where T1 : Component where T2 : Component where T3 : Component
    {
        component = null;
        component1 = null;
        component2 = null;
        component3 = null;
        if (gameObjects?.Length == 4)
        {
            component = gameObjects[0].GetComponent<T0>();
            component1 = gameObjects[1].GetComponent<T1>();
            component2 = gameObjects[2].GetComponent<T2>();
            component3 = gameObjects[3].GetComponent<T3>();
        }
        return component != null && component1 != null && component2 != null && component3 != null;
    }
}

测试代码

cs 复制代码
using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject[] GameObjects;
    private AudioListener audioListener;
    private SpriteRenderer spriteRenderer;
    private CircleCollider2D circleCollider2D;
    private Room[] rooms;
    private Room a;
    private Room b;
    private Room c;
    private Room d;
    private Sprite sprite;

    private void Awake()
    {
        // 组件链式初始化,适用于该情景"需要获取同一个游戏对象上较多的组件且针对不同组件存在不同的初始化逻辑"
        // new ComponentInitChain(gameObject).InitComponent(out audioListener)
        // .InitComponent(out spriteRenderer, c => sprite = c.sprite)
        // .InitComponent(out circleCollider2D, c => c.isTrigger = true);

        // 组件单步初始化,适用于该情景"需要获取同一个游戏对象上较少的组件,不需要对各组件的初始化进行代理"
        // bool res = new ComponentInitChain(gameObject).InitComponent(out audioListener, out spriteRenderer, out circleCollider2D);
        // Debug.Log(res);
        // Debug.Log(audioListener);
        // Debug.Log(spriteRenderer);
        // Debug.Log(circleCollider2D);

        // 获取不同游戏对象上的某种组件类型的组件合集
        // rooms = new Room[GameObjects.Length];
        // bool res = ComponentsInitChain.InitComponents(rooms, GameObjects);
        // Debug.Log(res);
        // for (int i = 0; i < rooms?.Length; i++)
        // {
        //     Debug.Log(rooms[i]);
        // }

        // 获取不同游戏对象上的相同类型组件
        // bool res = ComponentsInitChain.InitComponents(out a, out b, out c, out d, GameObjects);
        // Debug.Log(res);
        // Debug.Log(a);
        // Debug.Log(b);
        // Debug.Log(c);
        // Debug.Log(d);
    }
}

代码说明

ComponentInitChain适用于对单个游戏对象的组件进行初始化的情景,所以在实例化时需要传递对应的游戏对象,后续的组件初始化操作都针对该游戏对象。

ComponentsInitChain适用于对多个游戏对象的组件进行初始化的情景,相关方法都属于静态方法,所以调用方法时需要传递游戏对象。

测试代码中则针对四种常见的应用情况进行举例。

如果这篇文章对你有帮助,请给作者点个赞吧!

相关推荐
向宇it13 分钟前
【从零开始入门unity游戏开发之——C#篇30】C#常用泛型数据结构类——list<T>列表、`List<T>` 和数组 (`T[]`) 的选择
java·开发语言·数据结构·unity·c#·游戏引擎·list
keep-learner13 分钟前
Unity Dots理论学习-2.ECS有关的模块(1)
学习·unity·游戏引擎
虾球xz44 分钟前
游戏引擎学习第62天
学习·游戏引擎
唐沢5 小时前
Unity 读Excel,读取xlsx文件解决方案
unity·excel
虾球xz8 小时前
游戏引擎学习第61天
java·学习·游戏引擎
两水先木示12 小时前
【Unity3D】Jobs、Burst并行计算裁剪Texture3D物体
unity·jobs·burst
Thomas_YXQ18 小时前
Unity3D Huatuo技术原理剖析详解
unity·unity3d·游戏开发·性能调优·热更新
火云洞红孩儿20 小时前
基于AI IDE 打造快速化的游戏LUA脚本的生成系统
c++·人工智能·inscode·游戏引擎·lua·游戏开发·脚本系统
虾球xz21 小时前
游戏引擎学习第59天
学习·游戏引擎
zh路西法21 小时前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(二):从FSM开始的2D游戏角色操控底层源码编写
c++·游戏·unity·设计模式·状态模式