Entitas学习二 —— Entitas 入门

2024-02-14 01:18
文章标签 学习 入门 entitas

本文主要是介绍Entitas学习二 —— Entitas 入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. Entity(实体)、Component(组件)、System(系统)间的关系

如果你觉得想尽快看到HelloWorld,那就直接从第2步开始,然后再回来看这一步吧。

这里简单介绍ECS三者之间的关系。

 

Entity,即实体,显然,它是一个实质的带有功能的对象,但它又不仅限于角色、怪物这些实体。

因为,在Entitas中,就连鼠标点击产生的事件也作为实体。

 

组件就是一些零散的功能点,如:坐标、武器、攻击力等。

实体就是这些组件的载体,把部分组件组合起来。

 

比如,我有以下的组件:图片、攻击力、武器。

这些是零散的东西,总得有个角色把它们组合起来吧?所以,这个角色就是实体。

而组件是千奇百怪的,比如:坐标。

在产生点击事件的时候,得有个实体把坐标给组合起来,那么,就有个“点击事件实体”的东西了。

 

至于System(系统),可以理解为Controller(控制器),用来控制实体逻辑的。

不理解没关系,看完这篇的HelloWorld大家就明白了。

2. 创建Component(组件)

好吧,我们开始。

Entitas的基本思想就是,把实体和它的属性完全分开,以组件的形式组合这些属性。

 

我们从创建组件开始一步步走向HelloWorld吧。

创建一个DebugMessageComponent.cs文件,代码目录结构就随意了,只是学习而已。

using Entitas;[Game]
public class DebugMessageComponent : IComponent 
{    public string message;
}

注意两个地方,一个是给类加上一个[Game]特性,从目前我所理解的情况来看,这个Game的特性代表了这个组件是属于一个叫做GameEntity的实体。

这个组件叫做调试信息,拥有这个组件的实体就代码它拥有了调试信息这个属性。

3.自动生成Entity(实体)

Entitas会自动帮我们根据组件生成实体,我们是不需要在实体的创建上花费太多心思的。

现在,回到IDE,依次选择【Tools】-【Jenny】-【Generate】:

你会看到项目下多了一个GameDebugMessageComponent文件(Generated目录下都是自动生成的文件,不要去修改它们):

该文件里包含两个类:GameEntity和GameMather。

 

如之前所说,我们给组件赋予了[Game] 特性,所以它会帮我们生成GameEntity实体(的一部分)。

如果你仔细看的话,会发现,GameEntity是用partial定义的,也就是说,它是一个分部类。

 

什么是分部类?就是把一个类拆分为多个部分,在不同的地方定义。

并没有什么特别的,只是方便我们做不同的处理,比如在不同的文件里定义同一个类,这个文件定义一些属性,那个文件定义一些函数等待。

 

而Entitas会根据不同的组件生成多个实体的分部类,每个分部类里只定义一个组件的相关操作,这是Entitas的特点之一。

至于GameMatcher,是用来筛选实体的,这里暂时不多说。

4. 创建“控制器”——System(系统)

对于Entitas,组件只是定义一些属性,实体是自动生成的,而我们要做的事情大部分都在System里。

现在,我们来创建一个新的C#文件,命名为:DebugMessageSystem.cs

 

其内容如下:

using System.Collections.Generic;
using Entitas;
using UnityEngine;public class DebugMessageSystem : ReactiveSystem<GameEntity>
{public DebugMessageSystem(Contexts contexts) : base(contexts.game){}protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context){// 该控制器只关心含有DebugMessage组件的实体 return context.CreateCollector(GameMatcher.DebugMessage);}protected override bool Filter(GameEntity entity){// 只有hasDebugMessage为true的实体才会触发下面的Execute函数return entity.hasDebugMessage;}protected override void Execute(List<GameEntity> entities){// 满足GetTrigger和Filter的实体保存在entities列表里foreach (var e in entities){ // 打印信息Debug.Log(e.debugMessage.message);}}
}

这个System比较关键,我分步解释一下:

  • a 通常情况下,我们的System类都要继承ReactiveSystem(还有其他System我们以后再说)
  • b ReactiveSystem是干什么的呢?可以粗暴地理解为:监测那些属性发生了改变的实体,然后对它们做一些厉害的事情
  • c GetTrigger函数的作用:一个System通常只对某些类型的实体感兴趣,比如我们的DebugMessageSystem,它只对那些拥有DebugMessage组件的实体感兴趣,GetTrigger函数就是用来筛选实体的。之前生成的实体里包含了一个GameMatcher类,它也是一个分部类,作用就是筛选实体类型。
  • d Filter函数:这也是一个筛选函数,为毛已经有了GetTrigger的情况下还需要Filter函数?因为,GetTrigger函数仅仅是筛选实体类型,但是并不是这个实体类型下的所有实体我都感兴趣,Filter函数就是在已经筛选了实体类型的情况下,再根据具体的需求进一步筛选。这里筛选的就是那些有打印信息的实体。
  • e Execute函数是重点,经过GetTrigger和Filter的重重筛选后,我们终于得到了自己感兴趣的实体。这些实体会通过Execute的参数传递进来,我们可以对这些实体做我们想做的事情(咳咳,注意道德底线)。比如这里我们就是把所有有打印信息的实体的信息打印出来。

5.Systems(系统组)

所以,我们可以开始HelloWorld了么?

不,还不行,我还想继续说(旁白:那你自己说个够吧,反正我已经听不下去了)

 

快了快了,大家坚持一下。

我们现在要来创建一个管理System的System,因为一个游戏开发过程中,不可能只有一个System的,为了方便管理,便有了【Feature】System的概念。

 

我们先来创建一个TutorialSystems.cs类,内容如下:

using Entitas;public class TutorialSystems : Feature
{public TutorialSystems(Contexts contexts) : base ("Tutorial Systems"){Add(new DebugMessageSystem(contexts));//Add(new DebugMessageSystem2(contexts));//Add(new DebugMessageSystem3(contexts));//Add(new DebugMessageSystem4(contexts));}
}

这个类要继承Feature,它的内容很简单,就是在构造器里Add所有System进去,我们现在只有一个DebugMessageSystem,所以只需添加一个。

Feature就像一个管理System的管理器,有什么好处?等会大家就知道了。

6. 最后一步——让Entitas的东西和Unity关联

之前我们一直在做的事情基本上都和Unity无关,因此,想要让这组件、实体、系统运行起来,就必须把它们关联起来。

 

我们来创建一个GameController.cs文件,内容如下:

using Entitas;
using UnityEngine;public class GameController : MonoBehaviour
{Systems _systems;void Start(){// 获取Entitas的上下文对象,类似一个单例管理器var contexts = Contexts.sharedInstance;// 获取所需的System组_systems = new Feature("Systems").Add(new TutorialSystems(contexts));// 初始化System_systems.Initialize();}void Update(){// 调用System的Execute函数,这里并不是每帧都执行Execute逻辑,因为Syetem里Execute会在实体满足一定条件的情况下才执行的(GetTrigger和Filter函数的作用)_systems.Execute();}
}

7. 运行?

所以,我们可以运行了?

差不多是吧,在Unity里创建一个GameObject,然后把GameController挂上去,然后就能运行了。

 

所以,大家看到HelloWorld了吗?(旁白:并没有!)

看不到就对了,这就是Entitas的神奇之处。(旁白:神奇你妹啊!我只是想看个HelloWorld,再不出现我就Alt+F4了啊!)

 

大家别急(靠,我自己都急了),虽然所有代码都正常运行了,但是别忘了,我们的DebugMessageSystem的Execute函数是什么情况下执行的?

拥有DebugMessage组件的实体(GetTrigger函数限制的),并且hasDebugMessage属性为true(Filter函数限制的)才会触发Execute函数。

 

我们现在没有任何GameEntity,是不可能触发Execute函数的。

什么情况下才有新的GameEntity出现,这个是由我们来决定的,这个问题就和“什么时候出现怪物”是一样的。

 

不过,既然是HelloWorld,我们可以自己添加一些测试实体。

方法就是,在GameController的Start函数里自己添加实体,代码如下:

void Start(){// 获取Entitas的上下文对象,类似一个单例管理器var contexts = Contexts.sharedInstance;// 获取所需的System组_systems = new Feature("Systems").Add(new TutorialSystems(contexts));// 初始化System_systems.Initialize();// 测试,添加一些测试实体contexts.game.CreateEntity().AddDebugMessage("Hello World!");}

获取game的上下文对象,调用CreateEntity函数即可创建实体。

创建完实体后呢,对,得给它添加DebugMessage组件(AddDebugMessage函数),添加组件的同时传递一个DebugMessage字符串。

 

于是,这个实体就同时满足了【拥有DebugMessage组件】、【hasDebugMessage属性为true】的条件。

再次运行游戏,在Console里,大家会看到姗姗来迟的HelloWorld…太感人了。

8. 唠叨一下

可能大家觉得,Entitas的HelloWorld也太难出现了吧,得写一堆东西。

确实,毕竟是框架,不是语言。

我们得按照框架的把代码搭起来才能做一些简单的事情,可能大家对于Entitas的认识还是很模糊,我已经把官方的HelloWorld教程精简了,可它还是很复杂。

这篇关于Entitas学习二 —— Entitas 入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/707142

相关文章

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

POI从入门到实战轻松完成EasyExcel使用及Excel导入导出功能

《POI从入门到实战轻松完成EasyExcel使用及Excel导入导出功能》ApachePOI是一个流行的Java库,用于处理MicrosoftOffice格式文件,提供丰富API来创建、读取和修改O... 目录前言:Apache POIEasyPoiEasyExcel一、EasyExcel1.1、核心特性

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx