How would I continue an object's movement in the same direction as per last user input?

If I have a Vector3 variable called movement and I feed this various pieces of user input (Vertical and Horizontal axis movement) how could I then have my code update this movement variable to continue moving in the same direction as per last input until new input is received?

What I’m trying to do is smooth multiplayer movement. So I have each player send their position once plus their movement vector (which is fed into Move()) and then lerp from the old position to the new one. But this is laggy from time to time so I’m trying to solve the lag. My idea was, continue moving the player using the last known movement vector and only lerp to the new position when a new position is received.

Is this a good solution to the problem of lag?

How do I continue the movement in the same direction as the Vector3 fed to Move()?

EDIT: I’ve tried numerous different things but there’s still slightly choppy movement or slingshot type behaviour when lerping to the next position. I still need help with prediction/interpolation.

If you’re problem is laggy movements over the network you can use the NetworkInterpolatedTransform:

using UnityEngine;
using System.Collections;

public class NetworkInterpolatedTransform : MonoBehaviour {
	
	public double interpolationBackTime = 0.1; 
	
	internal struct  State
	{
		internal double timestamp;
		internal Vector3 pos;
		internal Quaternion rot;
	}

	// We store twenty states with "playback" information
	State[] m_BufferedState = new State[20];
	// Keep track of what slots are used
	int m_TimestampCount;
	
	void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
	{
		// Always send transform (depending on reliability of the network view)
		if (stream.isWriting)
		{
			Vector3 pos = transform.localPosition;
			Quaternion rot = transform.localRotation;
			stream.Serialize(ref pos);
			stream.Serialize(ref rot);
		}
		// When receiving, buffer the information
		else
		{
			// Receive latest state information
			Vector3 pos = Vector3.zero;
			Quaternion rot = Quaternion.identity;
			stream.Serialize(ref pos);
			stream.Serialize(ref rot);
			
			// Shift buffer contents, oldest data erased, 18 becomes 19, ... , 0 becomes 1
			for (int i=m_BufferedState.Length-1;i>=1;i--)
			{
				m_BufferedState *= m_BufferedState[i-1];*
  •  	}*
    
  •  	// Save currect received state as 0 in the buffer, safe to overwrite after shifting*
    
  •  	State state;*
    
  •  	state.timestamp = info.timestamp;*
    
  •  	state.pos = pos;*
    
  •  	state.rot = rot;*
    
  •  	m_BufferedState[0] = state;*
    
  •  	// Increment state count but never exceed buffer size*
    
  •  	m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length);*
    
  •  	// Check integrity, lowest numbered state in the buffer is newest and so on*
    
  •  	for (int i=0;i<m_TimestampCount-1;i++)*
    
  •  	{*
    

if (m_BufferedState*.timestamp < m_BufferedState[i+1].timestamp)
_
Debug.Log(“State inconsistent”);_
_
}*_

* //Debug.Log("stamp: " + info.timestamp + "my time: " + Network.time + "delta: " + (Network.time - info.timestamp));*
* }*
* }*

* // This only runs where the component is enabled, which is only on remote peers (server/clients)*
* void Update () {*
* double currentTime = Network.time;*
* double interpolationTime = currentTime - interpolationBackTime;*
* // We have a window of interpolationBackTime where we basically play*
* // By having interpolationBackTime the average ping, you will usually use interpolation.*
* // And only if no more data arrives we will use extrapolation*

* // Use interpolation*
* // Check if latest state exceeds interpolation time, if this is the case then*
* // it is too old and extrapolation should be used*
* if (m_BufferedState[0].timestamp > interpolationTime)
_
{_
for (int i=0;i<m_TimestampCount;i++)
_
{_
_
// Find the state which matches the interpolation time (time+0.1) or use last state*_
if (m_BufferedState*.timestamp <= interpolationTime || i == m_TimestampCount-1)
_ {
// The state one slot newer (<100ms) than the best playback state*
* State rhs = m_BufferedState[Mathf.Max(i-1, 0)];*
* // The best playback state (closest to 100 ms old (default time))_
State lhs = m_BufferedState;*

* // Use the time between the two slots to determine if interpolation is necessary*
* double length = rhs.timestamp - lhs.timestamp;*
* float t = 0.0F;*
* // As the time difference gets closer to 100 ms t gets closer to 1 in*
* // which case rhs is only used*
* if (length > 0.0001)*
* t = (float)((interpolationTime - lhs.timestamp) / length);*

* // if t=0 => lhs is used directly*
* transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t);*
* transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t);*
* return;*
* }*
* }*
* }*
* // Use extrapolation. Here we do something really simple and just repeat the last*
* // received state. You can do clever stuff with predicting what should happen.*
* else*
* {*
* State latest = m_BufferedState[0];*

* transform.localPosition = latest.pos;*
* transform.localRotation = latest.rot;*
* }*
* }*
}
Sry for the long code but i couldn’t find it uploaded somewhere anymore and was to lazy to upload it myself :).
What you can do then is to add the script to the gameobject you have a networkView on and set the networkView’s observed to the script.
Worked for me. Hope it does for you too.
If you can’t use that script because you have another method for syncing movement (for example RPC’s) or you can’t use it for another reason let me know.