- 创建特效的方法:【明确:要想特效创建后,就显示正常;必须保证UParticleSystemComponent组件的数组EmitterInstances中的值是有效的】
UFUNCTION(BlueprintCallable, Category="Effects|Components|ParticleSystem", meta=(Keywords = "particle system", UnsafeDuringActorConstruction = "true"))
static UParticleSystemComponent* SpawnEmitterAttached(class UParticleSystem* EmitterTemplate, class USceneComponent* AttachToComponent, FName AttachPointName = NAME_None, FVector Location = FVector(ForceInit), FRotator Rotation = FRotator::ZeroRotator, FVector Scale = FVector(1.f), EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bAutoDestroy = true, EPSCPoolMethod PoolingMethod = EPSCPoolMethod::None, bool bAutoActivate=true);
- 创建粒子特效的时机,先看一段源码
void UParticleSystemComponent::InitParticles()
{
LLM_SCOPE(ELLMTag::Particles);
SCOPE_CYCLE_COUNTER(STAT_ParticleSystemComponent_InitParticles);
if (IsTemplate() == true)
{
return;
}
ForceAsyncWorkCompletion(ENSURE_AND_STALL);
check(GetWorld());
UE_LOG(LogParticles,Verbose,
TEXT("InitParticles @ %fs %s"), GetWorld()->TimeSeconds,
Template != NULL ? *Template->GetName() : TEXT("NULL"));
if (Template != NULL)
{
WarmupTime = Template->WarmupTime;
WarmupTickRate = Template->WarmupTickRate;
bIsViewRelevanceDirty = true;
const int32 GlobalDetailMode = GetCurrentDetailMode();
const bool bCanEverRender = CanEverRender();
//simplified version.
int32 NumInstances = EmitterInstances.Num();
int32 NumEmitters = Template->Emitters.Num();
const bool bIsFirstCreate = NumInstances == 0;
EmitterInstances.SetNumZeroed(NumEmitters);
bWasCompleted = bIsFirstCreate ? false : bWasCompleted;
bool bClearDynamicData = false;
int32 PreferredLODLevel = LODLevel;
bool bSetLodLevels = LODLevel > 0; //We should set the lod level even when creating all emitters if the requested LOD is not 0.
for (int32 Idx = 0; Idx < NumEmitters; Idx++)
{
UParticleEmitter* Emitter = Template->Emitters[Idx];
if (Emitter)
{
FParticleEmitterInstance* Instance = NumInstances == 0 ? NULL : EmitterInstances[Idx];
check(GlobalDetailMode < NUM_DETAILMODE_FLAGS);
const bool bDetailModeAllowsRendering = DetailMode <= GlobalDetailMode && (Emitter->DetailModeBitmask & (1 << GlobalDetailMode));
const bool bShouldCreateAndOrInit = bDetailModeAllowsRendering && Emitter->HasAnyEnabledLODs() && bCanEverRender;
if (bShouldCreateAndOrInit)
{
if (Instance)
{
Instance->SetHaltSpawning(false);
Instance->SetHaltSpawningExternal(false);
}
else
{
Instance = Emitter->CreateInstance(this);
EmitterInstances[Idx] = Instance;
}
if (Instance)
{
Instance->bEnabled = true;
Instance->InitParameters(Emitter, this);
Instance->Init();
PreferredLODLevel = FMath::Min(PreferredLODLevel, Emitter->LODLevels.Num());
bSetLodLevels |= !bIsFirstCreate;//Only set lod levels if we init any instances and it's not the first creation time.
}
}
else
{
if (Instance)
{
#if STATS
Instance->PreDestructorCall();
#endif
delete Instance;
EmitterInstances[Idx] = NULL;
bClearDynamicData = true;
}
}
}
}
if (bClearDynamicData)
{
ClearDynamicData();
}
if (bSetLodLevels)
{
if (PreferredLODLevel != LODLevel)
{
// This should never be higher...
check(PreferredLODLevel < LODLevel);
LODLevel = PreferredLODLevel;
}
for (int32 Idx = 0; Idx < EmitterInstances.Num(); Idx++)
{
FParticleEmitterInstance* Instance = EmitterInstances[Idx];
// set the LOD levels here
if (Instance)
{
Instance->CurrentLODLevelIndex = LODLevel;
// small safety net for OR-11322; can be removed if the ensure never fires after the change in SetTemplate (reset all instances LOD indices to 0)
if (Instance->CurrentLODLevelIndex >= Instance->SpriteTemplate->LODLevels.Num())
{
Instance->CurrentLODLevelIndex = Instance->SpriteTemplate->LODLevels.Num()-1;
ensureMsgf(false, TEXT("LOD access out of bounds (OR-11322). Please let olaf.piesche or simon.tovey know."));
}
Instance->CurrentLODLevel = Instance->SpriteTemplate->LODLevels[Instance->CurrentLODLevelIndex];
}
}
}
}
}
上述代码中,正真初始化EmitterInstances的值,见截图
而要执行上述截图代码,需要
bShouldCreateAndOrInit这个值为true;而这个条件的重点是bCanEverRender(记录能否渲染的值),而该值是由CanEverRender返回;
再看一段CanEverRender的源码
bool USceneComponent::CanEverRender() const
{
AActor* Owner = GetOwner();
if (Owner)
{
if (UChildActorComponent* ParentComponent = Owner->GetParentComponent())
{
if (!ParentComponent->CanEverRender())
{
return false;
}
}
}
const bool bShowInEditor =
#if WITH_EDITOR
GIsEditor ? (!Owner || !Owner->IsHiddenEd()) : false;
#else
false;
#endif
UWorld *World = GetWorld();
const bool bInGameWorld = World && World->UsesGameHiddenFlags();
const bool bShowInGame = (!Owner || !Owner->IsHidden());
return ((bInGameWorld && bShowInGame) || (!bInGameWorld && bShowInEditor));
}
发现关键的代码是const bool bShowInGame = (!Owner || !Owner->IsHidden());
,所以要想CanEverRender返回为true,必须确保组件所属的actor必须是在游戏中是显示的
- 总结:不管是用蓝图还是C++创建特效时,必须确保组件所属的actor必须是在游戏中是显示的,否则,初始化粒子效果,将不会显示