I created a camera shake tool that can shake the camera at intervals and stop automatically after specific duration time.
Just like below code, I created a UCameraShaker instance which derived from UObject, assigned to a TWeakObjectPtr, and saved the ptr to a TArray(maybe this step was unnecessary) which was a member variable with UPROPERTY().
I knew that TWeakObjectPtr cannot prevent the GC operation, so seconds later, the instance of UCameraShaker I just created would be destroyed, unsurprisingly.
I have no idea that how to keep these instances and will not be destroyed by GC. Add to root? But I think I can’t decide when to remove from root because there is no callback when the timer expired. Add reference count? How?
UCLASS(MinimalAPI)
class UCameraShakeHelper : public UKMObject
{
GENERATED_UCLASS_BODY()
public:
~UCameraShakeHelper();
UFUNCTION(BlueprintCallable, Category = "UCameraShakeHelper")
void ShakeCameraWithInterval(TSubclassOf<class UCameraShake> Shake, float Scale, float Interval, float TotalTime);
private:
UPROPERTY()
TArray<TWeakObjectPtr<UCameraShaker> > CameraShakerList;
};
void UCameraShakeHelper::ShakeCameraWithInterval(TSubclassOf<class UCameraShake> Shake, float Scale, float Interval, float TotalTime)
{
UWorld *World = GetWorld();
if (nullptr != World)
{
auto GameInstance = Cast<UROG2GameInstance>(World->GetGameInstance());
TWeakObjectPtr<UCameraShaker> Shaker = NewObject<UCameraShaker>(this);
Shaker->InitParams(Shake, Scale);
CameraShakerList.Add(Shaker);
auto &TimerHelper = GameInstance->GetTimerHelper();
TimerHelper.SetAutoStopTimer(Shaker.Get(), &UCameraShaker::OnShake, Interval, TotalTime);
}
}
You can declare the array as follows (using regular pointers):
Header:
UPROPERTY()
TArray<UCameraShaker*> Shakers;
Cpp:
UCameraShaker* shaker = NewObject<UCameraShaker>(this, UCameraShaker::StaticClass());
Shakers.Add(shaker);
1 Like
It works, but what if the Shakers array was removed? If I add the shaker to the array, I have to add a callback function to remove it from the array when the timer expire. So I want to make a optimization and remove this array. How to keep the shaker alive without Shakers array?
Good idea! I’ll have a try~
Thank you~
Is there anything else method to keep a object alive? Such as add reference count manually or something else?
You can just declare a class-level variable decorated with UPROPERTY(), e.g.
UPROPERTY()
UCameraShaker* Shaker;
This will instruct the GC to keep it alive until all references to it has been removed.
Crap, I was editing the previous comment and deleted it. Here it is:
=========================
Yes, I don’t think there’s really a perfect solution here. You could remove the array and have a single shaker reference decorated with UPROPERTY() to prevent Garbage Collection, but you’d still have the same problem. The point is that even with built-in GC, you still need to instruct it what to do in many cases.
You could add a callback to call Destroy on the shaker after it’s been used (whether it’s in an array or not) as you’ve suggested, but this means you’d have to spawn a new one each time you do a shake. Compared to keeping the reference alive (see below) this might actually be worse performance-wise.
On the other hand you can just keep this reference alive and re-use (re-init) it each time you need to do a shake. I do this in my project, and the performance hit seems negligible.
=========================
Is there anything else method to keep a object alive? Such as add reference count manually or something else?