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.

2 Likes

@nande Thank you sir.

Do we know of an epic unreal lecture that compared niagara to other methods while spawning stuff? or do you know any video that demonstrate that while focusing on performance ?

By the way, i will have to touch niagara eventually, for the Fx’s later on in the development. kinda scary tbh.

1 Like

No worries. For performance I didn’t see any effect on my game, I have 120fps constant on 3080.

For mobile its another scenario, I don’t want to misdirect you about it so better test it a bit see how it goes.

Also I can make couple of advices at this stage without knowing your game so consider or neglect what I say on your side since I don’t want to interfere your system or knowledge.

  • This niagara stuff is good when you have a mid/big monitor maybe a 3rd person or 1st person game or even topdown, however I am not sure it would be the best choice for mobile especially with tiny screens. If the actors are too tiny, its top down game can be hard to control sizings in the screen for player. You could even end up writing a middle ware for controlling sizings these between small screens and tablet screens for example. However it really depends also how important these are in your game as player feedback.
  • Floating combat text can be achieved with UMG also, eventually you will have a HUD in your game. You can just make a layer as HUD_Indicators_WGT and insert entries as Indicator_CombatText_WGT. Goes in sets text to its text layer, gets actor’s location and converts it to screen space , plays animation and goes away. Even widgets can be pooled like 10 of them they go collapsed until they are re used. This also should be quite efficient if crafted well and can be more readable player UX wise with the UMG framework. Screen sizings etc are more clear and scaling would be easier.
  • Floating Combat Text system you can limit it, like max 10 can be displayed at the same time on screen. This can be good for both readability and performance. If limit reached it’s ignored or re used from pool. Can be even conditions like : IF (CurrentCount= MaxCount & CurrentImpactType = EImpactTypeCritical) Spawn text else ignore etc.
  • Pool weapon projectilles, avoid projectile even where you can, go hitscan where possible, use niagara for projectille visual representations.

I would like to see what you do and end results sometime or hear about your findings on mobile side so we can have some insights.

1 Like

Hey thank for this info.Considering your points i will go with a component of UMG. i might even create a test project with it and play with the profiler before implement it into the actual project.

About the projectile, i used that term to describe an object being shot. its actually just an actor with timer on it that moves the actor with set transform. depends on its move interface. While designing this game i wanted to try something else in the mobile MID-core space and see how it goes.

Not having a hit scan allows me to create interesting ways for bullets to fly around and carry logic

2 Likes

all good. hmmm i can’t really add more than what grimnir said. he exposed it really well.

i can only add emphasis to what i think it’s important.

with performance it’s always important to test, and never make assumptions. it always depends on your project.

that’s a good idea, i thought about it, but i thought it would require some skill to make it work, and it might be complicated if the player can move the camera.

when using umg, components, actors, and other uobjects pooling is very important.

capping the amount of text is also a good technique.

i do not know. that’s a very specific thing, so i wouldn’t think there is. i do know that particles systems are meant to handle many instances of objects efficiently. the whole system is designed to have multiple instances spawning and respawning. at the sacrifice of having to make all instances generically and having a lightweight state. my intuition tells me that particles would be the most performant, but testing is ideal. also it’s good to explore different approaches so you can figure out the pros and cons of each for your specific game. Particles would be faster to spawn than uobjects i think. but if you use a pooling system that might be negligible. (i have a foss one if you want it). I would assume that particles memory consumption would be lower. As well as the time it takes to tick.

“best practices” is an oxymoron really, as “best” is always relative to a goal, and that goal is only known to you and your project. nobody can choose for you.

also, performance is not a good primary concern (and i try to specialize on performance), there’s also maintainability, ease of implementation, fun, and aesthetics; though particles can also achieve those, so it’s not a reason to ditch particles.

the problem i can see with particles is setting the start position for each particle. you might need a particle system component for each enemy on screen.

don’t be scared, niagara is pretty simple once you get how it works. there are plenty of tutorials and templates. i recommend you to play a little bit with it, at least to start getting to know it.

2 Likes