apotapov / gdx-artemis

Fork of artemis entity-system (http://gamadu.com/artemis/) refactored to integrate with Libgdx (http://libgdx.badlogicgames.com/)
Other
53 stars 5 forks source link

Component get from ComponentMapper is Null #7

Closed hnvn closed 10 years ago

hnvn commented 10 years ago

My system: public class ExpiringSystem extends DelayedEntityProcessingSystem { ComponentMapper em;

@SuppressWarnings("unchecked")
public ExpiringSystem() {
    super(Aspect.getAspectForAll(Expires.class));
}

@Override
public void initialize() {
    em = world.getMapper(Expires.class);
}

@Override
protected float getRemainingDelay(Entity e) {
    Expires expires = em.get(e);
    return expires.delay;                   -------------> NullPointerException <--------
}

@Override
protected void processDelta(Entity e, float accumulatedDelta) {
    Expires expires = em.get(e);
    expires.delay -= accumulatedDelta;
}

@Override
protected void processExpired(Entity e) {
    e.deleteFromWorld();
}

}

apotapov commented 10 years ago

I'll be honest I haven't touched DelayedEntityProcessingSystem much. I tried working with it at one point and it seemed pretty convoluted and buggy. (other people have reported similar experiences)

Can you describe what you are trying to do and how you are using the DelayedEntityProcessingSystem?

I'll try to spend some time on debugging it this week.

apotapov commented 10 years ago

I added a small unit test for the DelayedEntityProcessingSystem. Take a look and see if it makes sense and if that's how you are using it. The test passes but one thing I noticed that it keeps subtracting the accumulated delta from the expires.delay. So what you might want to do is compare delay to accumulatedDelta. Otherwise the delta is going to compound.

Just took another look and it doesn't seem like it's possible. I honestly think that DelayedProcessingEntitySystem is really badly designed. It seems to carry global accumulatedDelta that applies to multiple entries. I can see how that could be useful, but in practice it seems like a bad idea.

I would much rather manage the delay and the expiration of each system individually. The best way to do that is to keep a delay component. (basically what you are doing already) Then have the system update that component appropriately, and perform user defined action when the delay expires. The system should not maintain any sort of global accumulated delta. That needs to be done at the entity/component level.

I've always questioned the usefulness of both IntervalEntitySystem and DelayedEntitySystem. Personally I haven't found a good use case for either. The way they are currently implemented anyway. I've thought about deprecating them in favor of something a little more generic.

Thoughts?

hnvn commented 10 years ago

I agree with your thoughts. DelayedProcessingEntitySystem is badly designed and buggy. But I need a system which saves CPU time for controlling the lifetime of each entity. Also I'm having some problems related to the deleting of entity behavior of the system, I will check and report back later. Thanks for your quickly support!

2014/1/14 Andrew Potapov notifications@github.com

I added a small unit test for the DelayedEntityProcessingSystem. Take a look and see if it makes sense and if that's how you are using it. The test passes but one thing I noticed that it keeps subtracting the accumulated delta from the expires.delay. So what you might want to do is compare delay to accumulatedDelta. Otherwise the delta is going to compound.

Just took another look and it doesn't seem like it's possible. I honestly think that DelayedProcessingEntitySystem is really badly designed. It seems to carry global accumulatedDelta that applies to multiple entries. I can see how that could be useful, but in practice it seems like a bad idea.

I would much rather manage the delay and the expiration of each system individually. The best way to do that is to keep a delay component. (basically what you are doing already) Then have the system update that component appropriately, and perform user defined action when the delay expires. The system should not maintain any sort of global accumulated delta. That needs to be done at the entity/component level.

I've always questioned the usefulness of both IntervalEntitySystem and DelayedEntitySystem. Personally I haven't found a good use case for either. The way they are currently implemented anyway. I've thought about deprecating them in favor of something a little more generic.

Thoughts?

— Reply to this email directly or view it on GitHubhttps://github.com/apotapov/gdx-artemis/issues/7#issuecomment-32206798 .

hnvn commented 10 years ago

I'm having a very strange behavior of the system, when ComponentMapper sometimes returns a null value, even in the method inserted(Entity e). Such cases are often encountered when I reset the game screen, by deleting some entity and reset in a new game. I'm really confused!

2014/1/14 Hưng Hà hunghd.yb@gmail.com

I agree with your thoughts. DelayedProcessingEntitySystem is badly designed and buggy. But I need a system which saves CPU time for controlling the lifetime of each entity. Also I'm having some problems related to the deleting of entity behavior of the system, I will check and report back later. Thanks for your quickly support!

2014/1/14 Andrew Potapov notifications@github.com

I added a small unit test for the DelayedEntityProcessingSystem. Take a look and see if it makes sense and if that's how you are using it. The test passes but one thing I noticed that it keeps subtracting the accumulated delta from the expires.delay. So what you might want to do is compare delay to accumulatedDelta. Otherwise the delta is going to compound.

Just took another look and it doesn't seem like it's possible. I honestly think that DelayedProcessingEntitySystem is really badly designed. It seems to carry global accumulatedDelta that applies to multiple entries. I can see how that could be useful, but in practice it seems like a bad idea.

I would much rather manage the delay and the expiration of each system individually. The best way to do that is to keep a delay component. (basically what you are doing already) Then have the system update that component appropriately, and perform user defined action when the delay expires. The system should not maintain any sort of global accumulated delta. That needs to be done at the entity/component level.

I've always questioned the usefulness of both IntervalEntitySystem and DelayedEntitySystem. Personally I haven't found a good use case for either. The way they are currently implemented anyway. I've thought about deprecating them in favor of something a little more generic.

Thoughts?

— Reply to this email directly or view it on GitHubhttps://github.com/apotapov/gdx-artemis/issues/7#issuecomment-32206798 .

apotapov commented 10 years ago

There are some issues in regard to entity deleting right now. From what I've seen, if you have two systems both of which are processing the same set of entities, if the first system deletes the entity, the second system will still have that entity in it's list to process.

Currently, I avoid that by checking entity.isActive() in the second system. That's a hack though. I'll file a separate bug to fix that behaviour. (hopefully without adding too much overhead..)

hnvn commented 10 years ago

Ok, again thank you!

2014/1/15 Andrew Potapov notifications@github.com

There are some issues in regard to entity deleting right now. From what I've seen, if you have two systems both of which are processing the same set of entities, if the first system deletes the entity, the second system will still have that entity in it's list to process.

Currently, I avoid that by checking entity.isActive() in the second system. That's a hack though. I'll file a separate bug to fix that behaviour. (hopefully without adding too much overhead..)

— Reply to this email directly or view it on GitHubhttps://github.com/apotapov/gdx-artemis/issues/7#issuecomment-32283990 .

hnvn commented 10 years ago

I'm having a really hard problem to understand, in the process of investigating the cause of a component is null, I discovered in the entityPool have 2 entity has the same UUID!!? Here are my results in the entity list in pool:

9191285a-5c66-4898-9ada-817e7925a737 c945a39e-a740-4240-a8e5-584e9bd90427 e2cf8794-2ed3-4c97-895e-d7d28d1adad7 c8742688-bce9-4215-921c-88b971211005 4b8b2cb6-99c5-4468-b523-0c3aaec1c244 94b5c138-05bd-4db0-91a1-5f0a1ae4f33c c945a39e-a740-4240-a8e5-584e9bd90427 fea07c08-8ad9-4842-902c-827a2e03c4b9 5eda8b0b-1379-4f9e-b5cf-6d2d9839139d 96d871c6-1b7e-4d35-ac55-451eb4ca8474 58ca294a-1219-417c-b322-0c0553355454 607724ac-1683-4a89-947e-b08e92ec1664

UUID - c945a39e-a740-4240-a8e5-584e9bd90427 is duplicated!!!

apotapov commented 10 years ago

Interesting. Are you using UUID for a specific purpose?

Also, do you have a specific test case that replicates this issue? I'm curious how you are using Artemis in this case.

hnvn commented 10 years ago

I have found the cause duplicate UUID: Artemis add to the pool at the same entity twice, when the pool call reset function allocated a new UUID, there are two instances of the same entity in pool should the results in 2 instances received the same UUID. I think libgdx should block can add an object already exists in the pool (I have reported this issue to libgdx team). But I do not understand why Artemis could add duplicated objects in the pool!? The duplicate objects in the pool really dangerous, because when an action is performed on this object it also affects other objects, and this is the cause of a component can be null in the my program

2014-02-05 Andrew Potapov notifications@github.com:

Interesting. Are you using UUID for a specific purpose?

Also, do you have a specific test case that replicates this issue? I'm curious how you are using Artemis in this case.

Reply to this email directly or view it on GitHubhttps://github.com/apotapov/gdx-artemis/issues/7#issuecomment-34087773 .

hnvn commented 10 years ago

I finally figured out the cause of the strange behavior of the program. There is a bug in my program when an entity is called deleteFromWorld () two times, so the same entity to be added to entityPool twice.

apotapov commented 10 years ago

Cool. Good to know. :)