FAQ
Docs / Overview / FAQ
Frequently asked questions about ZenECS.
General Questions
What is ZenECS?
ZenECS is a pure C# Entity-Component-System (ECS) runtime designed for clarity, determinism, and zero dependencies. It provides a clean architecture for game development with optional Unity integration.
Why should I use ZenECS?
- Clean Architecture: Strict separation of data, simulation, and presentation
- Testability: Systems are pure functions, easy to test
- Engine Independence: Works with Unity, Godot, or standalone .NET
- Deterministic: Reproducible simulations for networking and replays
- Well Documented: Comprehensive documentation and examples
Is ZenECS production-ready?
Yes! ZenECS 1.0 is a Release Candidate with locked APIs. It's being used in production projects and is ready for serious game development.
How does ZenECS compare to Unity DOTS?
| Aspect | ZenECS | Unity DOTS |
|---|---|---|
| Performance | Good | Excellent |
| Clarity | High | Medium |
| Learning Curve | Gentle | Steep |
| Engine Dependency | None | Unity only |
| .NET Support | Full | Unity only |
ZenECS prioritizes clarity and maintainability over maximum performance.
Installation & Setup
How do I install ZenECS?
Unity (UPM):
https://github.com/Pippapips/ZenECS.git?path=Packages/com.zenecs.core
NuGet:
dotnet add package ZenECS.Core
See Installation Guide for details.
What are the requirements?
- .NET Standard 2.1 or higher
- Unity 2021.3+ (for Unity adapter)
- No external dependencies (Core package)
Do I need both Core and Unity Adapter?
- Core: Required for all projects
- Unity Adapter: Optional, only needed for Unity integration
Usage Questions
How do I create an entity?
Entity entity;
using (var cmd = world.BeginWrite())
{
entity = cmd.CreateEntity();
}
Or with command buffer:
using (var cmd = world.BeginWrite())
{
var entity = cmd.CreateEntity();
}
How do I add components?
using (var cmd = world.BeginWrite())
{
cmd.AddComponent(entity, new Position(0, 0));
}
Or with command buffer:
using (var cmd = world.BeginWrite())
{
cmd.AddComponent(entity, new Position(0, 0));
}
How do I query entities?
foreach (var (entity, pos, vel) in world.Query<Position, Velocity>())
{
// Process entities with both Position and Velocity
}
How do I write a system?
[FixedGroup]
public class MovementSystem : ISystem
{
public void Run(IWorld world, float deltaTime)
{
using var cmd = world.BeginWrite();
foreach (var (entity, pos, vel) in world.Query<Position, Velocity>())
{
cmd.ReplaceComponent(entity, new Position(
pos.X + vel.X * deltaTime,
pos.Y + vel.Y * deltaTime
));
}
}
}
When should I use Command Buffers?
Use command buffers when:
- Creating or destroying entities
- Adding or removing components
- Making structural changes during system execution
Command buffers ensure changes are applied at safe boundaries.
Architecture Questions
Why struct components?
- Performance: Value types, no heap allocation
- Cache-friendly: Contiguous memory layout
- Immutability: Encourages functional programming
Why multiple worlds?
Multiple worlds enable:
- Split-screen: Separate worlds for each player
- Server/Client: Isolated simulation spaces
- Game modes: Different worlds for different modes
- Testing: Isolated test worlds
How does the message bus work?
Messages are struct-based pub/sub:
// Publish
world.Publish(new DamageMessage { Target = entity, Amount = 10 });
// Subscribe (in system)
foreach (var msg in world.ConsumeMessages<DamageMessage>())
{
// React to message
}
Messages are processed deterministically during frame updates.
What is binding?
Binding connects ECS data to view layer reactively:
public class PositionBinder : IBinder<Position>
{
public void OnDelta(ComponentDelta<Position> delta)
{
transform.position = delta.NewValue;
}
}
Binders automatically receive updates when components change.
Performance Questions
Is ZenECS fast?
ZenECS is designed for good performance with a focus on clarity:
- Cache-friendly: Components in contiguous arrays
- Zero allocation: Queries use struct enumerators
- Efficient: Optimized for common use cases
For maximum performance, consider Unity DOTS.
Can I use ZenECS for large-scale games?
Yes! ZenECS scales well:
- Thousands of entities: Handled efficiently
- Many systems: Parallel execution possible
- Memory efficient: Component pooling and recycling
How does performance compare to Unity DOTS?
Unity DOTS is faster for very large-scale simulations (millions of entities). ZenECS prioritizes clarity and maintainability over maximum performance.
Unity Integration
How do I integrate with Unity?
Use the Unity Adapter package:
- Install
com.zenecs.adapter.unity - Add
EcsDriverto your scene - Use
EntityLinkto connect GameObjects - Create systems and register them
See Unity Adapter Overview for details.
Can I use ZenECS without Unity?
Yes! ZenECS Core has zero dependencies and works in any .NET environment:
- Standalone .NET applications
- Game servers
- Simulations
- Other game engines (with custom adapter)
How do EntityLink and GameObjects work?
EntityLink connects Unity GameObjects to ECS entities:
var link = gameObject.AddComponent<EntityLink>();
link.Attach(world, entity);
The link maintains the connection and can be queried to find the GameObject for an entity.
Advanced Questions
How do I save/load game state?
Use snapshots:
// Save
using var stream = File.Create("save.dat");
world.Save(stream);
// Load
using var stream = File.OpenRead("save.dat");
world.Load(stream);
See Snapshot I/O for details.
How do I handle version migrations?
Register migration functions:
world.RegisterMigration<OldComponent, NewComponent>((old) => new NewComponent
{
// Convert old to new
});
See Migration & PostMig for details.
Can I extend ZenECS?
Yes! ZenECS is designed for extensibility:
- Custom systems: Implement
ISystem - Custom binders: Implement
IBinder<T> - Custom hooks: Add write permissions and validators
- Custom formatters: Implement
IComponentFormatter
See Extending ZenECS for details.
Troubleshooting
My system isn't running
Check:
- System is registered:
world.AddSystems([new MySystem()]) - System has correct attribute:
[FixedGroup]or[FrameGroup] - World is being stepped:
kernel.PumpAndLateFrame(...) - Entities match query: Entities have required components
Entities aren't being found
Check:
- Entities have required components
- Query matches component types
- Entities are alive:
world.IsAlive(entity) - World is correct: Using the right world instance
Components aren't updating
Check:
- Using command buffer for writes:
using var cmd = world.BeginWrite() - Replacing components:
cmd.ReplaceComponent(...) - System is running: Check system registration and execution
- World is being stepped:
kernel.PumpAndLateFrame(...)
See Also
- Quick Start - Get started quickly
- Troubleshooting - Common issues and solutions
- Architecture - Technical details
- Glossary - Terminology reference