UProjectileMovementComponent::HandleHitWall is not virtual

I have used HandleImpact in my derived class to allow our projectile to penetrate objects. I noticed in the UProjectileMovementComponent::TickComponent() function that it calls HandleHitWall() (which in turn calls HandleImpact that is virtual and I overridden it). Right after calling HandleHitWall() the TickComponent() then tries to slide the projectile across the wall (hence messing up my velocity settings to allow for penetration). I am not able to override HandleHitWall to return true to avoid this function from modifying our velocity. Please make HandleHitWall virtual.

Here is the header file:

protected:

	/** @return true if the simulation should stop. */
	bool HandleHitWall(const FHitResult& Hit, float TimeTick, const FVector& MoveDelta);

	/** Applies bounce logic (if enabled) to affect velocity upon impact, or stops the projectile if bounces are not enabled (or velocity is below threshold). Fires applicable events. */
	virtual void HandleImpact(const FHitResult& Hit, float TimeSlice=0.f, const FVector& MoveDelta = FVector::ZeroVector) override;

In the TickComponent() function:

		if (HandleHitWall(Hit, TimeTick, MoveDelta))
		{
			break;
		}
		...
		if (bIsSliding)
		{
			...
			else 
			{
				//adjust to move along new wall
				Velocity = ComputeSlideVector(Velocity, 1.f, Normal, Hit);
			}

If this is not the correct way to allow projectiles to penetrate objects then what is the correct way to allow penetration?

Overriding these functions will circumvent not having virtual on the HandleHitWall() function.
.h file:

	//UMovementComponent overrides - prevent messing with our penetration logic
	virtual FVector ComputeSlideVector(const FVector& Delta, const float Time, const FVector& Normal, const FHitResult& Hit) const override;

protected:
	//UProjectileMovementComponent overrides - prevent messing with our penetration logic
	virtual bool HandleSliding(FHitResult& Hit, float& SubTickTimeRemaining) override;

cpp file:

FVector UDragProjectileMovementComponent::ComputeSlideVector(const FVector& Delta, const float Time, const FVector& Normal, const FHitResult& Hit) const
{
	//Override this function because it messes with our penetration logic
	return Velocity;
}

bool UDragProjectileMovementComponent::HandleSliding(FHitResult& Hit, float& SubTickTimeRemaining)
{
	//Override this function because it messes with our penetration logic
	return false;
}

Hey Kory-

It sounds as though you were able to find a solution to the problem you were having. Since you point out the call to HandleImpact() from HandleHitWall(), another solution you could use would be to modify the source code to explictly call your overridden HandleImpact() function. Best of luck in your project with whichever solution you chose to go with.

Cheers

Doug Wilson

Sorry Doug, this was not a solution but a work-around rather. I would prefer that function be made virtual so we can override it the right way. Please put in a ticket to make that function virtual and we will fix our code once that is done.
Thanks,
Kory

Hey Kory-

A feature request for HandleHitWall() to be made virtual has been entered (UE-10106) for consideration.

Awesome, thanks Doug! (:

Hi Kory, I’m looking at the request to make HandleHitWall() virtual.

The more I look at that function the more I just want to remove it, or leave it non-virtual. Really all it’s doing is checking that the actor/component remains valid, and calls HandleImpact(). I think that the actor validity checks should occur outside a virtual because they always need to happen and users shouldn’t be able to accidentally remove those. I could move them to the tick/update loop if the function were removed.

In any case, I would like more background about what your virtual HandleHitWall() would look like so I can make sure you can still do what you want. As far as I can tell you would just be overriding the return value which will make the tick update stop.

			if (HandleHitWall(Hit, TimeTick, MoveDelta))
			{
				break;
			}

Maybe we need a different check during the update loop, or allow HandleHitWall to return an enum indicating that updates should stop, continue with deflection, or continue to the next loop update.

Thanks,
-Zak

If I remember correctly, I think it was to to get out of the Tick loop because the function calls later were messing up my custom terminal ballistics code. So I think having a way of returning early out of the Tick function would work for us and others. Basically, if I remember correctly, it was changing my velocity after I had already set it. I just wanted to handle the rest of the movement myself and exit out of the parent’s Tick function. So an enum would make sense.
Thanks Zak,
Kory

So what I’ve come up with to address this is the following (apologies if the formatting gets a bit screwy, I’ll add a screenshot of the code which is probably more readable):

Replaced HandleHitWall() with virtual HandleBlockingHit() that returns an enum:

	// Enum indicating how simulation should proceed after HandleBlockingHit() is called.
	enum class EHandleBlockingHitResult
	{
		// Assume velocity has been deflected, and trigger HandleDeflection().
		// This is the default return value of HandleBlockingHit().
		Deflect,
		// Advance to the next simulation update. Typically used when additional slide/multi-bounce logic can be ignored,
		// such as when an object that blocked the projectile is destroyed and movement should continue.
		AdvanceNextSubstep,
		// Abort all further simulation. Typically used when components have been invalidated or simulation stops.
		Abort,
	};

Added new virtual HandleDeflection() which wraps up all the old code that adjusted velocity in multi-bounce situations and handled logic deciding whether to call HandleSliding() with new velocity.

I think this should allow easier overrides to have “blocking hits” that allow the projectile to simply pass through-- you would override HandleBlockingHit to return “AdvanceNextSubstep” and be good to go.

Let me know if that makes sense and fits your needs. I think this will be useful in a lot of scenarios.

Yes, I think that would be very useful in a lot of scenarios as well. What I ended up doing for us was just creating my own projectile movement class, maybe now I can go back to the engine version with this addition.
Thanks so much,
Kory