Projectile spawned inside of a mesh won't collide!

Hello.

I have a Shooting System where the Projectile (rocket, grenade, etc…) spawns right where the Socket Location is.

In my case, my Character has this Socket Location for spawning projectiles:

0efa78632846ddbe84dc53c8693e809668cd1e25.jpeg

The problem comes out when the Player is in front of a wall, like in this case:

497330184c87275ad528cec5285a6c51f602636b.jpeg

You see that white character over there? When I shoot a rocket in that position, the rocket spawns **INSIDE **the wall and… it doesn’t explode!

Of course the Projectile items already have their Collision properties set up, and it works properly in “normal” cases.

But in this case, how can I overcome to this issue?

This is the code I use to spawn projectiles:



void AWeapon_Projectile::FireWeapon()
{
	FVector SocketLocation = MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket")));
	FVector SocketRotation = MyOwner->GetMesh()->GetSocketRotation((FName("WeaponSocket"))).Vector();
	FVector CameraLoc;
	FRotator CameraRot;
	MyOwner->GetActorEyesViewPoint(CameraLoc, CameraRot);

	FVector Origin = SocketLocation;
	FVector ShootDir = CameraRot.Vector();

	// trace from camera to check what's under crosshair
	const float ProjectileAdjustRange = 10000.0f;
	const FVector StartTrace = GetCameraDamageStartLocation(ShootDir);
	const FVector EndTrace = StartTrace + (ShootDir * ProjectileAdjustRange);
	FHitResult Impact = WeaponTrace(StartTrace, EndTrace);

	// and adjust directions to hit that actor
	if (Impact.bBlockingHit)
	{
		const FVector AdjustedDir = (Impact.ImpactPoint - Origin).GetSafeNormal();
		bool bWeaponPenetration = false;

		const float DirectionDot = FVector::DotProduct(AdjustedDir, ShootDir);
		if (DirectionDot < 0.0f)
		{
			// shooting backwards = weapon is penetrating
			bWeaponPenetration = true;
		}

		else if (DirectionDot < 0.5f)
		{
			// check for weapon penetration if angle difference is big enough
			// raycast along weapon mesh to check if there's blocking hit

			FVector MuzzleStartTrace = Origin - SocketRotation * 150.0f;
			FVector MuzzleEndTrace = Origin;
			FHitResult MuzzleImpact = WeaponTrace(MuzzleStartTrace, MuzzleEndTrace);

			if (MuzzleImpact.bBlockingHit)
			{
				bWeaponPenetration = true;
			}
		}

		if (bWeaponPenetration)
		{
			// spawn at crosshair position
			Origin = Impact.ImpactPoint - ShootDir * 10.0f;
		}
		else
		{
			// adjust direction to hit
			ShootDir = AdjustedDir;
		}
	}


	ServerFireProjectile(Origin, ShootDir);
}


I can say from experience that a collision shape that is spawned inside another collision shape does fire an OnOverlapBegin event. But the event may fire before you’re done initializing your projectile, for example if you bind a function to OnComponentBeginOverlap in the projectile actor’s BeginPlay, the event has already happened and your function won’t be called. If there is anything collision related that you do inside the projectile’s BeginPlay, try doing that earlier by using deferred actor spawning (spawn the actor deferred, setup collision, then finish spawning the actor). When you spawn the actor deferred, the actor is only registered to the world the moment you call FinishSpawning on the actor, thus then the OnBeginOverlap event happens.

Alternatively if you are binding a function to OnBeginOverlap, try disabling and re-enabling the collision, as a way to force OnBeginOverlaps to be redetected.

Hi and thanks for the reply.

My projectiles have a MovementComponent. Thus, I use the OnProjectileStop.AddDynamic() delegate.

But, actually, you suggested me this

So I created a new function called OnOverlap() and I bound a OnComponentBeginOverlap.AddDynamic() delegate to my CollisionComponent (whereas the previous delegate was bound to the MovementComponent).



/* .h  */

UFUNCTION()
void OnOverlap(class UPrimitiveComponent* OtherComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp2, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);


/* .cpp  */

// Inside the AProjectile constructor
CollisionComp->OnComponentBeginOverlap.AddDynamic(this, &AProjectile::OnOverlap);

// The function that the delegate is supposed to call
void AProjectile::OnOverlap(class UPrimitiveComponent* OtherComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp2, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("Projectile :: OnOverlap()")));
	OnImpact(FHitResult());
}


And these are the collision settings for my Projectile

eee.jpg

As you can see, **WorldStatic **objects are set to be Blocked.

This way, that object will instigate the ProjectileStop event

I already tried switching that from Block to Overlap (so that it could instigate the OnComponentOverlapBegin event)…

But… guess what… nothing happens (except that my **ProjectileStop **event is not fired anymore since I disabled the “Block” option for this experiment)

Object is hollow inside, in order for Overlap and Hit events to be fired, object must collide, see Collision Overview | Unreal Engine Documentation.

Yeah, and that’s the problem!

How can I overcome to this issue?

One naive solution would be to modify the WeaponSocket moving it closer to the Character… but… that’s not exactly what I want.

It really depends on your requirements. You could check if there’s anything between character and the weapon socket, if there is an obstruction, you could block ability to fire, play different animation, etc.

I tried to take a look at the ShooterGame example, but after some long hours, I have no idea where my problem is, nor how I can come up with a working solution.

I have never seen the structure of a FPS. Maybe my **WeaponSocket **is too far from the Character? Maybe I should put it closer? Or I should leave it where it is and do something else?

I tend to keep my WeaponSocket far from the Character because it happens that when I jump+forward, I collide with the projectile… and of course it mustn’t happen

UP - still

There are no naive solutions in game development, only solutions :wink:

The way that we handled this issue in our project was to check for existing overlaps after creating the projectile.

In our projectile class, post spawn we use the following code:



bool AProjectile::CheckForExistingOverlaps()
{
        TArray<AActor*> Actors;
	ColliderComponent->GetOverlappingActors(Actors);

	for (AActor* Actor : Actors)
	{
		if (Actor && Actor->IsValidLowLevel())
		{
                        // this is where we check if the actor hit is a valid hit, etc..
			if (HitActor(Actor, GetActorLocation()))
			{
				return true;
			}
		}
	}

        return false;
}

Hopefully this helps solve your issue.

Hi. Thanks for the reply. This is the code I wrote taking a leaf out of yours:



AProjectile* Projectile = Cast<AProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ProjectileClass, SpawnTM));
	
if (Projectile)
{		

	Projectile->Instigator = Instigator;
	Projectile->SetOwner(this);
	Projectile->InitVelocity(ShootDir);		// here we set the direction of our projectile

	UGameplayStatics::FinishSpawningActor(Projectile, SpawnTM);
}

TArray<AActor*> Actors;
Projectile->getCollisionComponent()->GetOverlappingActors(Actors);

if (Actors.Num() > 0)
{
	if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Something is overlapping the Projectile!")));
	Projectile->OnImpact(FHitResult());
}


Unfortunately, the GEngine DebugMessage is never printed.

The rocket either spawns correctly (without anything that overlaps it) or it spawns **INSIDE **a mesh (and maybe, since it spawns inside it’s unable to detect the collision).

I can’t find a real solution to this.

If someone who coded the ShooterGame can help me, I would appreciate! I’m following their coding pattern for my game

hello

I just had an idea but I am not sure if it will work because I haven’t tested. What you could do is add a trace at the spawn of your projectile.
The start position of your trace should be :
x: the x position of the pawn (the owner of the gun)
y: the y position of the pawn (the owner of the gun)
z: the z socket world position

The end position of the trace is simply the position at which the projectile is spawned in world coordinate.

Then if there is an object returned in this trace, it means that there was an object between the pawn and the weapon socket.
You could call a function that have the same logic as your projectile hit event.

I am sorry I am not able to provide example but this might help you.

THIS helped solving my problem.

Thank you very much.

The solution was brilliant and, at the same time, very easy and I’m shocked I didn’t come up with this before.

… ]

At spawn time, I performed a LineTrace from the Character position to the Projectile position that ignored the Character and the Projectile themselves.

Glad I was able to help :slight_smile: