Added linear interpolation between states
This commit is contained in:
parent
5e7bff96d0
commit
d2ce7bc506
|
@ -20,7 +20,7 @@
|
||||||
#define ENABLE_CLIENT_SIDE_PREDICTION
|
#define ENABLE_CLIENT_SIDE_PREDICTION
|
||||||
#define ENABLE_SERVER_RECONCILLIATION
|
#define ENABLE_SERVER_RECONCILLIATION
|
||||||
|
|
||||||
uint8_t colours[16][3] =
|
const uint8_t colours[16][3] =
|
||||||
{
|
{
|
||||||
{255, 255, 255},
|
{255, 255, 255},
|
||||||
{100, 176, 254},
|
{100, 176, 254},
|
||||||
|
@ -117,9 +117,11 @@ void * networkHandler(void * parameters)
|
||||||
recvfrom(udpSocket, updatedState, sizeof(struct gameState), 0, NULL, NULL);
|
recvfrom(udpSocket, updatedState, sizeof(struct gameState), 0, NULL, NULL);
|
||||||
|
|
||||||
// Only update the state if the given state is more recent than the current state:
|
// Only update the state if the given state is more recent than the current state:
|
||||||
if(updatedState->timestamp.tv_sec > arguments->state->timestamp.tv_sec)
|
if(updatedState->timestamp.tv_sec > arguments->state->timestamp.tv_sec ||
|
||||||
{
|
(updatedState->timestamp.tv_sec == arguments->state->timestamp.tv_sec &&
|
||||||
memcpy(arguments->state, updatedState, sizeof(struct gameState));
|
updatedState->timestamp.tv_usec > arguments->state->timestamp.tv_usec))
|
||||||
|
{
|
||||||
|
// memcpy(arguments->state, updatedState, sizeof(struct gameState));
|
||||||
#ifdef ENABLE_SERVER_RECONCILLIATION
|
#ifdef ENABLE_SERVER_RECONCILLIATION
|
||||||
// Throw away any already acknowledged inputs:
|
// Throw away any already acknowledged inputs:
|
||||||
while (arguments->inputBuffer->start != -1 &&
|
while (arguments->inputBuffer->start != -1 &&
|
||||||
|
@ -148,46 +150,16 @@ void * networkHandler(void * parameters)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if(updatedState->timestamp.tv_sec == arguments->state->timestamp.tv_sec &&
|
lerpStates(arguments->state, updatedState);
|
||||||
updatedState->timestamp.tv_usec > arguments->state->timestamp.tv_usec)
|
|
||||||
{
|
|
||||||
memcpy(arguments->state, updatedState, sizeof(struct gameState));
|
|
||||||
#ifdef ENABLE_SERVER_RECONCILLIATION
|
|
||||||
// Throw away any already acknowledged inputs:
|
|
||||||
while (arguments->inputBuffer->start != -1 &&
|
|
||||||
arguments->inputBuffer->inputs[arguments->inputBuffer->start].tickNumber < arguments->state->tickNumber)
|
|
||||||
{
|
|
||||||
arguments->inputBuffer->start = (arguments->inputBuffer->start + 1) % 256;
|
|
||||||
if(arguments->inputBuffer->start == arguments->inputBuffer->end)
|
|
||||||
{
|
|
||||||
arguments->inputBuffer->start = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t currentMessage = arguments->inputBuffer->start;
|
|
||||||
uint64_t lastTickNumber = arguments->inputBuffer->inputs[arguments->inputBuffer->start].tickNumber;
|
|
||||||
|
|
||||||
// Re-apply the currently unused messages:
|
|
||||||
while (currentMessage != 1 &&
|
|
||||||
currentMessage != arguments->inputBuffer->end)
|
|
||||||
{
|
|
||||||
updateInput(arguments->state, &arguments->inputBuffer->inputs[currentMessage]);
|
|
||||||
currentMessage = (currentMessage + 1) % 256;
|
|
||||||
if (arguments->inputBuffer->inputs[currentMessage].tickNumber != lastTickNumber)
|
|
||||||
{
|
|
||||||
doGameTick(arguments->state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void * gameThreadHandler(void * parameters)
|
void * gameThreadHandler(void * parameters)
|
||||||
{
|
{
|
||||||
struct threadParameters * arguments = parameters;
|
struct threadParameters * arguments = parameters;
|
||||||
|
|
||||||
#ifdef ENABLE_CLIENT_SIDE_PREDICTION
|
#ifdef ENABLE_CLIENT_SIDE_PREDICTION
|
||||||
|
struct gameState * nextStep = calloc(1, sizeof(struct gameState));
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
updateInput(arguments->state, arguments->message);
|
updateInput(arguments->state, arguments->message);
|
||||||
|
@ -204,7 +176,9 @@ void * gameThreadHandler(void * parameters)
|
||||||
arguments->inputBuffer->end = (arguments->inputBuffer->end + 1) % 256;
|
arguments->inputBuffer->end = (arguments->inputBuffer->end + 1) % 256;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
doGameTick(arguments->state);
|
memcpy(nextStep, arguments->state, sizeof(struct gameState));
|
||||||
|
doGameTick(nextStep);
|
||||||
|
lerpStates(arguments->state, nextStep);
|
||||||
usleep(15625);
|
usleep(15625);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include "cspt-state.h"
|
#include "cspt-state.h"
|
||||||
|
|
||||||
void updateInput(struct gameState * state, struct clientInput * message)
|
void updateInput(struct gameState * state, struct clientInput * message)
|
||||||
|
@ -11,7 +16,28 @@ void updateInput(struct gameState * state, struct clientInput * message)
|
||||||
state->clients[message->clientNumber].upAcceleration = message->up;
|
state->clients[message->clientNumber].upAcceleration = message->up;
|
||||||
state->clients[message->clientNumber].downAcceleration = message->down;
|
state->clients[message->clientNumber].downAcceleration = message->down;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lerpStates (struct gameState * state, struct gameState * endState)
|
||||||
|
{
|
||||||
|
// Create a copy of the initial state for interpolating to the final state:
|
||||||
|
struct gameState * startState = calloc(1, sizeof(struct gameState));
|
||||||
|
memcpy(startState, state, sizeof(struct gameState));
|
||||||
|
|
||||||
|
for (double progress = 0.0; progress < 1.0; progress += 0.01)
|
||||||
|
{
|
||||||
|
for (uint8_t index = 0; index < 16; index++)
|
||||||
|
{
|
||||||
|
// Movement:
|
||||||
|
state->clients[index].xPosition = startState->clients[index].xPosition +
|
||||||
|
(progress * (endState->clients[index].xPosition - startState->clients[index].xPosition));
|
||||||
|
state->clients[index].yPosition = startState->clients[index].yPosition +
|
||||||
|
(progress * (endState->clients[index].yPosition - startState->clients[index].yPosition));
|
||||||
|
}
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
free(startState);
|
||||||
|
memcpy(state, endState, sizeof(struct gameState));
|
||||||
}
|
}
|
||||||
|
|
||||||
void doGameTick(struct gameState * state)
|
void doGameTick(struct gameState * state)
|
||||||
|
|
|
@ -39,6 +39,8 @@ struct inputHistory
|
||||||
|
|
||||||
void updateInput(struct gameState * state, struct clientInput * message);
|
void updateInput(struct gameState * state, struct clientInput * message);
|
||||||
|
|
||||||
|
void lerpStates (struct gameState * state, struct gameState * endState);
|
||||||
|
|
||||||
void doGameTick(struct gameState * state);
|
void doGameTick(struct gameState * state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue