Hi
For the past couple of days I’ve been trying to make the destructibles work, and it seems that the system is either severely bugged, or I’m doing something drastically wrong.
I looked for some tutorials etc, but found nothing.
So I’m starting this thread in hope of getting some answers and establishing some ground knowledge on the subject.
My use case is very simple - I have a character wielding a shotgun, a powerful one at that, and I want to be able to wreak some havoc around.
Step 1
At first I tried to create a simple destructible box and have it break after applying some force to it.
So I selected one of the sample shapes - a box, right clicked on it in the content browser, and selected “Create Destructible Mesh”.
In the destructible editor, I clicked on the ‘Fracture’ button - not sure if it’s needed, but did it anyway.
Then I placed it on the level, a little above the ground.
Had to change the settings on the instance in order to get it to be simulated by physics and respond to collisions, but in the end the box started behaving as a regular, collidable static mesh - so far so good.
Step 2
I want to apply the simplest force to the object, just make it flip over and break or anything - no C++ code yet.
So I found a “RadialForceActor” class, which offered just what I was looking for - an ability to apply a force impulse and a damage to the destructibles.
I made sure that my destructible is withing the range of the force emitter, set the falloff of the later to ‘Rif_Constant’, and ran the simulation.
Nothing happened.
I tried moving the box above the ground to see if it’s still falling down - that still worked, but the emitter had no effect on the simulation whatsoever.
I tried what effect the “RadialForceActor” will have on a regular static mesh box ( with all physics simulation settings enabled ) - NONE WHATSOEVER.
Step 3
I took a sneak peek under the hood of how the RadialForceActor is implemented - it runs a query, and applies damage and a force impulse to the components it stumbles upon within its radius of influence.
So I tried creating a very simple piece of code that would test what components get turned up by a similar query:
TArray<struct FHitResult> outHits;
{
const float Range = 300.0f;
FVector shotDir = shooter->GetActorForwardVector();
FVector start = shooter->GetActorLocation() + shotDir * 200.0f;
FVector end = start + shotDir * Range;
FCollisionQueryParams params;
FCollisionShape collisionShape;
collisionShape.SetSphere( 100.0f );
GetWorld()->SweepMulti( outHits, start, end, FQuat::Identity, ECC_WorldDynamic, collisionShape, params );
}
It found hits with static and skeletal components, but not the DestructibleComponent ( even though it was using the same collision group as the rest of my test objects ).
Step 4
My last attempt was to try how it work when spawned from a blueprint.
So I created one based on an Actor class ( I saw that there’s a DestructibleActor class available, I’ll get to that in a sec ). I added a DestructibleComponent to it, set my shape in it, and placed it on the level.
The exact same thing happen - I wasn’t able to query the component using the cast pasted above. But this time the collision settings I made on the destructible component had no effect either - I could walk through the object.
Step 5
I got a bit desperate and started looking for anything that would work.
My suspicion was that perhaps I’m not using the Sweep correctly. So I tried a bit different approach. I created a custom Actor based class that creates a static mesh component and uses it to query for overlapping objects.
Here’s the code:
.H
/**
* A base class for all shotgun-like weapons
*/
UCLASS()
class AHatredBaseShotgun : public AActor
{
GENERATED_UCLASS_BODY()
public:
// The mesh of the weapon
UPROPERTY( VisibleDefaultsOnly, Category = Mesh )
TSubobjectPtr<USkeletalMeshComponent> ShotgunMesh;
/**
* Fires the weapon.
*
* @param shooter actor shooting the gun
* @param target an actor we're shooting at
*/
void Fire( AActor* shooter, AActor* target );
};
.CPP
AHatredBaseShotgun::AHatredBaseShotgun(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
, Damage( 100.0f )
, ImpulseStrength( 100.0f )
{
// shotgun visual mesh
{
ShotgunMesh = PCIP.CreateDefaultSubobject<USkeletalMeshComponent>( this, TEXT( "Mesh" ) );
RootComponent = ShotgunMesh;
}
}
void AHatredBaseShotgun::Fire( AActor* shooter, AActor* target )
{
// place the damage origin between the shooter and the target, so that it appears
// the targets gets blown away by the force impulse ( a hack until they implement a linear force impulse )
FVector origin = target->GetActorLocation();
FVector impulseDir = origin - shooter->GetActorLocation();
impulseDir.SafeNormal2D();
// randomize the hit height a bit
{
FVector boundsOrigin, boxExtent;
target->GetActorBounds( true, boundsOrigin, boxExtent );
float randVal = ( float ) FMath::Rand() / ( float ) RAND_MAX - 0.5f;
origin.Z = boundsOrigin.Z + randVal * boxExtent.Z;
}
TArray< UPrimitiveComponent* > components;
target->GetComponents( components );
// Iterate over each and apply an impulse
const int16 count = components.Num();
for ( int16 i = 0; i < count; ++i )
{
UPrimitiveComponent* pokeComp = components*;
if ( pokeComp )
{
// If DestructibleDamage is non-zero, see if this is a destructible, and do damage if so.
if ( Damage > SMALL_NUMBER )
{
UDestructibleComponent* destructibleComp = Cast<UDestructibleComponent>( pokeComp );
if ( destructibleComp != NULL )
{
destructibleComp->ApplyDamage( Damage, origin, impulseDir, ImpulseStrength );
}
}
// Do impulse after
pokeComp->AddImpulseAtLocation( impulseDir* ImpulseStrength, origin );
}
}
// also - apply damage to the actor
FDamageEvent damageEvent( DamageTypeClass );
target->TakeDamage( Damage, damageEvent, shooter->GetInstigatorController(), shooter );
}
‘Fire’ method is called from my custom Character class.
Surprisingly, this method managed to turn up overlaps with the Destructibles, even though I didn’t change the setup one bit!
But another problem arose - all objects seemed to ‘explode’ from within. No measure of force or damage applied, no matter the application method I called ( AddImpulse, AddImpulseAtLocation, AddForce, ApplyDamage, ApplyRadialDamage… ) seemed to change that.
I soon noticed that this behavior gets even worse when the placed prefab is scaled. The larger the scale of an object, the less predictable the physics was.
Step 6
Finally, I tried the DestructibleActor class - just for the sake of trying all available options.
Even though the class doesn’t have any code that would suggest it handling collision and damage in any way - it only provides a setup for a destructible component etc, the behavior I got from it was drastically different to the blueprints based off a simple Actor.
Even though the ‘explosions’ looked exactly the same, they seemed to be ‘toned down’ a notch ( not exploding so violently when the same amount of force and Damage was applied ).
I could notice that just by changing the base class of the component and then fixing the settings of the attached DestructibleComponent.
I guess the next step will be to actually debug how the engine executes those queries, but since that will be time consuming, and I’m, really looking for an easy way out here, I thought I’ll just ask.
So to those of you who made it through this long description - thank you, and could you please help me understand what am I ( or the engine ) doing wrong?
This feature is very important to the project I’m currently working on, and I need to know if the system is flawed, or is it just my lack of knowledge how to set things up that’s to blame.
I would also appreciate links to any available tutorials on the subject.
Cheers,