ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Unity中的对象引用-如何在脚本之间通信

2022-03-29 13:00:27  阅读:198  来源: 互联网

标签:脚本 void UnitFactory List private Unity 引用 public Unit


事先声明

  • 我们有一个单元管理节点(包含Transform和UnitFactory组件)和一个Unit预制体节点(包含Transform和Unit组件)
  • 要完成对实例化Unit预制体节点中Unit组件的获取

如果你是新游戏开发者那么你可能会通过以下代码实现

using UnityEngine;

public class UnitFactory : MonoBehaviour
{
    [SerializeField] private GameObject _unitPrefab;

    private GameObject _unitControler;
    private Unit _unitInstance;

    private void Start()
    {
        _unitControler = Instantiate(_unitPrefab);
        _unitInstance = _unitControler.GetComponent<Unit>();
    }
}

但是这样实现方式是慢的,尽管现在计算机运算速度很快,但我还是推荐你用下面这种方法

using UnityEngine;

public class UnitFactory : MonoBehaviour
{
    [SerializeField] private Unit _unitPrefab;

    private Unit _unitInstance;

    private void Start()
    {
        _unitInstance = Instantiate(_unitPrefab);
    }
}

只要脚本上继承自MonoBehaviour那么都是可以通过这种方法来获取组件的

如果我们在此基础上对更多单位进行管理,那么我们可以:
在UnitManager类中添加一个私有列表

    private List<Unit> _units = new List<Unit>();

注意:我们并没有引入List的命名空间,所以要在UnitManager脚本顶部加上:

using System.Collections.Generic;

然后我们在UnitFactory.Start函数中为List添加一些单位对象

    for (int i = 0; i < 10; i++)
    {
        _units.Add(Instantiate(_unitPrefab));
    }

假设我们想对单位位置进行实时控制,那么我们可以中UnitFactory.Update函数中加入

    foreach (var unit in _units)
    {
        unit.transform.position = Random.insideUnitSphere;
    }

嗯现在就很好,那么如果我们想在新脚本MapManager.cs中获取这些列表并且出于任何原因更改单元对象的位置,我们要做什么?

  • 在Hierarchy窗口中新建一个空对象,并且为它添加MapManager脚本

如果是这样的话很多东西都想访问,我们可以把UnitFactory变为静态单例
在UnitFactory中添加以下代码

    public static UnitFactory Instance;

    private void Awake() => Instance = this;

并且修改_units访问级别并修改名称为Units

    public List<Unit> Units = new List<Unit>();

如果你想保留_units原有数据可以把上面的代码修改为

    [FormerlySerializedAs("_units")]
    public List<Unit> Units = new List<Unit>();
//这一行引用必须要加否则会报错[FormerlySerializedAs("_units")]特性不存在
using UnityEngine.Serialization;

然后在MapManager中添加以下代码:

using UnityEngine;

public class MapManager : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        foreach (var unit in UnitFactory.Instance.Units)
        {
            unit.transform.position = Random.insideUnitSphere;
        }
    }
}

当然我们还可以为了不让UnitFactory.Instance.Units不让外部脚本设置它,只是获取,那么
我们可以把UnitFactory中的Units字段修改为属性的形式

public List<Unit> Units { get; private set; } = new List<Unit>();

另外我们通常写碰撞函数为了检测碰撞对象是否有Unit脚本

using UnityEngine;

public class Unit : MonoBehaviour
{
    private void OnCollisionEnter(Collision other)
    {
        var unit = other.gameObject.GetComponent<Unit>();
        if (unit != null)
        {
            //Do something.
        }
    }
}

我更推荐大家像下面这样做

using UnityEngine;

public class Unit : MonoBehaviour
{
    private void OnCollisionEnter(Collision other)
    {
        Unit unit;
        if (other.gameObject.TryGetComponent(out unit))
        {
            //Do something.
        }
    }
}

千万不要像下面这样调用对象中所有对应函数,这是非常不推荐的做法,影响性能

using UnityEngine;

public class Unit : MonoBehaviour
{
    public void Example(int i){}

    private void OnCollisionEnter(Collision other)
    {
        other.gameObject.SendMessage("Example", 10);
    }
}

今天的感悟就写到这里了,bye~

标签:脚本,void,UnitFactory,List,private,Unity,引用,public,Unit
来源: https://www.cnblogs.com/godshadow/p/16071153.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有