Lately i am trying out a lot with the new Entity Component System, as many of you do.
In my Background this is absolutely new to me, i understand a lot about the concepts, and i think, i understand the most, that is thrown upon me on the internet and youtube - especially from Unite - that is shown to me.
But i don’t really know much of all the use cases and scenarios, you would want to use, if you want to write new code.
Lately - i began, thinking about Newtonial Gravitation, which looks like a perfect scenario for entities and the ecs, so i tried to start.
This thread is for both:
Showing new and old ones, how i approach this Scenario and second, asking about things, where i now get stuck.
I will use this entry post as edit area, and will extend it with usage of this thread.
First: The bit of math for those ones, who are not aware of, what i am trying now.
Newtons Law of motion says, that a forced vector F is equal to a mass and its acceleration vector:
F = m * A
Newtons Law of Gravitation says, the force acting is equal to the gravitational constant G multiplied by the masses of two bodies, divided by the square of their masses center.
F = G * m1 * m2 / (d*d)
This is enough to begin, writing the first components and systems.
I know, that i can stick those two together and make up a smaller calculation later, but for clearance of doing this, i first decided to keep those two terms untouched, and begin with the Law of Motion.
As i want to have collisions later, i preferred to use a hybrid approach first, adding a rigidbody with no gravity setup to a simple sphered object, and i wrote two components, one for storing the value of mass, second storing a float3 for acceleration.
After scene load, i update the rigidbodies mass to match the mass set up in the component:
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void Init()
{
Rigidbody[] gravityObjects = GameObject.FindObjectsOfType<Rigidbody>();
for (int i = 0; i < gravityObjects.Length; i++)
gravityObjects[i].mass = gravityObjects[i].GetComponent<MassComponent>().Value.Value;
gravityObjects[i].AddRelativeForce(gravityObjects[i].GetComponent<VelocityComponent>().Value.Value);
}
With this, i could write a simple hybrid component system, that can now move my sphere with the given values:
public class AccelerateSystem : ComponentSystem
{
unsafe public struct AccelerationGroup
{
public Rigidbody rigidbody;
public Acceleration* acceleration;
}
unsafe protected override void OnUpdate()
{
var entities = GetEntities<AccelerationGroup>();
for (int i = 0; i < entities.Length; i++)
{
var entity = entities[i];
entity.rigidbody.AddForce(entity.acceleration->a * Time.deltaTime);
}
}
}
Lately i found out, that in many cases, the compiler wants me to use pointers.
I don’t really know much about the why, but i follow, and everything is working again.
I don’t really know, if that’s a good approach, but i get it working that way.
Now i had to introduce a Force to change that acceleration.
I called it the NetForce, because its value is a force value, calculated out of a net of forces, acting onto this body.
This looks quite easy too:
public class AccelerationSystem : JobComponentSystem
{
#region BurstCompile AccelerationCalculationJob
[BurstCompile]
struct AccelerationCalculationJob : IJobProcessComponentData<Acceleration, Mass, NetForce>
{
public void Execute(ref Acceleration acceleration, [ReadOnly]ref Mass mass, [ReadOnly]ref NetForce netForce)
{
acceleration.a = netForce.F / mass.Value;
}
}
#endregion
#region JobHandle OnUpdate
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var job = new AccelerationCalculationJob();
return job.Schedule(this, inputDeps);
}
#endregion
}
You see:
I can now write Burst Code very easy, without too much trouble !
Maybe i should learn a little bit more about the BurstCompilerFlags in future, to see, if i can optimize this, but it doesn’t look too bad, as i think.
Couldn’t be very much easier, if i wouldn’t try to concatenate things here, to maybe do them in a row, but logically, if i think about that, what the laws mean to do, i needn’t, or better say: it would be false to do that and don’t even match reality.
They can just calculate around as they do, that’s fine …
Now i am coming to my first real greater Job …
I have multiple of these objects flying around, all acting on each other.
If i would say, i have a sun, an earth and mars, the netforce vector for my earth would be the addition of the calculated forcevector with the sun and the force vector with mars.
So now, i need a possibility to compare entities with each other.
- Step here is to make a job for each entity to loop over all entities, that are inside the scene and calculate out a netforce vector out of all forces alltogether, but i don’t only write that code, i also saw very early that i should try to decrease the count of calculation by using some logics…
Coming back to my example, having sun, earth and mars, the forces acting onto two bodies are opposite with each other !
That leads to a nice result by reducing the needed amount of calculation by 2.
I also don’t need a stored reference to the object itself, so as it would look first, that i would need at least 6 calculations to do that, i am ending up by 3.
Example:
Calculating Sun:
With Sun - not needed
With Earth - calculate force
With Mars - calculate force
Calculating Earth:
With Sun - negative to sun
With Earth - not needed
With Mars - calculate force
Calculate Mars:
With Sun - negative to sun
With Earth - negative to earth
With Mars - not needed
This is now, where i am stuck …
I first don’t really know on how i would setup a job for this…
Do i use a NativeArray ? Are there good examples, to see usage more easy ?
Second is: How would i know, if a value is already calculated ? I could wear a flag, or something like this.
I am thinking on store the session each frame in something like a NetForceCalculatorEntity, so i can put the calculated values somewhere and just run through the job for each entity.
It would be a great help, if there are encouraged people, helping me with this bit of example, as it has several things and tries, that would help me to understand a lot for future implementations.
As told before, i will continue adding noticable result and code to the section above !
Thank you for reading !