示例#1
0
/// Remove a layer from this world.
///
/// @param[in] pLayer  Layer to remove.
///
/// @return  True if the layer was removed successfully, false if not.
///
/// @see AddLayer()
bool World::RemoveLayer( Layer* pLayer )
{
    HELIUM_ASSERT( pLayer );

    // Make sure the layer is part of this world.
    if( pLayer->GetWorld().Get() != this )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            TXT( "World::RemoveLayer(): Layer \"%s\" is not part of world \"%s\".\n" ),
            *pLayer->GetPath().ToString(),
            *GetPath().ToString() );

        return false;
    }

    // Detach all entities in the layer.
    size_t entityCount = pLayer->GetEntityCount();
    for( size_t entityIndex = 0; entityIndex < entityCount; ++entityIndex )
    {
        Entity* pEntity = pLayer->GetEntity( entityIndex );
        HELIUM_ASSERT( pEntity );
        pEntity->Detach();
    }

    // Remove the layer from the layer list and clear out all references back to this world.
    size_t index = pLayer->GetWorldIndex();
    HELIUM_ASSERT( index < m_layers.GetSize() );

    pLayer->ClearWorldInfo();
    m_layers.RemoveSwap( index );

    // Update the index of the layer which has been moved to fill the layer list entry we just removed.
    size_t layerCount = m_layers.GetSize();
    if( index < layerCount )
    {
        Layer* pMovedLayer = m_layers[ index ];
        HELIUM_ASSERT( pMovedLayer );
        HELIUM_ASSERT( pMovedLayer->GetWorldIndex() == layerCount );
        pMovedLayer->SetWorldIndex( index );
    }

    return true;
}
示例#2
0
/// Update all worlds for the current frame.
void WorldManager::Update()
{
    // Update the world time.
    UpdateTime();

    // Perform the entity pre-update.
    m_updatePhase = UPDATE_PHASE_PRE;
    {
        JobContext::Spawner< 1 > entityUpdateSpawner;
        JobContext* pContext = entityUpdateSpawner.Allocate();
        HELIUM_ASSERT( pContext );
        WorldManagerUpdate< EntityPreUpdate >* pJob = pContext->Create< WorldManagerUpdate< EntityPreUpdate > >();
        HELIUM_ASSERT( pJob );
        WorldManagerUpdate< EntityPreUpdate >::Parameters& rParameters = pJob->GetParameters();
        rParameters.pspWorlds = m_worlds.GetData();
        rParameters.worldCount = m_worlds.GetSize();
    }

    // Perform the entity post-update.
    m_updatePhase = UPDATE_PHASE_POST;
    {
        JobContext::Spawner< 1 > entityUpdateSpawner;
        JobContext* pContext = entityUpdateSpawner.Allocate();
        HELIUM_ASSERT( pContext );
        WorldManagerUpdate< EntityPostUpdate >* pJob = pContext->Create< WorldManagerUpdate< EntityPostUpdate > >();
        HELIUM_ASSERT( pJob );
        WorldManagerUpdate< EntityPostUpdate >::Parameters& rParameters = pJob->GetParameters();
        rParameters.pspWorlds = m_worlds.GetData();
        rParameters.worldCount = m_worlds.GetSize();
    }

    // Perform the entity synchronous update.
    m_updatePhase = UPDATE_PHASE_SYNCHRONOUS;

    size_t worldCount = m_worlds.GetSize();
    for( size_t worldIndex = 0; worldIndex < worldCount; ++worldIndex )
    {
        World* pWorld = m_worlds[ worldIndex ];
        HELIUM_ASSERT( pWorld );
        size_t layerCount = pWorld->GetLayerCount();
        for( size_t layerIndex = 0; layerIndex < layerCount; ++layerIndex )
        {
            Layer* pLayer = pWorld->GetLayer( layerIndex );
            HELIUM_ASSERT( pLayer );
            size_t entityCount = pLayer->GetEntityCount();
            for( size_t entityIndex = 0; entityIndex < entityCount; ++entityIndex )
            {
                Entity* pEntity = pLayer->GetEntity( entityIndex );
                HELIUM_ASSERT( pEntity );

                bool bNeedsSynchronousUpdate = pEntity->NeedsSynchronousUpdate();
                uint32_t deferredWorkFlags = pEntity->GetDeferredWorkFlags();
                if( !bNeedsSynchronousUpdate && !deferredWorkFlags )
                {
                    continue;
                }

                if( deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_DESTROY )
                {
                    pLayer->DestroyEntity( pEntity );
                    --entityIndex;

                    // Only the current entity should be destroyed; entity destruction should not trigger the
                    // immediate creation or destruction of other entities.
                    --entityCount;
                    HELIUM_ASSERT( pLayer->GetEntityCount() == entityCount );

                    continue;
                }

                // Entity::NeedsSynchronousUpdate() also checks the deferred work flags.
                if( bNeedsSynchronousUpdate /*deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_UPDATE*/ )
                {
                    pEntity->SynchronousUpdate( m_frameDeltaSeconds );

                    // Update the entity count in case a new entity was created during the synchronous update.
                    entityCount = pLayer->GetEntityCount();
                    HELIUM_ASSERT( entityIndex < entityCount );

                    // Update the deferred work flags and reassess entity destruction after the synchronous update.
                    deferredWorkFlags = pEntity->GetDeferredWorkFlags();

                    if( deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_DESTROY )
                    {
                        pLayer->DestroyEntity( pEntity );
                        --entityIndex;

                        // Only the current entity should be destroyed; entity destruction should not trigger the
                        // immediate creation or destruction of other entities.
                        --entityCount;
                        HELIUM_ASSERT( pLayer->GetEntityCount() == entityCount );

                        continue;
                    }
                }

                if( deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_REATTACH )
                {
                    pEntity->Detach();
                    pEntity->Attach();

                    // Entities should only be spawned during the synchronous update call, so the count should not
                    // have changed as a result of reattachment.
                    HELIUM_ASSERT( pLayer->GetEntityCount() == entityCount );
                }

                pEntity->ClearDeferredWorkFlags();
            }
        }
    }

    m_updatePhase = UPDATE_PHASE_INVALID;

    // Update the graphics scene for each world.
    for( size_t worldIndex = 0; worldIndex < worldCount; ++worldIndex )
    {
        World* pWorld = m_worlds[ worldIndex ];
        HELIUM_ASSERT( pWorld );
        pWorld->UpdateGraphicsScene();
    }
}