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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多