QSDK 1.1 Documentation

Programmers Tutorial: Unit 79

Purpose: More about entities. Advanced features like ticking control, asset management or persistence.
Concepts introduced: Q::Entity
Samples: entityt2, factory and factory2

The following includes are required for the code snippets:

#include <iostream>
#include <Q/q.h>
#include <Q/com.h>
#include <Q/gamedev.h>

Ticking

Entity instances can balance the processing load by tuning the way they are ticked. In general, applications do not need to tick all entities at the same frequency to have a realistic effects. Choosing an egocentric approach is often better. The closer to the player the entities are, the more they get ticked. Ticking can be enabled/disabled by Q::EntityInstance::setTicking(bool enabled). The ticking frequency can be modified using Q::EntityInstance::setTickDelay(float).

struct VariableTicker: public Q::Entity,
                       public Com::ComObject<Q::Entity, VariableTicker>
{
  // COM Object Declaration
  QCOM_DECLARE_COMPONENT;

  virtual void tick(float duration)
  {
    std::cout << "I am ticked (period=" << duration << ")" << std::endl;

    // change the ticking frequency to reflect the
    // distance with the observer
    float d = Player::thePlayer().position() - instance_->group().position();
    instance_->setTickDelay(d*tickingRate_);
  }

  virtual bool embody(Q::EntityInstance* instance)
  {
    // attach the simulated entity instance
    instance_ = instance;

    // set the ticking rate
    tickingRate_ = 2.0f;

    // do tick this entity
    instance_->setTicking(true);

    return true;
  }

  virtual void disembody(bool destroyed)
  {
    // detach the simulated entity instance
    instance_ = 0;
  }

  virtual void entered(unsigned int, Q::EntityInstance*, unsigned int)
  {
     // nothing to be done
  }

  virtual void exited(unsigned int, Q::EntityInstance*, unsigned int)
  {
     // nothing to be done
  }

  virtual void receive(Q::MessagePeer* from, Q::Message*, Q::MessageResult*)
  {
     // nothing to be done
  }

private:
  Q::EntityInstance::PTR    instance_; // the simulated entity instance
  float                     tickingRate_; 
};

Note that the duration passed as a parameter to Q::Entity::tick is the duration since the last time the entity got ticked. It is not the ticking duration of the application. Additionally,  entity ticks can be ordered within the same frame. If you want an entity to be always ticked before another one, e.g. because the latter follows the former, you can use Q::EntityInstance2::setTickPriority to order their ticks. Entities with higher priority are ticked before entities with lower priority. It only really makes sense for entities ticked every frame.

Iterating on entities

Entities may be accessed by several means. The simplest way is to keep a pointer on the relevant ones. Another one is to retrieve them by names for those who have one. Besides, it is possible to iterate through the set of active entities as follows:

std::cout << Q::EntityManager2::theManager()->activeCount()
          << " entities are currently active" << std::endl

std::cout << "Are actives" << std::endl;
for (Q::EntityIterator::PTR it = Q::EntityManager2::theManager()->actives();
     it->valid(); it->next()) {
  std::cout << it->current()->name() << std::endl;
}

Persistence

Entities are usually deactivated when all scope instances are out of scope. This default behavior may not be satisfying in some cases. For instance, if the activation of an entity has been forced, this one must remain active as long as necessary. Therefore, as entities may be forced to be activated, they also may be forced to remain active. This can be achieved using Q::EntityInstance::setPersistent(bool). Persistent entities are never deactivated. However they may be later on if their persistent flag is set to false.

Assets

Entities use assets and these dependent assets must be preloaded and ready when the entity gets activated. There are two main types of dependent assets: those associated with an entity type and those with a particular entity instance. Entity type dependencies are assets which are common to all entities of this type and are usually accessed in the entity constructor. Entity instance dependencies are assets which are specific to a particular entity and are usually accessed in the Q::Entity::embody method. For instance, character puppets will usually be entity type dependencies because all entities of the same type usually use the same puppet. On the other hand, inventory items will be entity instance dependencies because they are associated with a particular entity.

Besides type and instance dependencies are both divided into two sub-categories: lifetime assets and load assets. Lifetime assets are assets which are needed throughout the lifetime of the entity. Load assets are assets which are only needed when the entity gets created or activated. Roughly speaking, load assets are generally used to build the entity components but do not need to be held in memory once the components have been assembled, e.g. scripts or clips. Lifetime assets are assets the entity use regularly in its update, e.g. particle effects or animations.

For more details on how to author entity asset dependencies in QStudio, read here for entity types and here for entity instances. Read the QDemo2 production guide to see how the demo uses asset dependencies in its design.

Return to QSDK documentation Contents page. Contact details for support, information and fault-reporting.
Qube Software Limited © 2000-2004