• 13
• 18
• 19
• 27
• 9
• ### Similar Content

• By abarnes
Hello All!
I am currently pursuing a degree in video game programming, so far I have completed an intro to programming course and object oriented programming course. Both were taught using C++ as the programming langauge which I know is very popular for game development, but in these classes we do not actually do any game development. I would like to start to build my skills with C++ for game development as that is a common required thing for a job and am looking for ways to do this. Any recommendations such as books to read or youtube videos to watch will be greatly appreciated!
• By GytisDev
Hello,
me and few friends are developing simple city building game with unity for a school project, think something like Banished but much simpler. I was tasked to create the path-finding for the game so I mostly followed this tutorial series up to episode 5. Then we created simple working system for cutting trees. The problem is that the path-finding is working like 90% of the time, then it get stuck randomly then there's clearly a way to the objective (tree). I tried looking for some pattern when it happens but can't find anything. So basically I need any tips for how I should approach this problem.
Use this image to visualize the problem.
• By Orella
I'm having problems rotating GameObjects in my engine. I'm trying to rotate in 2 ways.
I'm using MathGeoLib to calculate maths in the engine.
First way: Rotates correctly around axis but if I want to rotate back, if I don't do it following the inverse order then rotation doesn't work properly.
e.g:
Rotate X axis 50 degrees, Rotate Y axis 30 degrees -> Rotate Y axis -50 degrees, Rotate X axis -30 degrees. Works.
Rotate X axis 50 degrees, Rotate Y axis 30 degrees -> Rotate X axis -50 degrees, Rotate Y axis -30 degrees. Doesn't.

Code:
void ComponentTransform::SetRotation(float3 euler_rotation) { float3 diff = euler_rotation - editor_rotation; editor_rotation = euler_rotation; math::Quat mod = math::Quat::FromEulerXYZ(diff.x * DEGTORAD, diff.y * DEGTORAD, diff.z * DEGTORAD); quat_rotation = quat_rotation * mod; UpdateMatrix();  } Second way: Starts rotating good around axis but after rotating some times, then it stops to rotate correctly around axis, but if I rotate it back regardless of the rotation order it works, not like the first way.

Code:
void ComponentTransform::SetRotation(float3 euler_rotation) { editor_rotation = euler_rotation; quat_rotation = math::Quat::FromEulerXYZ(euler_rotation.x * DEGTORAD, euler_rotation.y * DEGTORAD, euler_rotation.z * DEGTORAD); UpdateMatrix();  }
Rest of code:
#define DEGTORAD 0.0174532925199432957f void ComponentTransform::UpdateMatrix() { if (!this->GetGameObject()->IsParent()) { //Get parent transform component ComponentTransform* parent_transform = (ComponentTransform*)this->GetGameObject()->GetParent()->GetComponent(Component::CompTransform); //Create matrix from position, rotation(quaternion) and scale transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale); //Multiply the object transform by parent transform transform_matrix = parent_transform->transform_matrix * transform_matrix; //If object have childs, call this function in childs objects for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++) { ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform); child_transform->UpdateMatrix(); } } else { //Create matrix from position, rotation(quaternion) and scale transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale); //If object have childs, call this function in childs objects for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++) { ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform); child_transform->UpdateMatrix(); } } } MathGeoLib: Quat MUST_USE_RESULT Quat::FromEulerXYZ(float x, float y, float z) { return (Quat::RotateX(x) * Quat::RotateY(y) * Quat::RotateZ(z)).Normalized(); } Quat MUST_USE_RESULT Quat::RotateX(float angle) { return Quat(float3(1,0,0), angle); } Quat MUST_USE_RESULT Quat::RotateY(float angle) { return Quat(float3(0,1,0), angle); } Quat MUST_USE_RESULT Quat::RotateZ(float angle) { return Quat(float3(0,0,1), angle); } Quat(const float3 &rotationAxis, float rotationAngleRadians) { SetFromAxisAngle(rotationAxis, rotationAngleRadians); } void Quat::SetFromAxisAngle(const float3 &axis, float angle) { assume1(axis.IsNormalized(), axis); assume1(MATH_NS::IsFinite(angle), angle); float sinz, cosz; SinCos(angle*0.5f, sinz, cosz); x = axis.x * sinz; y = axis.y * sinz; z = axis.z * sinz; w = cosz; } Any help?
Thanks.
• By owenjr
Hi there!
I am trying to implement a basic AI for a Turrets game in SFML and C++ and I have some problems.
This AI follows some waypoints stablished in a Bezier Courve.
In first place, this path was followed only by one enemy. For this purpose, the enemy has to calculate his distance between his actual position
to the next waypoint he has to pick.
If the distance is less than a specific value we stablish, then, we get to the next point. This will repeat until the final destination is reached. (in the submitting code, forget about the var m_go)

Okay, our problem gets when we spawn several enemies and all have to follow the same path, because it produces a bad visual effect (everyone gets upside another).
In order to solve this visual problem, we have decided to use a repulsion vector. The calculus gets like this:

As you can see, we calculate the repulsion vector with the inverse of the distance between the enemy and his nearest neighbor.
Then, we get it applying this to the "theorical" direction, by adding it, and we get a resultant, which is the direction that
our enemy has to follow to not "collide" with it's neighbors. But, our issue comes here:

The enemys get sepparated in the middle of the curve and, as we spawn more enemys, the speed of all of them increases dramatically (including the enemies that don't calculate the repuslion vector).
1 - Is it usual that this sepparation occours in the middle of the trajectory?
2 - Is it there a way to control this direction without the speed getting affected?
3 - Is it there any alternative to this theory?

I submit the code below (There is a variable in Spanish [resultante] which it means resultant in English):

if (!m_pathCompleted) { if (m_currentWP == 14 && m_cambio == true) { m_currentWP = 0; m_path = m_pathA; m_cambio = false; } if (m_neighbors.size() > 1) { for (int i = 0; i < m_neighbors.size(); i++) { if (m_enemyId != m_neighbors[i]->GetId()) { float l_nvx = m_neighbors[i]->GetSprite().getPosition().x - m_enemySprite.getPosition().x; float l_nvy = m_neighbors[i]->GetSprite().getPosition().y - m_enemySprite.getPosition().y; float distance = std::sqrt(l_nvx * l_nvx + l_nvy * l_nvy); if (distance < MINIMUM_NEIGHBOR_DISTANCE) { l_nvx *= -1; l_nvy *= -1; float l_vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x; float l_vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y; float l_resultanteX = l_nvx + l_vx; float l_resultanteY = l_nvy + l_vy; float l_waypointDistance = std::sqrt(l_resultanteX * l_resultanteX + l_resultanteY * l_resultanteY); if (l_waypointDistance < MINIMUM_WAYPOINT_DISTANCE) { if (m_currentWP == m_path.size() - 1) { std::cout << "\n"; std::cout << "[GAME OVER]" << std::endl; m_go = false; m_pathCompleted = true; } else { m_currentWP++; } } if (l_waypointDistance > MINIMUM_WAYPOINT_DISTANCE) { l_resultanteX = l_resultanteX / l_waypointDistance; l_resultanteY = l_resultanteY / l_waypointDistance; m_enemySprite.move(ENEMY_SPEED * l_resultanteX * dt, ENEMY_SPEED * l_resultanteY * dt); } } else { float vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x; float vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y; float len = std::sqrt(vx * vx + vy * vy); if (len < MINIMUM_WAYPOINT_DISTANCE) { if (m_currentWP == m_path.size() - 1) { std::cout << "\n"; std::cout << "[GAME OVER]" << std::endl; m_go = false; m_pathCompleted = true; } else { m_currentWP++; } } if (len > MINIMUM_WAYPOINT_DISTANCE) { vx = vx / len; vy = vy / len; m_enemySprite.move(ENEMY_SPEED * vx * dt, ENEMY_SPEED * vy * dt); } } } } } else { float vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x; float vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y; float len = std::sqrt(vx * vx + vy * vy); if (len < MINIMUM_WAYPOINT_DISTANCE) { if (m_currentWP == m_path.size() - 1) { std::cout << "\n"; std::cout << "[GAME OVER]" << std::endl; m_go = false; m_pathCompleted = true; } else { m_currentWP++; } } if (len > MINIMUM_WAYPOINT_DISTANCE) { vx = vx / len; vy = vy / len; m_enemySprite.move(ENEMY_SPEED * vx * dt, ENEMY_SPEED * vy * dt); } } }
¡¡Thank you very much in advance!!

# C++ ECS : mega entity array VS many component arrays

## Recommended Posts

I have recently read T-machine's Entity Component System (ECS) data structure. (link)

Its "best" version (4th iteration) can be summarized into a single image (copy from T-machine's web) :-

This approach also appears in a VDO

" rel="external">
, with slide and source code ( https://github.com/CppCon/CppCon2015/tree/master/Tutorials/Implementation of a component-based entity system in modern C++ ) .

There are many people (including me) believe that the above approach lacks data locality, because Position-1,Position-2,Position-3, ... are not stored in a contiguous array.

However, many attempts failed to elegantly make it contiguous.  (e.g. stackoverflow's link

• I also realized that, to make it contiguous, the cost of query Entity<-->Component is unavoidably significantly higher. (I profiled)

I would like to hear that ....

I know that its depend on data access pattern (i.e. cache miss).  I still want to hear more opinion/argument about it, because I may need to rewrite a large part of my engine to make it support 30,000+ entity (personal greed).

Thank.

##### Share on other sites

Because of curiosity + stubbornness, I converted my engine to use T-machine's approaches.

Today, I find that T-machine's technique is slower by 2-3% for my game.

It is a little depressing though from the fact that T-machine's is far more difficult to implement.

Kylotan is absolutely correct.

IMHO, it is very hard for ECS to reach 30,000 non-trivial entities (without multithread) while maintaining 60fps.

##### Share on other sites

I was going to post some harsh criticism of the linked T-Machine article, but (along with the previous, well known series) it speaks for itself: figuring out what's wrong is a valuable learning experience that everyone deserves to make.

Just to point out the biggest problem, if components aren't the same size they cannot be stored in the same "megaarray", and if they are the same size they are wasting memory (if padded) and/or coherent access (if the array contains homogeneous "handles" of data stored elsewhere); there must be a good reason to do that.

##### Share on other sites

The biggest problem can be (arguably) solved by using assemblage.      https://gamedev.stackexchange.com/questions/58693/grouping-entities-of-the-same-component-set-into-linear-memory/58701#58701

However, this approach introduces a lot of inherent disadvantages :

• Micro memory management is needed
• harder to code
• hard to remove component
• lose some data locality of the same components
• pooling is less efficient at entity level
• entity type must be established before create it.

I believed the most tempting performance advantage might be that every query inside a certain entity is very fast.      However, my profiling result suggest that I was wrong again.

Oh, I used ~2 weeks to appreciate and believe this fact  (sad face)

Edited by hyyou

##### Share on other sites
8 hours ago, hyyou said:

A proliferation of arrays of different aggregates of components is the opposite of a single array of heterogeneous components. Which of the two flawed approaches have you tried?

Imposing arbitrary constraints (for example, that components of entities that have a different set of components should be segregated) and then suffering the consequences (that entities cannot gain or lose components, at least in a neat way, that visiting all components of a certain type is inefficient because of noncontiguous layout and complicated due to multiple arrays, etc.) without thinking of more sophisticated techniques is a typical stylistic trait of the T-Machine blog posts.

##### Share on other sites
Quote

Which of the two flawed approaches have you tried?

In my flawed prototype, I mixed both of them.

Every entity is stored in a single array.  Each and every entity must use less than 1024 bytes.

In the stress test, I reserved it [Entity 1st=1024 bytes][2nd=1024]....[1024] = 30,000 contiguous block.

Ex. In some bad cases, it can be :-

• Entity 1st= [Position  8 bytes][Velocity  16 bytes][ waste 1010 bytes ]
• Entity 2st= [GraphicHuge 524 bytes][Position 8 bytes][ waste 492 bytes ]  ....

There are some ways to optimize it (e.g. buddy allocator), but in nutshell, it is like that.

##### Share on other sites

For the record, after optimizing my own ECS I can say the following:

Most performance can be gained not by how you layout components, but how by optimizing iterations. For example, if you want to iterate over physics + position at some point:

for(auto& entity : entities.WithComponents<Position, Physics>())
{
}

A primitive approach might build a dynamic list by checking all entities, (=vector), return ths & then iterate over it again.
A better solution might involve iterators to save on the dynamic allocations.
An even better solution involves building the set of entities with those components on the first call, and then just invalidate or update this cached set whenever entities are modified.

This step gave the most performance in my case, and should be pretty mandatory of you want to handle 30000 entities, which will likely have vastly different sets of components.

Storing the components in a contingous array actually reduced the performance at first, as some have mentioned, due to the overhead of accessing them from different places. What I actually ended up doing was putting the pointers to the components inside my cache-set to, using a templated-solution to generate a cache-structure like this

struct Cache // "generated" by template
{
std::vector<std::tuple<Position*, Physics*>> components;
}

The components itself are stored in a contingous array, and put into this cache. Which is, I believe, the fasted you can get when iterating over distinct sets of components, as the this cache-array is as tighly packed as possible under those circumstances, and works with the least . Note that the actual implementation is really complicated, especially the part about updating the cache (since I didn't want to rebuild it on every change), but the results sure paid off in terms of performance. I don't have the exact figures, but all optimizations together were about 40% decrease in frametime for a testset of 10000 entities with animation/static sprites & collision.

You should decide for yourself if its worth the trouble, as others have said, getting the system to be useable should be the priority. Though if done right, you can apply all those optimizations in the background w/o affecting the systems interface, so once you see a need you can still resort to optimizing.

##### Share on other sites

@Juliean

Thank!  It is consistent with the profiler result.

I always thought that the profile result is wrong, because I use stack-allocator to allocate this as return result :-

entities.WithComponents<Position>()

Copying array shouldn't very expensive, right?   I was wrong.

Thank a lot, Juliean!!!   If you didn't say it explicitly, I will ignore it .... perhaps forever.

Edited by hyyou

##### Share on other sites
9 hours ago, hyyou said:

That's just another rewording of the unwieldy T-Machine stuff, and the answers below it tell you all you need to know:

• "The architecture was more of a pain in the butt than naive object systems and had no measurable performance advantages over some of the more flexible designs I compared it to."
• " What you've done is re-engineered C++ objects. The reason why this feels obvious is that if you replace the word "entity" with "class" and "component" with "member" this is a standard OOP design using mixins."

There's no silver bullet that will let you handle 30,000 heterogeneous entities without compromises. If a large number of those entities are homogeneous then you might be able to smash those, or the 'hot' data in them, into some contiguous arrays and see some significant benefit. But in the general case, what you want to do isn't really doable.

Remember there are simpler ways to get some cache-coherence benefits - store important properties inline instead of via pointers, move lesser-accessed data outside of the entities so that the 'hot' data is stored more compactly, allocate things from pools instead of via naive new calls, etc.