Entity学习文档

Entity

请大家关注一下我的微博 @NormanLin_BadPixel坏像素


一般来说,一个类的名字就能大概知道这个类是干啥的,比如ObjectEvent,很容易就知道是跟事件相关的。再来看我们今天要学的Entity,意思是实体。有经验的人应该对Entity不陌生(就连我都不陌生了)。这里希望不知道MVC框架的同学先去看一下MVC框架的介绍。我之前也只是了解了一下,也没有深入学习,也没有真正应用过。Unity3d之MVC框架的使用

那这个Entity就是用了MVC框架设计吗? 不是的,这里只是想引出一个概念,就是数据跟模型的分开管理。

flashyiyi : MVC是UI专用的模式,适用于横向铺量的项目。游戏(非UI部分)显然不是这样的项目。

这个Entity,就是数据。(我猜的哈哈)

使用BsonKnownTypes 属性指定已知类型,以便在将内容反序列化为对象时创建正确的类型。

不知道为什么要这样写。

可见这个类继承了Disposer,实现了ISupportInitialize接口

public interface ISupportInitialize
    {
        void BeginInit();
        void EndInit();
    }

接下来我们看到

private HashSet<Component> components;

之前没用过HashSet,就去百度了一下。发现HashSet是一个很有趣的类型,它不支持通过下标或者键来获取值,但是它在判断是否存在某个值上很快,对集合的运算也很快。但是我并没有发现哪里用到了这些特点。这里又出现了新的东西,那就是Component

Component

关于前面序列化的设置,我不是很理解。

接下来的很好理解,我希望大家自己能看懂。

值的一提的是,每个Entity里面都含有好多Component,而每个Component都有一个Entity。我想,Component的Entity应该是记录自己所属的实体。

顺便说一下,这里

public override void Dispose()
        {
            if (this.Id == 0)
            {
                return;
            }

            base.Dispose();

            this.Entity?.RemoveComponent(this.GetType());
        }

?. 是空条件运算符

空条件运算符:在之前的版本中对于 可空类型 或 动态类型 ,获取子元素往往较为复杂:

if(someSchool != null && someSchool.someGrade != null && someSchool.someGrade.someClass != null)
{
    return someSchool.someGrade.someClass.someOne;
}

在 C# 6 中,引入了新的运算符

return someSchool?.someGrade?.someClass?.someOne;
//也可以使用下标运算,例如
//return someArray?[0];

如果 ?. 运算符的左项为 null ,则直接返回 null 。对于方法或者委托的执行,可以使用 Invoke:someMethod?.Invoke(args);

作者:Trotyl Yu
链接:https://www.zhihu.com/question/27421302/answer/36589976
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这里的Component只是一个基类,之后我们再通过它的子类来具体了解一下这个类。

Entity

private Dictionary<Type, Component> componentDict = new Dictionary<Type, Component>();

回到Entity,我们又看到了一个字典,通过Type为键值储存了Component,现在这个componentDict和之前的components都有什么用我们后面揭晓

protected Entity()
{
    this.Id = IdGenerater.GenerateId();
}

这个IdGenerater应该是自动生成一个独一无二ID的工具。用来标识场景里的实体。
后面则是一个有指定ID的构造方法。

这里重写了Dispose方法,多实现了对自己所有的组件的处理。

foreach (Component component in this.GetComponents())
            {
                try
                {
                    component.Dispose();
                }
                catch (Exception e)
                {
                    Log.Error(e.ToString());
                }
            }
public K AddComponent<K>() where K : Component, new()

这是一个添加组件的方法,之后的几个只是多了几个参数。

K component = ComponentFactory.Create<K>(this);

这里不难猜出这只是一个组件工厂,提供创建组件的方法。里面应该有用对象池来进行管理。

public static T Create<T>(Entity entity) where T : Component
        {
            T disposer = ObjectPool.Instance.Fetch<T>();
            disposer.Entity = entity;
            ObjectEvents.Instance.Awake(disposer);
            return disposer;
        }

不出所料。另外在创建组件的时候,调用 ObjectEvents.Instance.Awake(disposer); 我们之前学过,这个方法会在ObjectEvents里调用disposer所实现的IAwake接口(如果有的话)

这里把组件加入Entity,组件会被存放在componentDict里面,如果组件是ComponentDB类型的,则会额外放入components,这是什么用?我也不是很清楚。不过CompoenntDB是通过Bson反序列化来的,可能是为了区分吗?之后再看看。

public void RemoveComponent<K>() where K : Component
public void RemoveComponent(Type type)

这两个则是移除组件的方法,第一个是直接指定一个Component来移除,第二个则是通过组件的Type来移除。但我们仔细看代码,其实第一个只是通过指定的Component来获取到指定的Type再来通过Type来移除。所以第一个方法可以改成:

public void RemoveComponent<K>() where K : Component
        {
            RemoveComponent(typeof(K));
        }

我猜的。如果作者有什么深意我就不知道了。

这里值得一提的是,在移除组件的时候,我们调用了component的Dispose方法。这里结合我们之前ObjectEvents的学习,我们知道,到这里component的Id才变成0,也就是说,如果component里面有Update的方法,则Update方法会在Component存在的时候随ObjectEvents的Update而调用。不过ObjectEvents应该不会直接调用Component,而是先通知Entity,再由Entity来调用Component。其实跟Unity自带的Update一样,只不过作者自己实现了一套,牛逼。这在网络同步上特别是帧同步上是很重要的。

后面的两个获取实体上的组件方法我就不多说了,大家自己看看就明白了。

public virtual void BeginInit()
public virtual void EndInit()

这就是 ISupportInitialize 需要实现的接口了。这个接口应该会在哪个地方统一调用,来统一管理需要初始化的东西。我们用Shift+F12来看看哪里掉用了,发现在ConfigComponent里调用了,另外还在BsonClassMapSerializer里面看到了。第一个看起来简单点,我们后面应该会讲到,但是第二个太长了,还是在Plugins里面的,这个水平不是现在的我能够窥视的,我只能猜了。既然这是Bson序列化反序列化的东西,那我们就姑且当它是在把数据反序列化成对象的时候调用的就行了。这样一想,就简单多了,连前面components和componentDict有什么区别都解决了。

因为我们序列化的时候,可能储存了一个实体的所有component信息,当反序列化的时候,components里放的就是我们储存好的component信息,会在EndInit这里把本有的component加入到componentDict里面。


至此,我们讲完了Entity顺便讲了它和Component的关系。大家可以继续回到最初的地方接着学习了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值