How do I make a 2D scrolling background with variable speed?

Hello,

I’ve got a working 2D scrolling background, using the following code:

public class Background : MonoBehaviour
{
	public bool CanScroll { get; set; }
	public float Speed
	{
		get { return _speed; }
		set { _speed = value; }
	}
	public float StartingSpeed
	{
		get { return _startingSpeed; }
	}

	[SerializeField] private float _startingSpeed = 0.1F;

	private Renderer _renderer;
	private float _speed;

	protected void Awake()
	{
		_renderer = GetComponent<Renderer>();
		CanScroll = true;
		_speed = _startingSpeed;
	}

	protected void Update()
	{
		if (!CanScroll) return;

		// Pretend to be endlessly scrolling
		float y = Mathf.Repeat(Time.time * _speed, 1);
		Vector2 offset = new Vector2(0, -y);
		_renderer.sharedMaterial.SetTextureOffset("_MainTex", offset);
	}
}

However, I want to be able to adjust _speed at runtime, and have it still scroll smoothly (or at least fake scrolling smoothly).

Currently when I adjust _speed at runtime, the background image will jump position very obviously, before switching to the new scrolling speed. And when I increase _speed in an Update loop, the background will suddenly scroll very quickly, when accelerating, then become slower when _speed stops increasing (that means when _speed is 15, it will be scrolling slower than when _speed is increasing, but at say 14.2, which doesn’t make sense to me).

Ideally, I want to be able to increase and decrease _speed from another script’s Update loop (through the Speed property) and have the background accelerate and decelerate smoothly.

Thanks for reading. Let me know if you need more information.

Here are some suggestions and an example that changes speed every 2 seconds with easing the speed.

  • don’t use Time.time to multiply your speed. When you change speed, you will get unpredictable position jumpings. Check out Time.deltaTime to be framerate independent.
  • store the actual speed, the desired speed and the texture position as seperate variables to get more control.
  • I’m unsure about your double private/publics and the custom get/set methods. I will leave it out in this example.

public class Background : MonoBehaviour {

	public bool CanScroll;
	
	private Renderer _renderer;
	public float _speed = 0.1f; //current scrolling speed
	private float _desiredSpeed; //desired scrolling speed
	private float _pos; //total texture offset
	private float _lastChange; //just for demonstration
	
	protected void Awake()
	{
		_renderer = GetComponent<Renderer>();
		CanScroll = true;

		_desiredSpeed = _speed;
		_lastChange = 0; //just for demonstration
	}
	
	protected void Update()
	{
		if (!CanScroll) return;

		//just for demonstration: change desired speed
		if (Time.time > _lastChange + 2) {
			_desiredSpeed = Random.Range(-2f, 2f);
			_lastChange = Time.time;
			Debug.Log ("Set Speed To " + _desiredSpeed);
		}

		//this is where the magic happens: easing by hand!
		//Play with the value 0.01f to speed up or slow down the easing. 
		_speed += (_desiredSpeed - _speed) * 0.01f;

		//add current speed to the position
		_pos += _speed * Time.deltaTime;
		
		//for me it works without Mathf.Repeat
		//float y = Mathf.Repeat(_pos, 1);
		Vector2 offset = new Vector2(0, _pos);
		_renderer.sharedMaterial.SetTextureOffset("_MainTex", offset);
	}
}

Hope this helps!

Try using a smooth damping Here to achieve smooth change in speed or use Lerp here