4
\$\begingroup\$

EDIT: half of my question seemed to disappear, but thankfully, it was still in the clipboard.

When I say entities, I mean instantiations of various classes in my engine (example class: Engine.Animation, or Engine.Scene). The language in question is Javascript.

The situation:


The current structure of my engine goes something like this:

// The single engine object that only stores constructor functions, 
// aka classes (or at least it used to only store those).
Engine = {};

Engine.Scene = function()
{
    ...
}

Lets take the Scene class as an example... It basically stores all the information needed to render the visual part of the game state, which is done by the Renderer class (renderer.render(scene, camera)).



The problem:


All worked well, but then I realized that the entities sometimes needed to be updated! The best (and, for now, the only) example of this is the scene.AlphaDown() method, which makes the scene transparent, "shuts it down", in a way.

I implemented this with the use of setInterval (the interval would call a function that used to lower the scene's alpha depending on how much time passed. This is the kind of "update method" I am talking about: the one that needs to be called iteratively, usually at 60FPS.) But, I was told that it was a bad practice (here and here). It was suggested to me that I use alternative ways of updating entities (without the use of setInterval).



The possible solution:


I meant to have an array in Engine, called toUpdate, in which different entities would push their update methods. Then, the Engine would have a central update() method, which would calculate the time since last updated, and call the entities' registered update methods, giving that time as an argument. In the previous example with a scene, AlphaDown() would register an update method by pushing it into the Engine.toUpdate array.  When the task of an update method (ie scene.alpha = 0) was completed, it would be removed from the toUpdate array.



The problem with the solution:


This method has it's flaws, though. First, it would require the user to call Engine.update() on each of his game loop iterations. Then, it would make the global Engine object have methods, but I just want to keep it a namespace of some sort, a collection of useful classes. I don't want to dictate how a loop should be structured!



The question:


Is my solution an acceptable way of updating entities? Are there some other, more standard ways? Should I strive to have my entities not have update methods that need to be iteratively called, and let the user implement them?

\$\endgroup\$
3
  • \$\begingroup\$ Were you told why setInterval was bad practice? (I'm just wondering). \$\endgroup\$ Jul 17, 2012 at 19:21
  • \$\begingroup\$ Experiencing huge technical difficulties at the moment, time to switch to a new ISP because I can't take this anymore. \$\endgroup\$
    – jcora
    Jul 17, 2012 at 19:25
  • \$\begingroup\$ For some reason, I cannot connect edit the question. The edit page loads normally, but when I click "save edits", it just keeps on connecting forever. It'd be great if someone re-formatted my question for me, this is unbearable. \$\endgroup\$
    – jcora
    Jul 17, 2012 at 19:31

1 Answer 1

2
\$\begingroup\$

Most of the time I've implemented two update types:

  • A fixed update, which the entity could specify the update interval. (e.g. Once per second, or 5 times per second, etc...)
  • A per-frame update.

The entity could register for either method, and if it did then the engine would put that entity into a list of entities to update, otherwise it was never updated. My entity manager class would then have the list of all entities, and a list of entities that receive updates, which is always a sub-set of the full list of entities.

It is certainly the case that many engines will have entities that can update every frame. This can be expensive, but only if you let it get out of hand. I've easily had a couple hundred entities updating every frame with no performance problems in some cases, but it will depend on how optimized your solution is and the platform you're running on.

How to architect a system to update entities (bear with me, I don't know Javascript, this is based on what I could learn in about 5 minutes, just now...):

Entity = {}

Entity = function() {
    var m_updateable = false;
    var m_updates_per_second = 0;  // Set to -1 if it should update per-frame
    var m_time_elapsed = 0.0;

    function set_updates( updates_per_second ) {
        m_updateable = true;
        m_updates_per_second = updates_per_second;
        notify_scene_mgr_updateable( self, true ); // Tell Scene Manager this entity is updateable now.
    }

    function set_not_updateable() {
        m_updateable = false;
        m_updates_per_second = 0;
        notify_scene_mgr_updateable( self, false ); // Tell Scene Manager this entity is no longer updateable.
    }

    // Returns 'true' if an update is needed.
    function needs_update( time_elapsed ) {
        if ( m_updates_per_second == -1 ) return true;

        m_time_elapsed = m_time_elapsed + time_elapsed;

        return ( m_time_elapsed > (1 / m_updates_per_second) );
    }

    // Called every frame if this entity is registered for per-frame updates
    function update( time_elapsed ) {
        // Do stuff here
    }

    // Called on an interval set by 'm_updates_per_second'
    function fixed_update( time_elapsed ) {
        m_time_elapsed = m_time_elapsed - time_elapsed;

        // Do stuff here
    }
}

SceneManager = {}

SceneManager = function() {
    var m_entities = [];
    var m_updateable_entities = [];

    function notify_scene_mgr_updateable( entity, is_updateable ) {
        if ( is_updateable ) {
            // If entity is not in m_updateable_entities, put them in that list
            m_updateable_entities.push(entity);
        } else {
            // If entity is in m_updateable_entities, remove them from that list
            m_updateable_entities.remove(entity);
        }
    }

    // Call this every frame
    function update_entities( time_elapsed ) {
        for(var i = 0; i < m_updateable_entities.length; i++){
            // Check if this entity needs an update
            if ( m_updateable_entities[i].needs_update( time_elapsed ) ) {
                // Does this entity get a per-frame update?
                if ( m_updateable_entities[i].m_updates_per_second == -1 ) {
                    // Do the per-frame update
                    m_updateable_entities[i].update( time_elapsed );
                } else {
                    // Do the fixed-interval update
                    m_updateable_entities[i].fixed_update( time_elapsed );
                }
            }

        }
    }
}
\$\endgroup\$
8
  • \$\begingroup\$ Not quite the thing that I'm asking here... I'm basically wandering about what should control the updates here. \$\endgroup\$
    – jcora
    Jul 17, 2012 at 19:39
  • 1
    \$\begingroup\$ Ah ok, I will update the answer to include that then. \$\endgroup\$
    – Nic Foster
    Jul 17, 2012 at 19:40
  • \$\begingroup\$ Thanks. If there are any uncertainties, just look at the question, or ask here, it was kinda tricky to word so I might've made some mistakes. Although I'm quite sure it's all correct. \$\endgroup\$
    – jcora
    Jul 17, 2012 at 19:45
  • \$\begingroup\$ I've added a small sample, hopefully it gets the point across, although I don't know javascript, I did the best I could with the 5 minutes of javascript I just learned online (just now). I know JS doesn't have classes, but the code sample was intended to show that you would need an object of some sort to encapsulate that data and functionality. \$\endgroup\$
    – Nic Foster
    Jul 17, 2012 at 20:07
  • 2
    \$\begingroup\$ 20 hours of programming saves 4 hours of design time. That is, it's best to design out what you're trying to do before coding it. So I agree. \$\endgroup\$
    – Nic Foster
    Jul 17, 2012 at 20:45

You must log in to answer this question.

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