为什么要在游戏开发中使用ECS模式
http://www.richardlord.net/blog/why-use-an-entity-framework
Why use an entity system framework for game development?
Following my previous post on entity systems for game development I received a number of good questions from developers. I answered many of them in the comments on that post, but one question stands out. It’s all very well explaining what an entity system framework is, and even building one, but why would you want to use one? In particular, why use the later component/system architecture I described and that I implement in Ashrather than the earlier object-oriented entity architecture as used, for example, inPushButton Engine.
So, in this post I will look more at what the final architecture is, what it gives us that other architectures don’t, and why I personally prefer this architecture.
The core of the architecture
First, it’s worth noting that the core of this architecture is the components and the systems. Components are value-objects that contain the state of the game, and systems are the logic that operates on that state, changing it as the game progresses. The other elements of the architecture are purely incidental, designed to make life easier.
The entity object is present to collect related components together. The relation between components is encapsulated by the concept of an entity and that is vital to the architecture, but it isn’t necessary to use an explicit Entity object for this. There are some frameworks that simply use an id to represent the entity, adding the entity id to every component to indicate which entity it belongs to. In this scenario there is no requirement for an entity object at all and entity based operations are performed through an entity manager, using the id to indicate which entity they are operating on.
As a concept, the entity is vital to the architecture. But as a code construct it is entirely optional. I include it because, when using an object-oriented language, the entity object makes life easier. In particular, it enables us to create the methods that operate on the entity as methods of an entity object and to track and manage the entity through this object, removing the need to track ids throughout the code.
While the concept of an entity is vital to the architecture, the concept of node objects is entirely incidental. The nodes are used as the objects in the collections of components supplied to the systems. We could instead provide each system with a collection of the relevant entities and let the systems pull the components they want to operate on out of the entities, using the get() method of the entity.
In Ash, the nodes serve two purposes. First they enable us to use a more efficient data structure in which the node objects that the systems receive are nodes in a linked list. This improves the execution speed of the framework.
Second, using the node objects enables us to apply strong, static typing throughout our code. The method to fetch a component from an entity necessarily returns an untyped object, which must then be cast to the correct component type for use in the game code. The properties on the node are already statically typed to the components’ data types, so no casting is necessary.
So, fundamentally, the entity architecture is about components and systems.
This is not object-oriented programming
We can build our entity architecture using an object-oriented language but, on a fundamental level, this is not object-oriented programming. The architecture is not about objects, it’s about data (components) and sub-routines that operate on that data (systems).
For many object-oriented programmers this is the hardest part of working with an entity system framework. Our tendency is to fall back to what we know and as an object-oriented programmer using an object-oriented language that means encapsulating data and operations together into objects. If you do this with a framework like Ash you will fail.
Data-Oriented Programming
Games tend to be about lots of fast changing state, with players, non-player characters, game objects like bullets and lasers, bats and balls, tables and chairs, and levels, scores, lives and more all having state that might include position, rotation, speed, acceleration, weight, colour, intention, goals, desires, friendships, enemies and more.
The state of the game can be encapsulated in this large mass of constantly changing data, and on a technical level the game is entirely about what this data is and how this data changes.
In a game a single little piece of this data may have many operations acting on it. Take, for example, a player character that has a position property that represents the character’s position in the game world. This single piece of data may be used by
- The render system, to draw the player in the world.
- The camera system, to position the camera relative to the player.
- The AI systems of all non-player characters, to decide how they should react to the player.
- The input system, which alters the player’s position based on user input.
- The physics system, which alters the player’s position based on the physics of the game world.
- The collision system, which tests whether the player is colliding with other objects and resolves those collisions.
and probably many more systems besides. If we try to build our game using objects that encapsulate data with the operations that act on that data, then we will build dependencies between all these different systems as they all want to be encapsulated with the player’s position data. This can’t be done unless we code the game as one single, massive class, so inevitably we break some parts of the game into separate systems and provide data to those systems – the physics system, the graphics system – while including other elements of the game logic within the entity objects themselves.
An entity architecture based on components and systems takes the idea of discrete systems to its logical conclusion. All operations are programmed as independent systems, and all game state is stored separately in a set of data components, which are provided to the systems according to their need.
The systems are decoupled form each other. Each system knows only about itself and the data it operates on. It knows and cares nothing at all about the other systems and how they may have affected by or used the data before or after this system gets to work with it.
Also, by embracing the system as the core logic of the architecture, we are encouraged to make many smaller and simpler systems rather than a few large complex ones, which again leads to simpler code and looser coupling.
This decoupling makes building your game much easier. It is why I enjoy working with this form of entity system so much, and why I built Ash.
Storing the game state
Another benefit of the component/system architecture is apparent when you want to save and restore the game state. Because the game state is contained entirely in the components, and because these are simple value objects, saving the game state is a relatively simple matter of serialising out the components, and restoring the game state involves just deserialising the data back in again.
In most cases, serialising a value-object is straightforward, and one could simply json-encode each component, with additional data to indicate its entity owner (an id) and its component type (a string), to save the game state.
Adam Martin wrote about comparing components in an entity system framework to data in a relational database (there’s lots of interesting entity related stuff on Adam’s blog), and emphasising that conversion between a relational database for long-term storage and components for game play doesn’t require any object/relational mapping, because components are simple copies of the relational database’s data structure rather than complex objects.
This leads further to the conclusion that a component/system architecture is ideal for an MMO game, since state will be stored in a relational database on the game servers, and much of the processing of that state will occur on the servers, where using a set of discrete, independent systems to process the data as the game unfolds is an excellent fit to both the data storage requirements of the state and the parallelism available on the servers.
Concurrency
Indeed, a component/system architecture is well suited to applying concurrency to a game. In most games, some of the systems are entirely independent of each other, including being independent of the order in which they are applied. This makes it easy to run these systems in parallel.
Further, most systems consist of a loop in which all nodes are processed sequentially. In many cases, the loop can be parallelised since the nodes can be updated independently of each other.
This gives us two places in the code where concurrency can be applied without altering the core logic of the game, which is inside the loop in the systems, or the core state of the game, which is in the components.
This makes adding concurrency to the game relatively simple.
We don’t need object-orientation
Finally, because the component/system architecture is not object-oriented, it lends itself to other programming languages that implement different programming paradigms like functional programming and procedural programming. While I created Ash as an Actionscript framework, this architecture would be well suited to Javascript for client side development or any of the many functional languages used for highly concurrent server side development.
Update: In-game editors
Tom Davies has pointed out that a very valuable benefit to him is how easy it is to create an in-game level editor when developing with an entity system framework like Ember orAsh. You can see his example here.
I agree with Tom, this is a very useful benefit of these frameworks. The complete separation of the game state and the game logic in an entity system framework makes it easy to create an editor that lets you alter the state (configuration, level design, AI, etc.) while playing the game. Add to this the easier saving and loading of state and you have a framework that is very well suited to in-game editing.
为什么要在游戏开发中使用ECS模式的更多相关文章
- [Unity游戏开发]向量在游戏开发中的应用(三)
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51088236 在上一篇博客中讲了利用向量点乘在游戏开发中应用的几种情景.本 ...
- [Unity游戏开发]向量在游戏开发中的应用(二)
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/50972976 在上一篇博客中讲了利用向量方向的性质来解决问题.这篇博客将继 ...
- [Unity游戏开发]向量在游戏开发中的应用(一)
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/50810102 向量在游戏开发中是非常实用的,我们在学校学完向量的知识后,只 ...
- Cocos2d-x游戏开发中的消息机制:CCNotificationCenter的使用
在HTML5游戏开发中,js可以使用Event对象的addEventListener(添加事件监听).dispatchEvent(触发事件)实现监听机制,如果在coocos2d-x中,去实现这种机制该 ...
- 二、Cocos2dx概念介绍(游戏开发中不同的坐标系,cocos2dx锚点)
注:ccp是cocos2dx中的一个宏定义,#define ccp(__X__,__Y__)CCPointMake((float)__X__, (float)__Y__),在此文章中表示坐标信息 1. ...
- [C++基金会]位计算 游戏开发中的应用
定义的位操作:通俗点说,,位计算是计算机操作二进制整数. 无论整数可以用二的方式来表示进度,不同类型的其长度的整数位的是不一样的.INT8要么char靠8个月2 位表示,INT16或者short是由1 ...
- 在基于TypeScript的LayaAir HTML5游戏开发中使用AMD
在基于TypeScript的LayaAir HTML5游戏开发中使用AMD AMD AMD是"Asynchronous Module Definition"的缩写,意思就是&quo ...
- 借助AMD来解决HTML5游戏开发中的痛点
借助AMD来解决HTML5游戏开发中的痛点 游戏开发的痛点 现在,基于国内流行引擎(LayaAir和Egret)和TypeScript的HTML5游戏开发有诸多痛点: 未采用TypeScript编译器 ...
- 游戏开发中IIS常见支持MIME类型文件解析
游戏开发中IIS常见支持MIME类型文件解析 .apkapplication/vnd.android .ipaapplication/vnd.iphone .csbapplication/octet- ...
随机推荐
- Cesium原理篇:5最长的一帧之影像
如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...
- C# ListView点击列头进行排序
/// <summary> /// This class is an implementation of the 'IComparer' interface. /// </summa ...
- TypeScript之面向对象初体验
1.安装nodejs和vscode: nodejs : https://nodejs.org/en/ Visual Studio Code : https://www.visualstudio.co ...
- php实现设计模式之 模板方法模式
<?php /** * 模板模式 * * 定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构可以定义该算法的某些特定步骤 * */ abstract class ...
- php实现设计模式之 策略模式
策略模式:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化.是一种行为模式. 策略模式包含三种角色 1 抽象策略角色: 策略类,通常由一个接口或 ...
- GJM : Unity3D HIAR -【 快速入门 】 八、开发云识别应用
开发云识别应用 为了解决识别图片数量限制,以及上线应用不能动态修改识别图片和 AR 内容的问题,我们在 HiAR SDK for Unity 新版本(v1.1.x 及后续版本)中集成了云识别功能.本文 ...
- push方法的兼容性问题
在IE8及以下中,不支持aplly方法中的第二个参数是 伪数组 需要对push方法进行封装. 将 push 的判断,放入一个沙箱中: 好处:在页面加载的时候就会执行这段代码,保证了代码只会检测一次 以 ...
- JQuery效果-淡入淡出、滑动、动画
一.JQuery Fading方法 JQuery 有四种fade方法 1.fadeIn() 淡入 对应也有$(selector).fadeIn(speed, ...
- 业务人员自助BI分析不够用,还要自助数据准备?
自助式BI工具,可以帮助业务人员充分了解和利用企业数据,通过可视化操作,拖拖拽拽来新建分析,生成可视化的报表,帮助企业决策.但近几年的调查研究发现,拥有强大分析策略和模型的产品,比如Tableau.q ...
- 写给自己:修改配置文件一定要cp一个.bak
写给自己:修改配置文件一定要cp一个.bak 毕竟不是每次的修改都一定对,而且很多时候是在服务器上直接修改原文件,修改后重启服务才知道是否修改正确,如果不加备份修改,造成服务器动荡,将会造成不可挽回的 ...