Skip to content

Instantly share code, notes, and snippets.

@Vanlalhriata
Created June 27, 2019 09:48
Show Gist options
  • Save Vanlalhriata/4b5004ab4746149a30126204fb5ee225 to your computer and use it in GitHub Desktop.
Save Vanlalhriata/4b5004ab4746149a30126204fb5ee225 to your computer and use it in GitHub Desktop.
Parallax sprites. Infinite horizontal scrolling. Moving camera. Unity.
using UnityEngine;
// Move background as the camera moves, the amount (moveFactor) depending on how far ([0,inf)) it is from the player.
// The sprite is repeated to the left and right to accomodate infinite horizontal scrolling. Infinite scrolling is achieved
// by moving the 3-sprite set by steps of the sprite width whenever the camera crosses the center of the left or right sprite.
// Since each instance of this component may have a different moveFactor, the absolute position at which this crossing of the
// left or right sprite's center also differs, and is therefore a calculated value (stepThreshold). For example, stepThreshold
// is sprite width when Distance is 0, since the background is stationary. For Distance of 1, stepThreshold is infinity since
// the background moves with the camera and thus the camera is always at the center of the sprite set, never crossing the left or right centers.
// Note:
// - Place sprite objects as children to this game object. This script will move this game object and its children (including the two generated sprites)
// as a whole. This also allows you to position the sprite how you want it.
// - This game object is assumed to be at (0,0). Children sprites can be moved around as desired.
// - Make sure you have a main camera in the scene.
public class BackgroundParallax : MonoBehaviour
{
[Tooltip("Distance of the background ranging from 0 to infinity (value of 1). Cannot be changed during runtime.")]
[Range(0,1)]
public float Distance;
private Transform cameraTransform;
private float initialCameraY;
private float stepThreshold; // The absolute horizontal distance at which to step-move sprites.
private Vector3 lastCameraPosition;
// The factor by which backgrounds will move wrt camera movement
private float moveFactor;
internal void Awake()
{
cameraTransform = Camera.main.transform;
initialCameraY = cameraTransform.position.y;
lastCameraPosition = Vector3.zero; // Assuming background x and camera start at 0;
// moveFactor = Mathf.Sin(Distance * Mathf.PI / 2f);
moveFactor = Distance;
var spriteRenderer = GetComponentInChildren<SpriteRenderer>();
if (null == spriteRenderer)
{
Debug.LogError("BackgroundParallax: Could not find SpriteRenderer component in children.");
}
stepThreshold = spriteRenderer.bounds.size.x / (1 - moveFactor); // Derived using brute force manual regression, not logic
Debug.Log(stepThreshold);
repeatSprites(spriteRenderer);
}
internal void FixedUpdate()
{
if (!cameraTransform.position.Equals(lastCameraPosition))
{
var x = getX();
var y = moveFactor * (cameraTransform.position.y - initialCameraY);
transform.position = new Vector3(x, y, transform.position.z);
lastCameraPosition = cameraTransform.position;
}
}
private void repeatSprites(SpriteRenderer spriteRenderer)
{
var spriteObject = spriteRenderer.gameObject;
var displacement = spriteRenderer.bounds.size.x;
// Left
GameObject.Instantiate(
spriteObject,
spriteObject.transform.position - new Vector3(displacement,0),
spriteObject.transform.rotation,
transform
);
// Right
GameObject.Instantiate(
spriteObject,
spriteObject.transform.position + new Vector3(displacement, 0),
spriteObject.transform.rotation,
transform
);
}
private float getX()
{
var cameraDistance = cameraTransform.position.x;
var distanceFromThreshold = cameraDistance % stepThreshold;
var thresholdCrossed = cameraDistance - distanceFromThreshold;
// Treat the threshold crossed point as the (new) center and move the background according to moveFactor.
// The effective cameraDistance to be considered with the new center is now the distance from the threshold crossed.
var x = thresholdCrossed + (distanceFromThreshold * moveFactor);
return x;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment