Open AemaethMonster opened 6 years ago
You can no longer access the component data with a reactive system. The component is already deleted. It is possible if you register for a group event:
public class FaceRemoveSystem : IInitializeSystem, ITearDownSystem {
private readonly IGroup<GameEntity> group;
public FaceRemoveSystem(GameContext game) {
group = game.GetGroup(GameMatcher.Face);
}
public void Initialize() {
group.OnEntityRemoved += Group_OnEntityRemoved;
}
public void TearDown() {
group.OnEntityRemoved -= Group_OnEntityRemoved;
}
private void Group_OnEntityRemoved(IGroup<GameEntity> group, GameEntity entity, int index, IComponent component) {
Object.Destroy(entity.face.gameobj);
e.face.sequence.Kill();
}
}
But be careful. This method is called immediately when the component is removed. This means there is no order and you should avoid such systems as much as possible. I hereby warned you :smile:
Thank you for the answer. Maybe I should write the same lines after every .RemoveFace(), instead of using the system like this.
Actually I think, when .RemoveComponent(), the component should be really removed at the very end of this frame. So that we can do some last thing before it disappear.
We solved a similar issue by introducing the DestroyedComponent
and deferring the actual destruction of the entity to the end of the frame.
You can use the same approach for removed faces.
Once you call e.RemoveXyzComponent()
the components is removed immediately. If you still need this data a later point of time, you must not remove it.
If removing the face only happens when you destroy an entity, you can just react do GameMatcher.Destroyed
and filter for e.hasFace
.
@sschmid DestroyedComponent is a nice solution that I need. But one problem raises.
What I write in DestroyedComponent.cs
public class DestroyedComponent : IComponent
{
public string component_name;
}
In reactive system
protected override void Execute(List<IDestroyableEntity> entities)
{
foreach (var e in entities)
{
// now we can access the ViewComponent and the DestroyedComponent
if (e.destroyed.component_name == "Action" && e.hasAction)
{
e.action.timeline_x.Kill();
e.action.timeline_y.Kill();
e.action.timeline_agl.Kill();
e.RemoveAction();
}
else if (e.destroyed.component_name == "Face" && e.hasFace)
{
sth
e.RemoveFace();
}
else if .....
}
}
The problem is that: If I remove two different components in a frame, like
e.ReplaceDestroyed("Action");
e.ReplaceDestroyed("Face");
, only one component will be removed.
I know why it happened. Because DestroyedSystem update every one frame. But I don't know how to fix it.
@Noicon
protected override void Execute(List<IDestroyableEntity> entities)
{
foreach (var e in entities)
{
// now we can access the ViewComponent and the DestroyedComponent
if (e.destroyed.component_name == "Action" && e.hasAction)
{
e.action.timeline_x.Kill();
e.action.timeline_y.Kill();
e.action.timeline_agl.Kill();
e.RemoveAction();
}
/* else is not suitable here */ if (e.destroyed.component_name == "Face" && e.hasFace)
{
sth
e.RemoveFace();
}
else if .....
}
}
I don't think the problem is here... In one trigger of reactive system, e.destroyed.component_name is one-single string, it can't be "Face" and "Action" at the same time.
Actually, all problems in this issue already solve in #755 . By writing my own .Add, .Replace, and .Remove, even doesn't need a react system to release the timeline(sequence). Thank all of you!!
public class DestroyedComponent : IComponent
{
public List<string> component_name;
}
Is it possible to use list to store component that needs to be deleted?
public class CommandComponent:IComponent
{
public List<CommandEnum> commandList;
}
public enum CommandEnum
{
None = 0,
AddRender,
RemoveRender,
Destory,
}
public static void AddSafeCommand(this GameEntity entity, CommandEnum command)
{
var list = new List<CommandEnum>();
if (entity.hasCommand)
{
list = entity.command.commandList;
}
list.Add(command);
entity.ReplaceCommand(list);
}
I treat all one-time operations in the system as a command, and then process them through the command system, but I don't know if the design is appropriate.
And it raises a new problem. If I disable the command system in editor debugging mode, the list data becomes very large in an instant.
private readonly Contexts _contexts;
private readonly IGroup<GameEntity> _commandGroup;
public CommandSystem(Contexts contexts)
{
_contexts = contexts;
_commandGroup = contexts.game.GetGroup(GameMatcher.Command);
}
public void Execute()
{
foreach (var entity in _commandGroup.GetEntities())
{
foreach (var command in entity.command.commandList)
{
switch (command)
{
case CommandEnum.None:
break;
case CommandEnum.AddRender:
if (entity.hasResource)
{
entity.AddSafeRender(entity.resource.resource);
}
break;
case CommandEnum.RemoveRender:
entity.RemoveSafeRender();
break;
case CommandEnum.Destory:
entity.RemoveSafeRender();
if (entity.isEnabled)
{
entity.Destroy();
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
My code↑. If Filter() return !entity.hasFace ,then in Execute(), e.face will raise a error. If Filter() return entity.hasFace, then it will never Execute(). Is that impossible to get the component's value, when it is just removed? Need help:)