34
\$\begingroup\$

After asking two questions about entity systems (1, 2), and reading some articles on them, I think that I understand them much better than before. I still have some uncertainties, mainly about building a particle emitter, an input system, and a camera. I obviously still have some problems understanding entity systems, and they might apply to a whole other range of objects, but I chose these three because they are very different concepts, should cover a pretty broad ground, and help me understand entity systems and how to handle problems like these, myself, as they come along.

I am building an engine in JavaScript, and I've implemented most of the core features, which include: input handling, flexible animation system, particle emitter, math classes and functions, scene handling, a camera and a render, and a whole bunch of other things that engines usually support. I read Byte56's answer, that got me interested into making the engine into an entity system. It would still remain a HTML5 game engine, with the basic scene philosophy, but it should support dynamic creation of entities from components.


The problem I have, now, is fitting my old engine concept into this new programming paradigm. These are some of the definitions from the previous questions, updated:

  • An Entity is an identifier. It doesn't have any data, it's not an object, it's a simple id that represents an index in the scenes list of all entities (which I actually plan to implement as a component matrix).

  • A Component is a data holder, but with methods that can operate on that data. The best example is a Vector2D, or a "Position" component. It has data: x and y, but also some methods that make operating on the data a bit easier: add(), normalize(), and so on.

  • A System is something that can operate on a set of entities that meet the certain requirements; usually the entities need to have a specified set of components, to be operated upon. The system is the "logic" part, the "algorithm" part, all the functionality supplied by components is purely for easier data management.


Camera

The camera has a Vector2D position property, a rotation property and some methods for centering it around a point. Each frame, it is fed to a renderer, along with a scene, and all the objects are translated according to its position. The scene is then rendered.

How could I represent this kind of an object in an entity system? Would the camera be an entity, a component, or combination (as per my answer)?

Particle Emitter

The problem I have with my particle emitter is, again, what should be what. I'm pretty sure that particles themselves shouldn't be entities, as I want to support over 10,000 of them, and I believe that creating that much entities would be a heavy blow on my performance.

How could I represent this kind of an object in an entity system?

Input Manager

The last one I want to talk about is how input should be handled. In my current version of the engine, there is a class called Input. It is a handler that subscribes to the browsers events, such as key presses and mouse position changes, and also maintains an internal state. Then, the player class has a react() method, which accepts an input object as an argument. The advantage of this is that the input object could be serialized into .JSON, and then shared over the network, allowing for smooth multiplayer simulations.

How does this translate into an entity system?

\$\endgroup\$

5 Answers 5

28
\$\begingroup\$
  • Camera: Making this a component would be pretty neat. It would just have a isRendering flag and depth range like Sean said. In addition to "field of view" (I guess you might call it scale in 2D?) and an output zone. The output zone could define the portion of the game window that this camera gets rendered to. It wouldn't have a separate position/rotation like you mention. The entity you create that has a camera component would use the position and rotation components of that entity. Then you'd have a camera system that looks for entities that have a camera, position and rotation components. The system takes that entity and draws all the entities it can "see" from it's position, rotation, depth of view and field of view, to the specified portion of the screen. That gives you lots of options for simulating multiple view ports, "character view" windows, local multiplayer, different layers of GUI and so on.

  • Particle Emitter: This too should just be a component. The particle system would look for entities that have a position, rotation and particle emitter. The emitter has all the properties needed to reproduce your current emitter, I'm not sure what all those are, stuff like: rate, initial velocity, decay time and so on. You wouldn't have to make multiple passes. The particle system knows which entities have that component. I imagine you could re-use a good deal of your existing code.

  • Inputs: I'd have to say making this into a component makes the most sense given the suggestions I make above. Your input system would get updated every frame with the current input events. Then when it's going through all it's entities that have the input component, it will apply those events. The input component would have a list of keyboard and mouse events all associated method callbacks. I'm not really sure where the method callbacks would live. Perhaps some input controller class? Whatever makes the most sense for later modification by users of your engine. But this would give you the power to easily apply input control to camera entities, player entities or whatever you needed. Want to synchronize the movement of a bunch of entities with the keyboard? Just give them all input components that respond to the same inputs and the input system applies those move events to all the components asking for them.

So most of this is just off the top of my head, so it probably won't make sense without further explanation. So just let me know what you're not clear on. Basically, I've given you a lot to work on :)

\$\endgroup\$
5
  • \$\begingroup\$ Another great answer! Thanks! Now, my only problem is storing and retrieving entities quickly, so the user can actually implement a game loop/logic... I'll try to figure it out by myself, but I must first learn how Javascript deals with arrays, objects and undefined values in memory to make a good guess... That will be a problem because different browsers might implement it differently. \$\endgroup\$
    – jcora
    Commented Jul 21, 2012 at 17:14
  • \$\begingroup\$ This feels architecturally pure but how does the rendering system determine the active camera short of iterating through all the entities? \$\endgroup\$
    – Pace
    Commented Apr 3, 2013 at 12:26
  • \$\begingroup\$ @Pace Since I'd want the active camera to be found very quickly, I would likely allow the camera system to keep a reference to the entities that have an active camera. \$\endgroup\$
    – House
    Commented Apr 3, 2013 at 14:31
  • \$\begingroup\$ Where do you put the logic to control multiple cameras (look at, rotate, move, etc.)? How do you control the multiple cameras? \$\endgroup\$
    – plasmacel
    Commented Mar 31, 2019 at 19:58
  • \$\begingroup\$ @plasmacel If you have multiple objects that share controls, it'll be the responsibility of your control system to determine which object receives the inputs. \$\endgroup\$
    – House
    Commented Apr 8, 2019 at 14:16
14
\$\begingroup\$

Here's how I approached this:

Camera

My camera is an entity like any other, which has attached components:

  1. Transform has Translation, Rotation and Scale properties, in addition to others for velocity, etc.

  2. Pov (Point of view) has FieldOfView, AspectRatio, Near, Far, and anything else required to produce a projection matrix, in addition to a IsOrtho flag used to switch between perspective and orthographic projections. Pov also provides a lazy-load ProjectionMatrix property used by the rendering system that's internally calculated on read, and cached until any of the other properties are modified.

There is no dedicated camera system. The Render System maintains a list of Pov's and contains logic for determining which one to use when rendering.

Input

An InputReceiver component can be attached to any entity. This has an attached event handler (or lambda if your language supports it) that is used to hold entity-specific input processing, which takes parameters for current and previous key state, current and previous mouse location and button state, etc. (Actually, there are separate handlers for mouse and keyboard).

For example, in an Asteroids-like test game I created when getting used to Entity/Component, I have two input lambda methods. One handles ship navigation by processing the arrow keys and the space bar (for firing). The other handles general keyboard input - keys for exit, pause, etc, restart level, etc. I create two components, attach each lambda to its own component, then assign the navigation receiver component to the ship entity, an the other one to a non-visible command processor entity.

Here's the event handler to handle keys that are held between frames that gets attached to the ship's InputReceiver component (C#):

  void ship_input_Hold(object sender, InputEventArgs args)
    {
        var k = args.Keys;
        var e = args.Entity;

        var dt = (float)args.GameTime.ElapsedGameTime.TotalSeconds;

        var verlet = e.As<VerletMotion>();
        var transform = e.As<Transform>();

        if (verlet != null)
        {

        /// calculate applied force 
            var force = Vector3.Zero;
            var forward = transform.RotationMatrix.Up * Settings.ShipSpeedMax;

            if (k.Contains(Keys.W))
                force += forward;

            if (k.Contains(Keys.S))
                force -= forward;

            verlet.Force += force * dt;
        }

        if (transform != null)
        {
            var theta = Vector3.Zero;

            if (k.Contains(Keys.A))
                theta.Z += Settings.TurnRate;

            if (k.Contains(Keys.D))
                theta.Z -= Settings.TurnRate;

            transform.Rotation += theta * dt;
        }

        if (k.Contains(Keys.Space))
        {
            var time = (float)args.GameTime.TotalGameTime.TotalSeconds - _rapidFireLast;

            if (time >= _rapidFireDelay)
            {
                Fire();
                _rapidFireLast = (float)args.GameTime.TotalGameTime.TotalSeconds;
            }
        }
    }

If your camera is mobile, give it its own InputReceiver and Transform component, attach a lambda or handler that implements whatever kind of control you want, and you're done.

This is kind of neat in that you can move the InputReceiver component with the navigation handler attached from the ship to an asteroid, or anything else for that matter, and fly that around instead. Or, by assigning a Pov component to anything else in your scene - an asteroid, street lamp, etc. - you can view your scene from that entity's perspective.

An InputSystem class that maintains an internal state for the keyboard, mouse, etc. InputSystem filters its internal entity collection to entities that have an InputReceiver component. In its Update() method, it iterates through that collection and calls the input handlers attached to each of those components in the same way that the rendering system draws each entity with a Renderable component.

Particles

This really depends on how you plan on interacting with the particles. If you just need a particle system that behaves like one object - say, a fireworks show that the player can't touch or hit - then I'd create a single entity, and a ParticleRenderGroup component that contains whatever information you need for the particles - decay, etc. - that isn't covered by your Renderable component. When rendering, the render system would see if an entity has the RenderParticleGroup attached and handle it accordingly.

If you need individual particles to participate in collision detection, respond to input, etc., but you just want to render them as a batch, I'd create a Particle component that contains that information on a per-particle basis, and create them as separate entities. The render system can still batch them, but they'll be treated as separate objects by the other systems. (This works very well with instancing.)

Then, either in your MotionSystem (or whatever your using that handles updating entity position, etc.) or in dedicated ParticleSystem, perform whatever processing is required for each particle per-frame. The RenderSystem would be responsible for building/batching and caching particle collections as they're created and destroyed, and render them as required.

One nice thing about this approach is that you don't have to have any special cases for collision, culling, etc. for particles; they code you write for every other kind of entity can still be used.

Conclusion

If you're considering going cross-platform - not super-applicable to JavaScript - all of your platform-specific code (namely, rendering and input) is isolated into two systems. Your game logic remains in platform-agnositic classes (motion, collision, etc.) so you shouldn't have to touch them when porting.

I understand and agree with Sean's position that shoe-horning things into a pattern in order to strictly adhere to the pattern, rather than tweaking the pattern to fill the needs of your application, is bad. I just don't see anything in Input, Camera or Particles that requires that sort of treatment.

\$\endgroup\$
1
  • \$\begingroup\$ Where do you put the logic to control multiple cameras (look at, rotate, move, etc.)? \$\endgroup\$
    – plasmacel
    Commented Mar 31, 2019 at 19:53
7
\$\begingroup\$

Input and game logic will likely be handled in a dedicated chunk of code outside the entity component system. It's technically possible to shove it into the design, but there's little benefit - game logic and UI is hacky and full of leaky abstractions no matter what you do, and trying to force the square peg into a round hole just for architectural purity is a waste of time.

Likewise, particle emitters are special beasts, especially if you care at all about performance. An emitter component makes sense, but graphics is going to be doing some special magic with those components, intermixed with the magic for the rest of rendering.

Regarding your camera, just give cameras an active flag and maybe a "depth" index, and let the graphics system render all of them that are enabled. This is actually handy for a lot of tricks, including GUIs ( want your GUI rendered in an orthographic mode on top of the game world? No problem, they're just two cameras with different object masks and GUI set to a higher layer). It's also useful for special effects layers and such.

\$\endgroup\$
5
\$\begingroup\$

Would the camera be an entity or simply a component?

I'm not sure what this question is really asking. Given that the only things you have in the game are entities, then cameras have to be entities. The camera functionality is implemented via some sort of camera component. Don't have separate "Position" and "Rotation" components - that is far too low level. They should be combined into some sort of WorldPosition component which would apply to any entity located in the world. As for which one to use... you have to get logic into the system somehow. Either you hard-code it into your camera handling system, or you attach scripts, or something. You can have an enabled/disabled flag on a camera component if it helps.

I'm pretty sure that particles themselves shouldn't be entities

Me too. A particle emitter would be an entity, and the particle system would track the particles associated with a given entity. Things like this are where you realise that "everything is an entity" is absurdly impractical. In practice, the only things that are entities are relatively complex objects that benefit from combinations of components.

As for Input: input doesn't exist in the game world as such so that's handled by a system. Not necessarily a 'component system' because not everything in your game is going to revolve around components. But there will be an input system. You might want to mark the entity that responds to input with some sort of Player component, but the input is going to be complex and completely game-specific so there's little point trying to make components for this.

\$\endgroup\$
1
\$\begingroup\$

Here are some of my ideas of solving these problems. They will probably have something wrong with them, and there will probably be a better approach, so please, direct me to those in your answer!

Camera:

There is a "Camera" component, which can be added to any entity. I can't really figure what data should I put in this component, though: I could have separate "Position" and "Rotation" components! The follow method doesn't need to be implemented, because it's already following the entity it is attached to! And I'm free to move it around. The problem with this system would be many different camera objects: how can the RendererSystem know which ones to use? And also, I used to just pass the camera object around, but now it seems that the RendererSystem will need to iterate two times over all the entities: first to find the ones acting like cameras, and second, to actually render everything.

ParticleEmitter:

There would be a ParticleSystem which would update all entities that had a "Emitter" component. Particles are dumb objects in a relative coordinate space, inside that component. There is a problem of rendering here: I would either need to make a ParticleRenderer system, or extend the functionality of the existing one.

Input system:

The main concern for me here was the logic, or the react() method. The only solution I came up with is a separate system for that, and a component for each system, that would indicate which one to use. This really seems too hacky, and I don't know how to handle it well. One thing is that, as long as I'm concerned, the Input can stay implemented as a class, but I don't see how could I integrate it to the rest of the game.

\$\endgroup\$
3
  • \$\begingroup\$ There isn't really a reason for the RendererSystem to iterate over all entities - it should already have a list of drawables (and cameras, and lights (unless lights are drawables)), or know where those lists are. Also, you will likely want to do culling for cameras you want to render, so maybe your camera could contain a list of drawable entity IDs that are visible to it. You could have many cameras and one active one, or one camera that gets attached to different POVs, both of which could be controlled by any number of things, like scripts and triggers and inputs \$\endgroup\$
    – user13213
    Commented Jul 21, 2012 at 15:41
  • \$\begingroup\$ @melak47, that's true, I thought about it too, but I wanted to implement it the way Aremis does it. But this "systems store references to relevant entities" seems to be more and more flawed... \$\endgroup\$
    – jcora
    Commented Jul 21, 2012 at 15:45
  • \$\begingroup\$ Doesn't Artemis store each Component type in it's own list? so wouldn't you have exactly those lists of drawable components, camera components, lights and what not somewhere? \$\endgroup\$
    – user13213
    Commented Jul 21, 2012 at 16:36

You must log in to answer this question.

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