I’ve been trying to initialize a component with some basic data using a Entities.ForEach() in a OnCreate method but the component doesn’t seem to be populating. How are you supposed to do this?
Unless you intentionally created an entity before OnCreate is called, entities usually don’t exist yet when OnCreate is called.
Also, UnityEngine.Debug.Log($“{/non string things to print/}”) works in Burst contexts, so you can use that to figure out whether Bursted code is executing or not.
I typically rely on GameObject Conversion for initializing components. For data that should be initialized to a hardcoded value (like 0 for counters), I will hardcode that initialization in the IConvertGameObjectToEntity.
For random initialization, I either do the randomization right after instantiation, or I use a reactive system.
I’m experimenting with thousands of cubes so it doesn’t make sense to do it manually. How do you update IComponentData variables on instantiation or with a reactive system?
Someone else can probably give you some simplified examples. I will give you some real-world examples.
Example 1: Instantiation - lsss-wip/Assets/_Code/SubSystems/Gameplay/OrbitalSpawnersProcGenSystem.cs at v0.2.0 · Dreaming381/lsss-wip · GitHub
Note that I am procedurally generating an entity from scratch here and then instantiating it. I could have instantiated an authored prefab and that’s usually what I do, but it didn’t make much sense for this particular system. Regardless of if the prefab is authored or generated from scratch, I tag it with a custom tag that I can then use in an Entities.ForEach afterwards. That happens here inside Randomize().
Example 2: ECB - lsss-wip/Assets/_Code/SubSystems/Gameplay/FireGunsSystem.cs at v0.2.0 · Dreaming381/lsss-wip · GitHub
Here I am actually instantiating authored prefabs in a parallel job using an EntityCommandBuffer.ParallelWriter. After instantiating each entity, I also call SetComponent to initialize the Translation and Rotation. If you were to change the git hash for this file, you will see it has changed in later versions to use a custom InstantiateCommandBuffer I wrote which combines the instantiation and initialization and performs quite a bit faster.
Example 3: Reactive System - lsss-wip/Assets/_Code/SubSystems/AI/AiExploreInitializePersonalitySystem.cs at v0.2.0 · Dreaming381/lsss-wip · GitHub
Here, the EntityQuery matches newly instantiated AI ships which still have an AiExplorePersonalityInitializerValues component. This system initializes all of these entities, then removes the AiExplorePersonalityInitializerValues component from all of them. This results in those entities never being processed by the system again.
I’m surprised no one has done a simple example on how to initialize variables for IComponentData. I’m basically asking for a helloworld here but I can definitely look what you’ve done for ramping up on ECS.
I’ve only been doing ECS for 3 days now but I’ll catch up soon enough. It seems pretty easy for the most part. It’s similar to the MVC design pattern I’ve used for most of my projects. Just unclear on what the best practices are.
I just create a system for it and disable it after running once.
Example code:
public class DestinationInitializationSystem : SystemBase
{
protected override void OnUpdate()
{
// Run once and set Destination for all Agents to their initial position, so prevent moving to float3.zero at the start.
Entities.ForEach((ref Destination destination, in Translation translation) =>
{
destination.Value = translation.Value;
})
.ScheduleParallel();
Debug.Log(nameof(DestinationInitializationSystem) + " run.");
Enabled = false;
}
}
Do you know if there’s a way to have two ForEach loops and only disable one of them within the same class? For example the first ForEach loop being the initialization and the second being the main loop.
I’d just use two different systems for that, one for initialization one for main loop. If you want one system initializing on OnStartRunning and main loop on OnUpdate could work (though I didn’t try this)
For this setup I would recommend adding [UpdateInGroup(InitializationSystemGroup)] to your initializing system, rather than using UpdateBefore/UpdateAfter. That way you don’t need to add any attributes to other systems that access the data - by default systems run later in SimulationSystemGroup