zoukankan      html  css  js  c++  java
  • UE3中Object和Actor的创建与销毁

    创建Object

    ① 在uc脚本中使用new运算符来创建

    /**********************************************************************************
        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的创建者是谁

    注2:new的实现在c++的UObject::execNew函数中

    一些示例:

    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;
    }

    销毁Object

    GC系统检查当前Object对象是否被Root类型Object对象直接或间接引用,如果没有则会销毁该Object

    当某个Root类型Object不再使用某个Object对象时,应及时将其设置成null,来防止因为被引用无法及时被GC回收

    注1:在UWorld::Tick中GC系统会按照一定的时间间隔调用UWorld::PerformGarbageCollection()来开始查找并标记那些对象是垃圾(GCMark),被标记的的object对象会触发BeginDestroy()调用

             时间间隔变量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;
    }
  • 相关阅读:
    多个手机号逗号分开
    字符转码
    短信发送AZDG加密算法
    判断手机所属三大运营商 移动、联通、电信
    MD5加密 时间差 流水号等方法
    VS2012的创建单元测试功能
    Oracle数据库操作类及连接方法
    python生成器,函数,数组
    javascript的单线程
    linux下/var/run目录下.pid文件的作用
  • 原文地址:https://www.cnblogs.com/kekec/p/9856138.html
Copyright © 2011-2022 走看看