Leviathan  0.8.0.0
Leviathan game engine
Leviathan::StateInterpolator Class Reference

#include <StateInterpolator.h>

Static Public Member Functions

template<class StateT , class ComponentT >
static std::tuple< bool, StateT > Interpolate (const StateHolder< StateT > &stateholder, ObjectID entity, ComponentT *entitycomponent, float elapsed)
 Interpolates states for component. More...
 

Detailed Description

Definition at line 10 of file StateInterpolator.h.

Member Function Documentation

◆ Interpolate()

template<class StateT , class ComponentT >
static std::tuple<bool, StateT> Leviathan::StateInterpolator::Interpolate ( const StateHolder< StateT > &  stateholder,
ObjectID  entity,
ComponentT *  entitycomponent,
float  elapsed 
)
inlinestatic

Interpolates states for component.

Will update the interpolation variables in the component (which should be derived from ComponentWithStates) Our caller should also check ComponentWithStates::StateMarked before calling us

Returns
Tuple of state valid and state. If the bool is false StateT will be garbage
Todo:
Would it make more sense to have the current world time as a parameter to? As interpolating to previous time might be needed at some point? Or as a separate method?

Definition at line 22 of file StateInterpolator.h.

24  {
25  // TODO: should this be stored in the component?
26  auto* entitysStates = stateholder.GetEntityStates(entity);
27 
28  if(!entitysStates) {
29  // Probably shouldn't throw here to make the code that uses this simpler
30  entitycomponent->StateMarked = false;
31  return std::make_tuple(false, StateT());
32  // throw Leviathan::InvalidState("Interpolated entity has no states in
33  // StateHolder");
34  }
35 
36  // Find interpolation start spot //
37  if(!entitycomponent->InterpolatingStartState ||
38  !entitysStates->IsStateValid(entitycomponent->InterpolatingStartState)) {
39  entitycomponent->InterpolatingEndState = nullptr;
40  entitycomponent->InterpolatingStartState = entitysStates->GetOldest();
41 
42  if(!entitycomponent->InterpolatingStartState) {
43 
44  // No states to interpolate //
45  entitycomponent->StateMarked = false;
46  entitycomponent->TimeSinceStartState = 0;
47  return std::make_tuple(false, StateT());
48  }
49  }
50 
51  // Find ending state //
52  if(!entitycomponent->InterpolatingEndState) {
53 
54  // TODO: apply INTERPOLATION_TIME here to only start interpolation when we have
55  // many states
56 
57  // TODO: should we only allow TickNumber + 2 states to be interpolated to
58  // as that is the way source engine does it and would avoid jitter if we miss
59  // one state packet later (use INTERPOLATION_TIME / TICKSPEED ?)
60  entitycomponent->InterpolatingEndState =
61  entitysStates->GetNewer(entitycomponent->InterpolatingStartState->StateTime);
62 
63  if(!entitycomponent->InterpolatingEndState) {
64 
65  // No ending state found //
66  entitycomponent->StateMarked = false;
67  // Not sure if this time reset here is a good idea or not...
68  entitycomponent->TimeSinceStartState = 0;
69  // Only one state should allow interpolating to the one available state
70  // with the same function so we return the first state here
71  // return std::make_tuple(false, StateT());
72  return std::make_tuple(true, *entitycomponent->InterpolatingStartState);
73  }
74  }
75 
76  entitycomponent->TimeSinceStartState += elapsed;
77 
78  // Duration is clamped to INTERPOLATION_TIME to make entities
79  // that have stopped moving (and then started again) not take a ridiculously long time
80  // to move to their new positions
81  const auto duration = std::min(entitycomponent->InterpolatingEndState->StateTime -
82  entitycomponent->InterpolatingStartState->StateTime,
84 
85  // This is a very unlikely case
86  if(entitycomponent->TimeSinceStartState == duration)
87  return std::make_tuple(true, *entitycomponent->InterpolatingEndState);
88 
89  // Check for having finished interpolating //
90  if(entitycomponent->TimeSinceStartState > duration) {
91 
92  // Hold over time to the next interpolation interval
93  entitycomponent->TimeSinceStartState -= duration;
94 
95  entitycomponent->InterpolatingStartState = entitycomponent->InterpolatingEndState;
96  entitycomponent->InterpolatingEndState = nullptr;
97 
98  // We need to recurse to get the correct interpolation state //
99  // We pass zero here as no additional time has passed
100  return Interpolate(stateholder, entity, entitycomponent, 0.f);
101  }
102 
103  const float progress = entitycomponent->TimeSinceStartState / duration;
104 
105  return std::make_tuple(true, entitycomponent->InterpolatingStartState->Interpolate(
106  *entitycomponent->InterpolatingEndState, progress));
107  }
static std::tuple< bool, StateT > Interpolate(const StateHolder< StateT > &stateholder, ObjectID entity, ComponentT *entitycomponent, float elapsed)
Interpolates states for component.
constexpr auto INTERPOLATION_TIME
Time in seconds to interpolate entities between states.
Definition: Define.h:29

The documentation for this class was generated from the following file: