Damage text on hit - Best practice ?

What method of showing such text will be the best for mobile in terms of performance ?

Tower defense game, static camera

Text will be spawned once (in one frame, most likely after a”do once” node, inside an event timer that shoots 45 times per second. In that one frame it will be turn on \ off every time the an enemy is hit. i will set visible on once hitting and change its text in one frame .

I hope to be able to get away (performance - wise) with some minor movement animation after setting the text visible (but i can give up on that if it will add a lot of overhead)

Is it cheaper to use the widget component in the enemy blueprint, or a text mesh plug-in or just 3d text mesh component on the enemy blueprint ?

-Max enemies on screen : 25

  • Average polycount per enemy: 1500 tris
  • Textures loaded to memory in a given level: 6 texture files 2048*2048 each
    -Renderer : Forward
    -FInal shading method (most likely): unlit shaders with baked information
    -Lowest target : Samsung A50 2019
    -Maximum Target device : Best iphone \ anroid phone

I would love for any insight on that : )

i think before worrying about performance you should start by having a proof of concept.

too early performance can hurt more than help.

a widget component that you activate/deactivate only when needed might give you the best tradeoff of practicality and performance.

1 Like

i believe the best method is niagara, Lyra uses this so you can steal their system.

but for 25 Objects its probably doesnt matter

1 Like

Hi there, my approach is something like below, it is quite performant.

  1. NS: Have a Niagara System that spawns a mesh (quad) with dynamic material instance and variables exposed. I spawn for up to 3 digits spawn single particle, however it can be per digit particle too. All digits together easier to control and nicer effects in terms of physics, drags, size changes etc.

  2. Metarial : Build your material, something that is light weight. There is a node ready for converting numbers, however if you want a custom one for artistic and other reason, you better create your node or function. You can have a simple 0-9 flip book and select frame at index and assemble your digits or you can seperate images if you wish. I am using a sprite sheet classic with UV drags.

  3. OnDamage receive, after whatever the steps you have in your systems when true damage calculated we pass that digit to a function. That spawns the niagara and gives variables. At this stage it is better to keep niagara and material instance active per user/actor, so we can just spawn the particle and reset system instead of killing, that would be much more nicer for limited hardware. For these I generally use an encapsulated actor component UDamageFeedbackComponent that does many things, flash enemy outline, set an icon overhead for status also a CombatTextFlow (damage etc that we are talking)

For materials masked domain think can be a better mobile fit. Since we use a single quad you don’t have to worry about polycount. Unlit shaders are fine for material and niagara. I didn’t test these on mobile but should be fine.

If you want to avoid Niagara, you can simply go oldschool, put a quad on top of your characters, animate the material with direction + fade and you will even have more optimised system. It really depends on the end results desired with in the current sandbox of constraints.

void UMGDamageFeedbackComponent::ReplayFloatingText(UNiagaraComponent* NiagaraComp, float DamageAmount, const FVector& ImpactLocation)
{
	if (!IsValid(NiagaraComp))
	{
		return;
	}

	// I use a location and this one checks material and sets then activate.
	// However it wont look very nice if there is dps more than the length of niagara
	// You can spawn or pool couple of systems and re use them.
	FVector SpawnLoc = ImpactLocation;
	SpawnLoc.Z += 50.f;
	NiagaraComp->SetWorldLocation(SpawnLoc);

	NiagaraComp->SetVariableFloat(DamageVariableName, DamageAmount);

	if (FloatingTextMaterial)
	{
		if (!IsValid(CachedFloatingTextMID))
		{
			CachedFloatingTextMID = UMaterialInstanceDynamic::Create(FloatingTextMaterial, this);
		}

		if (CachedFloatingTextMID)
		{
			NiagaraComp->SetVariableMaterial(FName("Material Interface"), CachedFloatingTextMID);
			CachedFloatingTextMID->SetScalarParameterValue(DamageVariableName, DamageAmount);
		}
	}

	NiagaraComp->DeactivateImmediate();
	NiagaraComp->Activate(true);
}

Material Function to convert 3 digit numbers into sprite sheet digits

Material used in floating text for niagara, I also fixed zero digits selected as prefix now it works nice.

Niagara

Untested in mobile

2 Likes

Made a custom node, I think this works better in terms of accuracy in digits.

float n = floor(abs(V));
float d0 = n - 10 * floor(n / 10);        // ones
float d1 = floor(n / 10) - 10 * floor(n / 100);   // tens
float d2 = floor(n / 100) - 10 * floor(n / 1000); // hundreds
return float3(d0, d1, d2);

1 Like

Im not sure what you meant by proof of concept. concept of what ?

i mean get something working. a concept of what you want to achieve. because it sounds like you are sure which way to implement it. also i struggle to understand exactly what you are aiming for. maybe a screenshot of a similar effect on another game could be nice.

though i think maybe the niagara text might be your best option.

Wow ! Thank you so much sir for the detailed explanation and examples.

I guess changing a number on a texture material is using the GPU, should be better for my case.
Do we know what is the cost of using niagara particles for that compared to shader tree of the material? (such as your first solution)

Niagara does look cool, Its a question of performance for me. this specific task is more about communicating to the player his item’s power in battle, i prefer that the processing power will be used on other things, such as the skills fx for examples. there i will use niagara as much as i can to make it cool

Each “bullet” is very intelligent and carry with it some good amount of behavior, on high attack speed and multi-shot it might get too much on old phones. this is why i try to save power where is possible

1 Like

I understand. The game is 6-ish months into development, its beyond basic prototype and its time to add some visual elements into it.

1 Like

ah good, i meant a proof of concept of the feature not the game. i still struggle to get what you’re trying to achieve. there are several ways to implement it.

if performance is what you care about, just a note: niagara particles are very performant when spawning and animating multiple instances. just beware that you can have gpu and cpu particles. both have their pros and cons. and while gpu particles might sound like a good choice, nowadays gpu are the usual bottleneck and cpu are under utilized, so depending on your game you can choose different things. also cpu particles can have a dynamic bound iirc. which means your actor can move and new particles emit in different positions, while the previous particles stays in place. you can do the same with gpu, but the bounds could be an issue.