2024-05-12
깃허브! |
---|
https://github.com/ChangJin-Lee/ARproject |
★ https://github.com/ChangJin-Lee/SimpleShooter |
느낀점
SpawnEmitterAttached로 특정 Socket 위치에 파티클 이펙트를 실행하도록 만들어 보았다.
스켈레탈 메시에 무기, 이펙트 등에 대한 접점으로 사용할 수 있는 위치입니다.
스켈레탈 메시에서 본에 오브젝트를 어태치할 때 이 어태치먼트를 오프셋해야 하는 경우가 있습니다. 수학 연산을 사용하여 오프셋 트랜스폼을 추정하는 대신 소켓 을 생성할 수 있습니다. 소켓은 스켈레톤 계층구조 내의 전용 어태치 포인트로, 부모로 지정된 본에 상대적으로 트랜스폼할 수 있습니다. 구성한 후에는 오브젝트, 무기 및 기타 액터를 소켓에 어태치할 수 있습니다.
UParticleSystemComponent* UGameplayStatics::SpawnEmitterAtLocation(const UObject* WorldContextObject, UParticleSystem* EmitterTemplate, FVector SpawnLocation, FRotator SpawnRotation, FVector SpawnScale, bool bAutoDestroy, EPSCPoolMethod PoolingMethod, bool bAutoActivateSystem)
{
UParticleSystemComponent* PSC = nullptr;
if (EmitterTemplate)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
PSC = InternalSpawnEmitterAtLocation(World, EmitterTemplate, SpawnLocation, SpawnRotation, SpawnScale, bAutoDestroy, PoolingMethod, bAutoActivateSystem);
}
}
return PSC;
}
UParticleSystemComponent* UGameplayStatics::SpawnEmitterAttached(UParticleSystem* EmitterTemplate, USceneComponent* AttachToComponent, FName AttachPointName, FVector Location, FRotator Rotation, FVector Scale, EAttachLocation::Type LocationType, bool bAutoDestroy, EPSCPoolMethod PoolingMethod, bool bAutoActivateSystem)
{
UParticleSystemComponent* PSC = nullptr;
if (EmitterTemplate)
{
if (AttachToComponent == nullptr)
{
UE_LOG(LogScript, Warning, TEXT("UGameplayStatics::SpawnEmitterAttached: NULL AttachComponent specified!"));
}
else
{
UWorld* const World = AttachToComponent->GetWorld();
if (World && !World->IsNetMode(NM_DedicatedServer))
{
PSC = CreateParticleSystem(EmitterTemplate, World, AttachToComponent->GetOwner(), bAutoDestroy, PoolingMethod);
if (PSC != nullptr)
{
PSC->SetupAttachment(AttachToComponent, AttachPointName);
if (LocationType == EAttachLocation::KeepWorldPosition)
{
const FTransform ParentToWorld = AttachToComponent->GetSocketTransform(AttachPointName);
const FTransform ComponentToWorld(Rotation, Location, Scale);
const FTransform RelativeTM = ComponentToWorld.GetRelativeTransform(ParentToWorld);
PSC->SetRelativeLocation_Direct(RelativeTM.GetLocation());
PSC->SetRelativeRotation_Direct(RelativeTM.GetRotation().Rotator());
PSC->SetRelativeScale3D_Direct(RelativeTM.GetScale3D());
}
else
{
PSC->SetRelativeLocation_Direct(Location);
PSC->SetRelativeRotation_Direct(Rotation);
if (LocationType == EAttachLocation::SnapToTarget)
{
// SnapToTarget indicates we "keep world scale", this indicates we we want the inverse of the parent-to-world scale
// to calculate world scale at Scale 1, and then apply the passed in Scale
const FTransform ParentToWorld = AttachToComponent->GetSocketTransform(AttachPointName);
PSC->SetRelativeScale3D_Direct(Scale * ParentToWorld.GetSafeScaleReciprocal(ParentToWorld.GetScale3D()));
}
else
{
PSC->SetRelativeScale3D_Direct(Scale);
}
}
PSC->RegisterComponentWithWorld(World);
if(bAutoActivateSystem)
{
PSC->ActivateSystem(true);
}
// Notify the texture streamer so that PSC gets managed as a dynamic component.
IStreamingManager::Get().NotifyPrimitiveUpdated(PSC);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (PSC->Template && PSC->Template->IsImmortal())
{
const FString OnScreenMessage = FString::Printf(TEXT("SpawnEmitterAttached spawned potentially immortal particle system! %s (%s) may stay in world despite never spawning particles after burst spawning is over."), *(PSC->GetPathName()), *(PSC->Template->GetName()));
GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)AttachToComponent), 3.f, FColor::Red, OnScreenMessage);
UE_LOG(LogParticles, Log, TEXT("GameplayStatics::SpawnEmitterAttached spawned potentially immortal particle system! %s (%s) may stay in world despite never spawning particles after burst spawning is over."),
*(PSC->GetPathName()), *(PSC->Template->GetPathName())
);
}
#endif
}
}
}
}
return PSC;
}