Here is my attempt at setting up a prefab system for ECS. It properly sets up archetypes for all your prefabs and allows you to store any instance data you want for each prefab. It also allows you to easily add batches of components or have prefabs inherit from each other. There is an extra cache miss for each component you add which is not default initialized but in most cases this should hopefully be ok. I thought this might be useful to other people so I'm sharing it here. The full source code can be found here: https://github.com/jseidenz/ecsprefabs Code (CSharp): // Setup prefabs public static class Prefabs { public static Prefab Asteroid = new Prefab() .AddPhysics() .Add(new Asteroid{}) .Add(new SceneLayer{}) .Add(new CircleSprite{}); public const long SHIP_RADIUS = 4000; public static Prefab Ship = new Prefab() .AddPhysics(radius:SHIP_RADIUS) .Add(new Thruster{}) .Add(new Health{}) .Add(new Gun{}) .Add(new CircleSprite { _Radius = SHIP_RADIUS, _Color = Color.green }); public static Prefab AIShip = new Prefab(Ship) .Add(new AI{}); public static Prefab PlayerShip = new Prefab(Ship) .Add(new PlayerInput{}); public const long BULLET_RADIUS = 400; public static Prefab Bullet = new Prefab() .AddPhysics(radius:BULLET_RADIUS) .Add(new SceneLayer{}) .Add(new Bullet{}) .Add(new CircleSprite { _Radius = BULLET_RADIUS, _Color = Color.yellow }); public static Prefab AddPhysics(this Prefab prefab, long radius = 1000) { return prefab .Add(new Position{}) .Add(new Rotation{}) .Add(new RigidBody{}) .Add(new CircleCollider{_Radius = radius}); } } Code (CSharp): // Spawn prefabs public class Example : ComponentSystem { struct Data { public int Length; public ComponentDataArray<Gun> _Guns; public ComponentDataArray<Position> _Positions; } [Inject] Data _Data; protected override void OnCreateManager(int capacity) { InitializePrefabManager.Initialize(); Prefabs.PlayerShip.Spawn() .Set(new Position{_X = 100, _Y = 100}); } protected override void OnUpdate() { for(int i = 0; i < _Data.Length; ++i) { PostUpdateCommands.Spawn(Prefabs.Bullet) .Set(_Data._Positions[i]); } } }
Thanks for sharing ! To be fully useful, I think you should add some way to spawn prefabs during system Update, for instance using PostUpdateCommands., etc.
Thank you for the feedback. I added support for spawning prefabs from EntityCommandBuffers and updated the example code.
Here is my version also using fluent interface Instead of using extension methods i'm inheriting ComponentSystem and also i'm using PostUpdateCommands Usage is almost the same in OnCreateManager: (define archetype and set defaults) Code (CSharp): DefineEntity( "car" ) .Add<Rotation>() .Add( new Position(){ Value = new float3(0, 1, 0) } ) .Add<Speed>(); in OnUpdate: (spawn and overwrite defaults) Code (CSharp): Spawn("car").Set(new Speed{Value = 10}); System code Code (CSharp): public abstract class EcsSystem : ComponentSystem{ protected abstract override void OnUpdate(); private static Dictionary<string, EntityDefinition> defs = new Dictionary<string, EntityDefinition>(); protected EntityDefinition DefineEntity( String name ){ var def = new EntityDefinition(); defs.Add( name, def ); return def; } public EcsSystem Spawn(string name){ EntityDefinition def = defs[name]; PostUpdateCommands.CreateEntity( def.GetArchetype( EntityManager ) ); def.Components.ForEach( cpi => cpi.PostUpdateSet( this ) ); return this; } public void Set<T>(T cp)where T: struct, IComponentData{ PostUpdateCommands.SetComponent( cp ); } } public class EntityDefinition{ private EntityArchetype _archetype; public List<ComponentType> Types = new List<ComponentType>(); public readonly List<IComponentDataWrapper> Components = new List<IComponentDataWrapper>(); public EntityArchetype GetArchetype(EntityManager em){ if( _archetype == default(EntityArchetype) ) _archetype = em.CreateArchetype(Types.ToArray()); return _archetype; } public EntityDefinition Add<T>() where T : struct, IComponentData{ Types.Add( ComponentType.Create<T>() ); return this; } public EntityDefinition Add<T>( T cd ) where T : struct, IComponentData{ Types.Add(ComponentType.Create<T>() ); Components.Add( new ComponentDataWrapper<T>( cd ) ); return this; } } public interface IComponentDataWrapper{ void PostUpdateSet(EcsSystem system); } class ComponentDataWrapper<T> : IComponentDataWrapper where T : struct, IComponentData{ public T _Component; public ComponentDataWrapper(T component){_Component = component;} public void PostUpdateSet( EcsSystem sys ){ sys.Set(_Component); } }
Hi, Are you aware that you can instantiate a gameobject (prefab) and have it automatically create all the IComponentData-derived components on the ECS side without creating any actual game objects? See EntityManagerExtensions.Instantiate(this EntityManager entityManager, GameObject srcGameObject)
Also, once an entity has been created, it can be used to instantiate clones in batch, which is vastly more efficient and should be the default for most simulations. See EntityManager.Instantiate(Entity, NativeArray<Entity>)
@deplinenoise - is there a way for that to work across worlds? IE: Let's say we have a world with no systems that we use to store prefabs entities in so they go untouched by normal worlds with systems. Or is there a universal way to freeze/exclude an entity in a world from normal processing?
Right now the only reasonably well working way of using prefabs is to instantiate the entities from the game object prefab directly.
this tread isn't about game object prefabs this is about pure entities it is useful to be able to construct and configure entity and store it in some form and then to instantiate it several times for example let's take a bullet in a shooter game, when you spawn it, it'll fly forward until hit something, and after hitting anything is removed, and when you have a machine gun you have to spawn lots of this bullets, also you bullets may have some default configuration options, like damage, size, speed depending on weapon used to spawn it great way to do it is to clone a hidden pre-constructed and pre-configured single bullet entity many times (separate for each kind of weapon) EntityManager.Instantiate is not good for this because original is not hidden (all systems affect original) EntityArchetype is not good because it do not store default component values not pre-configured (only list of component types) GameObject is not good because it is not an entity this is what we are talking about, not about using game object prefabs
The approach we are probably going to take is to have some kind of default "Inactive" component which is default disabled by all ComponentGroups. You could probably do exactly this manually for the time being.
In my case performance is not a key factor, so i've took a different approach: I'm constricting EntityDefinition objects at startup using chained commands this object is a container for 1) entity archetype and 2) list of components with defaults and at runtime i'm constructing entities from this object with one method Spawn() which adds several PostUpdateCommand-s ( thinking now about custom gui editor for it )
Did you manage to achieve your goal? I am also interested in this, doing everything in code is not really flexible
no news - custom editor for EntityDefinition is on hold the rest is here https://forum.unity.com/threads/ecs-prefabs.532225/#post-3506159
Hi, I am not so good in programming, but I have been working for games using unity 3d, tried to find a way to translate the below piece of code, Please help me to translate the below piece of code in ECS public GameObject pref; public void CreateObjs() { for (int i = 0; i < 10000;i++) { Instantiate(pref); } } also there are 2 more components attached with the prefab, Rigidbody and BoxCollider. Thanks
Is there a way to use it with hybrid ECS? E.g. System that inherited from ComponentSystem is going to create objects on scene from prefab using EntityManagerExtensions.Instantiate. Or it is impossible right now?
this is a very old post, there is a prefab component now to instantiate "pure" entities if you need a system that creates gemeObject each time you create an entity, you need to write a system for that yourself, there is no ready solution, but there is a way to convert gameobject to entity see https://forum.unity.com/threads/new-subscene-converttoentity-workflows.638785/
Could you tell me how you would write the prefabs on the 1st post using the prefab component? From what I see it doesn't allow you to set default values for IComponentDatas
when your entity has a prefab component on it, it is ignored by all systems, but you still can clone it using EntityManager.Instantiate(), all clones receive the exact same set of components as prefab had excluding prefab component which is removed on clone during instantiation.
I'm trying to use this function but all i get instantiated is an empty entity. What do i miss? scrGameObject is a prefab with multiple authoring components on it and a ConvertToEntity Component
Same behavior. This method just creates an empty entity. Help Please! Did you solve it or created a thread about this?