Our game performs 10 logical frames per second, so let’s say a unit has an attack speed of 0.3 seconds to attack once, which is programmed to attack once in 3 logical frames.
If it eats an attack speed plus 100% bonus, then its attack speed becomes 1.5 logic frames for 1 attack, what happens at such times?
Would it turn its attack speed into 2 logic frames for 1 attack because it can’t round up?
Or would it become in a cycle of every 3 logic frames, attacking 1 time on the 2nd logic frame and 1 time on the 3rd logic frame, and so on? (No attack, attack, attack, no attack, attack, attack)
Rounding and throwing away the remainder or rounding and accumulating the remainders (the two examples you gave) are options.
Unclear what you are asking here, it’s your system so you are going to need to decide and implement it. And that is the answer to the question “what happens at such times?”, whatever you decide.
What we want to achieve is that it doesn’t just start logical frame 2 at 150ms just because the next thing that should be executed is located at 150ms, which would cause substantial game acceleration, and we don’t want that, we want it to jump 1 logical frame every 100ms no matter what happens, as long as there is enough arithmetic to do it, and not at 150ms because it needs to make a logical frame at 150ms, instead of jumping to logical frame 2 at 150ms because it needs to perform an action in a logical frame.
At the same time, it should make sure that each event is executed in full, it won’t change its attack rate to 1 time in 2 logical frames because it doesn’t have enough logical frames, it should attack at 150ms once, so it will attack once in both logical frames 2 and 3
Frame: A logical update, 100ms delta. Action: A thing to do (e.g. attack) Length: The number of frames it takes to complete one action, as a float because we want to support fractions (this is the 3 and buffed 1.5 from your example).
The variables FramesToAction and Length need to be stored per unit, so the unit would be the logical place for them to reside (could be elsewhere as long as they are per unit, putting them in the unit avoids indirection and should be preferred unless you have good reason to put them somewhere else).
As to how to implement it in Blueprint (or C++ for that matter) it of course depends on how you are doing other things (the ‘actions’ in particular). While your first post suggested you had something implemented, I gather from the conversation since this is probably not the case, so instead of asking how that is implemented (because I’m guessing it’s not) I’ll just make assumptions.
The big assumption being that your actions are a bp class (or a class zoo with a common base class) containing a function that takes a Unit as parameter and has that unit perform whatever action it represents.