Kamilen
Kamilen

Reputation: 35

Collisions detection with OnComponentHit UE4 C++

I have problem with collisions. I want to make simple projectile. I have made an Actor which has Root, Sphere and mesh components. When this actor hits target object nothing happens. I have tried many ways, also with

void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);


void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

functions, but without any results..

Here is constructor of my custom projectile:

AProjectile_2::AProjectile_2()
{
    // 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;

    Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
    RootComponent = Root;

    mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("staticMesh"));
    static ConstructorHelpers::FObjectFinder<UStaticMesh>SphereMeshAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
    if (SphereMeshAsset.Succeeded())
    {
        mesh->SetStaticMesh(SphereMeshAsset.Object);
        mesh->SetWorldScale3D(FVector(0.2f));
    }
    mesh->SetEnableGravity(true);
    mesh->SetSimulatePhysics(true);
    mesh->SetupAttachment(Root);

    Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
    Sphere->InitSphereRadius(5.f);
    Sphere->SetupAttachment(Root);

    Sphere->SetCollisionProfileName(TEXT("Target"));

    Sphere->OnComponentHit.AddDynamic(this, &AProjectile_2::OnHit);
    Sphere->SetupAttachment(RootComponent);

    InitialLifeSpan = 5.f;
}

Here is a detect function

void AProjectile_2::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
    if ((OtherActor != NULL) && (OtherActor != this) && (OtherComp != NULL))
    {
        if (OtherActor && (OtherActor != this) && OtherComp && OtherActor->GetClass()->IsChildOf(ADestroypack::StaticClass()))
        {
            destroypack = (ADestroypack*)OtherActor;
            destroypack->decreasehp(50);
            destroypack->check_hp();
            destroypack->showhp();
        }
    }
}

Here my mesh is getting force to move

void AProjectile_2::Initvel(FVector Velocity)
{
    mesh->AddForce(Velocity * 300);
}

And here is my character function to shoot with RMB button

void AHero::Attack_right()
{
    FVector Location = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
    FRotator Rotation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorRotation();

    GetActorEyesViewPoint(Location, Rotation);
    projectiles = (AProjectile_2*) GetWorld()->SpawnActor(AProjectile_2::StaticClass(), &Location, &Rotation);
    FVector LaunchDir;
    LaunchDir = GetActorForwardVector() * 5000.f;
    projectiles->Initvel(LaunchDir);
}

If someone could say what am i doing wrong, or what is missing in my project i will be grateful.

OK! I have figure it out! :D I made a mistake adding Gravity and Physics to mesh and Sphere. I've deleted it from mesh, and it works now :)

AProjectile_2::AProjectile_2()
{
    // 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;

    //Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
    //RootComponent = Root;

    Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
    Sphere->SetSimulatePhysics(true);
    Sphere->SetEnableGravity(true);
    Sphere->SetNotifyRigidBodyCollision(true);
    Sphere->InitSphereRadius(40.f);
    Sphere->BodyInstance.SetCollisionProfileName("BlockAllDynamic");
    Sphere->SetCollisionProfileName(TEXT("Target"));
    Sphere->OnComponentHit.AddDynamic(this, &AProjectile_2::OnHit);
    RootComponent = Sphere;

    mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("staticMesh"));
    static ConstructorHelpers::FObjectFinder<UStaticMesh>SphereMeshAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
    if (SphereMeshAsset.Succeeded())
    {
        mesh->SetStaticMesh(SphereMeshAsset.Object);
        mesh->AddRelativeLocation(FVector(0.f, 0.f, 0.f));
        mesh->SetWorldScale3D(FVector(0.2f));
    }
    /*mesh->SetEnableGravity(true);
    mesh->SetSimulatePhysics(true);
    mesh->SetGenerateOverlapEvents(true);*/
    mesh->SetupAttachment(RootComponent);

    InitialLifeSpan = 5.f;
}

Upvotes: 2

Views: 18704

Answers (2)

Chris Gong
Chris Gong

Reputation: 8229

You should add the dynamic delegate in the BeginPlay function. The rest of the code in relation to the setup of the Sphere Component can stay in the constructor. The reason for this is that in Unreal, if you made the blueprint first, parent it to your projectile cpp class but then later added the OnComponentHit functionality declared in the constructor, it won't work. It will only work in the constructor if the blueprint was made with the cpp class, including the OnComponentHit delegate, from the very beginning. This is a very common issue that goes unnoticed often times.

Make sure to add the BeginPlay function to your header file if you haven't done so,

virtual void BeginPlay() override;

Then in your cpp file, declare the function and move your call to AddDynamic from the constructor to BeginPlay,

void AProjectile_2::BeginPlay()
{
    Super::BeginPlay();
    Sphere->OnComponentHit.AddDynamic(this, &AProjectile_2::OnHit);
}

Upvotes: 5

Israel dela Cruz
Israel dela Cruz

Reputation: 806

If you are using OnOverlapBegin, your components should be using Overlap for collision response against other components, rather than Block.

Upvotes: 0

Related Questions