Some ES design questions

Note , by KeyAction i do not mean JME’s KeyAction class. it is just random name i chose. You may call it KeyInfo or something , which has an int id of a key and boolean isPressed in it. Is it OK ?

In a word, I’d say “no”.

The key has nothing to do with “game”. In fact, what if the user pressed a joystick trigger? The idea of “key” should be so far abstracted up into the view that it has absolutely nothing to do with game objects. It’s a sign of something really wrong with the design.

Think about it this way: in a client/server environment, why would the server need to care about these key codes? The server should be dealing with game concepts.

3 Likes

So let me edit my word this way

I have an Input system which deals with input devices. My player can have different states like walking, shooting, eating , … . So i need to map these input keys with player states . And when ever a key input is detected by Input system it will add corresponding state (which is a component) to player entity. Is it a bit better now ?

If those states are “Walking” “Eating” or “Shooting”… then yes. Though each of those seems like separate components to me. After all, an entity may be walking, eating, and shooting all at the same time and it may be completely different systems that care about that.

2 Likes

And just to be clear, only that last part is that part that might interact with the ES. All parts up to “adding walking to a player” is not using the ES.

1 Like

Okay. I understood it now :relieved:
I think this was my mistake. I wanted to handle these parts you mentioned [quote=“pspeed, post:25, topic:37022”]
All parts up to “adding walking to a player” is not using the ES
[/quote]

by ES .
So i should handle just ES related parts with ES and do not try to add non ES parts to ES forcefully . I learned good tips today.:grinning:

Thanks so much for patiently answering my question. :heart:

Hi
This question is related to EntitySet

1 : Can we have more than one EntitySet in a system that each one listening to different component(s) ? (Or Is this a bad sign that i am merging two systems which should be separate ?)

2 : We have one EntitySet in our system listening to some components. So whenever one of those components changed then for example method
updateEntity(entities.getChangedEntities()); will include that entity in the returned set. Now what if we want to know actually which component(s) is/are changed on that entity ? (because we want to make different decisions based on which component is changed)

I have not a clear example use case for them yet, just want make it clear for myself for better deciding later.

Thanks

It does happen. Generally only one is the “looping” set. For example, a physics system might have one entity set that gives it the physical bodies that it iterates over every frame. It may have other sets that are used to collect velocity or impulses, etc…

You have to determine this yourself. But many times it’s already state you are keeping on your internal book-keeping objects. Though the “because we want to make different decisions” part worries me from a design standpoint. What decisions?

For example in my system i have entitySet=ed.getEntities( Foo.class, Bar.class );
if I detected component Foo is changed on my entity then i am going to change component Baz.class on entity and if i detected component Bar.class is updated then i am going to change Qux.class component on entity

but i can address this issue with first one. I can have two EntitySet which one of them only listen to Foo.class and other one only listen to Bar.class

then i start to doubt if this really should done in one system or i am wrongly merging two systems as one composite system ?? :thinking:
Maybe i should first find a good use case example then we can better decide on it.

Yes. Too hard to work in the hypothetical.

For me this “when Foo component changes on entity I add Baz component and if Bar component changes on entity I add Blabla component” sounds like you should have two system.
I also have sometimes more than one set in one system but only if they “interact” somehow to avoid nasty system to system communication.

1 Like

And usually they are closely related conceptually… often one set is merely helping maintain the other.

2 Likes

ES and Multi-threading


I want to experiment multi threading over ES. And as an example I want to make ModelViewState in sim-eth-es example to run multi threading.
(ModelViewState has direct interaction with Asset manager and Scene graph)

I know how to do multi threading in Java.
But not sure how should i do it on my system in Zay-ES and JME.
Can you please guide me to do it.

Thanks

Well, Zay-ES is already multithreaded. No problems there.

It doesn’t really make sense to make the ModelViewState multithreaded, though. You’d have to contend with a bunch of JME-specific threading crap and I don’t really see the point. Can you explain why you want to do this?

  • All models are being load from disk in this System (new model loading is not specific at game starting but it can happen any time in game) [ By new model I mean model which is not in asset manager cache]

  • My GUI text message geometries are being generated from atlas using TTF library inside this System. (generating text geometry from atlas for the first time cause a bit of lag in game :sweat_smile:). (Text geometry generation is not specific at game starting but it can happen any time in game)

So i want to do them in separate thread and when they are generated or loaded then add them to root node or gui node.

Edit : Actually i am going to make ModelViewState multi thread only if Asset manager is capable of running multi threaded otherwise I have no choice to keep it in game main thread.

If you think so, then lets chose an other system.
I just want to see an example of a multi threaded system to get the idea of how should i do my own.

Loading models on the background thread is one thing… it requires no interaction with the ES, really.

To make a multithreaded system you run your system code in a different thread. That’s all there is to it. For example, the sim-eth-es example runs the game systems in a separate game system thread. I know it’s on the server, but it doesn’t materially matter. If you wanted to run the physics system locally then you could still run it in a different thread… just by… running it in a different thread.

Nothing special has to happen to “enable” multithreading. Zay-ES is kind of already expecting you to do this.

So the base of system should be like this ?

    public class CharacterPhysicsState extends BaseAppState implements Runnable{
    Thread t;
    ...
    //Do my stuffs 

     @Override
        public void run() {
            
        }

    public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
    }

and in main class

public class Main extends SimpleApplication {

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    public Main() {
        CharacterPhysicsState phState=new CharacterPhysicsState();
        phState.start();
        super(phState, ...  )
              
    }

Well, it’s super-duper odd to have an AppState that implements Runnable and is also the thing that will be the background thread.

It’s kind of crazy and just looking for problems.

But you know, this is the part where we have problems with the hypothetical.

Let’s say you had a class that was your physics system. It is not an app state because it’s a physics system. It’s job is to do the physics of your game and never once does it ever touch a JME class because it is not doing visualization things, it is doing physics things with the ES.

It would be perfectly fine to spin that off into its own thread.

Ah…
So you are saying i should just run some internal parts of my BaseAppState which is considered to be my System and it has interaction with entities and components in other thread ?

Here is my character physic system for now :

public class CharacterPhysicsState extends BaseAppState {

    private Thread t;
    private SimpleApplication app;
    private EntityData ed;
    private EntitySet entities;
    private ModelViewState spatials;

    @Override
    protected void initialize(Application app) {
        this.app = (SimpleApplication) app;
        ed = this.app.getStateManager().getState(EntityDataState.class).getEntityData();
        entities = ed.getEntities(CharacterPhysicalAttribute.class, MotionBehavior.class, Speed.class , Direction.class);
        spatials = app.getStateManager().getState(ModelViewState.class);
    }

    @Override
    public void update(float tpf) {
        if (entities.applyChanges()) {
            // removeModels(entities.getRemovedEntities());
            addBetterCharacterControl(entities.getAddedEntities());
            updateCharacter(entities.getChangedEntities(), tpf);
        }
    }

    protected void updateCharacter(Set<Entity> changedEntities, float tpf) {
        for (Entity e : changedEntities) {
            e.get(MotionBehavior.class);
            Spatial character = spatials.getModel(e.getId());
            
            BetterCharacterControl control= character.getControl(BetterCharacterControl.class);
            control.setViewDirection(e.get(Direction.class).getViewDirection());
            Vector3f modelForwardDir = character.getWorldRotation().mult(Vector3f.UNIT_Z);
            Vector3f modelLeftDir = character.getWorldRotation().mult(Vector3f.UNIT_X);

            // WalkDirection is global!
            // You *can* make your character fly with this.
            Vector3f walkDirection = new Vector3f(0,0,0);
            float speed = e.get(Speed.class).getSpeed();
            MotionBehavior motion = e.get(MotionBehavior.class);

            if (motion.equals(BasicMotionBehaviors.IDLE)) {
                walkDirection.set(0, 0, 0);
            } else if (motion.equals(BasicMotionBehaviors.FORWARD)) {
                walkDirection.addLocal(modelForwardDir.mult(speed + tpf));
            } else if (motion.equals(BasicMotionBehaviors.BACKWARD)) {
                walkDirection.addLocal(modelForwardDir.negate().multLocal(speed + tpf));
            } else if (motion.equals(BasicMotionBehaviors.LEFT)) {
                walkDirection.addLocal(modelLeftDir.mult(speed + tpf));
            } else if (motion.equals(BasicMotionBehaviors.RIGHT)) {
                walkDirection.addLocal(modelLeftDir.negate().multLocal(speed + tpf));
            }
            
            control.setWalkDirection(walkDirection);
        }
    }

    protected void addBetterCharacterControl(Set<Entity> addedEntities) {
        for (Entity e : addedEntities) {
            Spatial s = spatials.getModel(e.getId());
            CharacterPhysicalAttribute phAtr = e.get(CharacterPhysicalAttribute.class);
            BetterCharacterControl characterControl = new BetterCharacterControl(phAtr.getRadius(), phAtr.getHeight(), phAtr.getMass());//TODO : Get measures as user data.
            characterControl.setJumpForce(phAtr.getJumpForce());
            characterControl.setGravity(phAtr.getNormalGravity());

            Quaternion rotation = s.getLocalRotation();
            Vector3f viewDir = new Vector3f(Vector3f.UNIT_Z);
            rotation.multLocal(viewDir);
            s.addControl(characterControl);
            characterControl.setViewDirection(viewDir);
        }
    }

    @Override
    protected void cleanup(Application app) {

    }

    @Override
    protected void onEnable() {

    }

    @Override
    protected void onDisable() {

    }

}

So If you were me how do you consider to change this to be multi thread ? Or you will not run this in separate thread at all ?