Why can’t the collision event of my projectiles be triggered on the client side in a multiplayer game after I changed the way of generating projectiles from direct spawning to using an object pool? Did I do something wrong in one of the steps? I’m seeking an answer.
This was my original approach. I directly spawned the projectile class through GetWorld()->SpawnActor. The projectiles generated in this way could normally detect collisions on both the listening server and the client.
Later, I switched to using a dynamic object pool, and the code is as follows.
I noticed that after the modification, I couldn’t trigger the ASProjectileBase::OnComponentHit event on the client side. However, it can be triggered normally on the listening server. Why is this the case? I can’t figure it out no matter how hard I think about it. I’m looking forward to getting an answer.
The following is the complete code of the ASProjectileBase class. If you need any other code, please let me know.
ASProjectileBase::ASProjectileBase()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
m_SphereCom = CreateDefaultSubobject<USphereComponent>("SphereCom");
m_SphereCom->OnComponentHit.AddDynamic(this, &ASProjectileBase::OnComponentHit);
m_SphereCom->SetCollisionProfileName("Projectile");
RootComponent = m_SphereCom;
m_ParticleSysCom = CreateDefaultSubobject<UParticleSystemComponent>("ParticleSystemCom");
m_ParticleSysCom->SetupAttachment(m_SphereCom);
m_AudioComp = CreateDefaultSubobject<UAudioComponent>("AudioComp");
m_AudioComp->SetupAttachment(RootComponent);
m_PjMoveCom = CreateDefaultSubobject<UProjectileMovementComponent>("ProjecMoveCom");
m_PjMoveCom->bRotationFollowsVelocity = true;
m_PjMoveCom->bInitialVelocityInLocalSpace = true;
m_PjMoveCom->ProjectileGravityScale = 0.0f;
m_PjMoveCom->InitialSpeed = 0.0f;
bReplicates = true;
SetReplicateMovement(true);
}
// Called when the game starts or when spawned
void ASProjectileBase::BeginPlay()
{
Super::BeginPlay();
SetIsUse(false);
}
void ASProjectileBase::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
Explode_Implementation();
}
void ASProjectileBase::Explode_Implementation()
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), m_EmittParticle, GetActorTransform());
UGameplayStatics::PlaySoundAtLocation(this, m_ImpactSound, GetActorLocation());
UGameplayStatics::PlayWorldCameraShake(this,m_ImpactShake, GetActorLocation(), m_ImpactShakeInnerRadius, m_ImpactShakeOuterRadius);
}
void ASProjectileBase::OnRep_Used()
{
SetActorEnableCollision(m_bUsed);
SetActorHiddenInGame(!m_bUsed);
SetActorTickEnabled(m_bUsed);
if (m_ParticleSysCom) {
m_ParticleSysCom->SetActive(m_bUsed);
}
if (m_bUsed) {
GetWorldTimerManager().ClearTimer(m_HideTimeHandle);
GetWorldTimerManager().SetTimer(m_HideTimeHandle, this, &ASProjectileBase::HideSelf, m_AliveTime);
}
}
void ASProjectileBase::PostInitializeComponents()
{
Super::PostInitializeComponents();
}
void ASProjectileBase::HideSelf()
{
SetIsUse(false);
}
// Called every frame
void ASProjectileBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ASProjectileBase::SetIsUse(bool bUse)
{
LogOnScreen(GetWorld(), FString::Printf(TEXT("SetIsUse: %d"), bUse));
if (HasAuthority()) {
m_bUsed = bUse;
OnRep_Used();
}
}
bool ASProjectileBase::IsUsed() const
{
return m_bUsed;
}
void ASProjectileBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ASProjectileBase, m_bUsed);
}