Game design mode-oriented to the idea of data programming

Source: Internet
Author: User

With the increasingly complex development of software requirements, the idea of object-oriented programming is gradually developed in the process programming thought of ancient times.

When people find object-oriented in coping with the benefits of high-level software, they are increasingly fascinated by object-oriented, eager to study how to abstract objects more gracefully.

However, modern development gradually found that the object-oriented programming layer of abstraction caused by the bloated, resulting in reduced operational efficiency, and this is the performance of the high-demand game programming area do not want to see.

So in modern game programming, the idea of data-oriented programming is getting more and more accepted (for example, the Unity2018 updated ECS Framework is a framework for data-oriented thinking).

What is data-oriented programming?

Let's start with a simple comparison:

    • Process-oriented thinking: Consider the steps (functions) required to solve the problem.
    • Object-oriented thinking: Consider the various models (classes) needed to solve the problem.
    • Data-oriented thinking: Consider the data access and layout as the core idea (data).

So what does it mean to think about data storage/layout? Introduce a concept about CPU processing data first: CPU multilevel cache.

CPU multi-level cache (CPU cache) when assembling a computer to buy the CPU, do not know if you have noticed a CPU parameter: N-level cache (n generally have 1/2/3) what is the CPU cache:

    • In more detail, the structure should be:CPU<----> register <---->CPU Cache <----> memory
    • You can see that the CPU cache is a storage area between memory and register, and that it has less storage space than memory, larger than register.
Why CPU multilevel caching is required:
    • The CPU is running too fast, and the CPU accesses the memory very slowly, so that in the processor clock cycle, the CPU often needs to wait for the register to read memory, wasting time.
    • CPU access to the CPU cache is much faster. To mitigate the mismatch between CPU and memory speed, the CPU cache stores pre-stored memory data that may potentially be accessed.
What is pre-stored in the CPU multilevel cache:
    • Time locality: If a data is accessed, it is likely to be accessed again in the near future.
    • Spatial locality: If a data is accessed, then the data adjacent to it can be accessed very quickly.
    • CPU Multilevel cache based on these two characteristics, it is generally stored data that is accessed + adjacent data that accesses the data.
CPU Cache Hit/miss:
    • The CPU caches the pending data or processed data in the specified address, which is called a CPU cache hit if the address is already present in the data that is about to be processed.
    • If the CPU cache is missing, go to memory address access.

Increase CPU Cache Hit ratio

To maximize the CPU cache hit rate, try to keep the data in use together.

Using contiguous arrays to store objects for batching

1, the traditional component mode, often allows the game object to hold one or more components of the reference data (pointer data).

(A typical Game object class that contains pointers to 2 of components)

Class Gameobject {    //.... The properties of Gameobject    component1* m_component1;    component2* M_component2;};  

The following image shows the structure of this traditional pattern:

In general, game objects/components tend to be objects with more batch operations (update/render/other operations per frame).

As you can see in the diagram, this refers to a structure that is extremely unfriendly to the CPU cache.

So one possible way is to have them all in a continuous array.

Note that an array of objects is not an array of pointers. If it is an array of pointers, this has no meaning for the CPU cache hit (because you want to jump to the non-contiguous memory through the pointer).

Gameobject G[max_gameobject_num]; Component1 A[max_component_num]; Component2 B[max_component_num];

(Continuous array storage allows for higher CPU cache hit rates in the following batch processing)

 for (int0; i < gameobjectsnum; + +i) {    g[i].update ();    G[i].draw ();}  for (int0; i < componet1num; + +i) {    a[i].update ();    A[i].draw ();}  for (int0; i < componet2num; + +i) {    b[i].update ();    B[i].draw ();}

2, this is a simple particle system:

Const int  the ; // Particle class class Particle {private:    bool  active;    VEC3 position;    VEC3 Velocity;     // .... The method required for other particles }; Particle particles[max_particle_num]; int particlenum;

It uses a typical lazy strategy, and when you want to delete a particle, you simply change the active tag without moving the memory.

Then, using the markers, you can skip the deleted particles when each frame is updated.

When you need to create a new particle, you only need to find the first deleted particle and change its properties.

 for (int0; i < particlenum; + +i)    {if  (particles[i].isactive ()) {        Particles[i].update ();    }}

On the face of it, it's very scientific, actually. The CPU cache hit rate is not high: Each batch CPU cache loads a lot of unused particle data (marks the deleted particles).

One possible approach is to copy the particle memory at the tail of the queue to the position of the particle when you want to delete the particles, and to record the reduced number of particles.

(The Move memory (copy memory) operation is the last thing programmers want to see, but the actual running batch brings a lot more overhead than the deletion, which is also a wonderful aspect of data-oriented programming. )

Particles[i] = Particles[particlenum];p articlenum--;

This allows us to ensure that the CPU cache is always hit at high hit rate in this particle bulk update operation.

 for (int0; i < particlenum; + +i) {    particles[i].update ();}

Cold data/Thermal data segmentation

One might argue that this maximizes the use of the CPU cache: All data (including component data) of an object is crammed into a class without any indirect storage of data in the form of pointers or references.

In fact, the idea is wrong, and we can't ignore one problem: thestorage space of the CPU cache is limited

So we want the CPU cache to store the data that is used frequently, not for the less-used data. This introduces the concept of cold data/thermal data segmentation.

Hot data: Often the data to be manipulated, we can generally be directly accessible as a member variable.

Cold data: Less-used data, which we typically access indirectly by reference/pointer (that is, a pointer or reference is stored).


A chestnut: For human beings, the position speed of life is often the variable that needs to operate, is the heat data;

The drop object only needs to be used when the human is dead, so it is cold data;

class Human {private:    float health ;     float Power;    VEC3 position;    VEC3 Velocity;    Lootdrop* drop;     // .... }; class lootdrop{    item[2] itemstodrop;     float chance;     // ....};

Extra

Data-oriented programming can be said to be an important idea of CPU optimization.

But in the actual development, must pay attention to not forget this principle:

Do not optimize prematurely!

Data-oriented programming is ultimately not about software requirements, but on CPU optimization.

In the late stages of the game's iterative development, if CPU performance bottlenecks occur, you should consider using data-oriented programming techniques.

Game design mode-oriented to the idea of data programming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.