Best basic practices concerning performance and code readability clarity/simplicity?


#21

Yes, but they are each separate concerns that may interact with the visuals in different ways.

If it were may, I’d have one visual thing that I could update with one or more ‘tracking’ things separately. Then I’d have a system for health trackers, a system for mana trackers, etc… separate systems. They all update that central visual which would sort out how to combine them into one logical display, probably based on some generic approach.

That way you could even easily support things like user-defined toggling of different layers or user-defined colors, etc…

And if you add another type of tracker thing tomorrow, NONE of your other code needs to be updated. Zero. Not a bit. That’s the beauty of the whole approach, really.


#22

I thought I’d address this separately. The whole idea of “MeatEater” vs “Vegetarian” sounds like an OOP concept… something that would be reflected in an interface.

When I referred to animals, I was actually invoking the idea of “duck typing”… which is so intrinsic to my thinking that I forget that’s not an automatic short hand for everyone else.

The idea of “duck typing” is the concept of “if it looks like a duck, walks like a duck, etc.” The idea that we don’t care if it IS a duck as long as it has the duck-like things we might want. So a cow would be something that is definitely NOT a duck.

It’s a helpful idea to remind ourselves to forget about OOP and think about “What do I need to operate on?” or “What do I need to read?” The type of the thing in our minds does not matter at all.

And any time you have a system that is asking for “All things with webbed feet OR cloven hooves” you are down a very strange path.


#23

I don’t exactly understand the question… so I will just wax poetic for a sec…

An EntitySet is static until you call applyChanges(). The Entity objects in that set only contain the components asked for… and they ALWAYS contain them. Except in some removedEntities cases, getting a ‘watched’ component from one of these Entity objects will never return null.

In the background, changes are being accumulated such that applyChanges() is very efficient. That’s a nice performance concern but you shouldn’t think too hard about it.

Your Entity values are static until you call applyChanges(). At that point, you can see the new values, check which ones are new to the set, which ones that are no longer in the set just left, and which ones were in the set before but one or more of their components has changed.

In my experience, for 99% of systems, it’s almost never worth worrying about which exact component changed in those last cases. If your target data structures are going to do something expensive with that information then they can (and should) easily check their own existing value when you call set on them. And it makes the code simpler.


#24

So, I was thinking on delegating initialization (from the gamesystem) to the visualization code (jme) related to the specific getAddedEntities() new ones exclusively, by registering listeners (interface) at the gamesystem pointing to the visualization code and all others.

But, I guess, instead of that it would be better to just, at the visualization code, check for a boolean (specific to the visualization), and if it was not initialized, do it.


Also, I think each ES system scope must be quite limited (cohesion): “what will it specifically deal with?”
so I could have a gameSystem (things like combat ex.: who fights who)
and a 3DPhysicsSystem (to calculate distances, travel time, target visibility etc)
and the final visualization, be it in 2D, 3D or even text mode.

But instead of that, If I am not wrong, it would be better to make the 3DPhysicsSystem dependent on JME and bullet, merely to re-use all the 3D calculations, already available and not reinvent the wheel, but that decision would also deny me “insta plug” an alternative 2D or even textmode engines (not that I want to actually plug other engines, I am just thinking).

What I mean is, an ES System may not need to be so 100% completely independent of the “visualization”, othewise we would have to reinvent many things that it provides, at least JME + bullet physics.

Or not?

and yes, I am asking before trying it, because trying and see that it should be different is quite time consuming to restructure and readapt everything :chimpanzee_facepalm:


#25

There are folks who have done this without Spatials, I think…

It is possible to use JME’s bullet wrapper without ever having instantiated a single spatial.

Whether or not you also need physics in the visualization layer to deal with things that aren’t represented as game objects (effects or whatever) is something else.

But your back-end should definitely have some physics engine.

Common systems to have on the back-end… at least I find I have them in most games with health, buffs, etc…
-PhysicsSystem (almost every game will have something like this to do some kind of physics… likely integrates with a third-party physics engine)
-DecaySystem (always always… kills an entity after some time has passed.)
Optional but common:
-HealthSystem (collects damage/healing entities and applies them to entity health every frame)
-XBuffSystem (sometimes per-buff systems that adjust an entities game attributes… whether attack power or mana or whatever)
…those systems are actually very similar.

You could effectively implement an entire asteroids clone with just those systems in the ‘game logic’ layer and some system/listener to handle collisions. All but the physics system are a surprisingly few lines of code. (10-15 lines of actual logic maybe)


#26

I’d like to understand more this point. I think you are talking about https://github.com/Simsilica/SiO2/blob/master/src/main/java/com/simsilica/es/EntityContainer.java but to me it looks like it’s adding a level of abstraction that can be useful if you do networking or other special stuff (not exactly “common”), but is not necessarily an upgrade over the ModelState+Factory combo that is showed on sample Zay-ES projects…

More generally, every now and then I check SiO2 but the only thing that I’ve found useful for my project is the event bus… maybe I’m missing something? :confused:


#27

Which sample zay-es projects? The ones that were written before or after SiO2 existed?

How are those ModelState’s managing the set of entities that they are watching?

With an EntityContainer or some “had to implement a bunch of boiler plate” way?

EntityContainer is precisely for the “classic” entity system case that other ESes FORCE you to use all the time. Where you just want to keep track of a set of entities with some set of components and do something with them… either on every frame (like a class “force you” ES) or when they enter/leave the set.

For example, even if you don’t want to pair up an object, you can always have an EntityContainer just to get the auto-management… add an getArray() that overrides the super-class one (for local accessibility) and you even have a garbage-free way of iterating over the entities every frame if you like.


#28

AsteroidPanic of course!

Which brings the question: should these examples be updated to make use of SiO2?


#29

For that one… I’m on the fence. On the one hand, SiO2 would simplify some things but on the other it hides some things that are useful to understanding.

It might be worth adding a comment pointing to siO2 and the other examples that would have reduced the boiler plate significantly. Perhaps an opportunity to point out why Zay-ES is different than other ES libraries in how it lets you access the entity sets directly.


#30

Personally I use EntityContainer for nearly every System (at least when it needs to manage view Related things like Controls or spatials)


#31

Yeah, me too… and quite often on the back end.


#32

I understand, and it would also convey the message that SiO2 is mandatory for ZayES. But then, how about providing a SiO2-fied AsteroidPanic on Simsilica-examples?

And about the package sim/GameSystem… it is basically another appstate manager?


#33

Yeah, sort of… but without the extra cruft that is only rendering specific. Like, 70% of app state is rendering specific.


#34

I don’t understand. Here, this is one of my appstates. You mean that 70% of this is rendering specific?

public class SoundAppState extends BaseAppState{
    private AudioNode music;
    private AudioNode[] shots;
    private AudioNode[] explosions;
    private AudioNode[] spawns;
 
    private static HashMap <String, AudioNode> sounds;
    
    public final static String MYSOUND1="mysound1";
    public final static String MYSOUND2="mysound2";
    
    private AssetManager assetManager;

    @Override
    protected void initialize(Application app) {
        sounds=new HashMap<>();
        this.assetManager = app.getAssetManager();
        /*
        music = new AudioNode(app.getAssetManager(), GM.getString("test_music"));
        music.setPositional(false);
        music.setLooping(true);
        music.setVolume(GM.getFloat("test_music"));
        ((SimpleApplication)app).getRootNode().attachChild(music);
        music.play();        
 */
    
        addSound(MYSOUND1);
        addSound(MYSOUND2);
}
    
    private AudioNode addSound(String soundName){
        Audio audio=Simonetta.getAudio(soundName);
        AudioNode node=new AudioNode(assetManager, "ogg/"+audio.id+".ogg");
        node.setPositional(false);
        node.setLooping(false);
        node.setVolume(audio.volume);
        ((SimpleApplication)getApplication()).getRootNode().attachChild(node);
        sounds.put(soundName, node);
        return node;
    }
    
    public static void play(String sound){
        if (sounds==null)
            return;
        sounds.get(sound).playInstance();
    }

    @Override
    protected void cleanup(Application app) {
    }

    @Override
    protected void onEnable() {
    }

    @Override
    protected void onDisable() {
    }
}

#35

Yes, BaseAppState hides a lot of JME-specific cruft from you. If you look at the AppState interface you will see lots of stuff you don’t want or need in a non-visualization context.

Like, what does “render” and “postRender” mean to my physics system on the server? Nothing.


#36

Yes, but still don’t fully understand the impact of this 70%. Either:

  1. the 70% is executed and slows down the application. Therefore the GameSystem should really be part of JME. Also there are system that are not part of the game, don’t involve rendering and yet I implement as AppState…

  2. the 70% is there, but is basically dead code and don’t slow down the application if you don’t use rendering. Then what is the point of having a GameSystem to begin with?


#37

Ok, take JME, put it in a box and send it to China. Never open the box. Don’t even look at it.

Now, say you want to still write a game using “Some Cool New Hotness” and don’t want to have to start over from scratch? Guess what? The game systems still work. Moreover, you didn’t have to import a bunch of useless crap just to have a simple game system interface.

But you know, if you want to have JME core jar on your server and all of these useless methods hanging around then that’s up to you.


#38

@Darkchaos
I ended storing on the component a Bean. The component will delegate the Bean getters publicly.
The Bean, at each setter will store a Runnable to be called when instantiating a new Component with custom specific new Bean’s fields values. but… may be it is harder to explain than see the monster I created :slight_smile: https://github.com/AquariusPower/DevConsLeJME/blob/master/Tests/src/main/java/com/github/devconslejme/tests/temp/ESCompEx.java
it can be used like this:
new ESCompEx(oldESCompEx, new CompBean() .setBoundingHeightZ(1) .setLastFocusTime(2) )

@pspeed but lets implement all the new cool hotness on JME too! please!? xD


#39

Lombok, @wither, plus some little bit of java8 magic removes nealy all boilerplate when modifing components.

Really, lombok is one of my default libs that gets added to every project.


#40

I have no idea what you have created. Could you explain the benefits to me?