Hi there, my approach is something like below, it is quite performant.
-
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.
-
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.
-
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





