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, int currenttick, int timeintick)
 Interpolates states for component. More...
 
template<class ComponentT >
static void AdjustClock (ComponentT &entitycomponent)
 

Detailed Description

Definition at line 10 of file StateInterpolator.h.

Member Function Documentation

◆ AdjustClock()

template<class ComponentT >
static void Leviathan::StateInterpolator::AdjustClock ( ComponentT &  entitycomponent)
inlinestatic

Definition at line 128 of file StateInterpolator.h.

129  {
130  const auto difference = entitycomponent->InterpolatingStartState->TickNumber
131  - entitycomponent->InterpolatingRemoteStartTick;
132 
133  entitycomponent->InterpolatingStartTime += difference * TICKSPEED;
134  entitycomponent->InterpolatingRemoteStartTick =
135  entitycomponent->InterpolatingStartState->TickNumber;
136  }
constexpr auto TICKSPEED
Number of milliseconds between engine and world ticks.
Definition: Define.h:22

◆ Interpolate()

template<class StateT , class ComponentT >
static std::tuple<bool, StateT> Leviathan::StateInterpolator::Interpolate ( const StateHolder< StateT > &  stateholder,
ObjectID  entity,
ComponentT *  entitycomponent,
int  currenttick,
int  timeintick 
)
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

Definition at line 21 of file StateInterpolator.h.

23  {
24  // TODO: should this be stored in the component?
25  auto* entitysStates = stateholder.GetEntityStates(entity);
26 
27  if(!entitysStates){
28  // Probably shouldn't throw here to make the code that uses this simpler
29  entitycomponent->StateMarked = false;
30  return std::make_tuple(false, StateT());
31  //throw Leviathan::InvalidState("Interpolated entity has no states in StateHolder");
32  }
33 
34  // Find interpolation start spot //
35  if(!entitycomponent->InterpolatingStartState ||
36  !entitysStates->IsStateValid(entitycomponent->InterpolatingStartState))
37  {
38  entitycomponent->InterpolatingEndState = nullptr;
39  entitycomponent->InterpolatingStartState = entitysStates->GetOldest();
40 
41  if(!entitycomponent->InterpolatingStartState){
42 
43  // No states to interpolate //
44  entitycomponent->StateMarked = false;
45  return std::make_tuple(false, StateT());
46  }
47 
48  // Adjust clock if the initial tick has been changed //
49  if(entitycomponent->InterpolatingStartTime != 0.f){
50 
51  if(entitycomponent->InterpolatingRemoteStartTick !=
52  entitycomponent->InterpolatingStartState->TickNumber)
53  {
54  AdjustClock(entitycomponent);
55  }
56  }
57  }
58 
59  // We cast the time from int64_t to float (visual studio was giving warnings about
60  // losing data here)
61  const float currentTime = static_cast<float>((currenttick * TICKSPEED) + timeintick);
62 
63  // Find ending state //
64  if(!entitycomponent->InterpolatingEndState){
65 
66  // TODO: should we only allow TickNumber + 2 states to be interpolated to
67  // as that is the way source engine does it and would avoid jitter if we miss
68  // one state packet later (use INTERPOLATION_TIME / TICKSPEED ?)
69  entitycomponent->InterpolatingEndState = entitysStates->GetMatchingOrNewer(
70  entitycomponent->InterpolatingStartState->TickNumber + 1);
71 
72  if(!entitycomponent->InterpolatingEndState){
73 
74  // No ending state found //
75  entitycomponent->StateMarked = false;
76  // Only one state should allow interpolating to the one available state
77  // with the same function so we return the first state here
78  //return std::make_tuple(false, StateT());
79  return std::make_tuple(true, *entitycomponent->InterpolatingStartState);
80  }
81 
82  // Initialize the remote time counter if this is the first time we start
83  // interpolating
84  if(entitycomponent->InterpolatingStartTime == 0.f){
85  entitycomponent->InterpolatingStartTime = currentTime;
86  entitycomponent->InterpolatingRemoteStartTick =
87  entitycomponent->InterpolatingStartState->TickNumber;
88  }
89  }
90 
91  const float passed = currentTime - entitycomponent->InterpolatingStartTime;
92 
93  // TODO: do we need to check for currentTime < 0?
94 
95  if(passed <= EPSILON)
96  return std::make_tuple(true, *entitycomponent->InterpolatingStartState);
97 
98  // Duration is clamped to INTERPOLATION_TIME to make entities
99  // that have stopped moving not take a ridiculously long time
100  // to move to their new positions
101  const auto duration = std::min((
102  entitycomponent->InterpolatingEndState->TickNumber -
103  entitycomponent->InterpolatingStartState->TickNumber) * TICKSPEED,
105 
106  if(passed == duration)
107  return std::make_tuple(true, *entitycomponent->InterpolatingEndState);
108 
109  // Check for having finished interpolating //
110  if(passed > duration){
111 
112  entitycomponent->InterpolatingStartState = entitycomponent->InterpolatingEndState;
113  entitycomponent->InterpolatingEndState = nullptr;
114 
115  AdjustClock(entitycomponent);
116 
117  // We need to recurse to get the correct interpolation state //
118  return Interpolate(stateholder, entity, entitycomponent, currenttick, timeintick);
119  }
120 
121  const float progress = passed / duration;
122 
123  return std::make_tuple(true, entitycomponent->InterpolatingStartState->Interpolate(
124  *entitycomponent->InterpolatingEndState, progress));
125  }
constexpr auto INTERPOLATION_TIME
Definition: Define.h:25
constexpr auto TICKSPEED
Number of milliseconds between engine and world ticks.
Definition: Define.h:22
static std::tuple< bool, StateT > Interpolate(const StateHolder< StateT > &stateholder, ObjectID entity, ComponentT *entitycomponent, int currenttick, int timeintick)
Interpolates states for component.
static void AdjustClock(ComponentT &entitycomponent)
constexpr float EPSILON
Definition: Define.h:63

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