1
\$\begingroup\$

I have implemented an ECS where more or less an Entity is just an ID, a Component is just a wrapper for data, and a System holds the logic on operating over different components. There is an Engine that has a list of the entities, a table of the components and a list of the different types of systems (update and draw systems).

I was working on handling input when I reached a conflict: how I would resolve opposing inputs (for example, pressing left and right at the same time). So I decided to try and implement the Command Pattern to work with the ECS.

But I'm stumped. I'm not sure how to create a command, let's say moveLeftCommand, without knowing the intimate details about each entity that would effect. Also, since all my logic is in the systems, (if I understand the Command Pattern) it should have an execute function which will carry out the command. How do I populate the execute command if there isn't any logic that "belongs" to an entity?

Thanks for any help!

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

How do I populate the execute command if there isn't any logic that "belongs" to an entity?

But there is a mechanism for applying logic to an entity: Systems. In ECS, Systems map behavior to entities that have a specific set of components (e.g. apply "move" logic to all entities that have a Transform and Velocity component). So in your case you would:

  1. Create a MoveCommand component with a direction.
  2. Create a MoveSystem that iterates over all entities with a MoveCommand component and a Position component (or its equivalent).
  3. In the MoveSystem modify the Position based on the direction in the MoveCommand and remove the component.
\$\endgroup\$
4
  • \$\begingroup\$ This answer is great for modeling a command pattern in ECS but it doesn't address the root issue of receiving inputs external to the ECS; i.e. "When is the MoveCommand component spawned?" \$\endgroup\$
    – BEVR1337
    Commented Feb 14, 2023 at 19:15
  • 1
    \$\begingroup\$ @BEVR1337 Unless I'm missing something there shouldn't be anything particular about how to receive external inputs. For an ECS system to be useful it has to have an externally accessible API for creating components (if not how would you initialize it?). When there's an input event you would call that API and spawn a new MoveCommand component in the ECS. \$\endgroup\$
    – Mattia
    Commented Feb 15, 2023 at 20:39
  • \$\begingroup\$ Thanks for adding clarity to an old question. I came to this question to understand how to issue commands/events predictably but I think I'm projecting my own question. For example, "how to create the pipeline between interrupts/events (issue the command to create a command component) and system update ticks (process the command component)?" \$\endgroup\$
    – BEVR1337
    Commented Feb 17, 2023 at 8:48
  • 1
    \$\begingroup\$ @BEVR1337: Happy to do it. Also if you want to flesh your comment out into a question I'd be happy to see if I can help with that too. \$\endgroup\$
    – Mattia
    Commented Feb 18, 2023 at 13:33
0
\$\begingroup\$

I hope this will be of some help.

I'm not sure it really matter if two keys are pressed at the same time because if I press forward and left then I move at diagonal left, forward and back does nothing because they cancel each other out its the same with left and right because they both have the same speed value they cancel each other out.

this is how I do my input handling:

 If Device.KeyBoredState.IsPressed(SharpDX.DirectInput.Key.A) Then
            _position.Z += _speed * CSng(Math.Sin(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds
            _position.X -= _speed * CSng(Math.Cos(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds

        End If
        If Device.KeyBoredState.IsPressed(SharpDX.DirectInput.Key.D) Then
            _position.Z -= _speed * CSng(Math.Sin(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds
            _position.X += _speed * CSng(Math.Cos(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds
        End If

        If Device.KeyBoredState.IsPressed(SharpDX.DirectInput.Key.W) Then
            _position.Z -= _speed * CSng(Math.Cos(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds
            _position.X -= _speed * CSng(Math.Sin(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds

        End If
        If Device.KeyBoredState.IsPressed(SharpDX.DirectInput.Key.S) Then
            _position.Z += _speed * CSng(Math.Cos(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds
            _position.X += _speed * CSng(Math.Sin(MathHelper.ToRadians(_yaw))) * _gametime.ElapsedGameTime.Milliseconds
        End If
\$\endgroup\$
1
  • 1
    \$\begingroup\$ This solves the left/right problem but doesn't directly answer the question about commands. \$\endgroup\$
    – lozzajp
    Commented Feb 14, 2017 at 12:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .