Hey,
how are you guys doing visual-only effects? I currently have a list of prefabs which get pooled and a system called WorldFXSystem which receives effect requests. Having a spreadsheet with audio and vfx references (ScriptableObject) instead of single prefabs seems like an improvement. So I’m not necessarily looking for better performance but better usability in the calling code and effect authoring.
How other systems request an effect. Note that the event name gets hashed (prob at compile time):
var ecb = GetSingleton<BeginInitializationEntityCommandBufferSystem.Singleton>().CreateCommandBuffer(state.WorldUnmanaged);
var worldFx = GetSingletonEntity<WorldFXSystem.Singleton>();
...
ecb.AppendToBuffer(worldFx, new QueuedFX("FX_ShootArrow", pos, quaternion.identity));
The WorldFXSystem, just for reference:
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using static Unity.Entities.SystemAPI;
public readonly struct QueuedFX : IBufferElementData {
public readonly int EffectType;
public readonly float3 Position;
public readonly quaternion Rotation;
public QueuedFX(in FixedString128Bytes name, float3 position, quaternion rotation) {
EffectType = HashUtil.Hash(name);
Position = position;
Rotation = rotation;
}
public QueuedFX(int effectType, float3 position, quaternion rotation) {
EffectType = effectType;
Position = position;
Rotation = rotation;
}
}
[UpdateInGroup(typeof(PresentationSystemGroup))]
public partial struct WorldFXSystem : ISystem {
public struct Singleton : IComponentData {
public int Dummy;
}
class EffectPool {
public List<GameObject> Effect;
public int Idx;
}
class EffectPools : IComponentData {
public List<int> NameHash;
public List<EffectPool> Pools;
}
public void OnCreate(ref SystemState state) {
var parent = new GameObject("WorldFX");
parent.hideFlags = HideFlags.DontSave;
var nameHashes = new List<int>();
var pools = new List<EffectPool>();
foreach (var fx in GameObjectAssets.Instance.FXPrefabs) {
var gos = new List<GameObject>(10);
for (int i = 0; i < 10; ++i) {
var newGO = Object.Instantiate(fx, parent.transform);
newGO.SetActive(false);
gos.Add(newGO);
}
var pool = new EffectPool() {
Effect = gos
};
nameHashes.Add(HashUtil.Hash(fx.name));
pools.Add(pool);
}
state.EntityManager.AddComponentObject(state.SystemHandle, new EffectPools {
NameHash = nameHashes,
Pools = pools
});
var e = state.EntityManager.CreateSingleton(new Singleton { });
state.EntityManager.AddBuffer<QueuedFX>(e);
}
public void OnDestroy(ref SystemState state) {
}
public void OnUpdate(ref SystemState state) {
var queuedFx = GetSingletonBuffer<QueuedFX>();
var pools = ManagedAPI.GetComponent<EffectPools>(state.SystemHandle);
for (int fxIdx = 0; fxIdx < queuedFx.Length; ++fxIdx) {
var queuedEffect = queuedFx[fxIdx];
int poolIdx = -1;
for (int i = 0; i < pools.NameHash.Count; ++i) {
if (pools.NameHash[i] == queuedEffect.EffectType) {
poolIdx = i;
break;
}
}
if (poolIdx == -1)
throw new System.Exception($"Effect type {queuedEffect.EffectType} not found");
var pool = pools.Pools[poolIdx];
var idx = pool.Idx;
pool.Idx = (pool.Idx + 1) % pool.Effect.Count;
var effect = pool.Effect[idx];
effect.SetActive(false);
effect.transform.SetPositionAndRotation(queuedEffect.Position, queuedEffect.Rotation);
effect.SetActive(true);
}
queuedFx.Clear();
}
}
Thank you ![]()