Project Architecture question

Dear all,

I am developing a JME3.2 project with usage of Physics.
I have implemented some architecture, and have questions if I should restructure the application:

I still did not implement Save/Load functionality
I still did not implement HUD Display and menu

This is how my classes are organized so far:

Questions:

  • what would be the best way to update scenegraph class object if CollsionListener registered collision?
  • is overall architecture fine or you would recommend adjust it?

Thank you,
Denis

Through a control or AppState - probably a control.

Looks pretty ok but it really depends on how it works for you. If adding features is like pulling teeth you might want to reconsider your design. The only thing I’d suggest is that you might want to look into an ECS like @pspeed’s Zay-Es.

2 Likes

Now that I’m reading this… I probably should split my CollisionAppstate into several controls, because it looks like an eldritch abomination of EntityId and class casting… :sweat:

1 Like

Truthfully, any architecture based on treating Spatials as game objects is going to collapse under its own weight eventually. For the right sized game, you might finish it before that happens, though.

2 Likes

This is my code:

public class MyCollisionControl extends AbstractControl {

    private EntityData ed;
    private EntitySet entities;
    private ModelState modelState;
    private Dyn4jMEAppState dyn4jMEAppState;

    public MyCollisionControl (ModelState modelState, Dyn4jMEAppState dyn4j) {
        this.ed = FightAppState2.ed;
        entities = ed.getEntities(MyCollidable.class);
        this.modelState = modelState;
        this.dyn4jMEAppState = dyn4j;
    }

    @Override
    protected void controlUpdate(float tpf) {
        entities.applyChanges();
        for (Entity e : entities) {
            Spatial coll= modelState.getSpatial(e.getId());
          // retrieve the physics bodies, then check collision
                if (dyn4jMEAppState.getPhysicsSpace(0).checkCollisionNP(body1,body2)) {
                    //hit! This destroy the spatial we're controlling...
                    //entities.release();
                }
            }
        }
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
    }

}

Please note what is NOT coded but always present on @pspeed examples :

entities.release();
entities = null;

Ather a collision the entity is removed, so does the Spatial and therefore the MyCollisionControl is gone. But if I call entities.release() within the loop, and then add a new MyCollisionControl to another spatial it doesn’t collide at all.

I don’t understand why…

I don’t know… this is already in a very strange direction to me.

Generally speaking, it’s very strange to marry an ES to controls. It’s unclear to me why the control even needs to know about physics at all in an ES.

Normally, physics would be a system that manages the physical entities. The spatials are just dumb followers of whatever the entity says (which is likely fed by the physics system but maybe not… it doesn’t care).

In your case, you seem to have a control that is somehow managing ALL collidable entities. Do you then have this control on every collidable spatial, ie: some huge N:N combinatorial mess?

It’s very strange to manage collisions this way instead of centrally as part of a global system. You end up doing at least twice the work if not more.

We’re kind of derailing OP’s thread but let’s bring it back to some “ES theory” just in case OP finds that approach interesting.

One of the ideas behind an entity system is to think of your game in the sense of bulk operations. It’s one way to look at system decomposition that might be helpful but it is certainly not the only way and certainly not the only benefit. (Think of a system in terms of bulk operations also nicely separates code concerns, etc., too… it’s just a ‘good thing.’)

Leave the ES structures aside for a moment…

So imagine if you have a million game objects that you want to perform simple physics on. Acceleration, velocity, etc…

Think of one giant memory coherent array of all acceleration vectors and velocity vectors. You loop over all one million and increase velocity by accleration * timeStep. There is literally no faster way to do that.

Next you do a similar loop over all velocity and positions, add velocity * timeStep to position.

This is the type of operation you want to think of in a data-centric design. It leads to some interesting things.

  1. it’s the fastest way. Provably so. And if you were writing native level highly optimized code, you avoid cache misses, memory can be streamed, all kinds of goodness we Java developers don’t care about but it’s interesting to think about anyway.

  2. decoupling. In this silly example, the velocity update and the position update are completely independent. You could swap out the implementation and nothing cares. You could decide that you don’t want acceleration at all and things will just be straight velocity. The position update loop doesn’t care about that.

  3. threading. There is no reason these two things couldn’t be run in parallel, really. If you don’t care about per-frame integrity then you really really don’t care. And if you were simulating a world with a million objects at once, I’m going to guess you probably aren’t going to care about frame-step-level integrity. But certainly in examples that DON’T involve physics, there are hundreds of cases where per-frame game-wide consistency is unimportant.

Unfortunately, collisions don’t allow us a nice loop like that since on some level you have to compare objects to other objects… however, almost always the physics engine you are using will have some kind of internal optimizations for you. Likely, you can either list out all of the contacts or at least iterate over the colliding bodies.

From there you could produce contacts or other synthesized results that follow on stages use. (I’m a fan of contact entities but now we’re starting to get back into ES-specific terms).

The bottom line is that this sort of data-centric decomposition is almost always a good thing. For the three reasons above and more.

4 Likes

I think that my approach might use some improvement. This is how I add physical stuff do dyn4j:

And this is how I check collisions:

So this is not managed by an ES, right?

My ES modelstate invoke the factory which in turn invoke the add(Spatial) I posted; so to answer your question I think it should be managed by an ES (or at least that is my goal).

Mmmm… after rereading ES best practices: position, model, hitbox - #7 by asser_fahrenholz I should probably leave Spatials out of D4Jspace… :frowning:

I had to go through the same thing with a project I was working on earlier (just getting back into coding after a bit of a break). It was a little hard to wrap my noodle around how to make it work but man o man… Once it’s setup… It’s soooooo much easier to control things via physics.