Leviathan  0.8.0.0
Leviathan game engine
StateInterpolator.h
Go to the documentation of this file.
1 // Leviathan Game Engine
2 // Copyright (c) 2012-2019 Henri Hyyryläinen
3 #pragma once
4 #include "Define.h"
5 // ------------------------------------ //
6 #include "StateHolder.h"
7 
8 namespace Leviathan {
9 
11 public:
21  template<class StateT, class ComponentT>
22  static std::tuple<bool, StateT> Interpolate(const StateHolder<StateT>& stateholder,
23  ObjectID entity, ComponentT* entitycomponent, float elapsed)
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  }
108 };
109 
110 
111 
112 
113 } // namespace Leviathan
int32_t ObjectID
Definition: EntityCommon.h:11
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
ObjectsComponentStates< StateT > const * GetEntityStates(ObjectID id) const
Returns a pointer to entity's states if they exist.
Definition: StateHolder.h:259
Holds state objects of type for quick access by ObjectID.
Definition: GameWorld.h:31
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12