1
\$\begingroup\$

I'm developing on a simple libGDX-based Game and im using the entity-component-system ashley.

For non-generic but custom behaviour (e.g. the Player Movement), I'm using "scripts" instead of reuseable and generic Entity-Systems. Therefore I've got an ScriptComponent and a ScriptSystem which runs init() and update() on all scripts related to an entity.

At some point I want to generate a map, counting game-related-properties etc. that brings me to the point where I'm confused about how to access those porperties from any script.

In other Engines/Enviroments like Unity3D the GameObjects (the entities) brings functionality to find other entities like FindGameObjectsWithTag(...).

But how can I realise that in ashley? Also should it be possible in an Entity-Framework to access specific entities in general?

Edit: Additional information

Here comes a simple example-usecase. This is very notional example I've just created for that post. I just wanted to demonstrate, that I thing there is a need of an "main Game Object" in a game which also uses a entity-component-framework like ashley. So I thought a correct way is, to let this main-game-object be an entitiy too which holds the main script. But I'm not sure, if this is a good approach.

Here I demonstrate this with having a PlayerScript which just sets the lives for the player accordingly to the difficulty level of the game (maybe set by the player on the main-menu-screen). This PlayerScript is attached to the ScriptComponent of the player entity.

public class PlayerScript extends Script {

 int playerLives;

  public void init() {
     GameEntity entity = getTheEntityByName("game"); // this method doesn't exist
     GameScriptComponent gsc = scriptComponentMapper.get(entity);
     GameScript mainGameScript = gsc.getScriptByName("game");
     if(mainGameScript.getDifficulty == "easy")
     playerLives = 999;
  }
}
\$\endgroup\$
  • \$\begingroup\$ I have never tried unity 3d, but you can create your own method to find entities, the Entity class has a flags data to use. And for the specific access you are talking about, can you add more details? what you want and what is your goals \$\endgroup\$ – ronscript Aug 15 '16 at 16:49
  • \$\begingroup\$ If you are talking about accessing the components, you should use PooledEngine. Because in that engine all components, entities can be pooled by calling .createEntity(), .createComponent \$\endgroup\$ – ronscript Aug 15 '16 at 16:51
  • \$\begingroup\$ @ronscript I've just edited the question with an example for better understanding \$\endgroup\$ – Marc M Aug 15 '16 at 20:21
1
\$\begingroup\$

In your given code example and goals, you want to load each system by a given script, because you are referencing or copying the pattern of unity 3d to achieve your goals, this is not possible for now. But I can give you an example or a pattern on how I create a system using your example code. In the mean time, I recommend you to read what is ECS and Ashley for a better understanding.

Why I used PooledEngine? because it allows the components and entities to be pooled automatically by retrieving them. Here is the basic usage, as you can you I created an entity using the engine. Now you just need to add it to the engine after entity components has been made.

// Assume this is your GameWorld class

PooledEngine engine = new PooledEngine();

Entity player = engine.createEntity();

Position position = engine.createComponent(Position.class);
player.add(position);

engine.addEntity(player);

Creating player components...

public class PlayerComponent implements Component {
     public final float SPEED = 6; // 6 meters / sec
}

Now who's gonna handle the player entity? we could create a PlayerSystem by extending IteratingSystem (read more about ashley why I use this to extend). Initialize its family, so that system will only handle which entity has that components, but still you can access its components without adding it on the family.

public class PlayerSystem extends IteratingSystem {
    public PlayerSystem() {
         super(Family.all(Player.class, Position.class).get());
    }

    public void processEntity(Entity entity, float deltaTime) {
        ... // You can now process each player entity here
    }
}

Now lets get back to our GameWorld class. Then add the player system to the engine.

PooledEngine engine = new PooledEngine();
engine.addSystem(PlayerSystem.class);


public Entity createPlayer(float x, float y) {
    Entity entity = engine.createEntity();

    PlayerComponent playerComponent = engine.createComponent(PlayerComponent.class);
    PositionComponent positionComponent = engine.createComponent(PositionComponent.class);

    entity.add(playerComponent);
    entity.add(positionComponent);

    engine.addEntity(entity);
    return player;
}

Now lets get back to your goals:

1.) Your first goal is to get the entity by name. You could just use Entity flags.

public class Flags {
    public static final int PLAYER = 0;
}

Entity entity = engine.createEntity();
entity.flags = Flags.PLAYER;

Then in the engine or in the player system iteration, you could just

// for engine
for(Entity entity : engine.getEntities()) {
    if(entity.flags == Flags.PLAYER) {...}
}
// or for player system
if (entity.flags == Flags.PLAYER) {
     // now you have an access to your custom player
}

2.) Globally access to your entity components. You should use ComponentMapper.getFor(Position.class) method. As the Ashley said it was fast.

ComponentMapper<PositionComponent> positionMap = ComponentMapper.getFor(PositionComponent.class);

PositionComponent position = positionMap.get(entity);

3.) On your third goal, you want to generate a system from a script? for now Ashley don't the support for that such a method. For now you could just use engine method to get the system. But if you want to load the system script, use libgdx json reader/writer, and read/write your system using json, here is the link for the documentation json.

engine.getSystem(PlayerSystem.class)
\$\endgroup\$
  • \$\begingroup\$ Okay thanks for that very big answer. Unfortunately, it seems like you don't understand my problem: I don't want to generate a system at any point but I just looking for a way to store centralized information/global information like the game script/logic itself. The script idea is to implement (system-like) logic for entities when not using a generic system. PlayerMovement is so special, that I dont want a special system for it. So Player-Entity hold a SystemComponent and runs the scripts which are related to it. See here: SCRIPT \$\endgroup\$ – Marc M Aug 15 '16 at 22:14
  • \$\begingroup\$ There's little to no downside to, in your case, have a new system generated for acting on one particular entity, especially if that entity exists for the majority of the game. Once it's registered, it'll only act on entities which own a Player comp (a list of one). If the system is no longer needed, it can be deregistered. What you're suggesting would go against the nature of ECS and introduce high coupling. Moreover, if you believe you'll be adding lots of game scripts over time, having a system makes even more sense. Think about it, why would you not want to create a new system? \$\endgroup\$ – Danny Yaroslavski May 24 '17 at 20:12
1
\$\begingroup\$

First off, it sounds like you're trying to shoehorn Unity3d concepts into LibGDX -- which is a completely natural tendency when trying to pick up a new system, but do realize that if you're not careful, you'll end up implementing things in a very non-LibGDX/Ashley way and just creating more work for yourself.

If you have some initialization code that needs to happen once, don't put it in an EntitySystem, component, or anything -- don't even use Ashley for that. Just execute it in the startup part of your program, perhaps next to the section that initializes the Ashley Engine and all of the corresponding EntitySystems. While Unity3d forces every piece of executable logic to be attached to an entity, LibGDX/Ashley doesn't.

While Ashley doesn't have (or need, IMO) "tags", it does have components and I just those instead (and you can use "marker", or stateless, components for that). If you really want tags, you could implement your own EntityListener that checks to see if a new entity has a TagComponent (which you'd make), and if it does, update a globally-reachable Map<String, List<Entity>> sort of thing. Just don't forget to also remove from the list when the entity is destroyed.

As for your specific PlayerScript example, I generally create an EntityCreator class with all sorts of create* methods in it, like createPlayer. This creates an entity, adds the required components to it, and returns it. The sort of initialization logic you're talking about would go here. The GameScript/GameScriptComponent you have would just be a regular object and probably passed in as a constructor argument for EntityCreator and saved as a field, where any of the create* methods can access it.

\$\endgroup\$
  • \$\begingroup\$ Agree with Max, for your particular example, initialization scripts like the one you mentioned would best be put in the EntityCreator, which could be initialized with a constructor injected GameFlags dependency. \$\endgroup\$ – Danny Yaroslavski May 24 '17 at 20:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.