From e96adda2c2dc2d00108bf77551a6e1a41846a222 Mon Sep 17 00:00:00 2001 From: Jeremiah Billmann Date: Wed, 20 May 2015 00:59:05 +0000 Subject: [PATCH] Refactoring client side prediction for players to make for consistent API calls with client side prediction for entities (#20) --- client/garageserver.io.js | 15 +++++++++++++-- documentation/ClientAPI.md | 11 ++++++----- documentation/QuickStart.md | 17 +++++++++-------- example/public/javascripts/game.js | 4 +++- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/client/garageserver.io.js b/client/garageserver.io.js index e58769e..4db2177 100644 --- a/client/garageserver.io.js +++ b/client/garageserver.io.js @@ -10,7 +10,7 @@ options = { onEvent(callback(data)), onWorldState(callback(state)), onPing(callback(pingDelay)), - onUpdatePlayerPrediction(callback(currentState, inputs, deltaTime) : newState), + onUpdateClientPredictionReady(callback(playerId, playerCurrentState, inputs, deltaTime)), onInterpolation(callback(previousState, targetState, amount) : newState), onReady(callback), logging: true @@ -20,6 +20,7 @@ api methods addInput(input) getPlayerStates : [, playerState] getEntityStates : [, entityState] + updatePlayerState(id, state) getId() : playerid sendServerEvent(data) */ @@ -301,7 +302,7 @@ var GarageServerIO = (function (socketio) { if (player.id === _stateController.id) { if (_stateController.clientSidePrediction && _options.onUpdatePlayerPrediction) { player.inputController.add(clientInput); - player.state = _options.onUpdatePlayerPrediction(player.state, [{ input: clientInput }], _stateController.physicsDelta); + _options.onUpdateClientPredictionReady(player.state, [{ input: clientInput }], _stateController.physicsDelta); } _socket.emit('i', [ clientInput, player.inputController.sequenceNumber, _stateController.renderTime ]); } @@ -339,6 +340,15 @@ var GarageServerIO = (function (socketio) { return entityStates; }, + + updatePlayerState = function (id, state) { + _playerController.entities.some(function(player) { + if (player.id === id) { + player.state = state; + return true; + } + }); + }, removePlayer = function (id) { _playerController.remove(id); @@ -428,6 +438,7 @@ var GarageServerIO = (function (socketio) { addInput: addInput, getPlayerStates: getPlayerStates, getEntityStates: getEntityStates, + updatePlayerState: updatePlayerState, getId: getId, sendServerEvent: sendServerEvent }; diff --git a/documentation/ClientAPI.md b/documentation/ClientAPI.md index 20a4091..9111199 100644 --- a/documentation/ClientAPI.md +++ b/documentation/ClientAPI.md @@ -113,16 +113,17 @@ The current ping in milliseconds. --- ```js -options.onUpdatePlayerPrediction(callback(currentState, inputs, deltaTime) : newState) +options.onUpdateClientPredictionReady(callback(playerId, playerCurrentState, inputs, deltaTime)) ``` -**_Returns:_ object literal** - -If using client side prediction, this callback should return the new state, `newState`, based on the current state, inputs to be processed, and the delta time. +If using client side prediction, this callback will fire when you should update player and entity states, based on the current states for player and entities, inputs to be processed, and the delta time. `callback` **function** Function to be invoked upon event firing. -`currentState` **object literal** +`playerId` **string** +The id of the player. + +`playerCurrentState` **object literal** The current state of the player. `inputs` **array** diff --git a/documentation/QuickStart.md b/documentation/QuickStart.md index 4e010cd..cca9dad 100644 --- a/documentation/QuickStart.md +++ b/documentation/QuickStart.md @@ -52,19 +52,20 @@ GarageServerIO.initializeGarageServer('http://insertmygameserverurlhere.com', { onReady: function () { // Call your game loop }, - onUpdatePlayerPrediction: function (state, inputs, deltaTime) { + onUpdateClientPredictionReady: function (playerId, playerCurrentState, inputs, deltaTime) { var newState = {}; - if (!player.state.x) { - player.state.x = 0; + if (!playerCurrentState.x) { + playerCurrentState.x = 0; } - for (i = 0; i < player.inputs.length; i ++) { - if (player.inputs[i].input === 'left') { - newState.x = player.state.x - (50 * deltaTime); + + for (i = 0; i < inputs.length; i ++) { + if (inputs[i].input === 'left') { + newState.x = playerCurrentState.x - (50 * deltaTime); } else if (inputs[i].input === 'right') { - newState.x = player.state.x + (50 * deltaTime); + newState.x = playerCurrentState.x + (50 * deltaTime); } } - return newState; + GarageServerIO.updatePlayerState(playerid, newState); }, onInterpolation: function (previousState, targetState, amount) { return { x: (previousState.x + amount * (targetState.x - previousState.x)) }; diff --git a/example/public/javascripts/game.js b/example/public/javascripts/game.js index 151883c..3cbe541 100644 --- a/example/public/javascripts/game.js +++ b/example/public/javascripts/game.js @@ -10,7 +10,9 @@ $(function () { GarageServerIO.initializeGarageServer('', { logging: true, onReady: startGame, - onUpdatePlayerPrediction: GamePhysics.getNewPlayerState, + onUpdateClientPredictionReady: function(playerId, playerCurrentState, inputs, deltaTime) { + GarageServerIO.updatePlayerState(playerId, GamePhysics.getNewPlayerState(playerCurrentState, inputs, deltaTime)); + }, onInterpolation: GamePhysics.getInterpolatedState });