admin管理员组

文章数量:1584341

unity dots

We’re rebuilding the core of Unity with our Data-Oriented Tech Stack, and many game studios are already seeing massive performance wins when using the Entity Component System (ECS), the C# Job System, and the Burst Compiler. At Unite Copenhagen, we had a chance to sit down with Far North Entertainment and go deep into how they implemented these DOTS features into their otherwise traditional Unity project.

我们正在使用面向数据的技术堆栈来重建Unity的核心,并且许多游戏工作室在使用实体组件系统(ECS),C#作业系统和Burst编译器时已经看到了巨大的性能提升。 在Unite Copenhagen,我们有机会与Far North Entertainment坐下来,深入研究他们如何将DOTS功能实现到他们原本传统的Unity项目中。

Far North Entertainment is a Swedish studio co-owned by five friends from engineering studies. Since releasing Down to Dungeon for Gear VR in early 2018, the company’s been working on a game that explores a classic PC game genre – the post-apocalyptic zombie survival game. What makes the project stand out is the number of zombies chasing you. The team’s vision included thousands of brain-hungry enemies coming after you in enormous hordes.

Far North Entertainment是一家瑞典工作室,由来自工程学的五个朋友共同拥有。 自2018年初发布Down to Dungeon for Gear VR以来,该公司一直在致力于探索经典PC游戏类型的游戏-世界末日后的僵尸生存游戏。 使该项目脱颖而出的原因是追逐您的僵尸数量。 团队的愿景包括成千上万的饥肠enemies的敌人成群结队地追你。

However, they quickly run into lots of performance issues when prototyping this idea. Spawning, despawning, updating, and animating all those zombies was a major bottleneck, even after the team tried implementing possible solutions like object pooling and animation instancing.

但是,在制作此想法的原型时,它们很快会遇到很多性能问题。 即使在团队尝试实施可能的解决方案(如对象池和动画实例化)之后,对所有这些僵尸进行生成,生成,更新和设置动画也是一个主要瓶颈。

This led the studio’s CTO Anders Eriksson to look at DOTS, and how to change his mindset from an object-oriented mindset to a data-oriented one. “The key insights that helped us make the shift was to stop thinking about objects and object hierarchies, and start to think about the data, how it is transformed and how it is accessed,” he says. That means that the code doesn’t have to be modeled around something that makes sense in real life and it doesn’t have to solve the most general case. He’s got a lot of advice for anyone trying to make the same shift:

这导致工作室的首席技术官Anders Eriksson着眼于DOTS,以及如何将其思维方式从面向对象的思维方式转变为面向数据的思维方式。 他说:“帮助我们做出转变的关键见解是,不再考虑对象和对象层次结构,而是开始考虑数据,如何转换和访问数据。” 这意味着代码不必围绕现实中有意义的事物建模,也不必解决最一般的情况。 对于试图做出相同转变的任何人,他都有很多建议:

“Ask yourself what the actual problem is that you are trying to solve, and what data is relevant for a specific solution. Will you do the same transformations of the same set of data over and over again? How much relevant data can you pack into a CPU cache line? If you are also looking to convert existing code, then identify how much garbage data you are filling the cache lines with. Can you split up the calculations on multiple threads, and/or utilize SIMD instructions?”

“问问自己您要解决的实际问题是什么,什么数据与特定解决方案有关。 您是否会一遍又一遍地对同一组数据进行相同的转换? 您可以将多少相关数据打包到CPU缓存行中? 如果您还希望转换现有代码,则确定要用多少垃圾数据填充高速缓存行。 您可以在多个线程上拆分计算,和/或利用SIMD指令吗?”

演示地址

The team came to understand that entities in Unity Component System are just lookup ids into streams of components. Components are just data, while the systems contain all logic and filter out entities with a certain component signature known as Archetypes. “I think one insight that helped us to visualize this was to think of ECS as an SQL database. Each Archetype is a table where each column is a component and each row is a unique entity. You then use the systems to query into these archetype tables to do operations on entities,” says Anders.

团队开始了解Unity组件系统中的实体只是组件流中的查找ID。 组件只是数据,而系统包含所有逻辑并过滤出具有某些组件签名(称为原型)的实体。 “我认为帮助我们将其可视化的一种见解是将ECS视为SQL数据库。 每个原型都是一个表,其中每一列都是一个组件,每一行都是唯一的实体。 然后,您可以使用系统查询这些原型表以对实体进行操作。” Anders说。

DOTS入门 (Getting started with DOTS)

To get to this understanding, he studied the Entity Component System documentation, the ECS Samples and the sample that we created with Nordeus and unveiled at Unite Austin. But general materials about data-oriented design were also extremely helpful to the team. “The talk from Mike Acton about Data-oriented design from CppCon 2014 is what initially opened our eyes to this way of programming.”

为了获得这种理解,他研究了实体组件系统文档 , ECS示例以及我们与Nordeus创建并在Unite Austin揭幕的示例 。 但是有关面向数据设计的一般材料对团队也非常有帮助。 “ 迈克·阿克顿 ( Mike Acton)关于CppCon 2014的面向数据的设计的演讲最初使我们对这种编程方式产生了兴趣 。”

The Far North team posted what they’ve learned on their Dev Blog and this September, came to Copenhagen to talk about their experiences switching to the data-oriented mindset at Unite.

远北团队在开发博客上发布了他们所学的知识,今年9月,他来到哥本哈根,谈论了他们在Unite转向面向数据思维方式的经验。

演示地址

This blog post builds on this presentation and explains the specifics of their implementation of ECS, the C# Job System, and the Burst Compiler in more detail. The Far North team has also kindly shared a lot of code examples from their project.

这篇博客文章基于此演示文稿,更详细地说明了其ECS,C#作业系统和Burst编译器的实现细节。 远北团队还从他们的项目中分享了很多代码示例。

整理僵尸数据 (Lining up zombie data)

“The problem we faced was with doing client-side interpolation of translations and rotations for thousands of entities,” says Anders. Their first object-oriented approach was to make an abstraction of a ZombieView script which inherited a more general EntityView parent class. An EntityView is a MonoBehaviour attached to a GameObject. It acts as a visual representation of the game model. Every ZombieView was responsible for handling its own translation and rotation interpolation in its Update function.

“我们面临的问题是对数千个实体进行平移和旋转的客户端插值,” Anders说。 他们的第一个面向对象的方法是对ZombieView脚本进行抽象,该脚本继承了更通用的EntityView父类。 EntityView是附加到GameObject的MonoBehaviour。 它充当游戏模型的可视化表示。 每个ZombieView都要在其Update函数中负责处理自己的平移和旋转插值。

This seems fine until you realize that every entity is allocated in a random place in memory. That means if you’re accessing thousands of entities, the CPU has to catch them one by one in memory, which is very slow. If you lay your data in neat continuous blocks, the CPU can cache a whole bunch of them at once. Most CPUs today can get around 128 or 256 bits per cycle from a cache.

除非您意识到每个实体都在内存中的随机位置分配,否则这似乎还不错。 这意味着如果您要访问数千个实体,CPU必须在内存中一个接一个地捕获它们,这非常慢。 如果将数据放置在整洁的连续块中,则CPU可以一次缓存一大堆数据。 当今,大多数CPU可以从缓存中获得每个周期大约128或256位。

The team decided to convert the enemies to DOTS with the hope to eliminate client-side performance bottlenecks. First in line was the Update function of the ZombieView. The team identified what parts of it should be separated into different systems, and what data would be needed. The first and most obvious thing was the interpolation of positions and rotations since the world of the game is a 2D grid.  Two floats represent where the zombie is heading, and the final component was a target position component that keeps track of the server position for the enemy.

团队决定将敌人转换为DOTS,希望消除客户端的性能瓶颈。 首先是ZombieView的Update函数。 该团队确定了应将其哪些部分分成不同的系统,以及需要哪些数据。 第一个也是最明显的事情是位置和旋转的插值,因为游戏的世界是一个2D网格。 两个浮点数代表僵尸的前进方向,最后一个组成部分是目标位置组成部分,用于跟踪敌人的服务器位置。

1

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[Serializable] public struct PositionData2D : IComponentData {     public float2 Position; } [Serializable] public struct HeadingData2D : IComponentData {     public float2 Heading; } [Serializable] public struct TargetPositionData : IComponentData {     public float2 TargetPosition; }

1

2 3 4 5 6 7

本文标签: 僵尸射击游戏UnityDOTS