UE3中Object和Actor的建立與銷燬

建立Objectc++

① 在uc腳本中使用new運算符來建立app

/**********************************************************************************
    outer : The value for the new object's Outer variable.
            The default value is None, which means the object is created within the "transient package", a virtual package for runtime objects.
    InName : The name for the new object.
    flags : Specifies object flags for the new object.
    class : The class to create an object of. No abstract object & No Actor.
**********************************************************************************/

new ( optional Object outer=none , optional String ObjName="" , optional int flags=0 ) class(template);

注1:outer記錄當前object的建立者是誰less

注2:new的實如今c++的UObject::execNew函數中編輯器

一些示例:ide

local TObject1 O1, O2, O3, O4;

O1 = new class'TObject1';
O2 = new(self) class'TObject1'; // O2.Outer=self
O3 = new(none, "TObject1_xxx") class'TObject1'; // O3.Name="TObject1_xxx"
O4 = new(self, "", 0) class'TObject1';

② 在c++中使用StaticConstructObject函數來建立函數

/**
 * Create a new instance of an object.  The returned object will be fully initialized.  If InFlags contains RF_NeedsLoad (indicating that the object still needs to load its object data from disk), components
 * are not instanced (this will instead occur in PostLoad()).  The different between StaticConstructObject and StaticAllocateObject is that StaticConstructObject will also call the class constructor on the object
 * and instance any components.
 * 
 * @param    Class        the class of the object to create
 * @param    InOuter        the object to create this object within (the Outer property for the new object will be set to the value specified here).
 * @param    Name        the name to give the new object. If no value (NAME_None) is specified, the object will be given a unique name in the form of ClassName_#.
 * @param    SetFlags    the ObjectFlags to assign to the new object. some flags can affect the behavior of constructing the object.
 * @param    Template    if specified, the property values from this object will be copied to the new object, and the new object's ObjectArchetype value will be set to this object.
 *                        If NULL, the class default object is used instead.
 * @param    Error        the output device to use for logging errors
 * @param    SubobjectRoot
 *                        Only used to when duplicating or instancing objects; in a nested subobject chain, corresponds to the first object that is not a subobject.
 *                        A value of INVALID_OBJECT for this parameter indicates that we are calling StaticConstructObject to duplicate or instance a non-subobject (which will be the subobject root for any subobjects of the new object)
 *                        A value of NULL indicates that we are not instancing or duplicating an object.
 * @param    InstanceGraph
 *                        contains the mappings of instanced objects and components to their templates
 *
 * @return    a pointer to a fully initialized object of the specified class.
 */
UObject* UObject::StaticConstructObject
(
    UClass*            InClass,
    UObject*        InOuter                                /*=GetTransientPackage()*/,
    FName            InName                                /*=NAME_None*/,
    EObjectFlags    InFlags                                /*=0*/,
    UObject*        InTemplate                            /*=NULL*/,
    FOutputDevice*    Error                                /*=GError*/,
    UObject*        SubobjectRoot                        /*=NULL*/,
    FObjectInstancingGraph* InInstanceGraph                /*=NULL*/
)
{
    // ... ...
    
    // Allocate the object.
    UObject* Result = StaticAllocateObject( InClass, InOuter, InName, InFlags, InTemplate, Error, NULL, SubobjectRoot, InstanceGraph );

    if( Result )
    {
        {
            // call the base UObject class constructor if the class is misaligned (i.e. a native class that is currently being recompiled)
            // 調用UObject::InternalConstructor,裏面會使用placement new來構造UObject,使得其能調用UObject()無參構造函數來初始化
            if ( !InClass->IsMisaligned() )
            {
                (*InClass->ClassConstructor)( Result );
            }
            else
            {
                (*UObject::StaticClass()->ClassConstructor)( Result );
            }
        }

        // ... ...
    }
    
    // ... ...

    return Result;
}

 

銷燬Objectthis

GC系統檢查當前Object對象是否被Root類型Object對象直接或間接引用,若是沒有則會銷燬該Objectspa

當某個Root類型Object再也不使用某個Object對象時,應及時將其設置成null,來防止由於被引用沒法及時被GC回收code

注1:在UWorld::Tick中GC系統會按照必定的時間間隔調用UWorld::PerformGarbageCollection()來開始查找並標記那些對象是垃圾(GCMark),被標記的的object對象會觸發BeginDestroy()調用component

         時間間隔變量TimeBetweenPurgingPendingKillObjects能夠在*Engine.ini的[Engine.Engine]標籤中配置,缺省配置爲60秒

注2:在Tick中調用UObject::IncrementalPurgeGarbage(TRUE)分幀來回收垃圾(GCSweep),在delete Object前還會觸發FinishDestroy()調用

         因爲Object是個對象,delete Object等價於:

        Object->~Object();  // ~Object是個虛析構函數,不一樣Object類型對象會先調用本身的析構函數,而後依次調父類的
        operator delete(Object);

        因爲UObject實現了void operator delete( void* Object, size_t Size )成員函數,最後會調用UObject中的delete操做符重載函數

        爲了減小內存碎片和減小分配和回收內存開銷,UE本身對UObject進行了內存管理,delete實際上不會真正地釋放內存

注3:也能夠經過執行obj gc來觸發UObject::CollectGarbage( GARBAGE_COLLECTION_KEEPFLAGS )調用,來GCMark並GCSweep垃圾

注4:編輯器的GC引用分析邏輯在void FArchiveTagUsedNonRecursive::PerformReachabilityAnalysis( EObjectFlags KeepFlags )

        遊戲的在void FArchiveRealtimeGC::PerformReachabilityAnalysis( EObjectFlags KeepFlags )中

 

建立Actor

① 在uc腳本中使用Spawn函數來建立

' Spawn an actor. Returns an actor of the specified class, not of class Actor (this is hardcoded in the compiler). 
' Returns None
if the actor could not be spawned (if that happens, there will be a log warning indicating why) Defaults to spawning at the spawner's location. ' ' @note: ActorTemplate is sent for replicated actors and therefore its properties will also be applied at initial creation on the client.
' However, because of this, ActorTemplate must be a static resource
(an actor archetype, default object, or a bStatic/bNoDelete actor in a level package) or the spawned Actor cannot be replicated native noexport final function coerce actor Spawn ( class<actor> SpawnClass, optional actor SpawnOwner, optional name SpawnTag, optional vector SpawnLocation, optional rotator SpawnRotation, optional Actor ActorTemplate, optional bool bNoCollisionFail );

一些示例:

local UTBot NewBot;
local Pawn NewPawn;
local class<HUD> NewHUDType;
local HUD NewHUD;

NewBot = Spawn(class'UTBot');
NewPawn = Spawn(class'UTPawn',,,vect(10.0,20.0,0.0),rot(1234, 5678 , 9012));

NewHUDType = class'UTEntryHUD';
NewHUD = Spawn(NewHUDType, self);  //self爲當前controller對象

 注:Spawn的實如今c++的AActor::execSpawn函數中

 

② 在cpp中使用SpawnActor函數來建立

// Create a new actor. Returns the new actor, or NULL if failure.
AActor* UWorld::SpawnActor
( 
    UClass* Class, 
    FName InName=NAME_None, 
    const FVector& Location=FVector(0,0,0), 
    const FRotator& Rotation=FRotator(0,0,0), 
    AActor* Template=NULL, 
    UBOOL bNoCollisionFail=0, 
    UBOOL bRemoteOwned=0, 
    AActor* Owner=NULL, 
    APawn* Instigator=NULL, 
    UBOOL bNoFail=0 
)
{
    // 遊戲世界WorldInfo是否建立完畢
    const UBOOL bBegunPlay = HasBegunPlay();
    
    FVector NewLocation = Location;
    // 根據Actor類型的碰撞信息和碰撞體大小調整Actor的位置
    if( (Template->bCollideWorld || (Template->bCollideWhenPlacing && (GetNetMode() != NM_Client))) && !bNoCollisionFail )
    {
        FindSpot(Template->GetCylinderExtent(), NewLocation, Template->bCollideComplex);
    }
    
    // 建立Actor
    ULevel* LevelToSpawnIn = Owner ? CastChecked<ULevel>(Owner->GetOuter()) : CurrentLevel;
    AActor* Actor = ConstructObject<AActor>( Class, LevelToSpawnIn, InName, RF_Transactional, Template );
    // 添加Actor到關卡中
    LevelToSpawnIn->Actors.AddItem( Actor );
    // 添加Actor到關卡的Tick列表中
    if (Actor->WantsTick())
    {
        LevelToSpawnIn->TickableActors.AddItem(Actor);
    }
    
    Actor->bTicked        = !Ticked;
    Actor->CreationTime = GetTimeSeconds();
    Actor->WorldInfo    = GetWorldInfo();

    // Set the actor's location and rotation.
    Actor->Location = NewLocation;
    Actor->Rotation = Rotation;
    
    // Initialize the actor's components.
    Actor->ConditionalForceUpdateComponents(FALSE,FALSE);

    // init actor's physics volume
    Actor->PhysicsVolume = GetWorldInfo()->PhysicsVolume;

    // Set owner.
    Actor->SetOwner( Owner );

    // Set instigator
    Actor->Instigator = Instigator;
    
    if (bBegunPlay)
    {
        Actor->InitRBPhys();
    }

    Actor->InitExecution();
    Actor->Spawned();

    if(bBegunPlay)
    {
        Actor->PreBeginPlay();
        {
            eventPreBeginPlay(); // 調用uc腳本的event PreBeginPlay()事件回調函數
            
            // ... ...
        }

        for(INT ComponentIndex = 0;ComponentIndex < Actor->Components.Num();ComponentIndex++)
        {
            if(Actor->Components(ComponentIndex))
            {
                Actor->Components(ComponentIndex)->ConditionalBeginPlay();
            }
        }
    }
    
    // Check for encroachment.
    if( !bNoCollisionFail )
    {
        CheckEncroachment( Actor, Actor->Location, Actor->Rotation, 1 );
    }
    else if ( Actor->bCollideActors )
    {
        Actor->FindTouchingActors();
    }

    if(bBegunPlay)
    {
        Actor->PostBeginPlay(); 
        {
            // Send PostBeginPlay.
            eventPostBeginPlay();// 調用uc腳本的event PostBeginPlay()事件回調函數

            // Init scripting.
            eventSetInitialState(); // 調用uc腳本的event SetInitialState()函數

            // Find Base
            if( !Base && bCollideWorld && bShouldBaseAtStartup && ((Physics == PHYS_None) || (Physics == PHYS_Rotating)) )
            {
                FindBase();
            }
        }
    }

    if( InTick )
    {
        NewlySpawned.AddItem( Actor );
    }
    
    return Actor;
}

 

銷燬Actor

Actor本質仍是一個Object,其回收是經過GC完成的,顯示調用uc的Destory和cpp中的DestroyActor只是去除Actor對象的全部引用,讓其能被GC視爲垃圾

① 在uc腳本中使用Destory函數來銷燬 

'Destroy this actor. Returns true if destroyed, false if indestructible.
'Destruction is latent. It occurs at the end of the tick.
native(279) final noexport function k2call bool Destroy();

② 在cpp中使用DestroyActor函數來銷燬

/**
 * Removes the actor from its level's actor list and generally cleans up the engine's internal state.
 * What this function does not do, but is handled via garbage collection instead, is remove references
 * to this actor from all other actors, and kill the actor's resources.  This function is set up so that
 * no problems occur even if the actor is being destroyed inside its recursion stack.
 *
 * @param    ThisActor                Actor to remove.
 * @param    bNetForce                [opt] Ignored unless called during play.  Default is FALSE.
 * @param    bShouldModifyLevel        [opt] If TRUE, Modify() the level before removing the actor.  Default is TRUE.
 * @return                            TRUE if destroy, FALSE if actor couldn't be destroyed.
 */
UBOOL UWorld::DestroyActor( 
    AActor* ThisActor, 
    UBOOL bNetForce=FALSE, 
    UBOOL bShouldModifyLevel=TRUE  
)
{
    check(ThisActor);
    check(ThisActor->IsValid());
    
    ThisActor->bPendingDelete = true;

    // Terminate any physics engine stuff for this actor right away.
    ThisActor->TermRBPhys(NULL);
// Tell this actor it's about to be destroyed.
    ThisActor->eventDestroyed();// 調用uc腳本的event Destroyed()事件回調函數
    ThisActor->PostScriptDestroyed();
    // Remove from base.
    if( ThisActor->Base )
    {
        ThisActor->SetBase( NULL );
    }
    
    // Make a copy of the array, as calling SetBase might change the contents of the array.
    TArray<AActor*> AttachedCopy = ThisActor->Attached;
    for( INT AttachmentIndex=0; AttachmentIndex < AttachedCopy.Num(); AttachmentIndex++ )
    {
        AActor* AttachedActor = AttachedCopy(AttachmentIndex);
        if( AttachedActor && AttachedActor->Base == ThisActor && !AttachedActor->bDeleteMe )
        {
            AttachedActor->SetBase( NULL );
        }
    }
    // Then empty the array.
    ThisActor->Attached.Empty();

    // Clean up all touching actors.
    INT iTemp = 0;
    for ( INT i=0; i<ThisActor->Touching.Num(); i++ )
    {
        if ( ThisActor->Touching(i) && ThisActor->Touching(i)->Touching.FindItem(ThisActor, iTemp) )
        {
            ThisActor->EndTouch( ThisActor->Touching(i), 1 );
            i--;
        }
    }

    // If this actor has an owner, notify it that it has lost a child.
    if( ThisActor->Owner )
    {
        ThisActor->SetOwner(NULL);
    }
    // Notify net players that this guy has been destroyed.
    if( NetDriver )
    {
        NetDriver->NotifyActorDestroyed( ThisActor );
    }

    // Remove the actor from the actor list.
    RemoveActor( ThisActor, bShouldModifyLevel );
    
    // Mark the actor and its direct components as pending kill.
    ThisActor->bDeleteMe = 1;
    ThisActor->MarkPackageDirty();
    ThisActor->MarkComponentsAsPendingKill( TRUE );

    // Clean up the actor's components.
    ThisActor->ClearComponents();

    // Return success.
    return TRUE;
}
相關文章
相關標籤/搜索