I'm having hard time converting OOP game objects to Ashley ECS framework. I have a character, gun & a bullet class. The character uses the gun as weapon, the gun class has a fire method that handles the creation of bullet. In the below code, is my current WeaponSystem that serves as a generic system for any weapon like Gun class.

public interface Weapon {
     void use();
}

public class WeaponComponent implements Component {
     Weapon weapon;
}

public class WeaponSystem extends IteratingSystem {

    ... // Constructor

    ... // Process Entity

    public void use(Entity weapon) {
         WeaponComponent weaponComponent = Components.getWeapon(weapon);
         weaponComponent.use();
         ... 
    }

}

The character system..

public class CharacterSystem extends IteratingSytem {

    ... // Constuctor

    ... // Process Entity

    public void attack(Entity character) {
        getEngine().getSystem(WeaponSystem.class).use(character);
        // also can be use like this
        // CharacterComponent characterComponent = ...
        // it seems that, it was redundant
        // characterComponent.weapon.use(); 
    }

}

And the user controlled system ...

public class UserControlledSystem extends IteratingSystem {
     ...

     public void move(Entity character) {
          ... Set character directions

          InputComponent input ...
          input.key == arrow key, etc...

          getEngine().getSystem(CharacterSystem.class).move(character, direction);
     }

     public void attack(Entity character) {
          getEngine().getSystem(CharacterSystem.class).attack(character);
     }
}

Based on this article, they are using event dispatcher. But do I really need to use dispatcher? Is that possible to not to use dispatcher, just purely ECS? Anyways let's back to the main question(How to convert and handle (controlling) OOP game objects via ECS?). Currently, the Ashley ECS Entity has an access to engine and systems. Like in the above code example, do you think it is the proper way of handling the system?

I'm not too familiar with Ashley's ECS system. The reason they are using the dispatcher is to share information across multiple objects. This is usually to reduce coupling in classes, which makes things easier to manage in practice, but not easier to design. Typically this method is MOSTLY used for event based systems.

Say a scripted game event, servers, or in stackless python.

For overly complex and large scale games where you have thousands of different objects that need to be managed by a single computer or something. Truthfully I'd be using the dispatch system,

You can use the ECS system without the need for broadcasting messages. But you'll find that as your project grows in complexity, the pure ECS system becomes a pain in the ass to convert to anyways.

Basically you'd do one or two things. You'd call update on the entity, and update it's components all at once. or you run through each system and update components. But sometime's you find that your systems requires data from other systems, this is where the dispatcher would shine best.

Both dispatcher and calling systems directly from systems breaks the architecture. A system should never be called directly to update, if anything, only call methods to set some flag or data to be handled when it's time for that system.

If the CharacterSystem knows about the WeaponSystem, then if you change the WeaponSystem to behave in a different way you might run into trouble. Same for UserControlledSystem: does it really have to know how to call the system to move it, and call it out of order?

A good way to solve this is to simply write down what you would need to do pass information for a system, a message, and make a component out of it, that could be destroyed or just reused, in an object pool or never even removed from the entity. Let's take a look at the UserControlled class. What if we just set the velocity instead of calling the system? If I press right, then I just set the velocity.x = 1f for example. Then, when the MovementSystem iterates, it tries to add that velocity to the character, and adjust position accordingly. But can we do this better? We can create a component that is UserControlsComponent, that has a few boolean flags to represent if a direction is being pressed. Then we create a UserControlsSystem, that checks these flags and acts. What is the advantage? Well, to start, suddendly we just take care of handling input, and setting some flags, which means we don't care about the end result, we just express the player wants to do something, for example, move right. Now the system in charge of transforming these flags into actions would read the flags, do actions accordingly, and set flags to false, to indicate they are consumed. What happens next is that suddendly, even if you are using different controllers, you could even create a System to handle that type of controller without duplicating code.

It does create a bit more code, but not necessarily complexity, because in the end, if the code is broken down into smaller, more easy to handle, readable chunks, you benefit from it, and you get more flexibility.

  • I love your idea!, I am now trying to implement/revise my system, Can you give an example on the character & gun, because I have a doubt in the future that when I add an artificial intelligence, the state-machine will be implemented too. Also should the weapon be controlled by the UserControlsComponent or only the character? – ronscript Aug 9 '16 at 7:36
  • Well, that depends. I suggest you keep it simple for now, and also make the weapon not aware of UserControlsComponent. When you iterate through the UserControlsSystem, and if fireWeapon = true, then you can set a flag on the player weapons to shoot, for example, shootMe = true. When the WeaponSystem iterates, it can check if the cooldown is over, if there is ammo, etc etc, do everything related to the weapon. – rvalerio Aug 9 '16 at 20:12
  • Later on, when you feel more comfortable with ECS, you will find that in fact the Weapon can have a PlayerControlledComponent, where you can define a key to use it, and whenever you press that key, it tries to execute, leading to you being able to remotely use an object like a turret, robot, etc. But let's not jump into this just yet, make it simple, make an object to hold intentions to move (boolean left, right, up, down, jump, fire1, etc) and go from there. – rvalerio Aug 9 '16 at 20:12
  • Regarding AI, it can make it easy later. If you have something that expresses intention to do an action, like that UserControlsComponent, then an AISystem only has to work with these, and change them accordingly as you need. You should then be able to interchangeably use either an AIComponent or PlayerControlledComponent to make a character move. – rvalerio Aug 9 '16 at 20:14

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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