Download

Falldamage problem C++

Hi,

I’m currently trying to do falldamage with C++.
I have already created it with Blueprint but now I have a Problem with getting the Players “is falling” bool.
I’m new to programming and didn’t find anything about it in the internet.

Therefor I already tried:

if (GetCharacterMovement()->IsFalling)

and

if (&UCharacterMovementComponent::IsFalling)

But non of those worked.
Could you please tell me how to do it correctly?

if (GetCharacterMovement()->MovementMode == EMovementMode::MOVE_Falling)
{
    //do stuff
}

Thanks,
it worked :smiley:

You had the right mindset, you could have just simply done:

GetCharacterMovement()->IsFalling();

just missed the parenthesis.

Checking the movement component work fine if you just care about giving some set amount of damage on falling. You could also calculate based on the change in velocity if you wanted something more fine-grained. In my current game, gravity is not consistent. The same fall on the surface of Mars (gravity .38g) or on Earth (1g) need to yield different amounts of damage, so I wanted a solution based on change of velocity.

In the header.h:



//////////////////////////////////////////////////////////////////////////
// Damage
	
	/** Identifies this character should take damage if falling */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Movement|Falling")
	bool bCanTakeFallDamage;
	
	/** This is the maximum change in velocity that a character can experience
	 *	without taking damage. Defaults to 1000.
	 *
	 * _It's not the fall that kills you, it's the sudden stop at the end._
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Movement|Falling")
	float SafeFallVelocity;
	
	/** How much damage to deal to this character when the stop is greater than
	 *	SafeFallVelocity. The actually delta velocity minus SafeFallVelocity will 
	 *	multiplied by this value and then applied as damage. Defaults to .1;
	 **/
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Movement|Falling")
	float FallDamageMultiplier;

protected:
	FVector PreviousVelocity;


And in the implementation.cpp:



void ABaseNPCCharacter::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);
	
	if (!bCanTakeFallDamage) return;
	
	// We deal with some big numbers here to avoid using sqrtf() every tick
	
	FVector Velocity = GetCharacterMovement()->Velocity;
	FVector DeltaVelocitySquared = (Velocity - PreviousVelocity) * (Velocity - PreviousVelocity);
	float DeltaSpeed = DeltaVelocitySquared.X + DeltaVelocitySquared.Y + DeltaVelocitySquared.Z;
	
	if (DeltaSpeed > (SafeFallVelocity * SafeFallVelocity))
	{
		// In this case, we have a sudden stop, and one that's sudden enough to cause damage. This should be rare enough that we can afford a sqrtf()
		float Damage = sqrtf(DeltaSpeed) * FallDamageMultiplier;
		FDamageEvent DamageEvent;
		TakeDamage(Damage, DamageEvent, GetController(), this);
	}
	
	PreviousVelocity = Velocity;
}


Definitely room for improvements, but it provides a pretty good approximation of reality if configured properly. Here are my default values from the constructor:



ABaseNPCCharacter::ABaseNPCCharacter()
{
	PreviousVelocity = FVector(0.f, 0.f, 0.f);
	bCanTakeFallDamage = false;
	SafeFallVelocity = 1000.f;
	FallDamageMultiplier = .1f;
}


Hi Jeff,

thanks for sharing your solution.
Using the velocity for falldamage is a pretty awesome idea.

For now I will use another way because I’m not interested in doing everything physically correct:

I take the difference between the characters Z-position when he starts jumping and his Z-position when he hits the Ground.
Then I use it as a X-value in a linear funktion to apply damage: f(x) = a(x-b)

Code:


	if (GetCharacterMovement()->MovementMode == EMovementMode::MOVE_Falling && ! bFalling)  // bFalling is for checking if the character just started jumping
	{
		FallstartZposition = this->GetActorLocation().Z;  // Z-value for startposition
	}


	if (GetCharacterMovement()->MovementMode != EMovementMode::MOVE_Falling && bFalling)
	{
		FallendZposition = this->GetActorLocation().Z;  // Z-value for endposition

		if (0.2*(FallstartZposition - FallendZposition - (FallDamageResistenz * 800)) > 0)       // Check if value will be bigger than 0
		{
			HealthDecrease = HealthDecrease + ((0.2*(FallstartZposition - FallendZposition - (FallDamageResistenz * 800))) / 100 * MaxHealth);    // Damagefunction
		}

	}

	bFalling = GetCharacterMovement()->MovementMode == EMovementMode::MOVE_Falling;

I’m using “FallDamageResistenz” so I can controll the falldistance until the character gets damage.

It’s probably not perfect because I’m very new to programming but it works for me:D

What matters is that it feels right to the player. A fall distance check wouldn’t work for me because of the variable gravity we have in our game, but every game is different. If this gives the result that feels right for your game, then it’s perfect. :slight_smile: